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.
- package/README.md +17 -4
- package/package.json +3 -2
- package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
- package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-OYLnAlB5.js → AIOps-DZwiXAIh.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-uc9kbLR6.js → ActionButton-aNzXoIJP.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BH901FG0.js → Analytics-ETQk4ZXt.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-qypKb8GL.js → AppLayout-D5oEbeEC.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-Q-uPWyLY.js → Artifacts-ja48FAne.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-B8hMGMim.js → Audit-DlN0YnDt.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BSs8rJL_.js → BackgroundAgents-CzvyNsRg.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-2YMU_nCd.js → Backup-DXgEC2MQ.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DyMppTuT.js → BaseInput-D9XqejLx.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-B5QGMaDO.js → Chat-BTwuYUlN.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-B8ts_JnN.js → ChatBubbleRenderer-0anIC2Wn.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-DAvtgEGd.js → Checkbox-CLuaQbDt.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BSChEVM3.js → Codegen-KwQUZs8A.js} +1 -1
- package/src/assets/web-panel/assets/{Col-G0zYohIP.js → Col-BCmROkzc.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CzCN0B_p.js → Community-CXlUEHR4.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DrIN3G8z.js → Compact-Dzx-lWI2.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CIsLa64Z.js → Compliance-CfXW82FF.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CGYoafsB.js → Cowork-DIISTRm2.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DJ1JPXuH.js → Cron-nyJ-KcFE.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-B-IqVFJl.js → Crosschain-Dtv1E4cV.js} +1 -1
- package/src/assets/web-panel/assets/{DID-CAAczPz_.js → DID-BCTpektS.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-Dkpel8VE.js → Dashboard-C1Q_m0So.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-ETNBf8-Z.js → Dropdown-BrQ5_PPL.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CJGDyjVD.js → EmailListRenderer-DjoNlONP.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-CL_hvVYe.js → EvolutionSettings-DaGaE6bX.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-iexOh6Dh.js → FamilyGuardDashboard-nJDWBECt.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DnDHvV5D.js → Federation-DhMUY_wG.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DLCDJjUp.js → FormItemContext-CbONJPuc.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CaCgXCjS.js → GenericCardRenderer-CDdX4dX-.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BVm-euUF.js → Git-DXbDVJdR.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DPnUvLWr.js → Governance-DbAfAvs1.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-5qCWSYKl.js → Inference-Dy-fGea2.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DXdv2oEh.js → KnowledgeGraph-DAxRpGUF.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BF2f7bBA.js → Logs-5L1UCR8X.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-u0FPafvT.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-Bp-0Y7Ng.js → Marketplace-DUk_McDG.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-dm-Xdi63.js → McpTools-B6PNsZ_p.js} +2 -2
- package/src/assets/web-panel/assets/{Memory-TBHK031z.js → Memory-BUUs8j5F.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BTILAlds.js → MobileBridge-pXRsgyuO.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DC0Clgzs.js → MobileProjects-D7v-2Hwm.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BvyWkmRw.js → Mtc-Deaj4faB.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-D7ksLoNa.js → MtcAudit-wUV0VUH1.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-Dpzu7X1t.js → Multisig-C67IIkts.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-DZ0ADHSB.js → NLProgramming-BCA_CWrW.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-hIdkmRug.js → Notes-D9eu14hQ.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-R3jyP6Vf.js → NotificationSettings-Cnd-J4LM.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-d1zrFkqx.js → OrderTableRenderer-C4pHUuyZ.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DoA5WMcc.js → Organization-4YExAbnp.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-DHjIloAQ.js → Overflow-BF-wFuZz.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-2TMon_Wy.js → P2P-CdiajqCT.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DEUxGSWO.js → PdhVaultBrowser-BkjfS6Th.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-CxKcZ-8X.js → Permissions-DrZ4D78_.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CcYtkHqc.js → PersonalDataHub-lDc6OXjz.js} +6 -6
- package/src/assets/web-panel/assets/{Pipeline-BxwOuq22.js → Pipeline-DqDS9ON1.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-VIx9pdsH.js → Privacy-BMekZRZu.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-COjp_erK.js → ProjectInit-LYS7NFvJ.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-x9NrZU80.js → ProjectSettings-CcJNHk9A.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DMgkw7QJ.js → Projects-DrfAHgdF.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-B_fR7Y7Y.js → Providers-aqsly9SR.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BUvzrn3V.js → QrScannerModal-ZWvR3zqg.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-C0sJwLy2.js → QuickAsk-BT5CgsvW.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CJC7Wpce.js → Recommend-Cz8Dz2RN.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-B62J6ZP0.js → RemoteSession-BlxPVbtQ.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-4f48kVBn.js → Reputation-B3VGBE-1.js} +1 -1
- package/src/assets/web-panel/assets/{Row-EzEMaYoV.js → Row-Bwv7vSEA.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-Dy0wD83j.js → RssFeed-DHI085r_.js} +3 -3
- package/src/assets/web-panel/assets/{Search-GeVRHQND.js → Search-DBler5T0.js} +1 -1
- package/src/assets/web-panel/assets/{Security-omLr1J7w.js → Security-BZdw43NW.js} +3 -3
- package/src/assets/web-panel/assets/{Services-DmGPaDAs.js → Services-Cslk5lUj.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CAla21Gm.js → Skeleton-Bur-C-25.js} +1 -1
- package/src/assets/web-panel/assets/Skills-v0zgLy0X.js +1 -0
- package/src/assets/web-panel/assets/{Sla-Cwi15-pZ.js → Sla-B1OWgQ51.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Cs8Zi1J8.js → SpeechSettings-CaBcEaV4.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-ipuJsDKP.js → SyncSettings-CBbG8L6J.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-C7EjXrnN.js +1 -0
- package/src/assets/web-panel/assets/{Templates-slUp9yXF.js → Templates-VBBOZ1H5.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-6edCSG5K.js → Tenant-CtQTj7IF.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DKq84G3h.js → Terminal-DXVTQjnl.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-Dg0Aw6se.js → TimelineRenderer-BRIno0aN.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-D63h7qYd.js → Tokens-uiiAfkYN.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-F7gTP_gv.js → Trigger-CPApN8o6.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-zw8Zqp8k.js → Trust-T2jKVwCE.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-C-YBUmod.js → UkeySign-C2U_gbzP.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-AhVxTgmC.js → VideoEditing-BCdlr3Kj.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-C58zxjIg.js → Wallet-CWnjoSc1.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-D-n-rlfI.js → WebAuthn-CqSbYqHq.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-Ddc8gGD4.js → WorkflowEditor-Dr_I3jcr.js} +1 -1
- package/src/assets/web-panel/assets/{chat-C66V_U7w.js → chat-Cg21FKdE.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BcJyVZRj.js → colors-CK85tY9e.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-UgUXWcgP.js → compact-item-m-XYPC7W.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-oxEKHKYP.js → createContext-BmiEeNvs.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CkMEODFC.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CbqzrKQO.js → hasIn-CCw4KAoc.js} +1 -1
- package/src/assets/web-panel/assets/{index-CH13yc9x.js → index-6jXf-Lln.js} +1 -1
- package/src/assets/web-panel/assets/{index-BdFgUn1S.js → index-8KzhlvJ9.js} +1 -1
- package/src/assets/web-panel/assets/{index-D3xNhHF3.js → index-B7xJkhtJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DAIuMvVR.js → index-B8IC9ZeZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CrG-1Kqs.js → index-BGUYgc96.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bu1A2sXy.js → index-BGb1j2z9.js} +1 -1
- package/src/assets/web-panel/assets/{index-BQlGMcZ9.js → index-BHsiSoGY.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWFNv_EG.js → index-BIOTRzaF.js} +1 -1
- package/src/assets/web-panel/assets/{index-BrWZmUdA.js → index-BStyjmLG.js} +1 -1
- package/src/assets/web-panel/assets/{index-C-p9hhAz.js → index-BUYyhYP6.js} +1 -1
- package/src/assets/web-panel/assets/{index-CM2S5TJZ.js → index-BcfVHmFK.js} +1 -1
- package/src/assets/web-panel/assets/{index-7lSY8B9T.js → index-BiVPFsat.js} +1 -1
- package/src/assets/web-panel/assets/index-BjE5qaKn.js +1 -0
- package/src/assets/web-panel/assets/{index-B-h0Jgtj.js → index-Br0ZNdu1.js} +1 -1
- package/src/assets/web-panel/assets/{index-D8rgeCoC.js → index-Br9t_I1X.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRrxJygS.js → index-BtvVupUL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DO-5vgTW.js → index-Bv90WEWa.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBEL07sa.js → index-BvjC3t35.js} +1 -1
- package/src/assets/web-panel/assets/{index-UpN_kC9R.js → index-ByVvAXdl.js} +1 -1
- package/src/assets/web-panel/assets/{index-SzGgAqai.js → index-CBcgIWOe.js} +1 -1
- package/src/assets/web-panel/assets/{index-C3j9jTfB.js → index-CN2xbLGz.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bmhw_Ler.js → index-CYEzWoyZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Crqqbu-W.js → index-Cf5arJie.js} +1 -1
- package/src/assets/web-panel/assets/index-CsFH-2Zk.js +1 -0
- package/src/assets/web-panel/assets/{index-BMOY4PSW.js → index-D1sU5-XA.js} +1 -1
- package/src/assets/web-panel/assets/{index-BT2PZ9df.js → index-D7gS_TJl.js} +1 -1
- package/src/assets/web-panel/assets/{index-YvNh1UdB.js → index-DAlGVix-.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZ7mv_oS.js → index-DI9GJFcn.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ov77O9mH.js → index-DIlGxS2W.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJluGB2F.js → index-DMbrl43d.js} +1 -1
- package/src/assets/web-panel/assets/{index-C6X26RJu.js → index-DmSgfXuz.js} +1 -1
- package/src/assets/web-panel/assets/{index-DMbJ06sF.js → index-DpIy2HzE.js} +1 -1
- package/src/assets/web-panel/assets/{index-CUmYwZyf.js → index-DxRhnsEC.js} +1 -1
- package/src/assets/web-panel/assets/{index-BNIq0NAn.js → index-IskAKXhx.js} +1 -1
- package/src/assets/web-panel/assets/{index-DR4YKlLt.js → index-J81uvUMN.js} +1 -1
- package/src/assets/web-panel/assets/{index-RnxuL8wM.js → index-OIbfsi-o.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bp9rfr-P.js → index-lhoexBDH.js} +1 -1
- package/src/assets/web-panel/assets/{index-BpqJNeIj.js → index-sWUmvT8H.js} +1 -1
- package/src/assets/web-panel/assets/{index-CuZupgUw.js → index-yYmjkf38.js} +3 -3
- package/src/assets/web-panel/assets/{initDefaultProps-BK9ncFiF.js → initDefaultProps-Cc1XOmNe.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BxzXi1Pe.js → motion-BehsX88u.js} +1 -1
- package/src/assets/web-panel/assets/{move-CRmwRuah.js → move-BPx2YsqY.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BQq5_Znx.js → mtc-parser-BSFJgFQA.js} +1 -1
- package/src/assets/web-panel/assets/{omit-Ch4VNY2j.js → omit-DBN5KUeo.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CUioBhrz.js → pickAttrs-BDK1yZ-9.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-Hj3o1CrW.js → placementArrow-C4rMmKNJ.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-PfqJrlkI.js → responsiveObserve-BoeoOnxX.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BXcnR-Lu.js → slide-BKlr1bl9.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-C74a-ofo.js → statusUtils-Ky1apWPI.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-Bq57I3ls.js → styleChecker-DxxR7uXk.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-ITPUjcDw.js → useFlexGapSupport-DmsUqVe9.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DzPuXDIS.js → useFs-CwkG7sOg.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DYSgt9L5.js → usePersonalDataHub-CddgeEfF.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-NPs_EJEk.js → vnode-C_-H8i4Y.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DZzO6KVS.js → zoom-aAsHUMNE.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/permissions.js +27 -2
- package/src/data/changelog.json +26 -0
- package/src/lib/background-interaction-resolver.js +4 -0
- package/src/lib/context-memory-kernel/durable-memory-port.js +71 -15
- package/src/lib/context-memory-kernel/index.js +1 -0
- package/src/lib/context-memory-kernel/memory-service.js +43 -16
- package/src/lib/context-memory-kernel/runtime.js +5 -3
- package/src/lib/context-memory-kernel/segmented-memory-port.js +687 -0
- package/src/lib/packer/pack-update-applier.js +41 -17
- package/src/lib/packer/pkg-config-generator.js +119 -2
- package/src/lib/packer/pkg-runner.js +7 -0
- package/src/lib/packer/pkg-targets.js +83 -0
- package/src/lib/packer/web-panel-builder.js +7 -0
- package/src/lib/permission-authority.js +157 -13
- package/src/lib/process-execution-broker/index.js +11 -0
- package/src/lib/process-execution-broker/linux-subreaper-helper.js +87 -13
- package/src/lib/process-execution-broker/packer-build-policy.js +31 -0
- package/src/lib/process-execution-broker/platform-sandbox.js +11 -3
- package/src/lib/sandbox-egress-authority-monitor.js +62 -5
- package/src/lib/scoped-permission-store.js +119 -6
- package/src/lib/settings-authority-domain.cjs +37 -2
- package/src/lib/settings-loader.cjs +112 -42
- package/src/lib/settings-permission-authority.cjs +373 -0
- package/src/runtime/agent-core.js +79 -383
- package/src/runtime/headless-runner.js +8 -3
- package/src/runtime/headless-stream.js +10 -3
- package/src/runtime/permission-authority-host.js +137 -0
- package/src/runtime/provider-stream-state.js +379 -0
- package/src/assets/web-panel/assets/MarkdownRenderer-qNJS3ygh.js +0 -1
- package/src/assets/web-panel/assets/Skills-QqEyIKOI.js +0 -1
- package/src/assets/web-panel/assets/Tasks-BbVAg9Z7.js +0 -1
- package/src/assets/web-panel/assets/devWarning-BoDvrsgY.js +0 -1
- package/src/assets/web-panel/assets/index-BhqRbl5P.js +0 -1
- package/src/assets/web-panel/assets/index-DreT6MIR.js +0 -1
|
@@ -207,7 +207,7 @@ export async function scheduleReplace(ctx = {}) {
|
|
|
207
207
|
: null;
|
|
208
208
|
|
|
209
209
|
if (platform === "win32") {
|
|
210
|
-
return scheduleWindowsTransaction({
|
|
210
|
+
return await scheduleWindowsTransaction({
|
|
211
211
|
operation: "update",
|
|
212
212
|
resolvedNewPath,
|
|
213
213
|
layout,
|
|
@@ -681,7 +681,7 @@ function rollbackFailedPosixUpdate(ctx) {
|
|
|
681
681
|
}
|
|
682
682
|
}
|
|
683
683
|
|
|
684
|
-
function scheduleWindowsTransaction(ctx) {
|
|
684
|
+
async function scheduleWindowsTransaction(ctx) {
|
|
685
685
|
const {
|
|
686
686
|
operation,
|
|
687
687
|
resolvedNewPath,
|
|
@@ -771,26 +771,39 @@ function scheduleWindowsTransaction(ctx) {
|
|
|
771
771
|
|
|
772
772
|
let ready = false;
|
|
773
773
|
let childError = null;
|
|
774
|
+
let childExited = false;
|
|
775
|
+
const onChildExit = () => {
|
|
776
|
+
childExited = true;
|
|
777
|
+
};
|
|
778
|
+
const hasChildFailed = () =>
|
|
779
|
+
Boolean(childError) ||
|
|
780
|
+
childExited ||
|
|
781
|
+
child.exitCode != null ||
|
|
782
|
+
child.signalCode != null;
|
|
774
783
|
if (typeof child.once === "function") {
|
|
775
784
|
// Native spawn failures are normally emitted asynchronously. Attach
|
|
776
|
-
// before
|
|
785
|
+
// before yielding for readiness so both the no-ready and the
|
|
777
786
|
// post-transfer paths always consume the ChildProcess error event.
|
|
778
787
|
child.once("error", (error) => {
|
|
779
788
|
childError = error;
|
|
780
789
|
});
|
|
790
|
+
child.once("exit", onChildExit);
|
|
781
791
|
}
|
|
782
792
|
try {
|
|
783
793
|
ready =
|
|
784
794
|
Boolean(
|
|
785
|
-
waitForReadyImpl({
|
|
795
|
+
await waitForReadyImpl({
|
|
786
796
|
readyPath,
|
|
787
797
|
transactionId,
|
|
788
798
|
timeoutMs: WINDOWS_SIDECAR_READY_TIMEOUT_MS,
|
|
789
799
|
child,
|
|
800
|
+
hasChildFailed,
|
|
790
801
|
}),
|
|
791
|
-
) && !
|
|
802
|
+
) && !hasChildFailed();
|
|
792
803
|
} catch {
|
|
793
804
|
ready = false;
|
|
805
|
+
} finally {
|
|
806
|
+
child.removeListener?.("exit", onChildExit);
|
|
794
807
|
}
|
|
795
808
|
if (!ready) {
|
|
796
809
|
try {
|
|
@@ -840,6 +853,11 @@ function scheduleWindowsTransaction(ctx) {
|
|
|
840
853
|
function windowsGenerationJournalHelperSource() {
|
|
841
854
|
return String.raw`param()
|
|
842
855
|
$ErrorActionPreference = 'Stop'
|
|
856
|
+
# The journal contains only JSON primitives. Use the inbox .NET serializer and
|
|
857
|
+
# file/path APIs so each phase does not repeat PowerShell module discovery.
|
|
858
|
+
# Keep the same synchronous atomic replacement and durable flush protocol.
|
|
859
|
+
[void][Reflection.Assembly]::Load('System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35')
|
|
860
|
+
$Serializer = [Web.Script.Serialization.JavaScriptSerializer]::new()
|
|
843
861
|
$Action = [string]$env:JOURNAL_ACTION
|
|
844
862
|
$JournalPath = [string]$env:JOURNAL_FILE
|
|
845
863
|
$RetiredPath = [string]$env:JOURNAL_RETIRED
|
|
@@ -859,7 +877,7 @@ if (($Phase -eq 'committed') -ne ($Decision -eq 'commit')) { throw 'Invalid phas
|
|
|
859
877
|
if ($Action -eq 'write' -and $Phase -eq 'prepared') {
|
|
860
878
|
if ([IO.File]::Exists($JournalPath)) { throw 'A generation journal already exists' }
|
|
861
879
|
$Bytes = [Convert]::FromBase64String([string]$env:JOURNAL_INITIAL_BASE64)
|
|
862
|
-
$Journal = [Text.Encoding]::UTF8.GetString($Bytes)
|
|
880
|
+
$Journal = $Serializer.DeserializeObject([Text.Encoding]::UTF8.GetString($Bytes))
|
|
863
881
|
$ParentSource = @'
|
|
864
882
|
using System;
|
|
865
883
|
using System.Runtime.InteropServices;
|
|
@@ -887,10 +905,10 @@ public static class CcParentProcess {
|
|
|
887
905
|
}
|
|
888
906
|
'@
|
|
889
907
|
Add-Type -TypeDefinition $ParentSource -Language CSharp
|
|
890
|
-
$Journal
|
|
908
|
+
$Journal.Add('ownerPid', [CcParentProcess]::Get())
|
|
891
909
|
} else {
|
|
892
910
|
if (-not [IO.File]::Exists($JournalPath)) { throw 'Generation journal is missing' }
|
|
893
|
-
$Journal =
|
|
911
|
+
$Journal = $Serializer.DeserializeObject([IO.File]::ReadAllText($JournalPath, [Text.Encoding]::UTF8))
|
|
894
912
|
}
|
|
895
913
|
|
|
896
914
|
$ValidBefore = {
|
|
@@ -918,7 +936,7 @@ if ($Action -eq 'retire') {
|
|
|
918
936
|
if ([string]$Journal.phase -ne $Phase -or [string]$Journal.decision -ne $Decision) {
|
|
919
937
|
throw 'Generation journal decision changed before retirement'
|
|
920
938
|
}
|
|
921
|
-
$ReplacedPath =
|
|
939
|
+
$ReplacedPath = [IO.Path]::Combine([IO.Path]::GetDirectoryName($JournalPath), ('.chainlesschain.journal-retired-previous-' + [guid]::NewGuid().ToString('N')))
|
|
922
940
|
try {
|
|
923
941
|
if ([IO.File]::Exists($RetiredPath)) {
|
|
924
942
|
[IO.File]::Replace($JournalPath, $RetiredPath, $ReplacedPath, $true)
|
|
@@ -972,11 +990,11 @@ if ($Phase -ne 'prepared') {
|
|
|
972
990
|
$Journal.phase = $Phase
|
|
973
991
|
$Journal.decision = $Decision
|
|
974
992
|
$Journal.updatedAt = [DateTimeOffset]::UtcNow.ToString('o')
|
|
975
|
-
$Directory =
|
|
976
|
-
$StagingPath =
|
|
977
|
-
$ReplacedPath =
|
|
993
|
+
$Directory = [IO.Path]::GetDirectoryName($JournalPath)
|
|
994
|
+
$StagingPath = [IO.Path]::Combine($Directory, ('.chainlesschain.journal-' + [guid]::NewGuid().ToString('N')))
|
|
995
|
+
$ReplacedPath = [IO.Path]::Combine($Directory, ('.chainlesschain.journal-previous-' + [guid]::NewGuid().ToString('N')))
|
|
978
996
|
try {
|
|
979
|
-
$Payload = $Journal
|
|
997
|
+
$Payload = $Serializer.Serialize($Journal)
|
|
980
998
|
$PayloadBytes = [Text.UTF8Encoding]::new($false).GetBytes($Payload + [Environment]::NewLine)
|
|
981
999
|
$Stream = [IO.File]::Open($StagingPath, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::None)
|
|
982
1000
|
try {
|
|
@@ -1982,7 +2000,7 @@ export async function rollbackLastKnownGood(ctx = {}) {
|
|
|
1982
2000
|
: null;
|
|
1983
2001
|
|
|
1984
2002
|
if (platform === "win32") {
|
|
1985
|
-
const result = scheduleWindowsTransaction({
|
|
2003
|
+
const result = await scheduleWindowsTransaction({
|
|
1986
2004
|
operation: "rescue",
|
|
1987
2005
|
resolvedNewPath: rescueStagingPath,
|
|
1988
2006
|
layout,
|
|
@@ -2752,10 +2770,15 @@ function restartVerifiedExecutable(targetPath, restart, spawnImpl) {
|
|
|
2752
2770
|
}
|
|
2753
2771
|
}
|
|
2754
2772
|
|
|
2755
|
-
function waitForWindowsSidecarReady({
|
|
2773
|
+
async function waitForWindowsSidecarReady({
|
|
2774
|
+
readyPath,
|
|
2775
|
+
transactionId,
|
|
2776
|
+
timeoutMs,
|
|
2777
|
+
hasChildFailed,
|
|
2778
|
+
}) {
|
|
2756
2779
|
const deadline = Date.now() + timeoutMs;
|
|
2757
|
-
const waitCell = new Int32Array(new SharedArrayBuffer(4));
|
|
2758
2780
|
while (Date.now() < deadline) {
|
|
2781
|
+
if (hasChildFailed()) return false;
|
|
2759
2782
|
const stat = lstatOrNull(readyPath);
|
|
2760
2783
|
if (stat) {
|
|
2761
2784
|
try {
|
|
@@ -2769,7 +2792,8 @@ function waitForWindowsSidecarReady({ readyPath, transactionId, timeoutMs }) {
|
|
|
2769
2792
|
return false;
|
|
2770
2793
|
}
|
|
2771
2794
|
}
|
|
2772
|
-
|
|
2795
|
+
// Yield so native spawn errors and early exits can abort the handshake.
|
|
2796
|
+
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
2773
2797
|
}
|
|
2774
2798
|
return false;
|
|
2775
2799
|
}
|
|
@@ -20,6 +20,104 @@
|
|
|
20
20
|
import fs from "node:fs";
|
|
21
21
|
import { createRequire } from "node:module";
|
|
22
22
|
import path from "node:path";
|
|
23
|
+
import { linuxSubreaperTargetArchitectures } from "./pkg-targets.js";
|
|
24
|
+
import {
|
|
25
|
+
LINUX_SUBREAPER_SOURCE_DIGEST,
|
|
26
|
+
MAX_SUBREAPER_IMAGE_BYTES,
|
|
27
|
+
MAX_SUBREAPER_MANIFEST_BYTES,
|
|
28
|
+
subreaperDigest,
|
|
29
|
+
validateLinuxSubreaperArtifact,
|
|
30
|
+
} from "../process-execution-broker/linux-subreaper-artifact.js";
|
|
31
|
+
|
|
32
|
+
function linuxSubreaperAssets(cliRoot, targets) {
|
|
33
|
+
const architectures = linuxSubreaperTargetArchitectures(targets);
|
|
34
|
+
if (!architectures.length) return [];
|
|
35
|
+
const root = fs.realpathSync(cliRoot);
|
|
36
|
+
const assets = [];
|
|
37
|
+
function read(relative, maximum) {
|
|
38
|
+
const file = path.join(root, relative);
|
|
39
|
+
let directory = path.dirname(file);
|
|
40
|
+
while (directory !== root) {
|
|
41
|
+
const stat = fs.lstatSync(directory);
|
|
42
|
+
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
43
|
+
throw new Error("Invalid standalone Linux helper directory");
|
|
44
|
+
directory = path.dirname(directory);
|
|
45
|
+
}
|
|
46
|
+
const before = fs.lstatSync(file, { bigint: true });
|
|
47
|
+
if (
|
|
48
|
+
!before.isFile() ||
|
|
49
|
+
before.isSymbolicLink() ||
|
|
50
|
+
before.nlink !== 1n ||
|
|
51
|
+
before.size < 1n ||
|
|
52
|
+
before.size > BigInt(maximum)
|
|
53
|
+
)
|
|
54
|
+
throw new Error("Invalid standalone Linux helper asset");
|
|
55
|
+
const fd = fs.openSync(
|
|
56
|
+
file,
|
|
57
|
+
fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW || 0),
|
|
58
|
+
);
|
|
59
|
+
try {
|
|
60
|
+
const opened = fs.fstatSync(fd, { bigint: true });
|
|
61
|
+
if (
|
|
62
|
+
opened.dev !== before.dev ||
|
|
63
|
+
opened.ino !== before.ino ||
|
|
64
|
+
opened.size !== before.size
|
|
65
|
+
)
|
|
66
|
+
throw new Error("Standalone Linux helper asset changed");
|
|
67
|
+
const bytes = Buffer.alloc(Number(opened.size));
|
|
68
|
+
let offset = 0;
|
|
69
|
+
while (offset < bytes.length) {
|
|
70
|
+
const count = fs.readSync(
|
|
71
|
+
fd,
|
|
72
|
+
bytes,
|
|
73
|
+
offset,
|
|
74
|
+
bytes.length - offset,
|
|
75
|
+
offset,
|
|
76
|
+
);
|
|
77
|
+
if (count <= 0) throw new Error("Short standalone Linux helper asset");
|
|
78
|
+
offset += count;
|
|
79
|
+
}
|
|
80
|
+
const after = fs.fstatSync(fd, { bigint: true });
|
|
81
|
+
if (
|
|
82
|
+
after.size !== before.size ||
|
|
83
|
+
after.mtimeNs !== before.mtimeNs ||
|
|
84
|
+
after.ctimeNs !== before.ctimeNs ||
|
|
85
|
+
after.nlink !== 1n
|
|
86
|
+
)
|
|
87
|
+
throw new Error("Standalone Linux helper asset changed");
|
|
88
|
+
assets.push(file);
|
|
89
|
+
return bytes;
|
|
90
|
+
} finally {
|
|
91
|
+
fs.closeSync(fd);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
const source = read(
|
|
96
|
+
"src/lib/process-execution-broker/linux-subreaper-supervisor.c",
|
|
97
|
+
128 * 1024,
|
|
98
|
+
);
|
|
99
|
+
if (
|
|
100
|
+
subreaperDigest(
|
|
101
|
+
Buffer.from(source.toString("utf8").replace(/\r\n/g, "\n")),
|
|
102
|
+
) !== LINUX_SUBREAPER_SOURCE_DIGEST
|
|
103
|
+
)
|
|
104
|
+
throw new Error("Standalone Linux helper source digest mismatch");
|
|
105
|
+
for (const arch of architectures) {
|
|
106
|
+
const directory = `src/assets/linux-subreaper/linux-${arch}`;
|
|
107
|
+
validateLinuxSubreaperArtifact(
|
|
108
|
+
read(`${directory}/manifest.json`, MAX_SUBREAPER_MANIFEST_BYTES),
|
|
109
|
+
read(`${directory}/supervisor`, MAX_SUBREAPER_IMAGE_BYTES),
|
|
110
|
+
{ arch },
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
return assets.map(posixify);
|
|
114
|
+
} catch (cause) {
|
|
115
|
+
throw new Error(
|
|
116
|
+
"Standalone Linux targets require valid precompiled process supervision assets for every target architecture",
|
|
117
|
+
{ cause },
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
23
121
|
|
|
24
122
|
function capsuleBuilderAssets(cliRoot) {
|
|
25
123
|
const requireFromCli = createRequire(path.join(cliRoot, "package.json"));
|
|
@@ -108,6 +206,13 @@ export function generatePkgConfig(ctx) {
|
|
|
108
206
|
updatePublicKey = null,
|
|
109
207
|
} = ctx;
|
|
110
208
|
|
|
209
|
+
// pkg silently turns an empty target list into a host build. Require an
|
|
210
|
+
// explicit target so asset admission and the emitted build cannot diverge.
|
|
211
|
+
if (!Array.isArray(targets) || targets.length === 0)
|
|
212
|
+
throw new Error(
|
|
213
|
+
"Standalone builds require at least one explicit pkg target",
|
|
214
|
+
);
|
|
215
|
+
|
|
111
216
|
const bakedTokenMode =
|
|
112
217
|
typeof runtime.token === "string" ? runtime.token : "auto";
|
|
113
218
|
const bakedHost =
|
|
@@ -432,6 +537,7 @@ export function generatePkgConfig(ctx) {
|
|
|
432
537
|
`${posixify(cliRoot)}/src/lib/process-execution-broker/macos-mcp-launcher-protocol.json`,
|
|
433
538
|
`${posixify(cliRoot)}/install/install.ps1`,
|
|
434
539
|
...capsuleBuilderAssets(cliRoot).map(posixify),
|
|
540
|
+
...linuxSubreaperAssets(cliRoot, targets),
|
|
435
541
|
];
|
|
436
542
|
if (prebuildsDir) assets.push(`${posixify(prebuildsDir)}/**/*`);
|
|
437
543
|
// Project mode: bundle the collected .chainlesschain/ snapshot as an asset.
|
|
@@ -450,8 +556,8 @@ export function generatePkgConfig(ctx) {
|
|
|
450
556
|
`${posixify(cliRoot)}/src/**/*.js`,
|
|
451
557
|
`${posixify(cliRoot)}/src/**/*.cjs`,
|
|
452
558
|
`${posixify(cliRoot)}/bin/**/*.js`,
|
|
453
|
-
],
|
|
454
|
-
assets,
|
|
559
|
+
].map((pattern) => pkgRelativePath(pkgConfigDir, pattern)),
|
|
560
|
+
assets: assets.map((pattern) => pkgRelativePath(pkgConfigDir, pattern)),
|
|
455
561
|
targets,
|
|
456
562
|
outputPath: path.dirname(outputPath),
|
|
457
563
|
compress: compress ? "GZip" : "None",
|
|
@@ -476,3 +582,14 @@ export function generatePkgConfig(ctx) {
|
|
|
476
582
|
function posixify(p) {
|
|
477
583
|
return p.replace(/\\/g, "/");
|
|
478
584
|
}
|
|
585
|
+
|
|
586
|
+
function pkgRelativePath(directory, pattern) {
|
|
587
|
+
// pkg's walker joins every pattern to its config directory, even when the
|
|
588
|
+
// pattern is absolute. Emit relative globs so assets are actually embedded.
|
|
589
|
+
const relative = path.relative(directory, pattern);
|
|
590
|
+
if (path.isAbsolute(relative) || path.win32.isAbsolute(relative))
|
|
591
|
+
throw new Error(
|
|
592
|
+
"Standalone build assets and temporary config must be on the same filesystem drive",
|
|
593
|
+
);
|
|
594
|
+
return posixify(relative);
|
|
595
|
+
}
|
|
@@ -16,6 +16,10 @@ import path from "node:path";
|
|
|
16
16
|
import { createRequire } from "node:module";
|
|
17
17
|
import { PackError, EXIT } from "./errors.js";
|
|
18
18
|
import executionBroker from "../process-execution-broker/index.js";
|
|
19
|
+
import {
|
|
20
|
+
createPackerBuildPolicy,
|
|
21
|
+
PACKER_BUILD_TIMEOUT_MS,
|
|
22
|
+
} from "../process-execution-broker/packer-build-policy.js";
|
|
19
23
|
|
|
20
24
|
export const _deps = {
|
|
21
25
|
spawnSync: (...args) => executionBroker.spawnSync(...args),
|
|
@@ -55,6 +59,9 @@ export function runPkg(ctx) {
|
|
|
55
59
|
origin: "packer:pkg",
|
|
56
60
|
scope: "pack",
|
|
57
61
|
policy: "allow",
|
|
62
|
+
sandboxPolicy: createPackerBuildPolicy("packer:pkg"),
|
|
63
|
+
timeout: PACKER_BUILD_TIMEOUT_MS,
|
|
64
|
+
killSignal: "SIGKILL",
|
|
58
65
|
shell: false,
|
|
59
66
|
cwd: path.dirname(pkgConfigFile),
|
|
60
67
|
stdio: "inherit",
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Only resolve the platform/architecture needed to admit helper assets. Loading
|
|
2
|
+
// pkg's config module also loads pkg-fetch, whose Linux host probe runs ldd at
|
|
3
|
+
// import time. Target admission must remain free of subprocess side effects.
|
|
4
|
+
// Keep these token aliases aligned with the installed pkg parser via the
|
|
5
|
+
// differential tests. Linux, Alpine and linuxstatic need the same static ELF.
|
|
6
|
+
// ARM32 hosts require an explicit supported target architecture: unlike pkg,
|
|
7
|
+
// admission never invokes uname to infer a different ABI from the kernel.
|
|
8
|
+
const PLATFORMS = new Set([
|
|
9
|
+
"alpine",
|
|
10
|
+
"freebsd",
|
|
11
|
+
"linux",
|
|
12
|
+
"linuxstatic",
|
|
13
|
+
"macos",
|
|
14
|
+
"win",
|
|
15
|
+
]);
|
|
16
|
+
const ARCHITECTURES = new Set([
|
|
17
|
+
"x64",
|
|
18
|
+
"x86",
|
|
19
|
+
"armv7",
|
|
20
|
+
"arm64",
|
|
21
|
+
"ppc64",
|
|
22
|
+
"s390x",
|
|
23
|
+
"riscv64",
|
|
24
|
+
"loong64",
|
|
25
|
+
]);
|
|
26
|
+
const PLATFORM_ALIASES = new Map([
|
|
27
|
+
["darwin", "macos"],
|
|
28
|
+
["lin", "linux"],
|
|
29
|
+
["mac", "macos"],
|
|
30
|
+
["osx", "macos"],
|
|
31
|
+
["win32", "win"],
|
|
32
|
+
["windows", "win"],
|
|
33
|
+
]);
|
|
34
|
+
const ARCHITECTURE_ALIASES = new Map([
|
|
35
|
+
["ia32", "x86"],
|
|
36
|
+
["x86_64", "x64"],
|
|
37
|
+
]);
|
|
38
|
+
|
|
39
|
+
export function linuxSubreaperTargetArchitectures(
|
|
40
|
+
targets,
|
|
41
|
+
{ platform = process.platform, arch = process.arch } = {},
|
|
42
|
+
) {
|
|
43
|
+
if (
|
|
44
|
+
!Array.isArray(targets) ||
|
|
45
|
+
targets.length === 0 ||
|
|
46
|
+
targets.some(
|
|
47
|
+
(target) =>
|
|
48
|
+
typeof target !== "string" || !target.trim().replace(/-/g, ""),
|
|
49
|
+
)
|
|
50
|
+
) {
|
|
51
|
+
throw new Error("Standalone builds require explicit nonempty pkg targets");
|
|
52
|
+
}
|
|
53
|
+
const architectures = new Set();
|
|
54
|
+
for (const rawTarget of targets) {
|
|
55
|
+
const target = rawTarget.trim();
|
|
56
|
+
let targetPlatform = PLATFORM_ALIASES.get(platform) || platform;
|
|
57
|
+
let targetArch = ARCHITECTURE_ALIASES.get(arch) || arch;
|
|
58
|
+
if (target !== "host") {
|
|
59
|
+
for (const token of target.split("-")) {
|
|
60
|
+
if (!token || token === "latest" || token.startsWith("node")) continue;
|
|
61
|
+
const resolvedPlatform = PLATFORM_ALIASES.get(token) || token;
|
|
62
|
+
if (PLATFORMS.has(resolvedPlatform)) {
|
|
63
|
+
targetPlatform = resolvedPlatform;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const resolvedArch = ARCHITECTURE_ALIASES.get(token) || token;
|
|
67
|
+
if (ARCHITECTURES.has(resolvedArch)) {
|
|
68
|
+
targetArch = resolvedArch;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
throw new Error(`Unknown token '${token}' in '${target}'`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (!["linux", "alpine", "linuxstatic"].includes(targetPlatform)) continue;
|
|
75
|
+
if (targetArch !== "x64" && targetArch !== "arm64") {
|
|
76
|
+
throw new Error(
|
|
77
|
+
`Unsupported standalone Linux process supervision architecture: ${targetArch}`,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
architectures.add(targetArch);
|
|
81
|
+
}
|
|
82
|
+
return [...architectures];
|
|
83
|
+
}
|
|
@@ -12,6 +12,10 @@ import fs from "node:fs";
|
|
|
12
12
|
import path from "node:path";
|
|
13
13
|
import { PackError, EXIT } from "./errors.js";
|
|
14
14
|
import executionBroker from "../process-execution-broker/index.js";
|
|
15
|
+
import {
|
|
16
|
+
createPackerBuildPolicy,
|
|
17
|
+
PACKER_BUILD_TIMEOUT_MS,
|
|
18
|
+
} from "../process-execution-broker/packer-build-policy.js";
|
|
15
19
|
|
|
16
20
|
export const _deps = {
|
|
17
21
|
spawnSync: (...args) => executionBroker.spawnSync(...args),
|
|
@@ -61,6 +65,9 @@ export function ensureWebPanel(ctx) {
|
|
|
61
65
|
origin: "packer:web-panel-build",
|
|
62
66
|
scope: "pack",
|
|
63
67
|
policy: "allow",
|
|
68
|
+
sandboxPolicy: createPackerBuildPolicy("packer:web-panel-build"),
|
|
69
|
+
timeout: PACKER_BUILD_TIMEOUT_MS,
|
|
70
|
+
killSignal: "SIGKILL",
|
|
64
71
|
shell: false,
|
|
65
72
|
cwd: cliRoot,
|
|
66
73
|
stdio: "inherit",
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
/** Resolve static settings plus CLI-owned workspace-scoped permission rules. */
|
|
2
2
|
|
|
3
3
|
import settingsLoader from "./settings-loader.cjs";
|
|
4
|
+
import persistentSettings from "./settings-permission-authority.cjs";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import {
|
|
6
7
|
ScopedPermissionStore,
|
|
7
8
|
getScopedPermissionRevision,
|
|
8
9
|
subscribeScopedPermissionRevision,
|
|
10
|
+
projectScopedPermissionObservation,
|
|
9
11
|
} from "./scoped-permission-store.js";
|
|
10
12
|
|
|
11
13
|
const {
|
|
12
14
|
applyManagedPermissionPolicy,
|
|
13
|
-
|
|
15
|
+
inspectSettingsSources,
|
|
16
|
+
projectSettingsObservation,
|
|
14
17
|
getSettingsPermissionRevision,
|
|
15
18
|
subscribeSettingsPermissionRevision,
|
|
16
19
|
} = settingsLoader;
|
|
@@ -47,9 +50,14 @@ const combinedAuthority = Object.freeze({
|
|
|
47
50
|
});
|
|
48
51
|
|
|
49
52
|
function freezeSnapshot(value) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
const pending = [value];
|
|
54
|
+
const seen = new WeakSet();
|
|
55
|
+
while (pending.length) {
|
|
56
|
+
const current = pending.pop();
|
|
57
|
+
if (!current || typeof current !== "object" || seen.has(current)) continue;
|
|
58
|
+
seen.add(current);
|
|
59
|
+
for (const child of Object.values(current)) pending.push(child);
|
|
60
|
+
Object.freeze(current);
|
|
53
61
|
}
|
|
54
62
|
return value;
|
|
55
63
|
}
|
|
@@ -80,15 +88,41 @@ export function loadPermissionAuthority({
|
|
|
80
88
|
env = process.env,
|
|
81
89
|
baseRules = null,
|
|
82
90
|
scopedStore = null,
|
|
91
|
+
settingsAuthority: persistentAuthority = null,
|
|
83
92
|
} = {}) {
|
|
84
93
|
const settingsRevision = getSettingsPermissionRevision();
|
|
85
94
|
const scopedRevision = baseRules ? null : getScopedPermissionRevision();
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
95
|
+
const persistent = persistentAuthority
|
|
96
|
+
? persistentSettings.readSettingsPermissionAuthority(persistentAuthority)
|
|
97
|
+
: null;
|
|
98
|
+
if (persistentAuthority) {
|
|
99
|
+
const bound =
|
|
100
|
+
persistentSettings.settingsPermissionAuthorityOptions(
|
|
101
|
+
persistentAuthority,
|
|
102
|
+
);
|
|
103
|
+
if (
|
|
104
|
+
path.resolve(cwd) !== bound.cwd ||
|
|
105
|
+
(settingsFile &&
|
|
106
|
+
path.resolve(cwd, settingsFile) !== bound.settingsFile) ||
|
|
107
|
+
(managedSettingsFile &&
|
|
108
|
+
path.resolve(managedSettingsFile) !== bound.managedSettingsFile)
|
|
109
|
+
)
|
|
110
|
+
throw new TypeError("persistent settings authority options mismatch");
|
|
111
|
+
}
|
|
112
|
+
const settingsObservation =
|
|
113
|
+
persistent?.observation ||
|
|
114
|
+
inspectSettingsSources({
|
|
115
|
+
cwd,
|
|
116
|
+
settingsFile,
|
|
117
|
+
managedSettingsFile,
|
|
118
|
+
env,
|
|
119
|
+
});
|
|
120
|
+
const loaded = persistent
|
|
121
|
+
? persistentSettings.projectSettingsPermissionObservation(
|
|
122
|
+
settingsObservation,
|
|
123
|
+
{ env },
|
|
124
|
+
)
|
|
125
|
+
: projectSettingsObservation(settingsObservation, { env });
|
|
92
126
|
const sources = baseRules ? {} : { ...loaded.sources };
|
|
93
127
|
let rules = baseRules
|
|
94
128
|
? applyManagedPermissionPolicy(baseRules, loaded.managed, sources)
|
|
@@ -98,7 +132,29 @@ export function loadPermissionAuthority({
|
|
|
98
132
|
// Explicit caller rules retain their historical replacement semantics.
|
|
99
133
|
// Managed-only policy also suppresses every user-owned scoped grant.
|
|
100
134
|
if (!baseRules) {
|
|
101
|
-
|
|
135
|
+
const bound = persistentAuthority
|
|
136
|
+
? persistentSettings.settingsPermissionAuthorityOptions(
|
|
137
|
+
persistentAuthority,
|
|
138
|
+
)
|
|
139
|
+
: null;
|
|
140
|
+
const store =
|
|
141
|
+
scopedStore ||
|
|
142
|
+
new ScopedPermissionStore({
|
|
143
|
+
cwd,
|
|
144
|
+
...(bound
|
|
145
|
+
? {
|
|
146
|
+
filePath: bound.scopedFile,
|
|
147
|
+
settingsAuthority: persistentAuthority,
|
|
148
|
+
}
|
|
149
|
+
: {}),
|
|
150
|
+
});
|
|
151
|
+
scoped = persistent
|
|
152
|
+
? projectScopedPermissionObservation(
|
|
153
|
+
store,
|
|
154
|
+
persistentAuthority,
|
|
155
|
+
persistent.scopedObservation,
|
|
156
|
+
)
|
|
157
|
+
: store.list();
|
|
102
158
|
const managedOnly =
|
|
103
159
|
loaded.managed?.allowManagedPermissionRulesOnly === true;
|
|
104
160
|
scoped = {
|
|
@@ -136,6 +192,17 @@ export function loadPermissionAuthority({
|
|
|
136
192
|
error.code = "CC_SCOPED_PERMISSION_AUTHORITY_CHANGED";
|
|
137
193
|
throw error;
|
|
138
194
|
}
|
|
195
|
+
if (
|
|
196
|
+
persistent &&
|
|
197
|
+
persistentSettings.readSettingsPermissionAuthority(persistentAuthority)
|
|
198
|
+
.snapshot !== persistent.snapshot
|
|
199
|
+
) {
|
|
200
|
+
const error = new Error(
|
|
201
|
+
"persistent settings changed while permission authority was loading",
|
|
202
|
+
);
|
|
203
|
+
error.code = "CC_SETTINGS_PERMISSION_AUTHORITY_CHANGED";
|
|
204
|
+
throw error;
|
|
205
|
+
}
|
|
139
206
|
return freezeSnapshot({
|
|
140
207
|
...loaded,
|
|
141
208
|
rules,
|
|
@@ -143,12 +210,18 @@ export function loadPermissionAuthority({
|
|
|
143
210
|
scoped,
|
|
144
211
|
hasRules: hasRules(rules),
|
|
145
212
|
settingsRevision,
|
|
213
|
+
settingsObservation,
|
|
214
|
+
...(persistent ? { persistentSettingsRevision: persistent.snapshot } : {}),
|
|
146
215
|
...(scopedRevision ? { scopedRevision } : {}),
|
|
147
216
|
});
|
|
148
217
|
}
|
|
149
218
|
|
|
150
219
|
export function createPermissionRulesProvider(options = {}) {
|
|
151
|
-
const
|
|
220
|
+
const persistentAuthority = options.settingsAuthority ?? null;
|
|
221
|
+
const bound = persistentAuthority
|
|
222
|
+
? persistentSettings.settingsPermissionAuthorityOptions(persistentAuthority)
|
|
223
|
+
: null;
|
|
224
|
+
const cwd = path.resolve(options.cwd || bound?.cwd || process.cwd());
|
|
152
225
|
const captured = Object.freeze({
|
|
153
226
|
cwd,
|
|
154
227
|
settingsFile: options.settingsFile
|
|
@@ -164,15 +237,86 @@ export function createPermissionRulesProvider(options = {}) {
|
|
|
164
237
|
? freezeSnapshot(cloneRules(options.baseRules))
|
|
165
238
|
: null,
|
|
166
239
|
scopedStore: options.scopedStore || null,
|
|
240
|
+
settingsAuthority: persistentAuthority,
|
|
167
241
|
});
|
|
242
|
+
if (
|
|
243
|
+
bound &&
|
|
244
|
+
(cwd !== bound.cwd ||
|
|
245
|
+
(captured.settingsFile && captured.settingsFile !== bound.settingsFile) ||
|
|
246
|
+
(captured.managedSettingsFile &&
|
|
247
|
+
captured.managedSettingsFile !== bound.managedSettingsFile))
|
|
248
|
+
)
|
|
249
|
+
throw new TypeError("persistent settings authority options mismatch");
|
|
168
250
|
const provider = () => loadPermissionAuthority(captured);
|
|
251
|
+
const localAuthority = captured.baseRules
|
|
252
|
+
? settingsAuthority
|
|
253
|
+
: combinedAuthority;
|
|
169
254
|
providers.set(
|
|
170
255
|
provider,
|
|
171
|
-
|
|
256
|
+
persistentAuthority
|
|
257
|
+
? persistentProviderAuthority(persistentAuthority, localAuthority)
|
|
258
|
+
: localAuthority,
|
|
172
259
|
);
|
|
173
260
|
return Object.freeze(provider);
|
|
174
261
|
}
|
|
175
262
|
|
|
263
|
+
function persistentProviderAuthority(binding, localAuthority) {
|
|
264
|
+
let last = null;
|
|
265
|
+
function getSnapshot() {
|
|
266
|
+
const local = localAuthority.getSnapshot();
|
|
267
|
+
const durable =
|
|
268
|
+
persistentSettings.readSettingsPermissionAuthority(binding).snapshot;
|
|
269
|
+
if (last?.local !== local || last?.durable !== durable)
|
|
270
|
+
last = Object.freeze({ local, durable });
|
|
271
|
+
return last;
|
|
272
|
+
}
|
|
273
|
+
return Object.freeze({
|
|
274
|
+
getSnapshot,
|
|
275
|
+
assertWorkspace(cwd) {
|
|
276
|
+
if (
|
|
277
|
+
path.resolve(cwd) !==
|
|
278
|
+
persistentSettings.settingsPermissionAuthorityOptions(binding).cwd
|
|
279
|
+
)
|
|
280
|
+
throw Object.assign(
|
|
281
|
+
new Error("persistent permission authority workspace mismatch"),
|
|
282
|
+
{ code: "CC_SETTINGS_AUTHORITY_BINDING_CHANGED" },
|
|
283
|
+
);
|
|
284
|
+
},
|
|
285
|
+
assertWritableRoots(roots) {
|
|
286
|
+
persistentSettings.assertSettingsPermissionWritableRoots(binding, roots);
|
|
287
|
+
},
|
|
288
|
+
subscribePolicyRevision(listener) {
|
|
289
|
+
if (typeof listener !== "function")
|
|
290
|
+
throw new TypeError("permission revision listener must be a function");
|
|
291
|
+
let known = getSnapshot();
|
|
292
|
+
const remove = localAuthority.subscribePolicyRevision(listener);
|
|
293
|
+
// Persistence prevents official ABA loss between polls. Timers provide
|
|
294
|
+
// bounded observation, not a promise that another process has stopped
|
|
295
|
+
// before synchronous addRule returns.
|
|
296
|
+
const timer = setInterval(() => {
|
|
297
|
+
let next;
|
|
298
|
+
try {
|
|
299
|
+
next = getSnapshot();
|
|
300
|
+
} catch {
|
|
301
|
+
next = null;
|
|
302
|
+
}
|
|
303
|
+
if (next === known) return;
|
|
304
|
+
known = next;
|
|
305
|
+
try {
|
|
306
|
+
listener(next);
|
|
307
|
+
} catch {
|
|
308
|
+
/* isolate observers */
|
|
309
|
+
}
|
|
310
|
+
}, 100);
|
|
311
|
+
timer.unref?.();
|
|
312
|
+
return () => {
|
|
313
|
+
clearInterval(timer);
|
|
314
|
+
remove();
|
|
315
|
+
};
|
|
316
|
+
},
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
176
320
|
// A legacy callback cannot advertise a trusted revision subscription simply
|
|
177
321
|
// by copying properties onto itself. It still receives sampled revalidation.
|
|
178
322
|
export function permissionRulesProviderAuthority(provider) {
|