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.
Files changed (281) hide show
  1. package/package.json +10 -10
  2. package/src/assets/web-panel/assets/{AIOps-Dcl-X1Hw.js → AIOps-BDLu5Elz.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-ClMh9HzT.js → ActionButton-DH5us-CK.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-DPj0rSQ5.js → Analytics-BZ0u8IFG.js} +3 -3
  5. package/src/assets/web-panel/assets/AppLayout-Duu8xR14.js +9 -0
  6. package/src/assets/web-panel/assets/{Artifacts-L8781rE8.js → Artifacts-Br2YBbh_.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-CffB6WIP.js → Audit-C3C6a482.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-BkLhayyY.js → BackgroundAgents-CzHvebcj.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-BQnwFI78.js → Backup-DZNHYDFd.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-xuUGHQch.js → BaseInput-VRiC4fIx.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-feQXwWrg.js → Chat-Cm08WWAD.js} +5 -5
  12. package/src/assets/web-panel/assets/ChatBubbleRenderer-CGHYrugQ.js +1 -0
  13. package/src/assets/web-panel/assets/{Checkbox-DVaIiUGW.js → Checkbox-DtByk7d7.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-D2kEnzeU.js → Codegen-CphXXOfD.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-azDoyusS.js → Col-Hz86TnLR.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-OZdnPWM5.js → Community-HP03ltpD.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-VDMvBN-C.js → Compact-B_N1mqQz.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-CPJ_zgQ1.js → Compliance-CVztRpi8.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-iRBwcsOA.js → Cowork-wUVOyZih.js} +4 -4
  20. package/src/assets/web-panel/assets/{Cron-DrxrspUz.js → Cron-DW5TLJKw.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-D-rkAZXF.js → Crosschain-CrAFGhWH.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-5Pp1Xnmr.js → DID-pA-oD8ke.js} +2 -2
  23. package/src/assets/web-panel/assets/Dashboard-CXrd5gAw.js +3 -0
  24. package/src/assets/web-panel/assets/{Dropdown-BWj_E0Ie.js → Dropdown-EweJcsek.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-BT-wgSEh.js → EmailListRenderer-C9xVLPG4.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-1PzH23pa.js → FamilyGuardDashboard-CDcEEqlu.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-BxMIXGC6.js → Federation-DtZda9A_.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-CyJobBln.js → FormItemContext-CiYdcVz3.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-YkjFuQTN.js → GenericCardRenderer-DA13uwA0.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-C2a98Wp_.js → Git-DzRhZD1O.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-DKL3Fl84.js → Governance-D5RMgOSb.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-BJ2cQC_3.js → Inference-BgrPfSNk.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-DBAsOngt.js → KnowledgeGraph-DzjnD571.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-COt8g9LO.js → Logs-BhWzVDtN.js} +2 -2
  35. package/src/assets/web-panel/assets/{MarkdownRenderer-3Lfht1Fd.js → MarkdownRenderer-BDape9cx.js} +1 -1
  36. package/src/assets/web-panel/assets/{Marketplace-C9Zk9Pb2.js → Marketplace-DJtL5GV7.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-DDWDFWPO.js → McpTools-CZcQygI7.js} +5 -5
  38. package/src/assets/web-panel/assets/{Memory-BRmVye_o.js → Memory-DUWSDUUu.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-CppBbWpD.js → MobileBridge-BTwq2WKY.js} +1 -1
  40. package/src/assets/web-panel/assets/MobileProjects-NZvvfDME.js +1 -0
  41. package/src/assets/web-panel/assets/{Mtc-CcWpeGa6.js → Mtc-BiGugEQm.js} +6 -6
  42. package/src/assets/web-panel/assets/{MtcAudit-BcllEq0K.js → MtcAudit-DY7a6gUe.js} +4 -4
  43. package/src/assets/web-panel/assets/{Multisig-BFD1CarL.js → Multisig-BQbDu_w7.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-QNXXYvjz.js → NLProgramming-CM2wXTLv.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-07YwgQVy.js → Notes-DI6gGs1v.js} +4 -4
  46. package/src/assets/web-panel/assets/{NotificationSettings-bOccEInE.js → NotificationSettings-BsZOLWAB.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-DlRi29WL.js → OrderTableRenderer-C48mu09U.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-CBaezzEr.js → Organization-Cds0_tXr.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-Bl5NohFO.js → Overflow-WunYMD87.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-CLMal9Aw.js → P2P-Bo6j4DDv.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-CGO0NITk.js → PdhVaultBrowser-Bh2XPD5f.js} +3 -3
  52. package/src/assets/web-panel/assets/{Permissions-CPSw48E2.js → Permissions-EMvMMC8N.js} +3 -3
  53. package/src/assets/web-panel/assets/{PersonalDataHub-CDM5n134.js → PersonalDataHub-AX3ypUDV.js} +2 -2
  54. package/src/assets/web-panel/assets/{Pipeline-BdsqG7WV.js → Pipeline-BOx8HOgL.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-B6L4E-M7.js → Privacy-tBeTVQVM.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-DXPyZKRs.js → ProjectInit-CVYg1W4M.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-BrCC3xYT.js → ProjectSettings-Dvt5I7y1.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-BYmuHC2q.js → Projects-Cc7FC9-e.js} +1 -1
  59. package/src/assets/web-panel/assets/{Providers-CbCe2eUl.js → Providers-Ct8xqY-E.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-DkukgCrR.js → QrScannerModal-Cni8Ooja.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-D-htOrV8.js → QuickAsk-BJVLKdxr.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-Bm7SIfzu.js → Recommend-DPG8Rbbm.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-C9rP-iMc.js → RemoteSession-DsdR7dCt.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-kGlUgbsl.js → Reputation-Csg1YM-b.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-PBupbbUA.js → Row-D9DoFoEf.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-njlwKUGK.js → RssFeed-BsvKrXMS.js} +2 -2
  67. package/src/assets/web-panel/assets/{Search-DLdEmgBw.js → Search-DFUStfgQ.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-SXGPSHdu.js → Security-ILg1zxdK.js} +4 -4
  69. package/src/assets/web-panel/assets/{Services-CuFGnNsb.js → Services-Dd41PCaY.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-CtUC0mDa.js → Skeleton-Bzo1cN80.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-P1qgOVFn.js → Skills-BDHh17P0.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-CsppE8YV.js → Sla-jl7UTiRY.js} +1 -1
  73. package/src/assets/web-panel/assets/{SpeechSettings-Cq1oG56m.js → SpeechSettings-BePa-RF6.js} +1 -1
  74. package/src/assets/web-panel/assets/{SyncSettings-DdKW6V-C.js → SyncSettings-DiqqDKGZ.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-BCc9san5.js → Tasks-DYQ_6lxj.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-CcHC1dMA.js → Templates-JiDeI06L.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-CA4PqU22.js → Tenant-hhgI6zwS.js} +1 -1
  78. package/src/assets/web-panel/assets/Terminal-CjTZPa37.js +3 -0
  79. package/src/assets/web-panel/assets/{TimelineRenderer-DHWTSvOy.js → TimelineRenderer-B8uB5Llk.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-Ddz-P_yh.js → Tokens-C3b_6r2z.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-ePmrmLZ1.js → Trigger-tIP7HKVe.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-DmuK1CCE.js → Trust-vjoc11vJ.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-CqqBuRrT.js → UkeySign-DUPBnGuH.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-BGlR3uWM.js → VideoEditing-CBvhUY5T.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-Ba_Qx6Ga.js → Wallet-DUaQ0uA5.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-29neXKt2.js → WebAuthn-DllSivjE.js} +5 -5
  87. package/src/assets/web-panel/assets/{WorkflowEditor-lD0lR0UQ.js → WorkflowEditor-xc8D3uO6.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-B3stH01u.js → chat-BVicU7oA.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-Czly56MN.js → colors-DJzLmhLm.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-C0TkbkAJ.js → compact-item-BvYRfThE.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-BJmpSlf1.js → createContext-DGXxCBKR.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-BT46Y_QI.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-D1q-zw7u.js → hasIn-SBDJB1y4.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-DV-twjNO.js → index-1SdDS6lR.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-B-kTvMq7.js → index-9gdI7uUW.js} +1 -1
  96. package/src/assets/web-panel/assets/index-B7nuIywP.js +1 -0
  97. package/src/assets/web-panel/assets/{index-Bm_-RKal.js → index-BJZf9DhV.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CQftlZn-.js → index-BO1itZaY.js} +3 -3
  99. package/src/assets/web-panel/assets/{index-Dw3L_smW.js → index-BTrBGBJs.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-C7sFKQ53.js → index-BYqz4Wrr.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DlvsSuBC.js → index-Bf-ctERC.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-ChESIe5r.js → index-CKyEivf8.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DaqEHaCg.js → index-CdGY9P8a.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DZeoKL6t.js → index-Cf-O_g_8.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-XWV8JWMc.js → index-CloCgBUR.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-CpMIdPJ0.js → index-CoJAO1Lm.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CgS8XUBU.js → index-Crk5NTb0.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DmUta2lw.js → index-Cs2rmLFt.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Dpz_7sf-.js → index-CtwqO5qo.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DRcQsPez.js → index-D7HimK0M.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BEt2-3x5.js → index-DCdRAgjy.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-CHvPlzWJ.js → index-DCqRS6da.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BDHXx65P.js → index-DHVLJ8q0.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-K4YaPDOn.js → index-DKrvvWm4.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-C1pOqU7D.js → index-DMarmfrv.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DAhrn9EJ.js → index-DRfiXB_p.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-cPjWjvmW.js → index-Dm_77jgR.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-C27TnOoT.js → index-DnjPdvR6.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-upY9rkGZ.js → index-DonCnfMr.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CbvNJUwu.js → index-DvUTDYXX.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BVwJ3jht.js → index-FxZzRyE1.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DIF6XHIi.js → index-MjC4G09d.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-B8KqsomG.js → index-VMfwIH5G.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-8GKykbS4.js → index-YJkzy8ZF.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DpGs96FC.js → index-d5BVd-cL.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DO8xOwxi.js → index-e4fXH_WO.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-Cu_4HaUS.js → index-hxTODbM1.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Cf7Gr3NG.js → index-lpaGoTH3.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DBqAm8es.js → index-wcCL-miV.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-ZDUhX41Z.js → index-xfluRkCT.js} +1 -1
  131. package/src/assets/web-panel/assets/index-ycwAfC-i.js +1 -0
  132. package/src/assets/web-panel/assets/{index-z8ATo2aQ.js → index-z1ZylsLq.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-QWEXi6-t.js → initDefaultProps-C1zO1KnY.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-BfrQwvV1.js → motion-CWLtEGmC.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-Dn7x0H9t.js → move-DzD_C3Vm.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-F61D_TgE.js → mtc-parser-D880PYJl.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-4SQZ39PF.js → omit-CFR_z2ov.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-C7DTe126.js → pickAttrs-srIhgrSC.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-40NeyzDK.js → placementArrow-C1rXpibP.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-BiUJ6qWs.js → responsiveObserve-C30gRcSS.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-CacJTM3f.js → slide-CvtKiMfV.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-K812HB-k.js → statusUtils-DNHO7ITG.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-CKeHA2eM.js → styleChecker-Dt_Sl-g4.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-CKl4FqXF.js → useFlexGapSupport-Cjev42Gh.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-DPoiJjSZ.js → useFs-Baxglj2V.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-aHwBspmt.js → usePersonalDataHub-B4NkcLaP.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-DrA-GuCT.js → vnode-mIRkdT7o.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-G3LMswgy.js → zoom-HzI5DlH_.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/auth/npm-auth.js +30 -5
  151. package/src/commands/agenda.js +64 -2
  152. package/src/commands/agent.js +45 -3
  153. package/src/commands/background-session.js +103 -0
  154. package/src/commands/config.js +70 -5
  155. package/src/commands/context.js +36 -2
  156. package/src/commands/hub.js +19 -1
  157. package/src/commands/memory.js +21 -6
  158. package/src/commands/permissions.js +57 -1
  159. package/src/commands/plugin.js +2 -0
  160. package/src/commands/review.js +23 -11
  161. package/src/commands/routine.js +31 -8
  162. package/src/commands/session.js +11 -3
  163. package/src/commands/team.js +20 -7
  164. package/src/commands/update.js +65 -10
  165. package/src/esm-bridge.js +3 -0
  166. package/src/gateways/terminal/PtyManager.js +8 -1
  167. package/src/gateways/ws/message-dispatcher.js +3 -0
  168. package/src/gateways/ws/session-protocol.js +26 -0
  169. package/src/gateways/ws/ws-agent-handler.js +107 -69
  170. package/src/gateways/ws/ws-server.js +92 -4
  171. package/src/harness/jsonl-session-store.js +13 -6
  172. package/src/harness/mcp-client.js +200 -1
  173. package/src/index.js +123 -55
  174. package/src/lazy-dispatch.js +86 -85
  175. package/src/lib/__tests__/personal-data-hub-aichat-wizard.test.js +15 -0
  176. package/src/lib/agent-coordinator.js +4 -0
  177. package/src/lib/agent-ipc-bus.js +32 -2
  178. package/src/lib/agent-sandbox.js +16 -2
  179. package/src/lib/agent-schedule-store.js +55 -0
  180. package/src/lib/agent-tool-admission.js +104 -0
  181. package/src/lib/api-key-helper.js +10 -2
  182. package/src/lib/async-hook-supervisor.cjs +26 -4
  183. package/src/lib/background-interaction-resolver.js +71 -0
  184. package/src/lib/background-session-transport.js +59 -1
  185. package/src/lib/changelog.js +19 -11
  186. package/src/lib/channels/channel-manager.js +6 -0
  187. package/src/lib/channels/telegram-channel.js +11 -1
  188. package/src/lib/channels/webhook-channel.js +15 -3
  189. package/src/lib/checkpoint-store.js +10 -2
  190. package/src/lib/cloud/bundle.js +12 -2
  191. package/src/lib/code-review.js +32 -8
  192. package/src/lib/computer-use/control-backend.js +18 -3
  193. package/src/lib/context-breakdown.js +46 -0
  194. package/src/lib/context-source-ledger.js +43 -0
  195. package/src/lib/crash-reporter.js +6 -0
  196. package/src/lib/diff-review-follow-up.js +154 -0
  197. package/src/lib/downloader.js +17 -3
  198. package/src/lib/ensure-utf8.js +11 -3
  199. package/src/lib/event-runtime-producer.js +58 -0
  200. package/src/lib/event-runtime-store.js +354 -0
  201. package/src/lib/event-runtime-worker.js +109 -0
  202. package/src/lib/execution-backend.js +72 -21
  203. package/src/lib/git-integration.js +19 -4
  204. package/src/lib/hook-manager.js +34 -15
  205. package/src/lib/hook-runner.cjs +48 -3
  206. package/src/lib/hooks-v2-producers.js +15 -0
  207. package/src/lib/hooks-v2-runtime.js +70 -21
  208. package/src/lib/host-adb-bridge.js +111 -21
  209. package/src/lib/ide-context.js +128 -1
  210. package/src/lib/interaction-adapter.js +39 -0
  211. package/src/lib/ipc-attach-protocol.js +98 -0
  212. package/src/lib/json-schema-validate.js +190 -36
  213. package/src/lib/lan-pairing-preflight.js +13 -2
  214. package/src/lib/lsp/__tests__/lsp-server-registry.test.js +18 -0
  215. package/src/lib/lsp/lsp-client.js +18 -1
  216. package/src/lib/lsp/lsp-manager.js +4 -0
  217. package/src/lib/lsp/lsp-server-registry.js +11 -0
  218. package/src/lib/mcp-oauth.js +8 -2
  219. package/src/lib/npm-invocation.js +29 -0
  220. package/src/lib/packer/pkg-runner.js +13 -2
  221. package/src/lib/packer/precheck.js +33 -16
  222. package/src/lib/packer/web-panel-builder.js +16 -2
  223. package/src/lib/permission-rules.cjs +5 -1
  224. package/src/lib/personal-data-hub-aichat-wizard.js +22 -6
  225. package/src/lib/personal-data-hub-wiring.js +27 -3
  226. package/src/lib/plan-mode.js +204 -11
  227. package/src/lib/plugin-monitor-supervisor.js +39 -4
  228. package/src/lib/plugin-runtime/bin.js +45 -0
  229. package/src/lib/plugin-runtime/hooks.js +14 -1
  230. package/src/lib/plugin-runtime/install.js +2 -1
  231. package/src/lib/plugin-runtime/lsp.js +3 -0
  232. package/src/lib/plugin-runtime/mcp.js +8 -1
  233. package/src/lib/plugin-runtime/monitors.js +4 -0
  234. package/src/lib/plugin-runtime/plugin-options.js +74 -7
  235. package/src/lib/plugin-runtime/signature.js +45 -0
  236. package/src/lib/pr-create.js +21 -8
  237. package/src/lib/pr-link-ledger.js +15 -3
  238. package/src/lib/process-execution-broker/credential-agent.js +295 -0
  239. package/src/lib/process-execution-broker/index.js +440 -14
  240. package/src/lib/process-execution-broker/patch-child-process.js +2 -3
  241. package/src/lib/process-execution-broker/platform-sandbox.js +351 -0
  242. package/src/lib/process-manager.js +18 -3
  243. package/src/lib/provenance-api.js +6 -0
  244. package/src/lib/proxy-bootstrap.js +19 -0
  245. package/src/lib/publish-workspace.js +14 -6
  246. package/src/lib/repl-rewind.js +9 -4
  247. package/src/lib/secret-store.js +159 -0
  248. package/src/lib/service-manager.js +64 -29
  249. package/src/lib/session-hooks.js +328 -473
  250. package/src/lib/session-telemetry-middleware.js +6 -0
  251. package/src/lib/settings-hook-events.cjs +61 -1
  252. package/src/lib/settings-hooks.cjs +4 -0
  253. package/src/lib/side-effect-ledger.js +22 -0
  254. package/src/lib/sub-agent-context.js +5 -0
  255. package/src/lib/sub-agent-profiles.js +4 -0
  256. package/src/lib/trace-api.js +6 -0
  257. package/src/lib/turn-context.js +14 -8
  258. package/src/lib/unattended-action-policy.js +83 -0
  259. package/src/lib/update-notice.js +9 -45
  260. package/src/lib/with-file-lock.js +7 -0
  261. package/src/lib/ws-server.js +1 -0
  262. package/src/repl/agent-repl.js +71 -13
  263. package/src/repl/clipboard-copy.js +8 -2
  264. package/src/repl/pr-comments.js +30 -7
  265. package/src/runtime/agent-core.js +439 -87
  266. package/src/runtime/agent-runtime.js +1 -0
  267. package/src/runtime/coding-agent-contract-shared.cjs +52 -0
  268. package/src/runtime/coding-agent-policy.cjs +20 -0
  269. package/src/runtime/diagnostics.js +73 -8
  270. package/src/runtime/headless-runner.js +63 -0
  271. package/src/runtime/headless-stream.js +269 -17
  272. package/src/runtime/mcp-config.js +16 -1
  273. package/src/workers/background-agent-worker.js +80 -1
  274. package/src/assets/web-panel/assets/AppLayout-7iSKDmlI.js +0 -9
  275. package/src/assets/web-panel/assets/ChatBubbleRenderer-DcbUHeGW.js +0 -1
  276. package/src/assets/web-panel/assets/Dashboard-BAKYNavw.js +0 -3
  277. package/src/assets/web-panel/assets/MobileProjects-C4GKn1dH.js +0 -1
  278. package/src/assets/web-panel/assets/Terminal-Fj7ea0In.js +0 -3
  279. package/src/assets/web-panel/assets/devWarning-CDI8Sbaj.js +0 -1
  280. package/src/assets/web-panel/assets/index-96LBR96V.js +0 -1
  281. 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
- execSync(`taskkill /PID ${pid} /T /F`, { stdio: "ignore" });
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,6 @@
1
+ /**
2
+ * Provenance API stub
3
+ */
4
+ export function brokeredProvenance(data) {
5
+ // No-op stub for tests
6
+ }
@@ -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 { execSync } from "child_process";
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
- let cmd = "npm publish";
64
- if (options.tag) cmd += ` --tag ${options.tag}`;
65
- if (options.access) cmd += ` --access ${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
- execSync(cmd, {
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.succeed(`Published ${pkg.name}@${pkg.version}`);
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}`);
@@ -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
- if (branch && n !== null)
418
- return { command: "branch", n, scope, writeIntent, confirmed };
419
- if (n === null) return { command: "list", scope };
420
- return { command: "turn", n, scope, confirmed };
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 };