chainlesschain 0.162.174 → 0.162.176
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 +10 -10
- package/src/assets/web-panel/assets/{AIOps-Dcl-X1Hw.js → AIOps-BDLu5Elz.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-ClMh9HzT.js → ActionButton-DH5us-CK.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DPj0rSQ5.js → Analytics-BZ0u8IFG.js} +3 -3
- package/src/assets/web-panel/assets/AppLayout-Duu8xR14.js +9 -0
- package/src/assets/web-panel/assets/{Artifacts-L8781rE8.js → Artifacts-Br2YBbh_.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CffB6WIP.js → Audit-C3C6a482.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BkLhayyY.js → BackgroundAgents-CzHvebcj.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BQnwFI78.js → Backup-DZNHYDFd.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-xuUGHQch.js → BaseInput-VRiC4fIx.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-feQXwWrg.js → Chat-Cm08WWAD.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-CGHYrugQ.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-DVaIiUGW.js → Checkbox-DtByk7d7.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-D2kEnzeU.js → Codegen-CphXXOfD.js} +1 -1
- package/src/assets/web-panel/assets/{Col-azDoyusS.js → Col-Hz86TnLR.js} +1 -1
- package/src/assets/web-panel/assets/{Community-OZdnPWM5.js → Community-HP03ltpD.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-VDMvBN-C.js → Compact-B_N1mqQz.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CPJ_zgQ1.js → Compliance-CVztRpi8.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-iRBwcsOA.js → Cowork-wUVOyZih.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-DrxrspUz.js → Cron-DW5TLJKw.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-D-rkAZXF.js → Crosschain-CrAFGhWH.js} +1 -1
- package/src/assets/web-panel/assets/{DID-5Pp1Xnmr.js → DID-pA-oD8ke.js} +2 -2
- package/src/assets/web-panel/assets/Dashboard-CXrd5gAw.js +3 -0
- package/src/assets/web-panel/assets/{Dropdown-BWj_E0Ie.js → Dropdown-EweJcsek.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BT-wgSEh.js → EmailListRenderer-C9xVLPG4.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-1PzH23pa.js → FamilyGuardDashboard-CDcEEqlu.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BxMIXGC6.js → Federation-DtZda9A_.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CyJobBln.js → FormItemContext-CiYdcVz3.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-YkjFuQTN.js → GenericCardRenderer-DA13uwA0.js} +1 -1
- package/src/assets/web-panel/assets/{Git-C2a98Wp_.js → Git-DzRhZD1O.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DKL3Fl84.js → Governance-D5RMgOSb.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BJ2cQC_3.js → Inference-BgrPfSNk.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DBAsOngt.js → KnowledgeGraph-DzjnD571.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-COt8g9LO.js → Logs-BhWzVDtN.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-3Lfht1Fd.js → MarkdownRenderer-BDape9cx.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-C9Zk9Pb2.js → Marketplace-DJtL5GV7.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DDWDFWPO.js → McpTools-CZcQygI7.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-BRmVye_o.js → Memory-DUWSDUUu.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CppBbWpD.js → MobileBridge-BTwq2WKY.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-NZvvfDME.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-CcWpeGa6.js → Mtc-BiGugEQm.js} +6 -6
- package/src/assets/web-panel/assets/{MtcAudit-BcllEq0K.js → MtcAudit-DY7a6gUe.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-BFD1CarL.js → Multisig-BQbDu_w7.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-QNXXYvjz.js → NLProgramming-CM2wXTLv.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-07YwgQVy.js → Notes-DI6gGs1v.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-bOccEInE.js → NotificationSettings-BsZOLWAB.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DlRi29WL.js → OrderTableRenderer-C48mu09U.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-CBaezzEr.js → Organization-Cds0_tXr.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Bl5NohFO.js → Overflow-WunYMD87.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CLMal9Aw.js → P2P-Bo6j4DDv.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CGO0NITk.js → PdhVaultBrowser-Bh2XPD5f.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CPSw48E2.js → Permissions-EMvMMC8N.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-CDM5n134.js → PersonalDataHub-AX3ypUDV.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-BdsqG7WV.js → Pipeline-BOx8HOgL.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-B6L4E-M7.js → Privacy-tBeTVQVM.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-DXPyZKRs.js → ProjectInit-CVYg1W4M.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BrCC3xYT.js → ProjectSettings-Dvt5I7y1.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BYmuHC2q.js → Projects-Cc7FC9-e.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-CbCe2eUl.js → Providers-Ct8xqY-E.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DkukgCrR.js → QrScannerModal-Cni8Ooja.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-D-htOrV8.js → QuickAsk-BJVLKdxr.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Bm7SIfzu.js → Recommend-DPG8Rbbm.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-C9rP-iMc.js → RemoteSession-DsdR7dCt.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-kGlUgbsl.js → Reputation-Csg1YM-b.js} +1 -1
- package/src/assets/web-panel/assets/{Row-PBupbbUA.js → Row-D9DoFoEf.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-njlwKUGK.js → RssFeed-BsvKrXMS.js} +2 -2
- package/src/assets/web-panel/assets/{Search-DLdEmgBw.js → Search-DFUStfgQ.js} +1 -1
- package/src/assets/web-panel/assets/{Security-SXGPSHdu.js → Security-ILg1zxdK.js} +4 -4
- package/src/assets/web-panel/assets/{Services-CuFGnNsb.js → Services-Dd41PCaY.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CtUC0mDa.js → Skeleton-Bzo1cN80.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-P1qgOVFn.js → Skills-BDHh17P0.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CsppE8YV.js → Sla-jl7UTiRY.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-Cq1oG56m.js → SpeechSettings-BePa-RF6.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DdKW6V-C.js → SyncSettings-DiqqDKGZ.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-BCc9san5.js → Tasks-DYQ_6lxj.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CcHC1dMA.js → Templates-JiDeI06L.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CA4PqU22.js → Tenant-hhgI6zwS.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-CjTZPa37.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-DHWTSvOy.js → TimelineRenderer-B8uB5Llk.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Ddz-P_yh.js → Tokens-C3b_6r2z.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-ePmrmLZ1.js → Trigger-tIP7HKVe.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DmuK1CCE.js → Trust-vjoc11vJ.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CqqBuRrT.js → UkeySign-DUPBnGuH.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BGlR3uWM.js → VideoEditing-CBvhUY5T.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Ba_Qx6Ga.js → Wallet-DUaQ0uA5.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-29neXKt2.js → WebAuthn-DllSivjE.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-lD0lR0UQ.js → WorkflowEditor-xc8D3uO6.js} +1 -1
- package/src/assets/web-panel/assets/{chat-B3stH01u.js → chat-BVicU7oA.js} +1 -1
- package/src/assets/web-panel/assets/{colors-Czly56MN.js → colors-DJzLmhLm.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-C0TkbkAJ.js → compact-item-BvYRfThE.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BJmpSlf1.js → createContext-DGXxCBKR.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BT46Y_QI.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-D1q-zw7u.js → hasIn-SBDJB1y4.js} +1 -1
- package/src/assets/web-panel/assets/{index-DV-twjNO.js → index-1SdDS6lR.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-kTvMq7.js → index-9gdI7uUW.js} +1 -1
- package/src/assets/web-panel/assets/index-B7nuIywP.js +1 -0
- package/src/assets/web-panel/assets/{index-Bm_-RKal.js → index-BJZf9DhV.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQftlZn-.js → index-BO1itZaY.js} +3 -3
- package/src/assets/web-panel/assets/{index-Dw3L_smW.js → index-BTrBGBJs.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7sFKQ53.js → index-BYqz4Wrr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DlvsSuBC.js → index-Bf-ctERC.js} +1 -1
- package/src/assets/web-panel/assets/{index-ChESIe5r.js → index-CKyEivf8.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaqEHaCg.js → index-CdGY9P8a.js} +1 -1
- package/src/assets/web-panel/assets/{index-DZeoKL6t.js → index-Cf-O_g_8.js} +1 -1
- package/src/assets/web-panel/assets/{index-XWV8JWMc.js → index-CloCgBUR.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpMIdPJ0.js → index-CoJAO1Lm.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgS8XUBU.js → index-Crk5NTb0.js} +1 -1
- package/src/assets/web-panel/assets/{index-DmUta2lw.js → index-Cs2rmLFt.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dpz_7sf-.js → index-CtwqO5qo.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRcQsPez.js → index-D7HimK0M.js} +1 -1
- package/src/assets/web-panel/assets/{index-BEt2-3x5.js → index-DCdRAgjy.js} +1 -1
- package/src/assets/web-panel/assets/{index-CHvPlzWJ.js → index-DCqRS6da.js} +1 -1
- package/src/assets/web-panel/assets/{index-BDHXx65P.js → index-DHVLJ8q0.js} +1 -1
- package/src/assets/web-panel/assets/{index-K4YaPDOn.js → index-DKrvvWm4.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1pOqU7D.js → index-DMarmfrv.js} +1 -1
- package/src/assets/web-panel/assets/{index-DAhrn9EJ.js → index-DRfiXB_p.js} +1 -1
- package/src/assets/web-panel/assets/{index-cPjWjvmW.js → index-Dm_77jgR.js} +1 -1
- package/src/assets/web-panel/assets/{index-C27TnOoT.js → index-DnjPdvR6.js} +1 -1
- package/src/assets/web-panel/assets/{index-upY9rkGZ.js → index-DonCnfMr.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbvNJUwu.js → index-DvUTDYXX.js} +1 -1
- package/src/assets/web-panel/assets/{index-BVwJ3jht.js → index-FxZzRyE1.js} +1 -1
- package/src/assets/web-panel/assets/{index-DIF6XHIi.js → index-MjC4G09d.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8KqsomG.js → index-VMfwIH5G.js} +1 -1
- package/src/assets/web-panel/assets/{index-8GKykbS4.js → index-YJkzy8ZF.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpGs96FC.js → index-d5BVd-cL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DO8xOwxi.js → index-e4fXH_WO.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cu_4HaUS.js → index-hxTODbM1.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cf7Gr3NG.js → index-lpaGoTH3.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBqAm8es.js → index-wcCL-miV.js} +1 -1
- package/src/assets/web-panel/assets/{index-ZDUhX41Z.js → index-xfluRkCT.js} +1 -1
- package/src/assets/web-panel/assets/index-ycwAfC-i.js +1 -0
- package/src/assets/web-panel/assets/{index-z8ATo2aQ.js → index-z1ZylsLq.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-QWEXi6-t.js → initDefaultProps-C1zO1KnY.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BfrQwvV1.js → motion-CWLtEGmC.js} +1 -1
- package/src/assets/web-panel/assets/{move-Dn7x0H9t.js → move-DzD_C3Vm.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-F61D_TgE.js → mtc-parser-D880PYJl.js} +1 -1
- package/src/assets/web-panel/assets/{omit-4SQZ39PF.js → omit-CFR_z2ov.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-C7DTe126.js → pickAttrs-srIhgrSC.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-40NeyzDK.js → placementArrow-C1rXpibP.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BiUJ6qWs.js → responsiveObserve-C30gRcSS.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CacJTM3f.js → slide-CvtKiMfV.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-K812HB-k.js → statusUtils-DNHO7ITG.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-CKeHA2eM.js → styleChecker-Dt_Sl-g4.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CKl4FqXF.js → useFlexGapSupport-Cjev42Gh.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DPoiJjSZ.js → useFs-Baxglj2V.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-aHwBspmt.js → usePersonalDataHub-B4NkcLaP.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DrA-GuCT.js → vnode-mIRkdT7o.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-G3LMswgy.js → zoom-HzI5DlH_.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/auth/npm-auth.js +30 -5
- package/src/commands/agenda.js +64 -2
- package/src/commands/agent.js +45 -3
- package/src/commands/background-session.js +103 -0
- package/src/commands/config.js +70 -5
- package/src/commands/context.js +36 -2
- package/src/commands/hub.js +19 -1
- package/src/commands/memory.js +21 -6
- package/src/commands/permissions.js +57 -1
- package/src/commands/plugin.js +2 -0
- package/src/commands/review.js +23 -11
- package/src/commands/routine.js +31 -8
- package/src/commands/session.js +11 -3
- package/src/commands/team.js +20 -7
- package/src/commands/update.js +65 -10
- package/src/esm-bridge.js +3 -0
- package/src/gateways/terminal/PtyManager.js +8 -1
- package/src/gateways/ws/message-dispatcher.js +3 -0
- package/src/gateways/ws/session-protocol.js +26 -0
- package/src/gateways/ws/ws-agent-handler.js +107 -69
- package/src/gateways/ws/ws-server.js +92 -4
- package/src/harness/jsonl-session-store.js +13 -6
- package/src/harness/mcp-client.js +200 -1
- package/src/index.js +123 -55
- package/src/lazy-dispatch.js +86 -85
- package/src/lib/__tests__/personal-data-hub-aichat-wizard.test.js +15 -0
- package/src/lib/agent-coordinator.js +4 -0
- package/src/lib/agent-ipc-bus.js +32 -2
- package/src/lib/agent-sandbox.js +16 -2
- package/src/lib/agent-schedule-store.js +55 -0
- package/src/lib/agent-tool-admission.js +104 -0
- package/src/lib/api-key-helper.js +10 -2
- package/src/lib/async-hook-supervisor.cjs +26 -4
- package/src/lib/background-interaction-resolver.js +71 -0
- package/src/lib/background-session-transport.js +59 -1
- package/src/lib/changelog.js +19 -11
- package/src/lib/channels/channel-manager.js +6 -0
- package/src/lib/channels/telegram-channel.js +11 -1
- package/src/lib/channels/webhook-channel.js +15 -3
- package/src/lib/checkpoint-store.js +10 -2
- package/src/lib/cloud/bundle.js +12 -2
- package/src/lib/code-review.js +32 -8
- package/src/lib/computer-use/control-backend.js +18 -3
- package/src/lib/context-breakdown.js +46 -0
- package/src/lib/context-source-ledger.js +43 -0
- package/src/lib/crash-reporter.js +6 -0
- package/src/lib/diff-review-follow-up.js +154 -0
- package/src/lib/downloader.js +17 -3
- package/src/lib/ensure-utf8.js +11 -3
- package/src/lib/event-runtime-producer.js +58 -0
- package/src/lib/event-runtime-store.js +354 -0
- package/src/lib/event-runtime-worker.js +109 -0
- package/src/lib/execution-backend.js +72 -21
- package/src/lib/git-integration.js +19 -4
- package/src/lib/hook-manager.js +34 -15
- package/src/lib/hook-runner.cjs +48 -3
- package/src/lib/hooks-v2-producers.js +15 -0
- package/src/lib/hooks-v2-runtime.js +70 -21
- package/src/lib/host-adb-bridge.js +111 -21
- package/src/lib/ide-context.js +128 -1
- package/src/lib/interaction-adapter.js +39 -0
- package/src/lib/ipc-attach-protocol.js +98 -0
- package/src/lib/json-schema-validate.js +190 -36
- package/src/lib/lan-pairing-preflight.js +13 -2
- package/src/lib/lsp/__tests__/lsp-server-registry.test.js +18 -0
- package/src/lib/lsp/lsp-client.js +18 -1
- package/src/lib/lsp/lsp-manager.js +4 -0
- package/src/lib/lsp/lsp-server-registry.js +11 -0
- package/src/lib/mcp-oauth.js +8 -2
- package/src/lib/npm-invocation.js +29 -0
- package/src/lib/packer/pkg-runner.js +13 -2
- package/src/lib/packer/precheck.js +33 -16
- package/src/lib/packer/web-panel-builder.js +16 -2
- package/src/lib/permission-rules.cjs +5 -1
- package/src/lib/personal-data-hub-aichat-wizard.js +22 -6
- package/src/lib/personal-data-hub-wiring.js +27 -3
- package/src/lib/plan-mode.js +204 -11
- package/src/lib/plugin-monitor-supervisor.js +39 -4
- package/src/lib/plugin-runtime/bin.js +45 -0
- package/src/lib/plugin-runtime/hooks.js +14 -1
- package/src/lib/plugin-runtime/install.js +2 -1
- package/src/lib/plugin-runtime/lsp.js +3 -0
- package/src/lib/plugin-runtime/mcp.js +8 -1
- package/src/lib/plugin-runtime/monitors.js +4 -0
- package/src/lib/plugin-runtime/plugin-options.js +74 -7
- package/src/lib/plugin-runtime/signature.js +45 -0
- package/src/lib/pr-create.js +21 -8
- package/src/lib/pr-link-ledger.js +15 -3
- package/src/lib/process-execution-broker/credential-agent.js +295 -0
- package/src/lib/process-execution-broker/index.js +440 -14
- package/src/lib/process-execution-broker/patch-child-process.js +2 -3
- package/src/lib/process-execution-broker/platform-sandbox.js +351 -0
- package/src/lib/process-manager.js +18 -3
- package/src/lib/provenance-api.js +6 -0
- package/src/lib/proxy-bootstrap.js +19 -0
- package/src/lib/publish-workspace.js +14 -6
- package/src/lib/repl-rewind.js +9 -4
- package/src/lib/secret-store.js +159 -0
- package/src/lib/service-manager.js +64 -29
- package/src/lib/session-hooks.js +328 -473
- package/src/lib/session-telemetry-middleware.js +6 -0
- package/src/lib/settings-hook-events.cjs +61 -1
- package/src/lib/settings-hooks.cjs +4 -0
- package/src/lib/side-effect-ledger.js +22 -0
- package/src/lib/sub-agent-context.js +5 -0
- package/src/lib/sub-agent-profiles.js +4 -0
- package/src/lib/trace-api.js +6 -0
- package/src/lib/turn-context.js +14 -8
- package/src/lib/unattended-action-policy.js +83 -0
- package/src/lib/update-notice.js +9 -45
- package/src/lib/with-file-lock.js +7 -0
- package/src/lib/ws-server.js +1 -0
- package/src/repl/agent-repl.js +71 -13
- package/src/repl/clipboard-copy.js +8 -2
- package/src/repl/pr-comments.js +30 -7
- package/src/runtime/agent-core.js +439 -87
- package/src/runtime/agent-runtime.js +1 -0
- package/src/runtime/coding-agent-contract-shared.cjs +52 -0
- package/src/runtime/coding-agent-policy.cjs +20 -0
- package/src/runtime/diagnostics.js +73 -8
- package/src/runtime/headless-runner.js +63 -0
- package/src/runtime/headless-stream.js +269 -17
- package/src/runtime/mcp-config.js +16 -1
- package/src/workers/background-agent-worker.js +80 -1
- package/src/assets/web-panel/assets/AppLayout-7iSKDmlI.js +0 -9
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DcbUHeGW.js +0 -1
- package/src/assets/web-panel/assets/Dashboard-BAKYNavw.js +0 -3
- package/src/assets/web-panel/assets/MobileProjects-C4GKn1dH.js +0 -1
- package/src/assets/web-panel/assets/Terminal-Fj7ea0In.js +0 -3
- package/src/assets/web-panel/assets/devWarning-CDI8Sbaj.js +0 -1
- package/src/assets/web-panel/assets/index-96LBR96V.js +0 -1
- package/src/assets/web-panel/assets/index-DyQkiW24.js +0 -1
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform-specific sandbox enforcement for ProcessExecutionBroker (P0-1)
|
|
3
|
+
*
|
|
4
|
+
* Implements OS-level sandboxing primitives:
|
|
5
|
+
* - Windows: Job Object + restricted token + basic mitigations
|
|
6
|
+
* - macOS: Seatbelt sandbox profiles
|
|
7
|
+
* - Linux: seccomp-bpf (when available) + NO_NEW_PRIVS + resource limits
|
|
8
|
+
*
|
|
9
|
+
* Security model:
|
|
10
|
+
* 1. All child processes are placed into an isolated sandbox before exec
|
|
11
|
+
* 2. Filesystem access is restricted by default (explicit allowlist only)
|
|
12
|
+
* 3. Network access is blocked by default (explicit opt-in)
|
|
13
|
+
* 4. Privilege escalation is prevented (NO_NEW_PRIVS, restricted tokens)
|
|
14
|
+
* 5. Resource limits prevent DoS (CPU, memory, process count)
|
|
15
|
+
*
|
|
16
|
+
* Part of Phase 1 Implementation - 2026-07-22
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import os from "node:os";
|
|
20
|
+
import path from "node:path";
|
|
21
|
+
import fs from "node:fs";
|
|
22
|
+
import crypto from "node:crypto";
|
|
23
|
+
import { createRequire } from "node:module";
|
|
24
|
+
|
|
25
|
+
const require = createRequire(import.meta.url);
|
|
26
|
+
|
|
27
|
+
const platform = os.platform();
|
|
28
|
+
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// macOS Seatbelt Sandbox
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Generate a minimal Seatbelt sandbox profile that denies everything by default
|
|
35
|
+
* and only allows whitelisted paths + basic operations.
|
|
36
|
+
*
|
|
37
|
+
* @param {Object} opts
|
|
38
|
+
* @param {string[]} opts.allowRead - Paths allowed for read
|
|
39
|
+
* @param {string[]} opts.allowWrite - Paths allowed for write (includes read)
|
|
40
|
+
* @param {boolean} [opts.allowNetwork=false] - Allow network access
|
|
41
|
+
* @param {boolean} [opts.allowExec=true] - Allow process exec (subprocess spawning)
|
|
42
|
+
* @returns {string} sandbox profile content
|
|
43
|
+
*/
|
|
44
|
+
export function generateMacSeatbeltProfile(opts = {}) {
|
|
45
|
+
const {
|
|
46
|
+
allowRead = [],
|
|
47
|
+
allowWrite = [],
|
|
48
|
+
allowNetwork = false,
|
|
49
|
+
allowExec = true,
|
|
50
|
+
} = opts;
|
|
51
|
+
|
|
52
|
+
const lines = [
|
|
53
|
+
"(version 1)",
|
|
54
|
+
"(deny default)",
|
|
55
|
+
// Basic system operations always allowed
|
|
56
|
+
"(allow signal (target self))",
|
|
57
|
+
"(allow process-exec (literal \"/usr/bin/env\"))",
|
|
58
|
+
"(allow process-exec (literal \"/bin/sh\"))",
|
|
59
|
+
"(allow process-exec (literal \"/bin/bash\"))",
|
|
60
|
+
"(allow sysctl-read)",
|
|
61
|
+
"(allow mach-lookup)",
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
if (allowExec) {
|
|
65
|
+
lines.push("(allow process-fork)");
|
|
66
|
+
lines.push("(allow process-exec)");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (allowNetwork) {
|
|
70
|
+
lines.push("(allow network*)");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Allow read/write to specific paths
|
|
74
|
+
for (const p of allowRead) {
|
|
75
|
+
const abs = path.resolve(p);
|
|
76
|
+
lines.push(`(allow file-read* (subpath "${abs}"))`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
for (const p of allowWrite) {
|
|
80
|
+
const abs = path.resolve(p);
|
|
81
|
+
lines.push(`(allow file-read* file-write* (subpath "${abs}"))`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Always allow read access to system paths needed for basic execution
|
|
85
|
+
lines.push('(allow file-read* (subpath "/usr/lib"))');
|
|
86
|
+
lines.push('(allow file-read* (subpath "/System/Library"))');
|
|
87
|
+
lines.push('(allow file-read* (subpath "/usr/local/lib"))');
|
|
88
|
+
lines.push('(allow file-read* (literal "/etc/passwd"))');
|
|
89
|
+
|
|
90
|
+
return lines.join("\n");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Apply macOS sandbox via SBWritableProfile or sandbox-exec wrapper.
|
|
95
|
+
*
|
|
96
|
+
* For spawned processes, the preferred approach is to launch with sandbox-exec
|
|
97
|
+
* as the wrapper binary, passing the profile as an argument. This avoids needing
|
|
98
|
+
* to call sandbox_init from the child.
|
|
99
|
+
*
|
|
100
|
+
* @param {string} command - Original command
|
|
101
|
+
* @param {string[]} args - Original args
|
|
102
|
+
* @param {Object} spawnOpts - Spawn options to mutate (adds sandbox-exec wrapper)
|
|
103
|
+
* @param {Object} sandboxOpts - Sandbox options
|
|
104
|
+
*/
|
|
105
|
+
export function applyMacSandbox(command, args, spawnOpts, sandboxOpts = {}) {
|
|
106
|
+
if (platform !== "darwin") return { applied: false };
|
|
107
|
+
|
|
108
|
+
// Generate temporary profile file
|
|
109
|
+
const profileContent = generateMacSeatbeltProfile(sandboxOpts);
|
|
110
|
+
const profilePath = path.join(
|
|
111
|
+
os.tmpdir(),
|
|
112
|
+
`chainless-sb-${crypto.randomBytes(8).toString("hex")}.sb`,
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
fs.writeFileSync(profilePath, profileContent, { mode: 0o600 });
|
|
116
|
+
|
|
117
|
+
// Wrap command with sandbox-exec
|
|
118
|
+
const newArgs = ["-f", profilePath, command, ...args];
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
applied: true,
|
|
122
|
+
wrapper: "sandbox-exec",
|
|
123
|
+
profilePath,
|
|
124
|
+
newCommand: "sandbox-exec",
|
|
125
|
+
newArgs,
|
|
126
|
+
cleanup: () => {
|
|
127
|
+
try {
|
|
128
|
+
fs.unlinkSync(profilePath);
|
|
129
|
+
} catch {
|
|
130
|
+
// ignore cleanup errors
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
// Windows Job Object Sandbox
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Apply Windows Job Object limits + basic mitigations.
|
|
142
|
+
*
|
|
143
|
+
* On Windows we:
|
|
144
|
+
* 1. Set CREATE_BREAKAWAY_FROM_JOB to ensure child can be placed into our own job
|
|
145
|
+
* 2. Add JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE so children die when parent exits
|
|
146
|
+
* 3. Set basic process memory/CPU limits if specified
|
|
147
|
+
* 4. Set creation flags for restricted token (best-effort)
|
|
148
|
+
*
|
|
149
|
+
* Note: Full Win32 Job Object API requires ffi/n-rap invocation.
|
|
150
|
+
* This function sets the spawn flags and returns metadata for post-spawn association.
|
|
151
|
+
*
|
|
152
|
+
* @param {string} command
|
|
153
|
+
* @param {string[]} args
|
|
154
|
+
* @param {Object} spawnOpts
|
|
155
|
+
* @param {Object} sandboxOpts
|
|
156
|
+
*/
|
|
157
|
+
export function applyWindowsSandbox(command, args, spawnOpts, sandboxOpts = {}) {
|
|
158
|
+
if (platform !== "win32") return { applied: false };
|
|
159
|
+
|
|
160
|
+
// Set creation flags for Job Object support
|
|
161
|
+
// CREATE_BREAKAWAY_FROM_JOB = 0x01000000
|
|
162
|
+
// CREATE_NO_WINDOW = 0x08000000
|
|
163
|
+
const CREATE_BREAKAWAY_FROM_JOB = 0x01000000;
|
|
164
|
+
const CREATE_NO_WINDOW = 0x08000000;
|
|
165
|
+
|
|
166
|
+
const existingFlags = spawnOpts.windowsHide
|
|
167
|
+
? CREATE_NO_WINDOW
|
|
168
|
+
: 0;
|
|
169
|
+
spawnOpts.windowsVerbatimArguments = false;
|
|
170
|
+
|
|
171
|
+
// Set environment variable to signal sandboxed mode to any child-aware tools
|
|
172
|
+
const env = { ...(spawnOpts.env || process.env) };
|
|
173
|
+
env.CHAINLESS_SANDBOXED = "1";
|
|
174
|
+
spawnOpts.env = env;
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
applied: true,
|
|
178
|
+
needsPostSpawn: true,
|
|
179
|
+
jobFlags: CREATE_BREAKAWAY_FROM_JOB | existingFlags,
|
|
180
|
+
limits: sandboxOpts.limits || null,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Post-spawn: associate a Windows process with a Job Object.
|
|
186
|
+
* Uses PowerShell for lightweight isolation (best-effort; full ffi approach
|
|
187
|
+
* requires koffi/n-rap).
|
|
188
|
+
*
|
|
189
|
+
* @param {ChildProcess} proc - The spawned child process
|
|
190
|
+
* @param {Object} sandboxResult - Result from applyWindowsSandbox
|
|
191
|
+
*/
|
|
192
|
+
export async function postSpawnWindowsSandbox(proc, sandboxResult) {
|
|
193
|
+
if (platform !== "win32" || !proc.pid) return;
|
|
194
|
+
|
|
195
|
+
// Best-effort: set CPU affinity and priority via Node's built-in methods
|
|
196
|
+
try {
|
|
197
|
+
proc.renice && proc.renice(10); // Lower priority
|
|
198
|
+
} catch {
|
|
199
|
+
// ignore
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Full Job Object association via ffi would go here when koffi is available.
|
|
203
|
+
// For now, we rely on:
|
|
204
|
+
// 1. Parent process explicitly killing children on exit (broker handles this)
|
|
205
|
+
// 2. CREATE_NO_WINDOW for UI isolation
|
|
206
|
+
// 3. Environment variable signaling sandbox mode
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ---------------------------------------------------------------------------
|
|
210
|
+
// Linux seccomp/resource-limit Sandbox
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Apply Linux sandbox: NO_NEW_PRIVS + rlimits + (optionally) seccomp.
|
|
215
|
+
*
|
|
216
|
+
* For Node.js spawned children, the most portable approach without native deps
|
|
217
|
+
* is to use `prlimit` (util-linux) wrapper and set `child_process` uid/gid/groups.
|
|
218
|
+
*
|
|
219
|
+
* @param {string} command
|
|
220
|
+
* @param {string[]} args
|
|
221
|
+
* @param {Object} spawnOpts
|
|
222
|
+
* @param {Object} sandboxOpts
|
|
223
|
+
*/
|
|
224
|
+
export function applyLinuxSandbox(command, args, spawnOpts, sandboxOpts = {}) {
|
|
225
|
+
if (platform !== "linux") return { applied: false };
|
|
226
|
+
|
|
227
|
+
const { limits = {} } = sandboxOpts;
|
|
228
|
+
|
|
229
|
+
// Apply resource limits via spawn options (if supported by Node version)
|
|
230
|
+
// Node 19+ supports `gid`, `uid` in spawn options for privilege dropping
|
|
231
|
+
spawnOpts.gid = spawnOpts.gid || undefined;
|
|
232
|
+
spawnOpts.uid = spawnOpts.uid || undefined;
|
|
233
|
+
|
|
234
|
+
// Mark environment
|
|
235
|
+
const env = { ...(spawnOpts.env || process.env) };
|
|
236
|
+
env.CHAINLESS_SANDBOXED = "1";
|
|
237
|
+
spawnOpts.env = env;
|
|
238
|
+
|
|
239
|
+
// If we want hard limits and prlimit is available, wrap the command.
|
|
240
|
+
// Prlimit path: /usr/bin/prlimit
|
|
241
|
+
let newCommand = command;
|
|
242
|
+
let newArgs = [...args];
|
|
243
|
+
|
|
244
|
+
const prlimitParts = [];
|
|
245
|
+
if (limits.cpu) prlimitParts.push(`--cpu=${limits.cpu}`);
|
|
246
|
+
if (limits.as) prlimitParts.push(`--as=${limits.as}`);
|
|
247
|
+
if (limits.nofile) prlimitParts.push(`--nofile=${limits.nofile}`);
|
|
248
|
+
if (limits.nproc) prlimitParts.push(`--nproc=${limits.nproc}`);
|
|
249
|
+
|
|
250
|
+
if (prlimitParts.length > 0 && fs.existsSync("/usr/bin/prlimit")) {
|
|
251
|
+
newCommand = "/usr/bin/prlimit";
|
|
252
|
+
newArgs = [...prlimitParts, command, ...args];
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
applied: true,
|
|
257
|
+
newCommand,
|
|
258
|
+
newArgs,
|
|
259
|
+
needsSetSid: true, // Use setsid to create new process group for clean killing
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// ---------------------------------------------------------------------------
|
|
264
|
+
// Unified sandbox apply
|
|
265
|
+
// ---------------------------------------------------------------------------
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Apply platform-appropriate sandbox for a child process.
|
|
269
|
+
*
|
|
270
|
+
* @param {string} command
|
|
271
|
+
* @param {string[]} args
|
|
272
|
+
* @param {Object} spawnOpts - Will be MUTATED with sandbox flags/env
|
|
273
|
+
* @param {"default"|"strict"|"network-only"} profileName
|
|
274
|
+
* @returns {{ applied: boolean, wrapper?: string, newCommand?: string, newArgs?: string[], cleanup?: Function, needsPostSpawn?: boolean }}
|
|
275
|
+
*/
|
|
276
|
+
export function applySandbox(command, args, spawnOpts, profileName = "default") {
|
|
277
|
+
const profiles = {
|
|
278
|
+
default: {
|
|
279
|
+
allowNetwork: false,
|
|
280
|
+
allowExec: true,
|
|
281
|
+
allowRead: [os.homedir(), "/tmp"],
|
|
282
|
+
allowWrite: [os.tmpdir()],
|
|
283
|
+
limits: {
|
|
284
|
+
cpu: 30, // seconds
|
|
285
|
+
nofile: 256,
|
|
286
|
+
nproc: 64,
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
strict: {
|
|
290
|
+
allowNetwork: false,
|
|
291
|
+
allowExec: false,
|
|
292
|
+
allowRead: [],
|
|
293
|
+
allowWrite: [os.tmpdir()],
|
|
294
|
+
limits: {
|
|
295
|
+
cpu: 10,
|
|
296
|
+
as: 256 * 1024 * 1024, // 256MB address space
|
|
297
|
+
nofile: 64,
|
|
298
|
+
nproc: 8,
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
"network-only": {
|
|
302
|
+
allowNetwork: true,
|
|
303
|
+
allowExec: true,
|
|
304
|
+
allowRead: [os.homedir()],
|
|
305
|
+
allowWrite: [os.tmpdir()],
|
|
306
|
+
limits: {
|
|
307
|
+
cpu: 60,
|
|
308
|
+
nofile: 512,
|
|
309
|
+
nproc: 128,
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
const profile = profiles[profileName] || profiles.default;
|
|
315
|
+
|
|
316
|
+
// Dispatch to platform handler
|
|
317
|
+
if (platform === "darwin") {
|
|
318
|
+
return applyMacSandbox(command, args, spawnOpts, profile);
|
|
319
|
+
}
|
|
320
|
+
if (platform === "win32") {
|
|
321
|
+
return applyWindowsSandbox(command, args, spawnOpts, profile);
|
|
322
|
+
}
|
|
323
|
+
if (platform === "linux") {
|
|
324
|
+
return applyLinuxSandbox(command, args, spawnOpts, profile);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Unknown platform - no sandbox applied
|
|
328
|
+
return { applied: false };
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Post-spawn sandbox setup (called after child process starts).
|
|
333
|
+
* Currently only needed on Windows for Job Object association.
|
|
334
|
+
*
|
|
335
|
+
* @param {ChildProcess} proc
|
|
336
|
+
* @param {Object} sandboxResult
|
|
337
|
+
*/
|
|
338
|
+
export async function postSpawnSandbox(proc, sandboxResult) {
|
|
339
|
+
if (platform === "win32" && sandboxResult?.needsPostSpawn) {
|
|
340
|
+
await postSpawnWindowsSandbox(proc, sandboxResult);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
export default {
|
|
345
|
+
applySandbox,
|
|
346
|
+
postSpawnSandbox,
|
|
347
|
+
generateMacSeatbeltProfile,
|
|
348
|
+
applyMacSandbox,
|
|
349
|
+
applyWindowsSandbox,
|
|
350
|
+
applyLinuxSandbox,
|
|
351
|
+
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { spawn, execSync } from "node:child_process";
|
|
2
1
|
import {
|
|
3
2
|
readFileSync,
|
|
4
3
|
writeFileSync,
|
|
@@ -10,6 +9,12 @@ import { join } from "node:path";
|
|
|
10
9
|
import { getPidFilePath, getBinDir, ensureDir, getStatePath } from "./paths.js";
|
|
11
10
|
import { isWindows } from "./platform.js";
|
|
12
11
|
import logger from "./logger.js";
|
|
12
|
+
import { executionBroker } from "./process-execution-broker/index.js";
|
|
13
|
+
|
|
14
|
+
export const _deps = {
|
|
15
|
+
spawn: (...args) => executionBroker.spawn(...args),
|
|
16
|
+
execFileSync: (...args) => executionBroker.execFileSync(...args),
|
|
17
|
+
};
|
|
13
18
|
|
|
14
19
|
export function startApp(options = {}) {
|
|
15
20
|
ensureDir(getStatePath());
|
|
@@ -44,10 +49,14 @@ export function startApp(options = {}) {
|
|
|
44
49
|
|
|
45
50
|
logger.verbose(`Starting: ${appPath} ${args.join(" ")}`);
|
|
46
51
|
|
|
47
|
-
const child = spawn(appPath, args, {
|
|
52
|
+
const child = _deps.spawn(appPath, args, {
|
|
48
53
|
detached: true,
|
|
49
54
|
stdio: "ignore",
|
|
50
55
|
env: { ...process.env, ...options.env },
|
|
56
|
+
origin: "app:start",
|
|
57
|
+
policy: "allow",
|
|
58
|
+
scope: "app",
|
|
59
|
+
shell: false,
|
|
51
60
|
});
|
|
52
61
|
|
|
53
62
|
child.unref();
|
|
@@ -90,7 +99,13 @@ export function stopApp() {
|
|
|
90
99
|
|
|
91
100
|
try {
|
|
92
101
|
if (isWindows()) {
|
|
93
|
-
|
|
102
|
+
_deps.execFileSync("taskkill", ["/PID", String(pid), "/T", "/F"], {
|
|
103
|
+
stdio: "ignore",
|
|
104
|
+
origin: "app:stop",
|
|
105
|
+
policy: "allow",
|
|
106
|
+
scope: "app",
|
|
107
|
+
shell: false,
|
|
108
|
+
});
|
|
94
109
|
} else {
|
|
95
110
|
process.kill(pid, "SIGTERM");
|
|
96
111
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proxy bootstrap stub for unit tests
|
|
3
|
+
*/
|
|
4
|
+
let _proxyEnabled = false;
|
|
5
|
+
|
|
6
|
+
export function enableProxy() {
|
|
7
|
+
if (process.env.HTTPS_PROXY || process.env.HTTP_PROXY) {
|
|
8
|
+
_proxyEnabled = true;
|
|
9
|
+
}
|
|
10
|
+
return _proxyEnabled;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function proxyEnabled() {
|
|
14
|
+
return _proxyEnabled;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function isLazy() {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
@@ -4,11 +4,15 @@
|
|
|
4
4
|
* @module lib/publish-workspace
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import executionBroker from "./process-execution-broker/index.js";
|
|
8
8
|
import { logger } from "./logger.js";
|
|
9
9
|
import path from "path";
|
|
10
10
|
import fs from "fs";
|
|
11
11
|
|
|
12
|
+
export const _deps = {
|
|
13
|
+
execFileSync: (...args) => executionBroker.execFileSync(...args),
|
|
14
|
+
};
|
|
15
|
+
|
|
12
16
|
/**
|
|
13
17
|
* Get all workspace packages
|
|
14
18
|
* @returns {Array<{name: string, path: string, version: string}>}
|
|
@@ -60,16 +64,20 @@ export function getWorkspacePackages() {
|
|
|
60
64
|
export function publishPackage(pkg, options = {}) {
|
|
61
65
|
try {
|
|
62
66
|
logger.info(`Publishing ${pkg.name}@${pkg.version}...`);
|
|
63
|
-
|
|
64
|
-
if (options.tag)
|
|
65
|
-
if (options.access)
|
|
67
|
+
const args = ["publish"];
|
|
68
|
+
if (options.tag) args.push("--tag", String(options.tag));
|
|
69
|
+
if (options.access) args.push("--access", String(options.access));
|
|
66
70
|
|
|
67
|
-
|
|
71
|
+
_deps.execFileSync("npm", args, {
|
|
72
|
+
origin: "publish-workspace:npm",
|
|
73
|
+
scope: "publish",
|
|
74
|
+
policy: "allow",
|
|
75
|
+
shell: false,
|
|
68
76
|
cwd: pkg.path,
|
|
69
77
|
stdio: "inherit",
|
|
70
78
|
encoding: "utf8",
|
|
71
79
|
});
|
|
72
|
-
logger.
|
|
80
|
+
logger.success(`Published ${pkg.name}@${pkg.version}`);
|
|
73
81
|
return true;
|
|
74
82
|
} catch (err) {
|
|
75
83
|
logger.error(`Failed to publish ${pkg.name}: ${err.message}`);
|
package/src/lib/repl-rewind.js
CHANGED
|
@@ -414,10 +414,15 @@ export function parseRewindArg(arg) {
|
|
|
414
414
|
else if (t === "--yes" || t === "-y") confirmed = true;
|
|
415
415
|
else if (n === null && /^\d+$/.test(t)) n = Number(t);
|
|
416
416
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
417
|
+
const result =
|
|
418
|
+
branch && n !== null
|
|
419
|
+
? { command: "branch", n, scope, writeIntent }
|
|
420
|
+
: n === null
|
|
421
|
+
? { command: "list", scope }
|
|
422
|
+
: { command: "turn", n, scope };
|
|
423
|
+
// Only include confirmed when true (non-interactive confirmation flag)
|
|
424
|
+
if (confirmed) result.confirmed = true;
|
|
425
|
+
return result;
|
|
421
426
|
}
|
|
422
427
|
|
|
423
428
|
/** Render the picker list (shared by /rewind and double-Esc). */
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Small OS-backed secret store used by plugin options and other user-scoped
|
|
3
|
+
* credentials. Secrets never fall back to plaintext JSON:
|
|
4
|
+
* - Windows: DPAPI (CurrentUser) encrypted blobs in the user data dir
|
|
5
|
+
* - macOS: Keychain via `security`
|
|
6
|
+
* - Linux: Secret Service via `secret-tool`
|
|
7
|
+
*
|
|
8
|
+
* The command runner is injectable so the protocol is deterministic in unit
|
|
9
|
+
* tests and so callers can route it through ProcessExecutionBroker.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import crypto from "node:crypto";
|
|
13
|
+
import fs from "node:fs";
|
|
14
|
+
import os from "node:os";
|
|
15
|
+
import path from "node:path";
|
|
16
|
+
import { getElectronUserDataDir } from "./paths.js";
|
|
17
|
+
import { executionBroker } from "./process-execution-broker/index.js";
|
|
18
|
+
|
|
19
|
+
const DPAPI_SCRIPT = [
|
|
20
|
+
"$ErrorActionPreference='Stop'",
|
|
21
|
+
"Add-Type -AssemblyName System.Security",
|
|
22
|
+
"$raw=[Console]::In.ReadToEnd()",
|
|
23
|
+
"$b=[Convert]::FromBase64String($raw)",
|
|
24
|
+
"$p=[Security.Cryptography.ProtectedData]::Protect($b,$null,[Security.Cryptography.DataProtectionScope]::CurrentUser)",
|
|
25
|
+
"[Console]::Write([Convert]::ToBase64String($p))",
|
|
26
|
+
].join("; ");
|
|
27
|
+
|
|
28
|
+
const DPAPI_UNPROTECT_SCRIPT = [
|
|
29
|
+
"$ErrorActionPreference='Stop'",
|
|
30
|
+
"Add-Type -AssemblyName System.Security",
|
|
31
|
+
"$raw=[Console]::In.ReadToEnd()",
|
|
32
|
+
"$b=[Convert]::FromBase64String($raw)",
|
|
33
|
+
"$p=[Security.Cryptography.ProtectedData]::Unprotect($b,$null,[Security.Cryptography.DataProtectionScope]::CurrentUser)",
|
|
34
|
+
"[Console]::Write([Convert]::ToBase64String($p))",
|
|
35
|
+
].join("; ");
|
|
36
|
+
|
|
37
|
+
function defaultRunner(file, args, input = undefined) {
|
|
38
|
+
const result = executionBroker.spawnSync(file, args, {
|
|
39
|
+
origin: "secret-store",
|
|
40
|
+
policy: "allow",
|
|
41
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
42
|
+
encoding: "utf8",
|
|
43
|
+
windowsHide: true,
|
|
44
|
+
...(input !== undefined ? { input } : {}),
|
|
45
|
+
});
|
|
46
|
+
if (result.status !== 0) {
|
|
47
|
+
throw new Error(String(result.stderr || "secret store command failed").trim());
|
|
48
|
+
}
|
|
49
|
+
return String(result.stdout || "").trim();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function safeToken(value) {
|
|
53
|
+
return crypto
|
|
54
|
+
.createHash("sha256")
|
|
55
|
+
.update(String(value || ""))
|
|
56
|
+
.digest("hex")
|
|
57
|
+
.slice(0, 32);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function chooseBackend(platform = process.platform) {
|
|
61
|
+
if (platform === "win32") return "dpapi";
|
|
62
|
+
if (platform === "darwin") return "keychain";
|
|
63
|
+
if (platform === "linux" || platform === "freebsd") return "secret-service";
|
|
64
|
+
return "unavailable";
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function readJson(file, readFile = fs.readFileSync) {
|
|
68
|
+
try {
|
|
69
|
+
const value = JSON.parse(readFile(file, "utf8"));
|
|
70
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
71
|
+
? value
|
|
72
|
+
: {};
|
|
73
|
+
} catch {
|
|
74
|
+
return {};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function writeJson(file, value, deps = {}) {
|
|
79
|
+
const mkdirSync = deps.mkdirSync || fs.mkdirSync;
|
|
80
|
+
const writeFileSync = deps.writeFileSync || fs.writeFileSync;
|
|
81
|
+
mkdirSync(path.dirname(file), { recursive: true });
|
|
82
|
+
writeFileSync(file, JSON.stringify(value, null, 2), { encoding: "utf8", mode: 0o600 });
|
|
83
|
+
try { fs.chmodSync(file, 0o600); } catch {}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function createDpapiBackend({ file, runner, readFile, writeFile, mkdirSync } = {}) {
|
|
87
|
+
const storeFile = file || path.join(getElectronUserDataDir(), "plugin-secrets.dpapi.json");
|
|
88
|
+
const load = () => readJson(storeFile, readFile);
|
|
89
|
+
const save = (v) => writeJson(storeFile, v, { writeFileSync: writeFile, mkdirSync });
|
|
90
|
+
return {
|
|
91
|
+
name: "dpapi",
|
|
92
|
+
set(key, value) {
|
|
93
|
+
const payload = Buffer.from(String(value), "utf8").toString("base64");
|
|
94
|
+
const encoded = runner("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", DPAPI_SCRIPT], payload);
|
|
95
|
+
const data = load(); data[key] = encoded; save(data);
|
|
96
|
+
},
|
|
97
|
+
get(key) {
|
|
98
|
+
const encoded = load()[key];
|
|
99
|
+
if (!encoded) return null;
|
|
100
|
+
const plain = runner("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", DPAPI_UNPROTECT_SCRIPT], encoded);
|
|
101
|
+
return Buffer.from(plain, "base64").toString("utf8");
|
|
102
|
+
},
|
|
103
|
+
delete(key) {
|
|
104
|
+
const data = load();
|
|
105
|
+
if (!Object.prototype.hasOwnProperty.call(data, key)) return false;
|
|
106
|
+
delete data[key]; save(data); return true;
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function createKeychainBackend({ service, runner } = {}) {
|
|
112
|
+
const name = service || "com.chainlesschain.plugin";
|
|
113
|
+
return {
|
|
114
|
+
name: "keychain",
|
|
115
|
+
set(key, value) {
|
|
116
|
+
runner("security", ["add-generic-password", "-a", key, "-s", name, "-w", String(value), "-U"]);
|
|
117
|
+
},
|
|
118
|
+
get(key) {
|
|
119
|
+
try { return runner("security", ["find-generic-password", "-a", key, "-s", name, "-w"]) || null; } catch { return null; }
|
|
120
|
+
},
|
|
121
|
+
delete(key) {
|
|
122
|
+
try { runner("security", ["delete-generic-password", "-a", key, "-s", name]); return true; } catch { return false; }
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function createSecretServiceBackend({ service, runner } = {}) {
|
|
128
|
+
const name = service || "chainlesschain-plugin";
|
|
129
|
+
return {
|
|
130
|
+
name: "secret-service",
|
|
131
|
+
set(key, value) {
|
|
132
|
+
runner("secret-tool", ["store", "--label", `${name}:${key}`, "service", name, "account", key], String(value));
|
|
133
|
+
},
|
|
134
|
+
get(key) {
|
|
135
|
+
try { return runner("secret-tool", ["lookup", "service", name, "account", key]) || null; } catch { return null; }
|
|
136
|
+
},
|
|
137
|
+
delete(key) {
|
|
138
|
+
try { runner("secret-tool", ["clear", "service", name, "account", key]); return true; } catch { return false; }
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Create a fail-closed secret store. `memory` is intended for tests only. */
|
|
144
|
+
export function createSecretStore(options = {}) {
|
|
145
|
+
const backend = options.backend || chooseBackend(options.platform);
|
|
146
|
+
const runner = options.runner || defaultRunner;
|
|
147
|
+
if (backend === "memory") {
|
|
148
|
+
const values = options.values || new Map();
|
|
149
|
+
return { name: "memory", set: (k, v) => values.set(k, String(v)), get: (k) => values.get(k) ?? null, delete: (k) => values.delete(k) };
|
|
150
|
+
}
|
|
151
|
+
if (backend === "dpapi") return createDpapiBackend({ ...options, runner });
|
|
152
|
+
if (backend === "keychain") return createKeychainBackend({ ...options, runner });
|
|
153
|
+
if (backend === "secret-service") return createSecretServiceBackend({ ...options, runner });
|
|
154
|
+
throw new Error(`No OS secret store available for platform ${options.platform || process.platform}`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function secretRef(key) { return { __cc_secret_ref: String(key) }; }
|
|
158
|
+
export function isSecretRef(value) { return Boolean(value && typeof value === "object" && value.__cc_secret_ref); }
|
|
159
|
+
export { chooseBackend };
|