chainlesschain 0.166.82 → 0.166.84
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/package.json +1 -1
- 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-DMzLSUWK.js → AIOps-OYLnAlB5.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CgnA23oA.js → ActionButton-uc9kbLR6.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CtXmm8Qe.js → Analytics-BH901FG0.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-C5RIh5jA.js → AppLayout-qypKb8GL.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-DM525zx0.js → Artifacts-Q-uPWyLY.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-ChBx6f2l.js → Audit-B8hMGMim.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BBHDxCda.js → BackgroundAgents-BSs8rJL_.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-B-qzCAoM.js → Backup-2YMU_nCd.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-C5yoIWAD.js → BaseInput-DyMppTuT.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-NmTrci9a.js → Chat-B5QGMaDO.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-B8ts_JnN.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-KdFSU3vd.js → Checkbox-DAvtgEGd.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-L__BOv_4.js → Codegen-BSChEVM3.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Dfuw4IQV.js → Col-G0zYohIP.js} +1 -1
- package/src/assets/web-panel/assets/{Community-BRlEhSbx.js → Community-CzCN0B_p.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-D7dRkv8n.js → Compact-DrIN3G8z.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CdlFYNR3.js → Compliance-CIsLa64Z.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-Ey7ksHq4.js → Cowork-CGYoafsB.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DBH__wGJ.js → Cron-DJ1JPXuH.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-D3nu9dw7.js → Crosschain-B-IqVFJl.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DS6vZBNv.js → DID-CAAczPz_.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DwFRk2T0.js → Dashboard-Dkpel8VE.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-D7b73q3I.js → Dropdown-ETNBf8-Z.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DPNaVH36.js → EmailListRenderer-CJGDyjVD.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-BEsOtdpf.js → EvolutionSettings-CL_hvVYe.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-ijSqsSsF.js → FamilyGuardDashboard-iexOh6Dh.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-C0BOzPDh.js → Federation-DnDHvV5D.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DkF5NoAg.js → FormItemContext-DLCDJjUp.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DQsMcyJj.js → GenericCardRenderer-CaCgXCjS.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DQRt88PU.js → Git-BVm-euUF.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DIjPmDN8.js → Governance-DPnUvLWr.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BWMFtT7i.js → Inference-5qCWSYKl.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-M7TfkUVl.js → KnowledgeGraph-DXdv2oEh.js} +1 -1
- package/src/assets/web-panel/assets/Logs-BF2f7bBA.js +2 -0
- package/src/assets/web-panel/assets/MarkdownRenderer-qNJS3ygh.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-Crd9MYHg.js → Marketplace-Bp-0Y7Ng.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-C37yOQV0.js → McpTools-dm-Xdi63.js} +2 -2
- package/src/assets/web-panel/assets/{Memory-BBsijJCd.js → Memory-TBHK031z.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CiXIQCju.js → MobileBridge-BTILAlds.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-C0KSvQm5.js → MobileProjects-DC0Clgzs.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-C0XaQsOY.js → Mtc-BvyWkmRw.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-DPqggKhw.js → MtcAudit-D7ksLoNa.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-Bie0ZVHe.js → Multisig-Dpzu7X1t.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BbuJlQ5b.js → NLProgramming-DZ0ADHSB.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-CgqrJV8w.js → Notes-hIdkmRug.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-CusdZEQl.js → NotificationSettings-R3jyP6Vf.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-B7RrCvCQ.js → OrderTableRenderer-d1zrFkqx.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-BnFpz3bb.js → Organization-DoA5WMcc.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-C_4_HyyZ.js → Overflow-DHjIloAQ.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-D0KpHxeg.js → P2P-2TMon_Wy.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-DEUxGSWO.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-D2LxL66N.js → Permissions-CxKcZ-8X.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CvSNIxt0.js → PersonalDataHub-CcYtkHqc.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-rUl-SM7V.js → Pipeline-BxwOuq22.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BD8cWSNd.js → Privacy-VIx9pdsH.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-RM7J4X2F.js → ProjectInit-COjp_erK.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BIH38RsB.js → ProjectSettings-x9NrZU80.js} +2 -2
- package/src/assets/web-panel/assets/Projects-DMgkw7QJ.js +1 -0
- package/src/assets/web-panel/assets/{Providers-B9Kja2RK.js → Providers-B_fR7Y7Y.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-ByDKowTD.js → QrScannerModal-BUvzrn3V.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DqEN1QOE.js → QuickAsk-C0sJwLy2.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CLrYwNiv.js → Recommend-CJC7Wpce.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DyDltVPC.js → RemoteSession-B62J6ZP0.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-BfP8rJ1-.js → Reputation-4f48kVBn.js} +1 -1
- package/src/assets/web-panel/assets/{Row-BpnP6r1H.js → Row-EzEMaYoV.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CBNI1lCN.js → RssFeed-Dy0wD83j.js} +3 -3
- package/src/assets/web-panel/assets/{Search-CLjrM-xj.js → Search-GeVRHQND.js} +1 -1
- package/src/assets/web-panel/assets/{Security-dRXtg-Mq.js → Security-omLr1J7w.js} +3 -3
- package/src/assets/web-panel/assets/{Services-DAHCtOHL.js → Services-DmGPaDAs.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-D11Jgtur.js → Skeleton-CAla21Gm.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DchvTO4k.js → Skills-QqEyIKOI.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BFOc2SbL.js → Sla-Cwi15-pZ.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Dud1xDd2.js → SpeechSettings-Cs8Zi1J8.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CILfsA2S.js → SyncSettings-ipuJsDKP.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-C6Qrah_5.js → Tasks-BbVAg9Z7.js} +1 -1
- package/src/assets/web-panel/assets/{Templates--puiHyCR.js → Templates-slUp9yXF.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-cz5vITz_.js → Tenant-6edCSG5K.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-YRs75Gz8.js → Terminal-DKq84G3h.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-C5myb_QZ.js → TimelineRenderer-Dg0Aw6se.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Bk60iMIj.js → Tokens-D63h7qYd.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BAb-Fd4z.js → Trigger-F7gTP_gv.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BlqwmpEB.js → Trust-zw8Zqp8k.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-C6jvuF-7.js → UkeySign-C-YBUmod.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-7zbsdQUj.js → VideoEditing-AhVxTgmC.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BAouk_kp.js → Wallet-C58zxjIg.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-BQapv504.js → WebAuthn-D-n-rlfI.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-ChUXM-Qx.js → WorkflowEditor-Ddc8gGD4.js} +1 -1
- package/src/assets/web-panel/assets/{chat-7B6U8zgJ.js → chat-C66V_U7w.js} +1 -1
- package/src/assets/web-panel/assets/{colors-C8UqaLpe.js → colors-BcJyVZRj.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-x47giTCj.js → compact-item-UgUXWcgP.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-D6ZwjgaZ.js → createContext-oxEKHKYP.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BoDvrsgY.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-Cv3d9-Bu.js → hasIn-CbqzrKQO.js} +1 -1
- package/src/assets/web-panel/assets/{index-BM-NYjej.js → index-7lSY8B9T.js} +1 -1
- package/src/assets/web-panel/assets/{index-CUUgXcPh.js → index-B-h0Jgtj.js} +1 -1
- package/src/assets/web-panel/assets/{index-CrGQsbpb.js → index-BMOY4PSW.js} +1 -1
- package/src/assets/web-panel/assets/{index-DvoMGeL9.js → index-BNIq0NAn.js} +1 -1
- package/src/assets/web-panel/assets/{index-nogjrcQE.js → index-BQlGMcZ9.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1ElqYDD.js → index-BT2PZ9df.js} +1 -1
- package/src/assets/web-panel/assets/{index-yYdCdtY1.js → index-BZ7mv_oS.js} +1 -1
- package/src/assets/web-panel/assets/{index-N9hNOl1i.js → index-BdFgUn1S.js} +1 -1
- package/src/assets/web-panel/assets/index-BhqRbl5P.js +1 -0
- package/src/assets/web-panel/assets/{index-DVBG0Jqz.js → index-Bmhw_Ler.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dv5E07PZ.js → index-Bp9rfr-P.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTBkdyLk.js → index-BpqJNeIj.js} +1 -1
- package/src/assets/web-panel/assets/{index-EDWA9JL1.js → index-BrWZmUdA.js} +1 -1
- package/src/assets/web-panel/assets/{index-DtBUgc0G.js → index-Bu1A2sXy.js} +1 -1
- package/src/assets/web-panel/assets/{index-BMPk5D1m.js → index-C-p9hhAz.js} +1 -1
- package/src/assets/web-panel/assets/{index-D9lFBkS4.js → index-C3j9jTfB.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLHnYXVa.js → index-C6X26RJu.js} +1 -1
- package/src/assets/web-panel/assets/{index-jgN2e0Oy.js → index-CH13yc9x.js} +1 -1
- package/src/assets/web-panel/assets/{index-CXG6yiAf.js → index-CJluGB2F.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQ0-ny-o.js → index-CM2S5TJZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7Dorc7r.js → index-CUmYwZyf.js} +1 -1
- package/src/assets/web-panel/assets/{index-IVelXaiQ.js → index-CrG-1Kqs.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cc2bhSuI.js → index-Crqqbu-W.js} +1 -1
- package/src/assets/web-panel/assets/{index-DD-V-N_m.js → index-CuZupgUw.js} +3 -3
- package/src/assets/web-panel/assets/{index-BUzw-kDo.js → index-D3xNhHF3.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ce666S9v.js → index-D8rgeCoC.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cbf4RqOd.js → index-DAIuMvVR.js} +1 -1
- package/src/assets/web-panel/assets/{index-BGxo1YH0.js → index-DBEL07sa.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTisPSqa.js → index-DMbJ06sF.js} +1 -1
- package/src/assets/web-panel/assets/{index-CXIUyx4U.js → index-DO-5vgTW.js} +1 -1
- package/src/assets/web-panel/assets/{index-CUtcWTSe.js → index-DR4YKlLt.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4ZHX6wo.js → index-DRrxJygS.js} +1 -1
- package/src/assets/web-panel/assets/{index-CiVEatgH.js → index-DWFNv_EG.js} +1 -1
- package/src/assets/web-panel/assets/index-DreT6MIR.js +1 -0
- package/src/assets/web-panel/assets/{index-Dc0hePXV.js → index-Ov77O9mH.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cc6jr0Yb.js → index-RnxuL8wM.js} +1 -1
- package/src/assets/web-panel/assets/{index-dbM4QvQZ.js → index-SzGgAqai.js} +1 -1
- package/src/assets/web-panel/assets/{index-CaPZ_8kP.js → index-UpN_kC9R.js} +1 -1
- package/src/assets/web-panel/assets/{index-WhoNHp50.js → index-YvNh1UdB.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DkKS5xtR.js → initDefaultProps-BK9ncFiF.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CU-zBUIg.js → motion-BxzXi1Pe.js} +1 -1
- package/src/assets/web-panel/assets/{move-zBE0VEd4.js → move-CRmwRuah.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-B9WyO1je.js → mtc-parser-BQq5_Znx.js} +1 -1
- package/src/assets/web-panel/assets/{omit-6sCoBNTL.js → omit-Ch4VNY2j.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DDRv_sFc.js → pickAttrs-CUioBhrz.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-Cy_CBDw5.js → placementArrow-Hj3o1CrW.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-CIczLq9K.js → responsiveObserve-PfqJrlkI.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DFfZCvnG.js → slide-BXcnR-Lu.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DW-0HUl-.js → statusUtils-C74a-ofo.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BPYaBorP.js → styleChecker-Bq57I3ls.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DYPoOaZc.js → useFlexGapSupport-ITPUjcDw.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-ODUEWR17.js → useFs-DzPuXDIS.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CstUt15X.js → usePersonalDataHub-DYSgt9L5.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-D2GW8xCL.js → vnode-NPs_EJEk.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-Bz6GoDwq.js → zoom-DZzO6KVS.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +21 -10
- package/src/data/changelog.json +39 -0
- package/src/gateways/ws/session-protocol.js +19 -5
- package/src/gateways/ws/ws-agent-handler.js +6 -0
- package/src/gateways/ws/ws-session-gateway.js +133 -21
- package/src/lib/agent-execution-policy.js +177 -0
- package/src/lib/authority-launch-environment.js +99 -0
- package/src/lib/claude-project-auto-memory.js +7 -30
- package/src/lib/evolution/volcengine-function-replay-store.js +38 -28
- package/src/lib/host-tool-policy-authority.js +151 -0
- package/src/lib/permission-authority.js +109 -6
- package/src/lib/plugin-runtime/settings.js +9 -1
- package/src/lib/sandbox-egress-authority-monitor.js +3 -2
- package/src/lib/scoped-permission-store.js +229 -119
- package/src/lib/session-manager.js +20 -5
- package/src/lib/settings-authority-domain.cjs +966 -0
- package/src/lib/settings-authority-record.cjs +701 -0
- package/src/lib/settings-loader.cjs +175 -19
- package/src/lib/settings-source-observation.cjs +278 -0
- package/src/lib/sub-agent-context.js +36 -18
- package/src/lib/unattended-action-policy.js +456 -38
- package/src/repl/agent-repl.js +43 -15
- package/src/repl/repl-tool-executor.js +39 -0
- package/src/runtime/agent-core.js +272 -5
- package/src/runtime/agent-runtime.js +15 -3
- package/src/runtime/headless-runner.js +13 -4
- package/src/runtime/headless-stream.js +9 -0
- package/src/runtime/policies/agent-policy.js +5 -4
- package/src/assets/web-panel/assets/ChatBubbleRenderer-pPuUDG2V.js +0 -1
- package/src/assets/web-panel/assets/Logs-BZv9Z6BY.js +0 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-D5NZGdg3.js +0 -1
- package/src/assets/web-panel/assets/PdhVaultBrowser-Cfd_C9nc.js +0 -7
- package/src/assets/web-panel/assets/Projects-CTgx3Fxc.js +0 -1
- package/src/assets/web-panel/assets/devWarning-BFfV5AtN.js +0 -1
- package/src/assets/web-panel/assets/index-DUz_bv5i.js +0 -1
- package/src/assets/web-panel/assets/index-rQ59l7GO.js +0 -1
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
deleteSession as dbDeleteSession,
|
|
37
37
|
} from "../../lib/session-manager.js";
|
|
38
38
|
import { buildSystemPrompt } from "../../runtime/agent-core.js";
|
|
39
|
+
import { createHostToolPolicyAuthority } from "../../lib/host-tool-policy-authority.js";
|
|
39
40
|
import { SubAgentRegistry } from "../../lib/sub-agent-registry.js";
|
|
40
41
|
import {
|
|
41
42
|
createWorktree,
|
|
@@ -71,7 +72,39 @@ import {
|
|
|
71
72
|
} from "../../harness/jsonl-session-store.js";
|
|
72
73
|
|
|
73
74
|
export const WS_SESSION_ROLLOUT_EVENT = "ws_session_state";
|
|
74
|
-
const WS_SESSION_ROLLOUT_SCHEMA = "chainlesschain.ws-session-rollout/
|
|
75
|
+
const WS_SESSION_ROLLOUT_SCHEMA = "chainlesschain.ws-session-rollout/v2";
|
|
76
|
+
const LEGACY_WS_SESSION_ROLLOUT_SCHEMA = "chainlesschain.ws-session-rollout/v1";
|
|
77
|
+
const WS_HOST_POLICY_SCHEMA = "chainlesschain.ws-host-tool-policy/v1";
|
|
78
|
+
const SESSION_HOST_POLICY_CONTROLLERS = new WeakMap();
|
|
79
|
+
|
|
80
|
+
function bindSessionHostToolPolicy(session, controller) {
|
|
81
|
+
SESSION_HOST_POLICY_CONTROLLERS.set(session, controller);
|
|
82
|
+
Object.defineProperties(session, {
|
|
83
|
+
hostManagedToolPolicyAuthority: { value: controller.authority },
|
|
84
|
+
hostManagedToolPolicy: {
|
|
85
|
+
enumerable: true,
|
|
86
|
+
get: () => controller.authority.getSnapshot().policy,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function canonicalHostToolPolicy(journal, fallback = null) {
|
|
92
|
+
if (!journal || !Object.hasOwn(journal, "hostToolPolicy")) return fallback;
|
|
93
|
+
const stored = journal.hostToolPolicy;
|
|
94
|
+
if (
|
|
95
|
+
!stored ||
|
|
96
|
+
stored.schema !== WS_HOST_POLICY_SCHEMA ||
|
|
97
|
+
!Object.hasOwn(stored, "policy")
|
|
98
|
+
) {
|
|
99
|
+
throw canonicalWsStateError(
|
|
100
|
+
"CC_WS_CANONICAL_STATE_CORRUPT",
|
|
101
|
+
"Canonical host policy is invalid",
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
// Validate known authority fields before restoring any execution capability.
|
|
105
|
+
return createHostToolPolicyAuthority(stored.policy).authority.getSnapshot()
|
|
106
|
+
.policy;
|
|
107
|
+
}
|
|
75
108
|
|
|
76
109
|
function canonicalWsStateError(code, message) {
|
|
77
110
|
const error = new Error(message);
|
|
@@ -475,6 +508,9 @@ export class WSSessionManager {
|
|
|
475
508
|
throw error;
|
|
476
509
|
}
|
|
477
510
|
const type = options.type || "agent";
|
|
511
|
+
const hostPolicyController = createHostToolPolicyAuthority(
|
|
512
|
+
options.hostManagedToolPolicy ?? null,
|
|
513
|
+
);
|
|
478
514
|
const baseProjectRoot = options.projectRoot || this.defaultProjectRoot;
|
|
479
515
|
const hostAuthorizedBaseRoot =
|
|
480
516
|
normalizeHostWorkspaceRoot(baseProjectRoot) ===
|
|
@@ -583,7 +619,6 @@ export class WSSessionManager {
|
|
|
583
619
|
baseUrl,
|
|
584
620
|
mcpClient: this.mcpClient,
|
|
585
621
|
enabledToolNames,
|
|
586
|
-
hostManagedToolPolicy: options.hostManagedToolPolicy || null,
|
|
587
622
|
sessionBudgetRoot: options.sessionBudgetRoot || null,
|
|
588
623
|
externalToolDefinitions: externalTools.definitions,
|
|
589
624
|
externalToolDescriptors: externalTools.descriptors,
|
|
@@ -605,6 +640,7 @@ export class WSSessionManager {
|
|
|
605
640
|
createdAt: new Date().toISOString(),
|
|
606
641
|
lastActivity: new Date().toISOString(),
|
|
607
642
|
};
|
|
643
|
+
bindSessionHostToolPolicy(session, hostPolicyController);
|
|
608
644
|
bindCanonicalHostSystemPrefix(session, messages);
|
|
609
645
|
this._bindSessionStateJournal(session, createWsSessionState());
|
|
610
646
|
bindSessionHooksV2Workspace(
|
|
@@ -726,14 +762,28 @@ export class WSSessionManager {
|
|
|
726
762
|
if (!this.db) return null;
|
|
727
763
|
|
|
728
764
|
try {
|
|
729
|
-
const dbSession = dbGetSession(this.db, sessionId
|
|
765
|
+
const dbSession = dbGetSession(this.db, sessionId, {
|
|
766
|
+
strictMetadata: true,
|
|
767
|
+
});
|
|
730
768
|
if (!dbSession) return null;
|
|
731
769
|
|
|
732
770
|
const messages =
|
|
733
771
|
typeof dbSession.messages === "string"
|
|
734
772
|
? JSON.parse(dbSession.messages)
|
|
735
773
|
: dbSession.messages || [];
|
|
736
|
-
const metadata = this._normalizeSessionMetadata(dbSession.metadata
|
|
774
|
+
const metadata = this._normalizeSessionMetadata(dbSession.metadata, {
|
|
775
|
+
strict: true,
|
|
776
|
+
});
|
|
777
|
+
const canonicalSessionState =
|
|
778
|
+
metadata.canonicalJsonlSession === true
|
|
779
|
+
? this._readCanonicalSessionState(dbSession.id, { required: true })
|
|
780
|
+
: null;
|
|
781
|
+
const hostPolicyController = createHostToolPolicyAuthority(
|
|
782
|
+
canonicalHostToolPolicy(
|
|
783
|
+
canonicalSessionState,
|
|
784
|
+
metadata.hostManagedToolPolicy ?? null,
|
|
785
|
+
),
|
|
786
|
+
);
|
|
737
787
|
const baseProjectRoot =
|
|
738
788
|
metadata.baseProjectRoot ||
|
|
739
789
|
metadata.projectRoot ||
|
|
@@ -744,10 +794,6 @@ export class WSSessionManager {
|
|
|
744
794
|
metadata,
|
|
745
795
|
);
|
|
746
796
|
const planManager = this._hydratePlanManager(metadata.planSnapshot);
|
|
747
|
-
const canonicalSessionState =
|
|
748
|
-
metadata.canonicalJsonlSession === true
|
|
749
|
-
? this._readCanonicalSessionState(dbSession.id, { required: true })
|
|
750
|
-
: null;
|
|
751
797
|
const sessionStateJournal = canonicalSessionState
|
|
752
798
|
? hydrateCanonicalWsSessionState(canonicalSessionState)
|
|
753
799
|
: hydrateWsSessionState(
|
|
@@ -806,7 +852,6 @@ export class WSSessionManager {
|
|
|
806
852
|
enabledToolNames: this._normalizeEnabledToolNames(
|
|
807
853
|
metadata.enabledToolNames,
|
|
808
854
|
),
|
|
809
|
-
hostManagedToolPolicy: metadata.hostManagedToolPolicy || null,
|
|
810
855
|
sessionBudgetRoot: metadata.sessionBudgetRoot || null,
|
|
811
856
|
externalToolDefinitions: externalTools.definitions,
|
|
812
857
|
externalToolDescriptors: externalTools.descriptors,
|
|
@@ -830,6 +875,7 @@ export class WSSessionManager {
|
|
|
830
875
|
createdAt: dbSession.created_at,
|
|
831
876
|
lastActivity: new Date().toISOString(),
|
|
832
877
|
};
|
|
878
|
+
bindSessionHostToolPolicy(session, hostPolicyController);
|
|
833
879
|
if (Array.isArray(metadata.canonicalHostSystemPrefix)) {
|
|
834
880
|
bindCanonicalHostSystemPrefix(
|
|
835
881
|
session,
|
|
@@ -875,6 +921,10 @@ export class WSSessionManager {
|
|
|
875
921
|
: { changed: false };
|
|
876
922
|
const created = this.createSession({
|
|
877
923
|
sessionId,
|
|
924
|
+
hostManagedToolPolicy: canonicalHostToolPolicy(
|
|
925
|
+
canonicalSessionState,
|
|
926
|
+
options.hostManagedToolPolicy ?? null,
|
|
927
|
+
),
|
|
878
928
|
type: options.type || "agent",
|
|
879
929
|
provider: options.provider,
|
|
880
930
|
model: options.model,
|
|
@@ -1049,9 +1099,27 @@ export class WSSessionManager {
|
|
|
1049
1099
|
const session = this.sessions.get(sessionId);
|
|
1050
1100
|
if (!session) return null;
|
|
1051
1101
|
|
|
1052
|
-
|
|
1102
|
+
const controller = SESSION_HOST_POLICY_CONTROLLERS.get(session);
|
|
1103
|
+
if (!controller) {
|
|
1104
|
+
const error = new Error("Session host policy authority is unavailable");
|
|
1105
|
+
error.code = "CC_HOST_TOOL_POLICY_AUTHORITY_UNAVAILABLE";
|
|
1106
|
+
throw error;
|
|
1107
|
+
}
|
|
1108
|
+
controller.commit(hostManagedToolPolicy ?? null);
|
|
1053
1109
|
session.lastActivity = new Date().toISOString();
|
|
1054
|
-
|
|
1110
|
+
try {
|
|
1111
|
+
this._persistCanonicalSessionState(
|
|
1112
|
+
session,
|
|
1113
|
+
this._ensureSessionStateJournal(session),
|
|
1114
|
+
);
|
|
1115
|
+
this._persistSessionState(sessionId, { throwOnError: true });
|
|
1116
|
+
} catch (error) {
|
|
1117
|
+
// Do not acknowledge a failed save or allow further execution from its
|
|
1118
|
+
// uncertain policy. The committed revision has already revoked monitors.
|
|
1119
|
+
controller.invalidate();
|
|
1120
|
+
error.code ||= "CC_WS_SESSION_POLICY_PERSISTENCE_FAILED";
|
|
1121
|
+
throw error;
|
|
1122
|
+
}
|
|
1055
1123
|
return session;
|
|
1056
1124
|
}
|
|
1057
1125
|
|
|
@@ -1707,7 +1775,7 @@ export class WSSessionManager {
|
|
|
1707
1775
|
};
|
|
1708
1776
|
}
|
|
1709
1777
|
|
|
1710
|
-
_persistSessionState(sessionId) {
|
|
1778
|
+
_persistSessionState(sessionId, { throwOnError = false } = {}) {
|
|
1711
1779
|
const session = this.sessions.get(sessionId);
|
|
1712
1780
|
if (!session || !this.db) return;
|
|
1713
1781
|
|
|
@@ -1726,13 +1794,21 @@ export class WSSessionManager {
|
|
|
1726
1794
|
);
|
|
1727
1795
|
persistedMessages = [...hostPrefix, ...conversation];
|
|
1728
1796
|
}
|
|
1729
|
-
dbSaveMessages(
|
|
1797
|
+
const saved = dbSaveMessages(
|
|
1730
1798
|
this.db,
|
|
1731
1799
|
sessionId,
|
|
1732
1800
|
persistedMessages,
|
|
1733
1801
|
this._serializeSessionMetadata(session),
|
|
1734
1802
|
);
|
|
1735
|
-
|
|
1803
|
+
if (throwOnError && saved?.updated !== true) {
|
|
1804
|
+
const error = new Error(
|
|
1805
|
+
"Session policy persistence did not update a record",
|
|
1806
|
+
);
|
|
1807
|
+
error.code = "CC_WS_SESSION_POLICY_PERSISTENCE_FAILED";
|
|
1808
|
+
throw error;
|
|
1809
|
+
}
|
|
1810
|
+
} catch (error) {
|
|
1811
|
+
if (throwOnError) throw error;
|
|
1736
1812
|
// Non-critical
|
|
1737
1813
|
}
|
|
1738
1814
|
|
|
@@ -1817,12 +1893,35 @@ export class WSSessionManager {
|
|
|
1817
1893
|
}
|
|
1818
1894
|
return null;
|
|
1819
1895
|
}
|
|
1820
|
-
if (
|
|
1896
|
+
if (
|
|
1897
|
+
![WS_SESSION_ROLLOUT_SCHEMA, LEGACY_WS_SESSION_ROLLOUT_SCHEMA].includes(
|
|
1898
|
+
event.data?.schema,
|
|
1899
|
+
)
|
|
1900
|
+
) {
|
|
1821
1901
|
throw canonicalWsStateError(
|
|
1822
1902
|
"CC_WS_CANONICAL_STATE_CORRUPT",
|
|
1823
1903
|
`canonical WebSocket session state has an invalid schema: ${sessionId}`,
|
|
1824
1904
|
);
|
|
1825
1905
|
}
|
|
1906
|
+
if (
|
|
1907
|
+
!event.data.journal ||
|
|
1908
|
+
typeof event.data.journal !== "object" ||
|
|
1909
|
+
Array.isArray(event.data.journal)
|
|
1910
|
+
) {
|
|
1911
|
+
throw canonicalWsStateError(
|
|
1912
|
+
"CC_WS_CANONICAL_STATE_CORRUPT",
|
|
1913
|
+
"Canonical WebSocket journal is missing or invalid",
|
|
1914
|
+
);
|
|
1915
|
+
}
|
|
1916
|
+
if (event.data.schema === WS_SESSION_ROLLOUT_SCHEMA) {
|
|
1917
|
+
if (!Object.hasOwn(event.data.journal, "hostToolPolicy")) {
|
|
1918
|
+
throw canonicalWsStateError(
|
|
1919
|
+
"CC_WS_CANONICAL_STATE_CORRUPT",
|
|
1920
|
+
"Canonical host policy is missing",
|
|
1921
|
+
);
|
|
1922
|
+
}
|
|
1923
|
+
canonicalHostToolPolicy(event.data.journal);
|
|
1924
|
+
}
|
|
1826
1925
|
return event.data.journal;
|
|
1827
1926
|
}
|
|
1828
1927
|
|
|
@@ -1833,7 +1932,13 @@ export class WSSessionManager {
|
|
|
1833
1932
|
WS_SESSION_ROLLOUT_EVENT,
|
|
1834
1933
|
{
|
|
1835
1934
|
schema: WS_SESSION_ROLLOUT_SCHEMA,
|
|
1836
|
-
journal:
|
|
1935
|
+
journal: {
|
|
1936
|
+
...serializeWsSessionState(journal),
|
|
1937
|
+
hostToolPolicy: {
|
|
1938
|
+
schema: WS_HOST_POLICY_SCHEMA,
|
|
1939
|
+
policy: session.hostManagedToolPolicy,
|
|
1940
|
+
},
|
|
1941
|
+
},
|
|
1837
1942
|
},
|
|
1838
1943
|
);
|
|
1839
1944
|
}
|
|
@@ -1914,20 +2019,27 @@ export class WSSessionManager {
|
|
|
1914
2019
|
};
|
|
1915
2020
|
}
|
|
1916
2021
|
|
|
1917
|
-
_normalizeSessionMetadata(metadata) {
|
|
1918
|
-
if (!metadata) {
|
|
2022
|
+
_normalizeSessionMetadata(metadata, { strict = false } = {}) {
|
|
2023
|
+
if (metadata == null || (!strict && !metadata)) {
|
|
1919
2024
|
return {};
|
|
1920
2025
|
}
|
|
1921
2026
|
|
|
1922
2027
|
if (typeof metadata === "string") {
|
|
1923
2028
|
try {
|
|
1924
|
-
|
|
1925
|
-
|
|
2029
|
+
const parsed = JSON.parse(metadata);
|
|
2030
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
2031
|
+
throw new TypeError("Invalid session metadata");
|
|
2032
|
+
return parsed;
|
|
2033
|
+
} catch (error) {
|
|
2034
|
+
if (strict) throw error;
|
|
1926
2035
|
return {};
|
|
1927
2036
|
}
|
|
1928
2037
|
}
|
|
1929
2038
|
|
|
1930
|
-
|
|
2039
|
+
if (typeof metadata === "object" && !Array.isArray(metadata))
|
|
2040
|
+
return metadata;
|
|
2041
|
+
if (strict) throw new TypeError("Invalid session metadata");
|
|
2042
|
+
return {};
|
|
1931
2043
|
}
|
|
1932
2044
|
|
|
1933
2045
|
_hydratePlanManager(snapshot) {
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { isProxy } from "node:util/types";
|
|
2
|
+
import { snapshotMcpJsonRpcInput } from "./mcp-call-ledger.js";
|
|
3
|
+
import { captureUnattendedActionPolicy } from "./unattended-action-policy.js";
|
|
4
|
+
|
|
5
|
+
function invalidPolicy(field) {
|
|
6
|
+
const error = new TypeError(`Agent execution policy ${field} is invalid`);
|
|
7
|
+
error.code = "CC_AGENT_EXECUTION_POLICY_INVALID";
|
|
8
|
+
return error;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function ownValue(options, field) {
|
|
12
|
+
const descriptor = Object.getOwnPropertyDescriptor(options, field);
|
|
13
|
+
if (!descriptor) {
|
|
14
|
+
if (field in options) throw invalidPolicy(field);
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
if (!("value" in descriptor)) throw invalidPolicy(field);
|
|
18
|
+
return descriptor.value;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function objectSnapshot(value, field) {
|
|
22
|
+
if (value == null) return null;
|
|
23
|
+
try {
|
|
24
|
+
const snapshot = snapshotMcpJsonRpcInput(value);
|
|
25
|
+
if (!snapshot || typeof snapshot !== "object" || Array.isArray(snapshot))
|
|
26
|
+
throw invalidPolicy(field);
|
|
27
|
+
return snapshot;
|
|
28
|
+
} catch {
|
|
29
|
+
throw invalidPolicy(field);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function stringList(value, field) {
|
|
34
|
+
if (value == null) return null;
|
|
35
|
+
try {
|
|
36
|
+
const snapshot = snapshotMcpJsonRpcInput(value);
|
|
37
|
+
if (
|
|
38
|
+
!Array.isArray(snapshot) ||
|
|
39
|
+
snapshot.some((entry) => typeof entry !== "string" || !entry.trim())
|
|
40
|
+
)
|
|
41
|
+
throw invalidPolicy(field);
|
|
42
|
+
return snapshot;
|
|
43
|
+
} catch {
|
|
44
|
+
throw invalidPolicy(field);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function booleanFields(value, fields, label) {
|
|
49
|
+
for (const field of fields) {
|
|
50
|
+
if (value[field] !== undefined && typeof value[field] !== "boolean")
|
|
51
|
+
throw invalidPolicy(`${label}.${field}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function captureSandbox(value) {
|
|
56
|
+
if (value === false) return null;
|
|
57
|
+
const sandbox = objectSnapshot(value, "sandbox");
|
|
58
|
+
if (!sandbox) return null;
|
|
59
|
+
booleanFields(sandbox, ["network"], "sandbox");
|
|
60
|
+
if (sandbox.policy !== undefined) {
|
|
61
|
+
const policy = objectSnapshot(sandbox.policy, "sandbox.policy");
|
|
62
|
+
if (!policy) throw invalidPolicy("sandbox.policy");
|
|
63
|
+
booleanFields(
|
|
64
|
+
policy,
|
|
65
|
+
["allowUnsandboxedCommands", "failIfUnavailable"],
|
|
66
|
+
"sandbox.policy",
|
|
67
|
+
);
|
|
68
|
+
for (const field of [
|
|
69
|
+
"allowRead",
|
|
70
|
+
"denyRead",
|
|
71
|
+
"allowWrite",
|
|
72
|
+
"denyWrite",
|
|
73
|
+
"allowedDomains",
|
|
74
|
+
"deniedDomains",
|
|
75
|
+
"excludedCommands",
|
|
76
|
+
]) {
|
|
77
|
+
if (policy[field] !== undefined)
|
|
78
|
+
stringList(policy[field], `sandbox.policy.${field}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return sandbox;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function captureToolAdmission(value) {
|
|
85
|
+
const admission = objectSnapshot(value, "toolAdmission");
|
|
86
|
+
if (!admission) return null;
|
|
87
|
+
const flags = [
|
|
88
|
+
"enforce",
|
|
89
|
+
"capabilityGranted",
|
|
90
|
+
"policyAllowed",
|
|
91
|
+
"permissionGranted",
|
|
92
|
+
"budgetOk",
|
|
93
|
+
"uiSupported",
|
|
94
|
+
];
|
|
95
|
+
booleanFields(admission, flags, "toolAdmission");
|
|
96
|
+
if (admission.tools !== undefined) {
|
|
97
|
+
const tools = objectSnapshot(admission.tools, "toolAdmission.tools");
|
|
98
|
+
if (!tools) throw invalidPolicy("toolAdmission.tools");
|
|
99
|
+
for (const [name, entry] of Object.entries(tools)) {
|
|
100
|
+
const override = objectSnapshot(entry, `toolAdmission.tools.${name}`);
|
|
101
|
+
if (!override) throw invalidPolicy(`toolAdmission.tools.${name}`);
|
|
102
|
+
booleanFields(override, flags, `toolAdmission.tools.${name}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return admission;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Copy startup/turn data before the first await. Live permission providers,
|
|
110
|
+
* host policy owners, Plan managers and ApprovalGates remain live capabilities.
|
|
111
|
+
* A later user turn may capture a different tool list; this turn's caller-owned
|
|
112
|
+
* arrays cannot change its model surface or execution ceiling midway through.
|
|
113
|
+
*/
|
|
114
|
+
export function captureAgentExecutionPolicy(
|
|
115
|
+
options = {},
|
|
116
|
+
{ hermetic = false } = {},
|
|
117
|
+
) {
|
|
118
|
+
if (!options || typeof options !== "object" || isProxy(options))
|
|
119
|
+
throw invalidPolicy("options");
|
|
120
|
+
const isolated = hermetic && ownValue(options, "hermeticExecution") === true;
|
|
121
|
+
const policy = {
|
|
122
|
+
sandbox: captureSandbox(ownValue(options, "sandbox")),
|
|
123
|
+
toolAdmission: isolated
|
|
124
|
+
? null
|
|
125
|
+
: captureToolAdmission(ownValue(options, "toolAdmission")),
|
|
126
|
+
unattendedActionPolicy: isolated
|
|
127
|
+
? null
|
|
128
|
+
: captureUnattendedActionPolicy(
|
|
129
|
+
ownValue(options, "unattendedActionPolicy"),
|
|
130
|
+
),
|
|
131
|
+
shellPolicyOverrides: stringList(
|
|
132
|
+
ownValue(options, "shellPolicyOverrides"),
|
|
133
|
+
"shellPolicyOverrides",
|
|
134
|
+
),
|
|
135
|
+
};
|
|
136
|
+
const classifyAllShell = ownValue(options, "classifyAllShell");
|
|
137
|
+
if (classifyAllShell != null) {
|
|
138
|
+
if (typeof classifyAllShell !== "boolean")
|
|
139
|
+
throw invalidPolicy("classifyAllShell");
|
|
140
|
+
policy.classifyAllShell = classifyAllShell;
|
|
141
|
+
}
|
|
142
|
+
for (const field of [
|
|
143
|
+
"additionalDirectories",
|
|
144
|
+
"enabledToolNames",
|
|
145
|
+
"disabledTools",
|
|
146
|
+
"allowedTools",
|
|
147
|
+
"disallowedTools",
|
|
148
|
+
"effectiveAllowedToolNames",
|
|
149
|
+
]) {
|
|
150
|
+
const value = ownValue(options, field);
|
|
151
|
+
if (value !== undefined) policy[field] = stringList(value, field);
|
|
152
|
+
}
|
|
153
|
+
return Object.freeze(policy);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Explicit lists intersect; deny lists always accumulate. [] means no tools. */
|
|
157
|
+
export function resolveAgentToolSelection(policy = {}, ceiling = null) {
|
|
158
|
+
const lists = [
|
|
159
|
+
ceiling,
|
|
160
|
+
policy.allowedTools,
|
|
161
|
+
policy.enabledToolNames,
|
|
162
|
+
policy.effectiveAllowedToolNames,
|
|
163
|
+
].filter(Array.isArray);
|
|
164
|
+
const enabledToolNames =
|
|
165
|
+
lists.length === 0
|
|
166
|
+
? null
|
|
167
|
+
: Object.freeze(
|
|
168
|
+
lists[0].filter((name) => lists.every((list) => list.includes(name))),
|
|
169
|
+
);
|
|
170
|
+
const disabledTools = Object.freeze([
|
|
171
|
+
...new Set([
|
|
172
|
+
...(policy.disabledTools || []),
|
|
173
|
+
...(policy.disallowedTools || []),
|
|
174
|
+
]),
|
|
175
|
+
]);
|
|
176
|
+
return Object.freeze({ enabledToolNames, disabledTools });
|
|
177
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/** Launcher-owned storage locations and permission switches. */
|
|
2
|
+
|
|
3
|
+
export const STORAGE_AUTHORITY_ENV_KEYS = Object.freeze([
|
|
4
|
+
"CHAINLESSCHAIN_HOME",
|
|
5
|
+
"CLAUDE_CONFIG_DIR",
|
|
6
|
+
"CLAUDE_CODE_PROJECT_DIR_NAME",
|
|
7
|
+
"CLAUDE_CODE_DISABLE_AUTO_MEMORY",
|
|
8
|
+
"CC_MANAGED_SETTINGS",
|
|
9
|
+
"ProgramData",
|
|
10
|
+
"PROGRAMDATA",
|
|
11
|
+
"CHAINLESSCHAIN_SECURITY_ANCHOR_HOME",
|
|
12
|
+
"LOCALAPPDATA",
|
|
13
|
+
"XDG_STATE_HOME",
|
|
14
|
+
// os.homedir() uses these launcher values too. Protecting only the explicit
|
|
15
|
+
// anchor override leaves its default location redirectable via settings env.
|
|
16
|
+
"HOME",
|
|
17
|
+
"USERPROFILE",
|
|
18
|
+
"HOMEDRIVE",
|
|
19
|
+
"HOMEPATH",
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
const PERMISSION_AUTHORITY_ENV_KEYS = Object.freeze([
|
|
23
|
+
"CC_PERMISSIONS_ALLOW",
|
|
24
|
+
"CC_PERMISSIONS_ASK",
|
|
25
|
+
"CC_PERMISSIONS_DENY",
|
|
26
|
+
"CC_BYPASS_PERMISSIONS",
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
function normalizeKey(key, platform) {
|
|
30
|
+
return platform === "win32" ? key.toUpperCase() : key;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function storageKeys(platform) {
|
|
34
|
+
return new Map(
|
|
35
|
+
STORAGE_AUTHORITY_ENV_KEYS.map((key) => [normalizeKey(key, platform), key]),
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Native process.env truncates names at NUL; validate before any assignment. */
|
|
40
|
+
export function isValidEnvironmentKey(key) {
|
|
41
|
+
return (
|
|
42
|
+
typeof key === "string" &&
|
|
43
|
+
key.length > 0 &&
|
|
44
|
+
!key.includes("\0") &&
|
|
45
|
+
!key.includes("=")
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Plugins may supply tool defaults, but cannot select a new authority domain. */
|
|
50
|
+
export function isPluginAuthorityEnvironmentKey(
|
|
51
|
+
key,
|
|
52
|
+
{ platform = process.platform } = {},
|
|
53
|
+
) {
|
|
54
|
+
if (typeof key !== "string") return false;
|
|
55
|
+
const normalized = normalizeKey(key, platform);
|
|
56
|
+
return [...STORAGE_AUTHORITY_ENV_KEYS, ...PERMISSION_AUTHORITY_ENV_KEYS].some(
|
|
57
|
+
(candidate) => normalizeKey(candidate, platform) === normalized,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function captureStorageAuthorityEnvironment(
|
|
62
|
+
env = process.env,
|
|
63
|
+
{ platform = process.platform } = {},
|
|
64
|
+
) {
|
|
65
|
+
const keys = storageKeys(platform);
|
|
66
|
+
const snapshot = {};
|
|
67
|
+
for (const [key, value] of Object.entries(env)) {
|
|
68
|
+
const canonicalKey = keys.get(normalizeKey(key, platform));
|
|
69
|
+
if (!canonicalKey || typeof value !== "string") continue;
|
|
70
|
+
if (
|
|
71
|
+
Object.hasOwn(snapshot, canonicalKey) &&
|
|
72
|
+
snapshot[canonicalKey] !== value
|
|
73
|
+
) {
|
|
74
|
+
const error = new Error(
|
|
75
|
+
"Conflicting launcher storage environment aliases",
|
|
76
|
+
);
|
|
77
|
+
error.code = "CC_STORAGE_AUTHORITY_ENV_AMBIGUOUS";
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
snapshot[canonicalKey] = value;
|
|
81
|
+
}
|
|
82
|
+
return Object.freeze(snapshot);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Remove newly introduced aliases before restoring the trusted snapshot. */
|
|
86
|
+
export function restoreStorageAuthorityEnvironment(
|
|
87
|
+
snapshot,
|
|
88
|
+
env = process.env,
|
|
89
|
+
{ platform = process.platform } = {},
|
|
90
|
+
) {
|
|
91
|
+
const captured = captureStorageAuthorityEnvironment(snapshot || {}, {
|
|
92
|
+
platform,
|
|
93
|
+
});
|
|
94
|
+
const keys = storageKeys(platform);
|
|
95
|
+
for (const key of Object.keys(env)) {
|
|
96
|
+
if (keys.has(normalizeKey(key, platform))) delete env[key];
|
|
97
|
+
}
|
|
98
|
+
Object.assign(env, captured);
|
|
99
|
+
}
|
|
@@ -15,11 +15,12 @@ import {
|
|
|
15
15
|
realpathSync,
|
|
16
16
|
writeFileSync,
|
|
17
17
|
} from "node:fs";
|
|
18
|
-
import {
|
|
18
|
+
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
19
|
+
import { resolveClaudeProjectStorageDir } from "./claude-project-storage-layout.js";
|
|
19
20
|
import {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
} from "./
|
|
21
|
+
captureStorageAuthorityEnvironment,
|
|
22
|
+
restoreStorageAuthorityEnvironment,
|
|
23
|
+
} from "./authority-launch-environment.js";
|
|
23
24
|
import {
|
|
24
25
|
assertSafeConfigDataRoot,
|
|
25
26
|
ensureClaudeProjectStorageTree,
|
|
@@ -40,29 +41,12 @@ export const CLAUDE_AUTO_MEMORY_MAX_SETTINGS_BYTES = 256 * 1024;
|
|
|
40
41
|
export const CLAUDE_AUTO_MEMORY_MAX_BINDING_BYTES = 4096;
|
|
41
42
|
export const CLAUDE_AUTO_MEMORY_MAX_EXISTING_FILES = 512;
|
|
42
43
|
|
|
43
|
-
const LAUNCH_ENV_KEYS = Object.freeze([
|
|
44
|
-
"CHAINLESSCHAIN_HOME",
|
|
45
|
-
CLAUDE_CONFIG_DIR_ENV,
|
|
46
|
-
"CLAUDE_CODE_PROJECT_DIR_NAME",
|
|
47
|
-
"CLAUDE_CODE_DISABLE_AUTO_MEMORY",
|
|
48
|
-
"CC_MANAGED_SETTINGS",
|
|
49
|
-
// Managed settings default path is derived from these trusted launcher
|
|
50
|
-
// values on Windows; include them so a project settings env map cannot
|
|
51
|
-
// redirect that authority after the snapshot.
|
|
52
|
-
"ProgramData",
|
|
53
|
-
"PROGRAMDATA",
|
|
54
|
-
]);
|
|
55
|
-
|
|
56
44
|
function autoMemoryError(code, message) {
|
|
57
45
|
const error = new Error(message);
|
|
58
46
|
error.code = code;
|
|
59
47
|
return error;
|
|
60
48
|
}
|
|
61
49
|
|
|
62
|
-
function owns(object, key) {
|
|
63
|
-
return Object.prototype.hasOwnProperty.call(object, key);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
50
|
function pathContains(parent, candidate) {
|
|
67
51
|
const relation = relative(parent, candidate);
|
|
68
52
|
return (
|
|
@@ -353,11 +337,7 @@ function isAutoMemoryDisabled(env) {
|
|
|
353
337
|
|
|
354
338
|
/** Capture storage-affecting environment authority before settings merge. */
|
|
355
339
|
export function captureClaudeStorageLaunchEnvironment(env = process.env) {
|
|
356
|
-
|
|
357
|
-
for (const key of LAUNCH_ENV_KEYS) {
|
|
358
|
-
if (typeof env[key] === "string") snapshot[key] = env[key];
|
|
359
|
-
}
|
|
360
|
-
return Object.freeze(snapshot);
|
|
340
|
+
return captureStorageAuthorityEnvironment(env);
|
|
361
341
|
}
|
|
362
342
|
|
|
363
343
|
/**
|
|
@@ -368,10 +348,7 @@ export function restoreClaudeStorageLaunchEnvironment(
|
|
|
368
348
|
snapshot,
|
|
369
349
|
env = process.env,
|
|
370
350
|
) {
|
|
371
|
-
|
|
372
|
-
if (owns(snapshot || {}, key)) env[key] = snapshot[key];
|
|
373
|
-
else delete env[key];
|
|
374
|
-
}
|
|
351
|
+
restoreStorageAuthorityEnvironment(snapshot, env);
|
|
375
352
|
}
|
|
376
353
|
|
|
377
354
|
/** Validate configuration/root and project-name authority before side effects. */
|