chainlesschain 0.162.189 → 0.162.197

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 (317) hide show
  1. package/README.md +84 -11
  2. package/bin/chainlesschain.js +7 -52
  3. package/completions/_cc +209 -0
  4. package/completions/cc.bash +18 -0
  5. package/completions/cc.fish +13 -0
  6. package/completions/cc.ps1 +226 -0
  7. package/package.json +10 -2
  8. package/src/assets/web-panel/assets/{AIOps-DbZft8w0.js → AIOps-D3Gu1a5d.js} +1 -1
  9. package/src/assets/web-panel/assets/{ActionButton-DoOZpwfN.js → ActionButton-DrwAoKaz.js} +1 -1
  10. package/src/assets/web-panel/assets/{Analytics-B0J0KLTW.js → Analytics-C7Q-gd_3.js} +3 -3
  11. package/src/assets/web-panel/assets/{AppLayout-D9eIR0qq.js → AppLayout-DgBtae-n.js} +4 -4
  12. package/src/assets/web-panel/assets/{Artifacts-BnZXEVeo.js → Artifacts-pQ6LcA-W.js} +1 -1
  13. package/src/assets/web-panel/assets/{Audit-X1ce4Bjn.js → Audit-DK61tocB.js} +1 -1
  14. package/src/assets/web-panel/assets/{BackgroundAgents-BvWR-y5v.js → BackgroundAgents-BOKgDFRh.js} +1 -1
  15. package/src/assets/web-panel/assets/{Backup-BublSGEd.js → Backup-Bo9G4vTP.js} +1 -1
  16. package/src/assets/web-panel/assets/{BaseInput-CR_77Hso.js → BaseInput-Do_dE9_v.js} +1 -1
  17. package/src/assets/web-panel/assets/{Chat-DixW52tq.js → Chat-COVvZzOL.js} +6 -6
  18. package/src/assets/web-panel/assets/ChatBubbleRenderer-BUUyJ5QO.js +1 -0
  19. package/src/assets/web-panel/assets/{Checkbox-CCv1C87K.js → Checkbox-Z9MJMolt.js} +1 -1
  20. package/src/assets/web-panel/assets/{Codegen-B03Cc3dd.js → Codegen-BVzWKVbf.js} +1 -1
  21. package/src/assets/web-panel/assets/{Col-CA06-6pU.js → Col-C8MnYcbT.js} +1 -1
  22. package/src/assets/web-panel/assets/{Community-Bj881J52.js → Community-DQxqw15l.js} +1 -1
  23. package/src/assets/web-panel/assets/{Compact-UZLTPoaL.js → Compact-BAUmrh3y.js} +1 -1
  24. package/src/assets/web-panel/assets/{Compliance-kGwzRb_0.js → Compliance-jPAkQ3zK.js} +1 -1
  25. package/src/assets/web-panel/assets/{Cowork-KundoYM8.js → Cowork-BBQyxbh8.js} +2 -2
  26. package/src/assets/web-panel/assets/{Cron-BYZyoqDe.js → Cron-W5koq8Z5.js} +2 -2
  27. package/src/assets/web-panel/assets/{Crosschain-BhrrppBX.js → Crosschain-BQhnu5hS.js} +1 -1
  28. package/src/assets/web-panel/assets/{DID-CdC6EguZ.js → DID-DD7PlI18.js} +2 -2
  29. package/src/assets/web-panel/assets/{Dashboard-CcQx3J4y.js → Dashboard-w_ILuwKI.js} +2 -2
  30. package/src/assets/web-panel/assets/{Dropdown-BpijtEzQ.js → Dropdown-qiDUAyAo.js} +1 -1
  31. package/src/assets/web-panel/assets/{EmailListRenderer-DfZjeZTe.js → EmailListRenderer-PDeBcI5H.js} +1 -1
  32. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BFYSf69C.js → FamilyGuardDashboard-SuArscRM.js} +1 -1
  33. package/src/assets/web-panel/assets/{Federation-Okdi3pJm.js → Federation-BCovZaUn.js} +1 -1
  34. package/src/assets/web-panel/assets/{FormItemContext-mH-HebKW.js → FormItemContext-DjlFdVFk.js} +1 -1
  35. package/src/assets/web-panel/assets/{GenericCardRenderer-xivV69x7.js → GenericCardRenderer-DoEZ7fcS.js} +1 -1
  36. package/src/assets/web-panel/assets/{Git-1rh_YBwg.js → Git-CV0-6GPI.js} +2 -2
  37. package/src/assets/web-panel/assets/{Governance-eAXkNxdY.js → Governance-B_SFN50w.js} +1 -1
  38. package/src/assets/web-panel/assets/{Inference-CS6dMVTN.js → Inference-heI0Eo6k.js} +1 -1
  39. package/src/assets/web-panel/assets/{KnowledgeGraph-Bq_TnkvD.js → KnowledgeGraph-Cz5INS5p.js} +1 -1
  40. package/src/assets/web-panel/assets/{Logs-KchHtiHt.js → Logs-BSFxiHkg.js} +2 -2
  41. package/src/assets/web-panel/assets/MarkdownRenderer-1mNozZ8v.js +1 -0
  42. package/src/assets/web-panel/assets/{Marketplace-CsmGcX5X.js → Marketplace-0TWTpE7k.js} +1 -1
  43. package/src/assets/web-panel/assets/{McpTools-BaPFnnyz.js → McpTools-CV4-wBLm.js} +4 -4
  44. package/src/assets/web-panel/assets/{Memory-2m-sUUf7.js → Memory-x5bH5rw5.js} +2 -2
  45. package/src/assets/web-panel/assets/{MobileBridge-D5nVZBRu.js → MobileBridge-DaBmUu9G.js} +1 -1
  46. package/src/assets/web-panel/assets/{MobileProjects-Bo8MLZvT.js → MobileProjects-DqnoFPgR.js} +1 -1
  47. package/src/assets/web-panel/assets/{Mtc-3GDvamGa.js → Mtc-B_zKEBif.js} +4 -4
  48. package/src/assets/web-panel/assets/{MtcAudit-D2zGuZCH.js → MtcAudit-BCfKD2yg.js} +4 -4
  49. package/src/assets/web-panel/assets/{Multisig-BBVQ4t6t.js → Multisig-DgYfj6c_.js} +3 -3
  50. package/src/assets/web-panel/assets/{NLProgramming-BIOCyOGp.js → NLProgramming-Dz09lFUm.js} +1 -1
  51. package/src/assets/web-panel/assets/{Notes-DVwBGpzc.js → Notes-Cuj6ugBE.js} +3 -3
  52. package/src/assets/web-panel/assets/{NotificationSettings-BDnHfIfX.js → NotificationSettings-DK2WXjhg.js} +1 -1
  53. package/src/assets/web-panel/assets/{OrderTableRenderer-C7Ek20ag.js → OrderTableRenderer-D1IAOQoo.js} +1 -1
  54. package/src/assets/web-panel/assets/{Organization-D3SRKaa7.js → Organization-9fqnPvTw.js} +4 -4
  55. package/src/assets/web-panel/assets/{Overflow-C2B8ahyn.js → Overflow-n5xHkhow.js} +1 -1
  56. package/src/assets/web-panel/assets/{P2P-2iwQzG65.js → P2P-B5AUWwH-.js} +2 -2
  57. package/src/assets/web-panel/assets/{PdhVaultBrowser-CoPiWqMN.js → PdhVaultBrowser-CoUDV6dy.js} +4 -4
  58. package/src/assets/web-panel/assets/{Permissions-yV5XNXo5.js → Permissions-DPRmQf_H.js} +4 -4
  59. package/src/assets/web-panel/assets/{PersonalDataHub-uCDJhMUF.js → PersonalDataHub-B37bsbEN.js} +4 -4
  60. package/src/assets/web-panel/assets/{Pipeline-hN7ucMOA.js → Pipeline-CCAuPqu9.js} +1 -1
  61. package/src/assets/web-panel/assets/{Privacy-CgU0ptN4.js → Privacy-B81msZdv.js} +1 -1
  62. package/src/assets/web-panel/assets/{ProjectInit-CfYPiT6j.js → ProjectInit-B-Py2NbF.js} +2 -2
  63. package/src/assets/web-panel/assets/{ProjectSettings-B0A2C4nw.js → ProjectSettings-CYsneiRB.js} +2 -2
  64. package/src/assets/web-panel/assets/{Projects-BE5C0ajn.js → Projects-Y975Mh6R.js} +1 -1
  65. package/src/assets/web-panel/assets/{Providers-CstQPf8W.js → Providers-uO-10aP1.js} +1 -1
  66. package/src/assets/web-panel/assets/{QrScannerModal-Co3z_ynk.js → QrScannerModal-Bj_6gJ0l.js} +1 -1
  67. package/src/assets/web-panel/assets/{QuickAsk-DMTS6pQ6.js → QuickAsk-BgpBCMPE.js} +1 -1
  68. package/src/assets/web-panel/assets/{Recommend-ETw4odUa.js → Recommend-DhUW3YUA.js} +1 -1
  69. package/src/assets/web-panel/assets/RemoteSession-DdeyfbkA.js +5 -0
  70. package/src/assets/web-panel/assets/{Reputation-BTVqQgKq.js → Reputation-fxW421xd.js} +1 -1
  71. package/src/assets/web-panel/assets/{Row-CBKKwwtO.js → Row-De73w1og.js} +1 -1
  72. package/src/assets/web-panel/assets/{RssFeed-BHUQ438I.js → RssFeed-3US_Q_lj.js} +2 -2
  73. package/src/assets/web-panel/assets/{Search-B4NqeUsF.js → Search-DbZ_DU74.js} +1 -1
  74. package/src/assets/web-panel/assets/{Security-BRjoYG5_.js → Security-DoIU1vMF.js} +4 -4
  75. package/src/assets/web-panel/assets/{Services-CxQzu3p3.js → Services-DB_RGqpc.js} +2 -2
  76. package/src/assets/web-panel/assets/{Skeleton-BKzwwmWO.js → Skeleton-DnzLaayC.js} +1 -1
  77. package/src/assets/web-panel/assets/{Skills-DrsFcgth.js → Skills-VzVXHENF.js} +1 -1
  78. package/src/assets/web-panel/assets/{Sla-D21tmXCH.js → Sla-DMfvjCAI.js} +1 -1
  79. package/src/assets/web-panel/assets/{SpeechSettings-CjyjLfp8.js → SpeechSettings-DQQOYWbF.js} +1 -1
  80. package/src/assets/web-panel/assets/{SyncSettings-Cu45-tnx.js → SyncSettings-Bmx3FG1P.js} +2 -2
  81. package/src/assets/web-panel/assets/{Tasks-oMcILYOj.js → Tasks-DOQyfb-2.js} +1 -1
  82. package/src/assets/web-panel/assets/{Templates-Bh-Zcr5R.js → Templates-D6hTRT7c.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tenant-68ns63aI.js → Tenant-CTPQZAzs.js} +1 -1
  84. package/src/assets/web-panel/assets/{Terminal-BLJkFykE.js → Terminal-B7vII3oH.js} +2 -2
  85. package/src/assets/web-panel/assets/{TimelineRenderer-xcrJLq-O.js → TimelineRenderer-BkiFJeXV.js} +1 -1
  86. package/src/assets/web-panel/assets/{Tokens-C6PpFJtf.js → Tokens-BPPdQMNo.js} +1 -1
  87. package/src/assets/web-panel/assets/{Trigger-BaKA7tdM.js → Trigger-BxG8JAEI.js} +1 -1
  88. package/src/assets/web-panel/assets/{Trust-BzhA57Jc.js → Trust-DHD7nMpM.js} +1 -1
  89. package/src/assets/web-panel/assets/{UkeySign-4_U3JkIR.js → UkeySign-B4BJpU47.js} +1 -1
  90. package/src/assets/web-panel/assets/{VideoEditing-162AANxX.js → VideoEditing-CRiGpFx2.js} +1 -1
  91. package/src/assets/web-panel/assets/{Wallet-B1viuql_.js → Wallet-BSDSNiem.js} +4 -4
  92. package/src/assets/web-panel/assets/{WebAuthn-ZVWazhCy.js → WebAuthn-DLTUh5Zv.js} +5 -5
  93. package/src/assets/web-panel/assets/WorkflowEditor-tW2MwjhD.js +1 -0
  94. package/src/assets/web-panel/assets/{chat-DmrHNuwq.js → chat-SgsLQ3FC.js} +1 -1
  95. package/src/assets/web-panel/assets/{colors-DAJ_M-PK.js → colors-BHjjLIKO.js} +1 -1
  96. package/src/assets/web-panel/assets/{compact-item-uIzmYwLs.js → compact-item-VceErdKq.js} +1 -1
  97. package/src/assets/web-panel/assets/{createContext-D_ZmuLwb.js → createContext-BZ332MYl.js} +1 -1
  98. package/src/assets/web-panel/assets/devWarning-DosMaL-k.js +1 -0
  99. package/src/assets/web-panel/assets/{hasIn-CDt_shTL.js → hasIn-CBTjJOjn.js} +1 -1
  100. package/src/assets/web-panel/assets/index-0O5ePnUq.js +1 -0
  101. package/src/assets/web-panel/assets/{index-rXdwUeE3.js → index-1n7xjKDU.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-BAvSmJXW.js → index-29wVzi-k.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-C16fYKFD.js → index-B2u26AS3.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-C5WcdJH2.js → index-B40dQn0G.js} +3 -3
  105. package/src/assets/web-panel/assets/{index-CaelyMgF.js → index-B5KAGxNo.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-OzTxFIJP.js → index-BC1xuQgX.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CzXqvMuP.js → index-BETEjuNr.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-clSX4PEc.js → index-BOtvPdHt.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-saf3VNeP.js → index-BPXFLYdW.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DdUMcwRB.js → index-BQSmZGgs.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DfSSy9uy.js → index-BRWhLbWF.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-GcKOHD_c.js → index-BTlc-Bve.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BHvlm0In.js → index-BY1wexYG.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-Cvak6Oe2.js → index-BcUenmCX.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CKyd472S.js → index-BeiqkxJG.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DvFhhe6r.js → index-BhXZEUAc.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DBFmcaCQ.js → index-By5jBtkV.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-DqDSF2RW.js → index-CLc19alH.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DeGBoLQA.js → index-CMVvxIS8.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-FyplHuNt.js → index-C_B9rFQE.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CeUpKjvi.js → index-CaIS_TNX.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-BRa4kJ_S.js → index-CawpdGTW.js} +1 -1
  123. package/src/assets/web-panel/assets/index-ChAzPigF.js +1 -0
  124. package/src/assets/web-panel/assets/{index-QsgfSZrV.js → index-CpumS98o.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BDF6EQBs.js → index-Cr4rjlW5.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-rS3gl_68.js → index-CrUgDQkf.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-D4n1lGTB.js → index-CtjLcCNU.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-ifxmu8SY.js → index-DUkVN794.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BTCXf1t-.js → index-D_SePDWj.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Bbxjfstq.js → index-DaCCy6lq.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-D9OE8B3d.js → index-DdefYBSw.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-CG0lY4h3.js → index-DePOeMDM.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-Bx4d6c1k.js → index-DgPvuIn2.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-Z8P4BexE.js → index-FJ3zC9LK.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-ByzGvpR9.js → index-_PHrIO4O.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-DwfvPe-j.js → index-fU7wNHDB.js} +1 -1
  137. package/src/assets/web-panel/assets/{index-CcZ9xJI9.js → index-iYQNU9za.js} +1 -1
  138. package/src/assets/web-panel/assets/{index-CbD_WW_6.js → index-vIXOpcjD.js} +1 -1
  139. package/src/assets/web-panel/assets/{initDefaultProps-pmfaD-aK.js → initDefaultProps-D1oZNz0D.js} +1 -1
  140. package/src/assets/web-panel/assets/{motion-CaQ2CpYF.js → motion-C8k6doMO.js} +1 -1
  141. package/src/assets/web-panel/assets/{move-CkKTqNbI.js → move-DJ4qSbYt.js} +1 -1
  142. package/src/assets/web-panel/assets/{mtc-parser-Dd4xsgRI.js → mtc-parser-CdpJD85j.js} +1 -1
  143. package/src/assets/web-panel/assets/{omit-BFuA5YEs.js → omit-B0V4slKA.js} +1 -1
  144. package/src/assets/web-panel/assets/{pickAttrs-DDfxOAJc.js → pickAttrs-Di5NiW1F.js} +1 -1
  145. package/src/assets/web-panel/assets/{placementArrow-Be595JCp.js → placementArrow-B5OMHgEM.js} +1 -1
  146. package/src/assets/web-panel/assets/{responsiveObserve-7byljUM3.js → responsiveObserve-C6U9IWql.js} +1 -1
  147. package/src/assets/web-panel/assets/{slide-CTWfOTaY.js → slide-BMyTH3rN.js} +1 -1
  148. package/src/assets/web-panel/assets/{statusUtils-CNZOuIxM.js → statusUtils-C7d6BG7Z.js} +1 -1
  149. package/src/assets/web-panel/assets/{styleChecker-DwOcBV78.js → styleChecker-CR50QnQy.js} +1 -1
  150. package/src/assets/web-panel/assets/{useFlexGapSupport-B6MNwAO9.js → useFlexGapSupport-DBEeoMb8.js} +1 -1
  151. package/src/assets/web-panel/assets/{useFs-CzyQjH9r.js → useFs-3r099cjv.js} +1 -1
  152. package/src/assets/web-panel/assets/{usePersonalDataHub-Dxh3KiVA.js → usePersonalDataHub-C5IYNdTK.js} +1 -1
  153. package/src/assets/web-panel/assets/{vnode-DVfZiS5N.js → vnode-DmEOLRHf.js} +1 -1
  154. package/src/assets/web-panel/assets/{zoom-BYme7fbY.js → zoom-DnpUiVCB.js} +1 -1
  155. package/src/assets/web-panel/index.html +1 -1
  156. package/src/cli-help.js +181 -0
  157. package/src/command-help-index.json +181 -0
  158. package/src/command-manifest.json +1271 -175
  159. package/src/command-surface-policy.js +312 -0
  160. package/src/commands/agent.js +76 -33
  161. package/src/commands/artifacts.js +400 -2
  162. package/src/commands/background-session.js +41 -3
  163. package/src/commands/checkpoint-restore-recovery.js +1476 -0
  164. package/src/commands/checkpoint.js +947 -22
  165. package/src/commands/compact.js +101 -25
  166. package/src/commands/config.js +506 -20
  167. package/src/commands/doctor.js +4 -1
  168. package/src/commands/hub.js +1 -1
  169. package/src/commands/mcp.js +688 -24
  170. package/src/commands/pack.js +16 -2
  171. package/src/commands/plugin.js +20 -12
  172. package/src/commands/session-mcp-recovery.js +218 -0
  173. package/src/commands/session.js +470 -110
  174. package/src/commands/setup.js +36 -10
  175. package/src/commands/skill.js +181 -110
  176. package/src/commands/status.js +21 -5
  177. package/src/commands/update.js +68 -6
  178. package/src/constants.js +11 -0
  179. package/src/data/changelog.json +14 -1
  180. package/src/gateways/ws/action-protocol.js +10 -0
  181. package/src/gateways/ws/session-protocol.js +555 -27
  182. package/src/gateways/ws/ws-agent-handler.js +541 -14
  183. package/src/gateways/ws/ws-session-gateway.js +129 -22
  184. package/src/gateways/ws/ws-session-state.js +431 -0
  185. package/src/harness/background-task-manager.js +233 -36
  186. package/src/harness/jsonl-session-store.js +2551 -167
  187. package/src/harness/mcp-client.js +802 -61
  188. package/src/harness/prompt-compressor.js +227 -27
  189. package/src/harness/session-index.js +89 -38
  190. package/src/harness/session-list-index.js +254 -0
  191. package/src/harness/structured-handoff.js +410 -0
  192. package/src/lazy-dispatch.js +747 -84
  193. package/src/lib/__tests__/logger.test.js +50 -2
  194. package/src/lib/advisor-runtime.js +1047 -0
  195. package/src/lib/agent-core.js +1 -0
  196. package/src/lib/agent-sandbox.js +120 -26
  197. package/src/lib/agent-session-export.js +20 -0
  198. package/src/lib/agent-team/team-runner.js +230 -8
  199. package/src/lib/artifact-store.js +131 -8
  200. package/src/lib/background-agent-supervisor.js +185 -13
  201. package/src/lib/background-interaction-journal.js +37 -9
  202. package/src/lib/background-launch-profile.js +1058 -0
  203. package/src/lib/checkpoint-restore-already-completed-controller.js +902 -0
  204. package/src/lib/checkpoint-restore-orchestrator.js +987 -0
  205. package/src/lib/checkpoint-restore-partial-rollback-controller.js +1953 -0
  206. package/src/lib/checkpoint-restore-recovery-controller.js +689 -0
  207. package/src/lib/checkpoint-restore-recovery.js +884 -0
  208. package/src/lib/checkpoint-restore-retention.js +126 -0
  209. package/src/lib/checkpoint-restore-saga.js +5079 -0
  210. package/src/lib/checkpoint-restore-session-recovery.js +1178 -0
  211. package/src/lib/checkpoint-restore-workspace-target-verifier.js +270 -0
  212. package/src/lib/checkpoint-store.js +1688 -97
  213. package/src/lib/checkpoint-timeline-authority.js +522 -0
  214. package/src/lib/checkpoint-timeline.js +642 -0
  215. package/src/lib/config-keys.js +18 -119
  216. package/src/lib/config-manager.js +446 -27
  217. package/src/lib/config-redaction.js +57 -0
  218. package/src/lib/config-schema.js +853 -0
  219. package/src/lib/cowork-mcp-tools.js +5 -0
  220. package/src/lib/cowork-task-runner.js +458 -63
  221. package/src/lib/delivery-coordinator.js +1234 -0
  222. package/src/lib/delivery-evidence.js +450 -0
  223. package/src/lib/doctor-checkup.js +199 -14
  224. package/src/lib/executable-path.js +34 -0
  225. package/src/lib/fatal-handler.js +16 -0
  226. package/src/lib/file-checkpoint.js +4909 -186
  227. package/src/lib/file-lines.js +125 -0
  228. package/src/lib/headless-config-command.js +16 -5
  229. package/src/lib/hook-runner.cjs +139 -38
  230. package/src/lib/hooks-v2-workspace-context.js +10 -0
  231. package/src/lib/impacted-gate-selector.js +424 -0
  232. package/src/lib/interaction-adapter.js +62 -0
  233. package/src/lib/jsonl-session-store.js +1 -35
  234. package/src/lib/logger.js +66 -14
  235. package/src/lib/mcp-call-ledger-store.js +1069 -0
  236. package/src/lib/mcp-call-ledger.js +747 -0
  237. package/src/lib/mcp-client.js +5 -0
  238. package/src/lib/mcp-conflict-scheduler.js +468 -0
  239. package/src/lib/mcp-effect-contract.js +102 -0
  240. package/src/lib/mcp-headers-helper-trust.js +145 -0
  241. package/src/lib/mcp-headers-helper.js +616 -0
  242. package/src/lib/mcp-host-recovery-runtime.js +131 -0
  243. package/src/lib/mcp-ledger-recovery-admission.js +1065 -0
  244. package/src/lib/mcp-recovery-adjudication.js +443 -0
  245. package/src/lib/output-context.js +86 -0
  246. package/src/lib/packer/file-identity.js +170 -0
  247. package/src/lib/packer/index.js +3 -0
  248. package/src/lib/packer/native-update-state.js +277 -0
  249. package/src/lib/packer/pack-update-applier.js +1983 -136
  250. package/src/lib/packer/pack-update-checker.js +34 -0
  251. package/src/lib/packer/pack-update-downloader.js +875 -86
  252. package/src/lib/packer/pack-update-signature.js +86 -0
  253. package/src/lib/packer/pkg-config-generator.js +6 -0
  254. package/src/lib/paths.js +65 -10
  255. package/src/lib/plan-mode.js +831 -14
  256. package/src/lib/plan-persistence.js +540 -0
  257. package/src/lib/plugin-runtime/hooks.js +227 -69
  258. package/src/lib/plugin-runtime/plugin-options.js +189 -44
  259. package/src/lib/pr-automation-policy.js +146 -8
  260. package/src/lib/process-execution-broker/credential-agent.js +7 -0
  261. package/src/lib/process-execution-broker/index.js +53 -8
  262. package/src/lib/process-execution-broker/workspace-transaction.js +976 -73
  263. package/src/lib/project-instructions.js +165 -29
  264. package/src/lib/project-mcp-trust.js +67 -0
  265. package/src/lib/public-ide-capability-manifest.js +278 -0
  266. package/src/lib/public-ide-capability-validation.js +351 -0
  267. package/src/lib/secret-store.js +267 -43
  268. package/src/lib/secure-fs.js +1089 -0
  269. package/src/lib/security-audit.js +58 -0
  270. package/src/lib/service-manager.js +34 -13
  271. package/src/lib/session-budget-runtime.js +1452 -0
  272. package/src/lib/session-host-snapshot.js +388 -0
  273. package/src/lib/session-message-provenance.js +429 -0
  274. package/src/lib/session-projection.js +804 -0
  275. package/src/lib/session-resource-budget.js +1495 -0
  276. package/src/lib/settings-hooks.cjs +138 -22
  277. package/src/lib/settings-loader.cjs +25 -2
  278. package/src/lib/side-effect-ledger-store.js +45 -23
  279. package/src/lib/skill-execution-identity.js +217 -0
  280. package/src/lib/skill-loader.js +299 -18
  281. package/src/lib/sub-agent-context.js +236 -28
  282. package/src/lib/sub-agent-registry.js +5 -0
  283. package/src/lib/subagent-contract.js +94 -0
  284. package/src/lib/todo-manager.js +185 -18
  285. package/src/lib/todo-persistence.js +417 -0
  286. package/src/lib/turn-binding-store.js +41 -23
  287. package/src/lib/with-file-lock.js +25 -1
  288. package/src/lib/ws-chat-handler.js +21 -0
  289. package/src/program-base.js +18 -0
  290. package/src/repl/advisor-command.js +103 -0
  291. package/src/repl/agent-repl.js +2332 -154
  292. package/src/repl/btw-command.js +93 -10
  293. package/src/repl/clipboard-image.js +119 -0
  294. package/src/repl/config-summary.js +64 -108
  295. package/src/repl/prompt-editor.js +233 -0
  296. package/src/repl/prompt-interactions.js +404 -0
  297. package/src/repl/prompt-stash.js +354 -0
  298. package/src/repl/prompt-suggestions.js +312 -0
  299. package/src/repl/repl-keybindings.js +227 -0
  300. package/src/repl/session-recap.js +217 -0
  301. package/src/repl/slash-command-registry.js +25 -4
  302. package/src/repl/terminal-layout.js +88 -0
  303. package/src/runtime/agent-core.js +1264 -325
  304. package/src/runtime/coding-agent-contract-shared.cjs +13 -1
  305. package/src/runtime/coding-agent-managed-tool-policy.cjs +7 -2
  306. package/src/runtime/diagnostics.js +32 -13
  307. package/src/runtime/headless-runner.js +298 -118
  308. package/src/runtime/headless-stream.js +353 -95
  309. package/src/runtime/mcp-config.js +148 -14
  310. package/src/runtime/status-diagnostics-lite.js +137 -0
  311. package/src/assets/web-panel/assets/ChatBubbleRenderer-DDHDpBBA.js +0 -1
  312. package/src/assets/web-panel/assets/MarkdownRenderer-TabqHW9B.js +0 -1
  313. package/src/assets/web-panel/assets/RemoteSession-B0rkE09d.js +0 -5
  314. package/src/assets/web-panel/assets/WorkflowEditor-tzdyUk-1.js +0 -1
  315. package/src/assets/web-panel/assets/devWarning-DIrncrV1.js +0 -1
  316. package/src/assets/web-panel/assets/index-D-Swwqld.js +0 -1
  317. package/src/assets/web-panel/assets/index-FMZAMKy8.js +0 -1
@@ -0,0 +1,616 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import executionBroker from "./process-execution-broker/index.js";
4
+ import hookShellCommand from "./hook-shell-command.cjs";
5
+ import {
6
+ currentHostHooksV2WorkspaceBinding,
7
+ resolveHostHooksV2WorkspaceBinding,
8
+ } from "./hooks-v2-workspace-context.js";
9
+ import { checkLocalMcpHeadersHelperTrust } from "./mcp-headers-helper-trust.js";
10
+ import { resolvePluginWorkspaceAuthority } from "./plugin-runtime/sandbox-policy.js";
11
+ import { resolveProjectMcpWorkspaceAuthority } from "./project-mcp-trust.js";
12
+
13
+ const { buildExplicitHookShellInvocation } = hookShellCommand;
14
+
15
+ export const MCP_HEADERS_HELPER_TIMEOUT_MS = 10_000;
16
+ export const MCP_HEADERS_HELPER_MAX_OUTPUT_BYTES = 64 * 1024;
17
+ const MAX_HELPER_COMMAND_BYTES = 32 * 1024;
18
+ const MAX_HEADER_COUNT = 128;
19
+ const MAX_HEADER_VALUE_BYTES = 16 * 1024;
20
+ const HEADER_NAME = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
21
+ const TRANSPORT_OWNED_HEADERS = new Set([
22
+ "accept",
23
+ "connection",
24
+ "content-length",
25
+ "content-type",
26
+ "host",
27
+ "mcp-protocol-version",
28
+ "mcp-session-id",
29
+ "sec-websocket-accept",
30
+ "sec-websocket-extensions",
31
+ "sec-websocket-key",
32
+ "sec-websocket-protocol",
33
+ "sec-websocket-version",
34
+ "transfer-encoding",
35
+ "upgrade",
36
+ ]);
37
+ const PUBLIC_CONFIG_SCOPES = new Set(["local", "project", "user", "managed"]);
38
+
39
+ function helperError(code, message) {
40
+ const error = new Error(message);
41
+ error.code = code;
42
+ return error;
43
+ }
44
+
45
+ function normalizeHelperCommand(value) {
46
+ if (
47
+ typeof value !== "string" ||
48
+ value.trim() === "" ||
49
+ value.includes("\0") ||
50
+ Buffer.byteLength(value, "utf8") > MAX_HELPER_COMMAND_BYTES
51
+ ) {
52
+ throw helperError(
53
+ "CC_MCP_HEADERS_HELPER_INVALID",
54
+ "MCP headersHelper must be a non-empty bounded command string",
55
+ );
56
+ }
57
+ return value;
58
+ }
59
+
60
+ function canonicalHelperCwd(value, realpath = fs.realpathSync.native) {
61
+ if (
62
+ typeof value !== "string" ||
63
+ value === "" ||
64
+ value.includes("\0") ||
65
+ !path.isAbsolute(value)
66
+ ) {
67
+ throw helperError(
68
+ "CC_MCP_HEADERS_HELPER_CWD_INVALID",
69
+ "MCP headersHelper requires an absolute trusted working directory",
70
+ );
71
+ }
72
+ let canonical;
73
+ let stats;
74
+ try {
75
+ canonical = realpath(path.resolve(value));
76
+ stats = fs.statSync(canonical);
77
+ } catch {
78
+ throw helperError(
79
+ "CC_MCP_HEADERS_HELPER_CWD_INVALID",
80
+ "MCP headersHelper working directory is unavailable",
81
+ );
82
+ }
83
+ if (!stats.isDirectory()) {
84
+ throw helperError(
85
+ "CC_MCP_HEADERS_HELPER_CWD_INVALID",
86
+ "MCP headersHelper working directory must be a directory",
87
+ );
88
+ }
89
+ return canonical;
90
+ }
91
+
92
+ function normalizeHeaderMap(value, source) {
93
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
94
+ throw helperError(
95
+ "CC_MCP_HEADERS_HELPER_OUTPUT_INVALID",
96
+ `MCP ${source} headers must be a JSON object of string values`,
97
+ );
98
+ }
99
+ const entries = Object.entries(value);
100
+ if (entries.length > MAX_HEADER_COUNT) {
101
+ throw helperError(
102
+ "CC_MCP_HEADERS_HELPER_OUTPUT_INVALID",
103
+ `MCP ${source} headers exceed the allowed entry count`,
104
+ );
105
+ }
106
+ const normalized = [];
107
+ for (const [name, headerValue] of entries) {
108
+ if (
109
+ !HEADER_NAME.test(name) ||
110
+ typeof headerValue !== "string" ||
111
+ /[\0-\x08\x0a-\x1f\x7f]/.test(headerValue) ||
112
+ Buffer.byteLength(headerValue, "utf8") > MAX_HEADER_VALUE_BYTES ||
113
+ (source === "dynamic" && TRANSPORT_OWNED_HEADERS.has(name.toLowerCase()))
114
+ ) {
115
+ throw helperError(
116
+ "CC_MCP_HEADERS_HELPER_OUTPUT_INVALID",
117
+ `MCP ${source} headers contain an invalid name or value`,
118
+ );
119
+ }
120
+ normalized.push([name, headerValue]);
121
+ }
122
+ return normalized;
123
+ }
124
+
125
+ function isPathInside(root, candidate) {
126
+ const relative = path.relative(path.resolve(root), path.resolve(candidate));
127
+ return (
128
+ relative === "" ||
129
+ (relative !== ".." &&
130
+ !relative.startsWith(`..${path.sep}`) &&
131
+ !path.isAbsolute(relative))
132
+ );
133
+ }
134
+
135
+ /**
136
+ * Resolve helper cwd only from an existing source authority. Project/local
137
+ * configs must run inside the host bootstrap's immutable workspace binding;
138
+ * plugin configs must carry the collector-issued opaque plugin authority.
139
+ */
140
+ export function resolveMcpHeadersHelperContext(config = {}, deps = {}) {
141
+ if (config.origin === "plugin:mcp") {
142
+ const resolvePlugin =
143
+ deps.resolvePluginWorkspaceAuthority || resolvePluginWorkspaceAuthority;
144
+ const pluginRoot = resolvePlugin(config.pluginWorkspaceAuthority, {
145
+ origin: config.origin,
146
+ pluginId: config.pluginId,
147
+ pluginVersion: config.pluginVersion,
148
+ pluginSource: config.pluginSource,
149
+ });
150
+ if (!pluginRoot) {
151
+ throw helperError(
152
+ "CC_MCP_HEADERS_HELPER_UNTRUSTED_WORKSPACE",
153
+ "Plugin MCP headersHelper is missing its trusted workspace authority",
154
+ );
155
+ }
156
+ return {
157
+ cwd: pluginRoot,
158
+ pluginRoot,
159
+ execution: {
160
+ origin: config.origin,
161
+ policy: config.policy || "allow",
162
+ scope: config.scope || "mcp",
163
+ pluginId: config.pluginId,
164
+ pluginVersion: config.pluginVersion,
165
+ pluginSource: config.pluginSource,
166
+ ...(config.sandboxPolicy
167
+ ? { sandboxPolicy: config.sandboxPolicy }
168
+ : {}),
169
+ },
170
+ };
171
+ }
172
+
173
+ const scope = config.configScope == null ? "user" : config.configScope;
174
+ if (!PUBLIC_CONFIG_SCOPES.has(scope)) {
175
+ throw helperError(
176
+ "CC_MCP_HEADERS_HELPER_UNTRUSTED_WORKSPACE",
177
+ "MCP headersHelper has an unsupported configuration source",
178
+ );
179
+ }
180
+ const hasBindingOverride = Object.prototype.hasOwnProperty.call(
181
+ deps,
182
+ "currentWorkspaceBinding",
183
+ );
184
+ const candidateBinding = hasBindingOverride
185
+ ? typeof deps.currentWorkspaceBinding === "function"
186
+ ? deps.currentWorkspaceBinding()
187
+ : null
188
+ : currentHostHooksV2WorkspaceBinding();
189
+ const binding = hasBindingOverride
190
+ ? (deps.resolveHostWorkspaceBinding || resolveHostHooksV2WorkspaceBinding)(
191
+ candidateBinding,
192
+ )
193
+ : candidateBinding;
194
+ if (scope === "local" || scope === "project") {
195
+ if (!binding?.workspaceRoot || !config.projectPath) {
196
+ throw helperError(
197
+ "CC_MCP_HEADERS_HELPER_UNTRUSTED_WORKSPACE",
198
+ "Project-local MCP headersHelper requires a trusted host workspace",
199
+ );
200
+ }
201
+ let projectRoot;
202
+ try {
203
+ projectRoot = fs.realpathSync.native(
204
+ path.resolve(String(config.projectPath)),
205
+ );
206
+ } catch {
207
+ throw helperError(
208
+ "CC_MCP_HEADERS_HELPER_UNTRUSTED_WORKSPACE",
209
+ "MCP headersHelper project authority is unavailable",
210
+ );
211
+ }
212
+ if (!isPathInside(projectRoot, binding.workspaceRoot)) {
213
+ throw helperError(
214
+ "CC_MCP_HEADERS_HELPER_UNTRUSTED_WORKSPACE",
215
+ "MCP headersHelper source does not belong to the trusted host workspace",
216
+ );
217
+ }
218
+ if (scope === "project") {
219
+ const resolveProject =
220
+ deps.resolveProjectMcpWorkspaceAuthority ||
221
+ resolveProjectMcpWorkspaceAuthority;
222
+ const authorityRoot = resolveProject(
223
+ config.projectMcpWorkspaceAuthority,
224
+ {
225
+ configSource: config.configSource,
226
+ serverName: config.serverName || config.name,
227
+ url: config.url,
228
+ transport: config.transport,
229
+ headersHelper: config.headersHelper,
230
+ },
231
+ );
232
+ if (!authorityRoot || path.resolve(authorityRoot) !== projectRoot) {
233
+ throw helperError(
234
+ "CC_MCP_HEADERS_HELPER_UNTRUSTED_WORKSPACE",
235
+ "Project MCP headersHelper is missing its trusted file authority",
236
+ );
237
+ }
238
+ }
239
+ if (scope === "local") {
240
+ const checkTrust =
241
+ deps.checkLocalMcpHeadersHelperTrust || checkLocalMcpHeadersHelperTrust;
242
+ const trust = checkTrust({
243
+ workspaceRoot: projectRoot,
244
+ serverName: config.serverName || config.name,
245
+ url: config.url,
246
+ transport: config.transport,
247
+ headersHelper: config.headersHelper,
248
+ });
249
+ if (trust?.status !== "trusted") {
250
+ throw helperError(
251
+ "CC_MCP_HEADERS_HELPER_UNTRUSTED_WORKSPACE",
252
+ "Local MCP headersHelper changed or has not been explicitly trusted",
253
+ );
254
+ }
255
+ }
256
+ return { cwd: binding.workspaceRoot, pluginRoot: null, execution: null };
257
+ }
258
+ return {
259
+ cwd: binding?.workspaceRoot || path.resolve(deps.cwd || process.cwd()),
260
+ pluginRoot: null,
261
+ execution: null,
262
+ };
263
+ }
264
+
265
+ /**
266
+ * Merge HTTP headers case-insensitively. A dynamic helper value replaces every
267
+ * static spelling of the same header name, while unrelated static headers stay
268
+ * intact. Duplicate spellings within either input collapse to the last value.
269
+ */
270
+ export function mergeMcpHeaders(staticHeaders = {}, dynamicHeaders = {}) {
271
+ const byLowerName = new Map();
272
+ for (const [name, value] of normalizeHeaderMap(staticHeaders, "static")) {
273
+ byLowerName.set(name.toLowerCase(), [name, value]);
274
+ }
275
+ for (const [name, value] of normalizeHeaderMap(dynamicHeaders, "dynamic")) {
276
+ byLowerName.set(name.toLowerCase(), [name, value]);
277
+ }
278
+ return Object.fromEntries(byLowerName.values());
279
+ }
280
+
281
+ function waitForHelperClose(child, timeoutMs) {
282
+ if (child?.exitCode != null || child?.signalCode != null) {
283
+ return Promise.resolve(true);
284
+ }
285
+ if (typeof child?.once !== "function") return Promise.resolve(false);
286
+ return new Promise((resolve) => {
287
+ let settled = false;
288
+ const finish = (value) => {
289
+ if (settled) return;
290
+ settled = true;
291
+ clearTimeout(timer);
292
+ child.off?.("close", onClose);
293
+ resolve(value);
294
+ };
295
+ const onClose = () => finish(true);
296
+ const timer = setTimeout(() => finish(false), timeoutMs);
297
+ child.once("close", onClose);
298
+ });
299
+ }
300
+
301
+ async function waitForPosixGroupExit(pid, kill, timeoutMs, deps = {}) {
302
+ const probe =
303
+ deps.probeGroupGone ||
304
+ (() => {
305
+ try {
306
+ kill(-pid, 0);
307
+ return false;
308
+ } catch (error) {
309
+ return error?.code === "ESRCH";
310
+ }
311
+ });
312
+ const deadline = Date.now() + timeoutMs;
313
+ do {
314
+ if (probe(pid) === true) return true;
315
+ await new Promise((resolve) => setTimeout(resolve, 10));
316
+ } while (Date.now() < deadline);
317
+ return probe(pid) === true;
318
+ }
319
+
320
+ /** Bounded whole-tree termination fence for a timed-out helper. */
321
+ export async function terminateMcpHeadersHelperTree(child, deps = {}) {
322
+ const platform = deps.platform || process.platform;
323
+ const sandboxManagedTree = deps.sandboxManagedTree === true;
324
+ const kill = deps.kill || process.kill.bind(process);
325
+ const spawnSync =
326
+ deps.spawnSync || executionBroker.spawnSync.bind(executionBroker);
327
+ const cleanupTimeoutMs = Math.max(
328
+ 1,
329
+ Math.min(2_000, Number(deps.cleanupTimeoutMs || 2_000)),
330
+ );
331
+ const pid = Number(child?.pid);
332
+ if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid) {
333
+ return { requested: false, closed: false, treeTerminated: false };
334
+ }
335
+
336
+ const closeFence = deps.alreadyClosed
337
+ ? Promise.resolve(true)
338
+ : waitForHelperClose(child, cleanupTimeoutMs);
339
+ let requested = false;
340
+ let treeTerminated = false;
341
+
342
+ if (platform === "win32") {
343
+ try {
344
+ const result = spawnSync("taskkill", ["/PID", String(pid), "/T", "/F"], {
345
+ shell: false,
346
+ windowsHide: true,
347
+ encoding: "utf8",
348
+ origin: "mcp:headers-helper:taskkill",
349
+ policy: "allow",
350
+ scope: "mcp",
351
+ });
352
+ if (!result?.error && result?.status === 0) {
353
+ requested = true;
354
+ treeTerminated = true;
355
+ }
356
+ } catch {
357
+ // Fall through to the direct child handle below.
358
+ }
359
+ } else if (!requested && !sandboxManagedTree) {
360
+ try {
361
+ kill(-pid, "SIGKILL");
362
+ requested = true;
363
+ } catch {
364
+ // The helper may have failed before becoming a process-group leader.
365
+ }
366
+ }
367
+
368
+ if (!requested) {
369
+ try {
370
+ requested = child.kill?.("SIGKILL") !== false;
371
+ } catch {
372
+ requested = false;
373
+ }
374
+ }
375
+
376
+ const [closed, posixTreeGone] = await Promise.all([
377
+ closeFence,
378
+ platform === "win32" || !requested || sandboxManagedTree
379
+ ? Promise.resolve(treeTerminated)
380
+ : waitForPosixGroupExit(pid, kill, cleanupTimeoutMs, deps),
381
+ ]);
382
+ if (platform !== "win32") {
383
+ // A strong Linux workspace contract launches bubblewrap as the direct
384
+ // child with a private PID namespace and a close fence. Once that child
385
+ // closes, Broker's process-tree guarantee confirms the namespace is empty;
386
+ // it must not be treated as an independently detached process group.
387
+ treeTerminated = sandboxManagedTree ? requested && closed : posixTreeGone;
388
+ }
389
+ return { requested, closed, treeTerminated };
390
+ }
391
+
392
+ /**
393
+ * Execute one trusted MCP headersHelper command and return its validated JSON
394
+ * object. The helper output is credential material: errors deliberately omit
395
+ * the command, stdout, and stderr.
396
+ */
397
+ export function runMcpHeadersHelper(spec, deps = {}) {
398
+ const command = normalizeHelperCommand(spec?.command);
399
+ const platform = deps.platform || process.platform;
400
+ const cwd = canonicalHelperCwd(
401
+ spec?.cwd,
402
+ deps.realpath || fs.realpathSync.native,
403
+ );
404
+ const invocation = buildExplicitHookShellInvocation(command, { platform });
405
+ const spawn = deps.spawn || executionBroker.spawn.bind(executionBroker);
406
+ const timeoutMs = Math.max(
407
+ 1,
408
+ Math.min(
409
+ MCP_HEADERS_HELPER_TIMEOUT_MS,
410
+ Number(deps.timeoutMs || MCP_HEADERS_HELPER_TIMEOUT_MS),
411
+ ),
412
+ );
413
+ const maxOutputBytes = Math.max(
414
+ 1024,
415
+ Math.min(
416
+ MCP_HEADERS_HELPER_MAX_OUTPUT_BYTES,
417
+ Number(deps.maxOutputBytes || MCP_HEADERS_HELPER_MAX_OUTPUT_BYTES),
418
+ ),
419
+ );
420
+ const env = {
421
+ ...(spec?.env || process.env),
422
+ CLAUDE_CODE_MCP_SERVER_NAME: String(spec?.serverName || ""),
423
+ CLAUDE_CODE_MCP_SERVER_URL: String(spec?.serverUrl || ""),
424
+ ...(spec?.pluginRoot
425
+ ? { CLAUDE_PLUGIN_ROOT: String(spec.pluginRoot) }
426
+ : {}),
427
+ };
428
+ const spawnOptions = {
429
+ cwd,
430
+ env,
431
+ stdio: ["ignore", "pipe", "pipe"],
432
+ shell: false,
433
+ windowsHide: true,
434
+ detached: platform !== "win32",
435
+ origin:
436
+ spec?.execution?.origin ||
437
+ `mcp:headers-helper:${String(spec?.serverName || "unknown")}`,
438
+ policy: spec?.execution?.policy || "allow",
439
+ scope: spec?.execution?.scope || "mcp",
440
+ pluginId: spec?.execution?.pluginId,
441
+ pluginVersion: spec?.execution?.pluginVersion,
442
+ pluginSource: spec?.execution?.pluginSource,
443
+ ...(spec?.execution?.sandboxPolicy
444
+ ? { sandboxPolicy: spec.execution.sandboxPolicy }
445
+ : {}),
446
+ auditRedactArgIndexes: [invocation.argv.length - 1],
447
+ };
448
+ const issueSandboxContract =
449
+ deps.issueSandboxExecutionContract ||
450
+ executionBroker.issueLinuxWorkspaceSandboxExecutionContract.bind(
451
+ executionBroker,
452
+ );
453
+ let sandboxExecutionContract;
454
+ try {
455
+ // Strong Linux workspace contracts deliberately reject detached launches:
456
+ // bubblewrap owns the whole process tree through its PID namespace. Probe
457
+ // with detached:false, then retain a detached process group only when no
458
+ // Broker-owned sandbox contract is issued.
459
+ sandboxExecutionContract = issueSandboxContract(
460
+ invocation.file,
461
+ invocation.argv,
462
+ { ...spawnOptions, detached: false },
463
+ cwd,
464
+ );
465
+ } catch {
466
+ throw helperError(
467
+ "CC_MCP_HEADERS_HELPER_SANDBOX_UNAVAILABLE",
468
+ "MCP headersHelper sandbox authority is unavailable",
469
+ );
470
+ }
471
+ const sandboxManagedTree = Boolean(sandboxExecutionContract);
472
+ const launchOptions = {
473
+ ...spawnOptions,
474
+ detached: sandboxManagedTree ? false : spawnOptions.detached,
475
+ };
476
+
477
+ return new Promise((resolve, reject) => {
478
+ let child;
479
+ try {
480
+ child = spawn(invocation.file, invocation.argv, {
481
+ ...launchOptions,
482
+ ...(sandboxExecutionContract ? { sandboxExecutionContract } : {}),
483
+ });
484
+ } catch {
485
+ reject(
486
+ helperError(
487
+ "CC_MCP_HEADERS_HELPER_START_FAILED",
488
+ "MCP headersHelper could not be started",
489
+ ),
490
+ );
491
+ return;
492
+ }
493
+
494
+ if (!child?.stdout || !child?.stderr) {
495
+ void terminateMcpHeadersHelperTree(child, {
496
+ ...deps,
497
+ platform,
498
+ sandboxManagedTree,
499
+ }).finally(() =>
500
+ reject(
501
+ helperError(
502
+ "CC_MCP_HEADERS_HELPER_START_FAILED",
503
+ "MCP headersHelper did not expose bounded output streams",
504
+ ),
505
+ ),
506
+ );
507
+ return;
508
+ }
509
+
510
+ let state = "running";
511
+ let stdout = "";
512
+ let stdoutBytes = 0;
513
+ let stderrBytes = 0;
514
+ const settle = (fn, value) => {
515
+ if (state === "settled") return;
516
+ state = "settled";
517
+ clearTimeout(timer);
518
+ fn(value);
519
+ };
520
+ const failAndTerminate = (error, cleanupDeps = {}) => {
521
+ if (state !== "running") return;
522
+ state = "terminating";
523
+ clearTimeout(timer);
524
+ void terminateMcpHeadersHelperTree(child, {
525
+ ...deps,
526
+ ...cleanupDeps,
527
+ platform,
528
+ sandboxManagedTree,
529
+ })
530
+ .catch(() => ({ closed: false, treeTerminated: false }))
531
+ .then((cleanup) => {
532
+ error.cleanupConfirmed =
533
+ cleanup.closed === true && cleanup.treeTerminated === true;
534
+ settle(reject, error);
535
+ });
536
+ };
537
+ const timer = setTimeout(
538
+ () =>
539
+ failAndTerminate(
540
+ helperError(
541
+ "CC_MCP_HEADERS_HELPER_TIMEOUT",
542
+ "MCP headersHelper exceeded its 10-second timeout",
543
+ ),
544
+ ),
545
+ timeoutMs,
546
+ );
547
+
548
+ child.stdout.on("data", (chunk) => {
549
+ if (state !== "running") return;
550
+ const buffer = Buffer.isBuffer(chunk)
551
+ ? chunk
552
+ : Buffer.from(String(chunk));
553
+ stdoutBytes += buffer.byteLength;
554
+ if (stdoutBytes > maxOutputBytes) {
555
+ failAndTerminate(
556
+ helperError(
557
+ "CC_MCP_HEADERS_HELPER_OUTPUT_TOO_LARGE",
558
+ "MCP headersHelper stdout exceeded the bounded output limit",
559
+ ),
560
+ );
561
+ return;
562
+ }
563
+ stdout += buffer.toString("utf8");
564
+ });
565
+ // Drain stderr so a noisy helper cannot block on a full pipe, but never
566
+ // retain or surface credential-bearing diagnostics.
567
+ child.stderr.on("data", (chunk) => {
568
+ if (state === "settled" || stderrBytes > maxOutputBytes) return;
569
+ stderrBytes += Buffer.isBuffer(chunk)
570
+ ? chunk.byteLength
571
+ : Buffer.byteLength(String(chunk));
572
+ });
573
+ child.once("error", () =>
574
+ failAndTerminate(
575
+ helperError(
576
+ "CC_MCP_HEADERS_HELPER_START_FAILED",
577
+ "MCP headersHelper process failed",
578
+ ),
579
+ ),
580
+ );
581
+ child.once("close", (code, signal) => {
582
+ if (state !== "running") return;
583
+ if (code !== 0) {
584
+ failAndTerminate(
585
+ helperError(
586
+ "CC_MCP_HEADERS_HELPER_FAILED",
587
+ `MCP headersHelper exited unsuccessfully (code ${code ?? "null"}, signal ${signal || "none"})`,
588
+ ),
589
+ { alreadyClosed: true },
590
+ );
591
+ return;
592
+ }
593
+ let parsed;
594
+ try {
595
+ parsed = JSON.parse(stdout.trim());
596
+ } catch {
597
+ settle(
598
+ reject,
599
+ helperError(
600
+ "CC_MCP_HEADERS_HELPER_OUTPUT_INVALID",
601
+ "MCP headersHelper stdout must be one JSON object of string headers",
602
+ ),
603
+ );
604
+ return;
605
+ }
606
+ try {
607
+ const headers = Object.fromEntries(
608
+ normalizeHeaderMap(parsed, "dynamic"),
609
+ );
610
+ settle(resolve, headers);
611
+ } catch (error) {
612
+ settle(reject, error);
613
+ }
614
+ });
615
+ });
616
+ }