chainlesschain 0.166.77 → 0.166.78

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 (222) hide show
  1. package/README.md +16 -7
  2. package/completions/_cc +1 -1
  3. package/completions/cc.bash +1 -1
  4. package/completions/cc.fish +1 -1
  5. package/completions/cc.ps1 +1 -1
  6. package/package.json +1 -1
  7. package/src/assets/linux-subreaper/linux-arm64/manifest.json +10 -0
  8. package/src/assets/linux-subreaper/linux-arm64/supervisor +0 -0
  9. package/src/assets/linux-subreaper/linux-x64/manifest.json +10 -0
  10. package/src/assets/linux-subreaper/linux-x64/supervisor +0 -0
  11. package/src/assets/web-panel/assets/{AIOps-CpiCBhRh.js → AIOps-DSyZEY2G.js} +1 -1
  12. package/src/assets/web-panel/assets/{ActionButton-CnU-Xvx-.js → ActionButton-DhNyZ577.js} +1 -1
  13. package/src/assets/web-panel/assets/{Analytics-BJW-CNtf.js → Analytics-HMMpxmyi.js} +3 -3
  14. package/src/assets/web-panel/assets/{AppLayout-UFQJL3G9.js → AppLayout-CwKMM5Ie.js} +5 -5
  15. package/src/assets/web-panel/assets/{Artifacts-Dr_IUDoY.js → Artifacts-CNzDmph7.js} +1 -1
  16. package/src/assets/web-panel/assets/{Audit-aglWo6rr.js → Audit-DxWpUW3V.js} +1 -1
  17. package/src/assets/web-panel/assets/{BackgroundAgents-Dm_TCiXC.js → BackgroundAgents-C1R2ST-P.js} +1 -1
  18. package/src/assets/web-panel/assets/{Backup-DUdX4-gA.js → Backup-B6biTaEV.js} +1 -1
  19. package/src/assets/web-panel/assets/{BaseInput-BTcLjy1o.js → BaseInput-CVnkD2Z5.js} +1 -1
  20. package/src/assets/web-panel/assets/{Chat-Bhy9qZrl.js → Chat-Dbewl4Je.js} +6 -6
  21. package/src/assets/web-panel/assets/{ChatBubbleRenderer-D0WrJQaQ.js → ChatBubbleRenderer-DVZ6SwC5.js} +1 -1
  22. package/src/assets/web-panel/assets/{Checkbox-CblrPa21.js → Checkbox-BqqiF1JE.js} +1 -1
  23. package/src/assets/web-panel/assets/{Codegen-SEAHzOlr.js → Codegen-BVMkGumc.js} +1 -1
  24. package/src/assets/web-panel/assets/{Col-DJz8iFOR.js → Col-DmiRHy96.js} +1 -1
  25. package/src/assets/web-panel/assets/{Community-RufKhcQt.js → Community-BDlpygqA.js} +1 -1
  26. package/src/assets/web-panel/assets/{Compact-Dlifx08U.js → Compact-B2NME_m-.js} +1 -1
  27. package/src/assets/web-panel/assets/{Compliance-DdhQWcHh.js → Compliance-BlzDLE-R.js} +1 -1
  28. package/src/assets/web-panel/assets/{Cowork-BLNn6oOm.js → Cowork-C8raPybB.js} +3 -3
  29. package/src/assets/web-panel/assets/{Cron-Dv-JWY2d.js → Cron-DA8Py0zP.js} +2 -2
  30. package/src/assets/web-panel/assets/{Crosschain-k7Pz7O-b.js → Crosschain-DU2XyHqB.js} +1 -1
  31. package/src/assets/web-panel/assets/{DID-C_10syUW.js → DID-Df098fT_.js} +2 -2
  32. package/src/assets/web-panel/assets/{Dashboard-CMyH6Szx.js → Dashboard-D1rT702x.js} +2 -2
  33. package/src/assets/web-panel/assets/{Dropdown-DjmD2Saa.js → Dropdown-BweXGo1O.js} +1 -1
  34. package/src/assets/web-panel/assets/{EmailListRenderer-36_IRUSo.js → EmailListRenderer-B9ShbgJH.js} +1 -1
  35. package/src/assets/web-panel/assets/EvolutionSettings-D75_iBoc.js +1 -0
  36. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DEgf9kyP.js → FamilyGuardDashboard-DrznZFVs.js} +1 -1
  37. package/src/assets/web-panel/assets/{Federation-DGO1wQls.js → Federation-DQZ2adIA.js} +1 -1
  38. package/src/assets/web-panel/assets/{FormItemContext-Doj1FmKW.js → FormItemContext-DN30Dowh.js} +1 -1
  39. package/src/assets/web-panel/assets/{GenericCardRenderer-GzOU27iT.js → GenericCardRenderer-DRdt0j1e.js} +1 -1
  40. package/src/assets/web-panel/assets/{Git-Dd7D1EDK.js → Git-wwRgStzk.js} +2 -2
  41. package/src/assets/web-panel/assets/{Governance-6IY8LcjI.js → Governance-CI4Uw0Nh.js} +1 -1
  42. package/src/assets/web-panel/assets/{Inference-BB9gl8q1.js → Inference-5TuE2AJI.js} +1 -1
  43. package/src/assets/web-panel/assets/{KnowledgeGraph-CeCed5wd.js → KnowledgeGraph-oXyvmFSR.js} +1 -1
  44. package/src/assets/web-panel/assets/{Logs-CYOeHuaI.js → Logs-ewudSWuv.js} +2 -2
  45. package/src/assets/web-panel/assets/{MarkdownRenderer-Bk8Zqc2R.js → MarkdownRenderer-Cz5nyufm.js} +1 -1
  46. package/src/assets/web-panel/assets/{Marketplace-D-_xgHgM.js → Marketplace-DcZeWFrs.js} +1 -1
  47. package/src/assets/web-panel/assets/{McpTools-NnaUTF5t.js → McpTools-BcV9p1RS.js} +3 -3
  48. package/src/assets/web-panel/assets/{Memory-CndN9pMt.js → Memory-CMhYvugt.js} +2 -2
  49. package/src/assets/web-panel/assets/{MobileBridge-BXblFmhY.js → MobileBridge-5RP2uwvT.js} +1 -1
  50. package/src/assets/web-panel/assets/{MobileProjects-CC26Dm2k.js → MobileProjects-BIuM9Ze4.js} +1 -1
  51. package/src/assets/web-panel/assets/{Mtc-BhaqWCiW.js → Mtc-DmBszTDe.js} +4 -4
  52. package/src/assets/web-panel/assets/{MtcAudit-D6fktM2w.js → MtcAudit-Czdp5ZGt.js} +5 -5
  53. package/src/assets/web-panel/assets/{Multisig-CFvahz7s.js → Multisig-DRWUuNr-.js} +3 -3
  54. package/src/assets/web-panel/assets/{NLProgramming-Co73Ivya.js → NLProgramming-IRQQN0-c.js} +1 -1
  55. package/src/assets/web-panel/assets/{Notes-B4g33L1o.js → Notes-CGhD1lW9.js} +4 -4
  56. package/src/assets/web-panel/assets/{NotificationSettings-lXd17EbN.js → NotificationSettings-BtyPgQAh.js} +1 -1
  57. package/src/assets/web-panel/assets/{OrderTableRenderer-BiOB0GIi.js → OrderTableRenderer-yUaqwCty.js} +1 -1
  58. package/src/assets/web-panel/assets/{Organization-JQ7_wQIA.js → Organization-C3kTVn5i.js} +4 -4
  59. package/src/assets/web-panel/assets/{Overflow-gwgJgozQ.js → Overflow-C2-0iZhq.js} +1 -1
  60. package/src/assets/web-panel/assets/{P2P-D9L_0gie.js → P2P-CISoEUxA.js} +2 -2
  61. package/src/assets/web-panel/assets/{PdhVaultBrowser-CbOPsFE9.js → PdhVaultBrowser-NfTVtvKQ.js} +5 -5
  62. package/src/assets/web-panel/assets/{Permissions-Cz42HNQf.js → Permissions-CfK0jJhm.js} +4 -4
  63. package/src/assets/web-panel/assets/{PersonalDataHub-DjorYtrF.js → PersonalDataHub-OsVxxh_j.js} +5 -5
  64. package/src/assets/web-panel/assets/{Pipeline-DyWPhmm5.js → Pipeline-DEmK_Ch2.js} +1 -1
  65. package/src/assets/web-panel/assets/{Privacy-DyfLMl2j.js → Privacy-D61s73b0.js} +1 -1
  66. package/src/assets/web-panel/assets/{ProjectInit-CyqDx1OE.js → ProjectInit-DkLF5gHb.js} +2 -2
  67. package/src/assets/web-panel/assets/{ProjectSettings-DsBw0Csy.js → ProjectSettings-BA7odTrI.js} +2 -2
  68. package/src/assets/web-panel/assets/{Projects-CRaSI25Z.js → Projects-CdI1GcAG.js} +1 -1
  69. package/src/assets/web-panel/assets/{Providers-CCI_klN-.js → Providers-D9BYyP1r.js} +1 -1
  70. package/src/assets/web-panel/assets/{QrScannerModal-DNsnlDdS.js → QrScannerModal-CXMItUDD.js} +1 -1
  71. package/src/assets/web-panel/assets/{QuickAsk-B9r2iaee.js → QuickAsk-8-tF9ffZ.js} +1 -1
  72. package/src/assets/web-panel/assets/{Recommend-BJDe03GR.js → Recommend-C2QGWOSi.js} +1 -1
  73. package/src/assets/web-panel/assets/{RemoteSession-J7JR3rRo.js → RemoteSession-B1M_v1lx.js} +3 -3
  74. package/src/assets/web-panel/assets/{Reputation-DR39AJeV.js → Reputation-D0WZHgv1.js} +1 -1
  75. package/src/assets/web-panel/assets/{Row-Dh77m3NZ.js → Row-D6nf9-c-.js} +1 -1
  76. package/src/assets/web-panel/assets/{RssFeed-BUdg28nJ.js → RssFeed-ClZ6M-mN.js} +3 -3
  77. package/src/assets/web-panel/assets/{Search-BNC7sGhj.js → Search-ZWkt8vuO.js} +1 -1
  78. package/src/assets/web-panel/assets/{Security-DISENGI7.js → Security-BUlQut2m.js} +4 -4
  79. package/src/assets/web-panel/assets/{Services-BBBGpJ1-.js → Services-Cd_3xJOc.js} +2 -2
  80. package/src/assets/web-panel/assets/{Skeleton-DMcIoIv2.js → Skeleton-C8e2-cHW.js} +1 -1
  81. package/src/assets/web-panel/assets/{Skills-QAyFbI3r.js → Skills-DucVRJp1.js} +1 -1
  82. package/src/assets/web-panel/assets/{Sla-CSg5wLH7.js → Sla-Csr5pUwI.js} +1 -1
  83. package/src/assets/web-panel/assets/{SpeechSettings-DMPxTc5x.js → SpeechSettings-CXvyaRAT.js} +1 -1
  84. package/src/assets/web-panel/assets/{SyncSettings-CPG7l30y.js → SyncSettings-KdsIcV5h.js} +2 -2
  85. package/src/assets/web-panel/assets/{Tasks-Y1kOVvVL.js → Tasks-B-eHmJm9.js} +1 -1
  86. package/src/assets/web-panel/assets/{Templates-jt9NagL0.js → Templates-BglVeaLK.js} +1 -1
  87. package/src/assets/web-panel/assets/{Tenant-DauuJICx.js → Tenant-BBbQ8qan.js} +1 -1
  88. package/src/assets/web-panel/assets/{Terminal-E9rnKeGq.js → Terminal-Ca_pCVBi.js} +2 -2
  89. package/src/assets/web-panel/assets/{TimelineRenderer-Cc7z2APG.js → TimelineRenderer-YD6XG_vZ.js} +1 -1
  90. package/src/assets/web-panel/assets/{Tokens-CV0UthRA.js → Tokens-2lRoeVli.js} +1 -1
  91. package/src/assets/web-panel/assets/{Trigger-BFcJJGfu.js → Trigger-C-3XNAU9.js} +1 -1
  92. package/src/assets/web-panel/assets/{Trust-BAydbNJA.js → Trust-k-1PxdLG.js} +1 -1
  93. package/src/assets/web-panel/assets/{UkeySign-DcOS6sqL.js → UkeySign-FG-qW646.js} +1 -1
  94. package/src/assets/web-panel/assets/{VideoEditing-BLHJZvif.js → VideoEditing-BNOe1cmd.js} +1 -1
  95. package/src/assets/web-panel/assets/{Wallet-4QFLKHwW.js → Wallet-D5C3i2Kw.js} +4 -4
  96. package/src/assets/web-panel/assets/{WebAuthn-BocEOOSj.js → WebAuthn-BOpztqd3.js} +5 -5
  97. package/src/assets/web-panel/assets/{WorkflowEditor-DCfF7D0B.js → WorkflowEditor-BpVrpUEv.js} +1 -1
  98. package/src/assets/web-panel/assets/{chat-CxvfsYGr.js → chat-DIuMHb38.js} +1 -1
  99. package/src/assets/web-panel/assets/{colors-KtQB9DmQ.js → colors-CTFJPyzQ.js} +1 -1
  100. package/src/assets/web-panel/assets/{compact-item-Dx4J6arN.js → compact-item-CONfmJcW.js} +1 -1
  101. package/src/assets/web-panel/assets/{createContext-Cq0olgzo.js → createContext-RkW5CRrz.js} +1 -1
  102. package/src/assets/web-panel/assets/devWarning-DaEBln_q.js +1 -0
  103. package/src/assets/web-panel/assets/{hasIn-Bf9-h3D-.js → hasIn-CW4XOjDC.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-CK2U_AHi.js → index-7wMSBCU7.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DMR-keCL.js → index-Akmg1WdH.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-6dDDSCHD.js → index-B54qoVff.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CmQuG0fr.js → index-B8r2t0Ch.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-ClUfSChI.js → index-B9XoBoty.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-B3xfiItB.js → index-B9aS2VLu.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DQDR-_ai.js → index-BFs1Tznc.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DZWjYfWt.js → index-BKgaRT0b.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-nmyDOh_b.js → index-BM7bOUvu.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-B_8UcDan.js → index-BMg2JFmW.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-C9yaUHm9.js → index-BRZsPxNn.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-Cz7f4Jaq.js → index-Bf19fKef.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CpO6DKuu.js → index-BkAbfBF-.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DFdEDvFn.js → index-CBjb2A5R.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-gt5N6VM_.js → index-CEZWQthY.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-0fi8DIVQ.js → index-CFGLf88d.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-hSzyoXri.js → index-CLUa68JH.js} +3 -3
  121. package/src/assets/web-panel/assets/{index-Cy865Hhq.js → index-CM2X25Er.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DDAe1UmZ.js → index-CX4T2uKN.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BMcC4cbj.js → index-CixqfdRk.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-DsCdl2Od.js → index-CkRojEip.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DnU-dUWd.js → index-Cvmc3f25.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-Br1mDMfO.js → index-D-lpTPS8.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CaIclw-E.js → index-D59GbWCN.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-DBRlZdZj.js → index-DAESljiJ.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-B8WuPI-h.js → index-DDHUx4Yz.js} +1 -1
  130. package/src/assets/web-panel/assets/index-DG1mcYTa.js +1 -0
  131. package/src/assets/web-panel/assets/{index-D2BfSIrn.js → index-DP5pPedy.js} +1 -1
  132. package/src/assets/web-panel/assets/index-DRs5Pe8u.js +1 -0
  133. package/src/assets/web-panel/assets/{index-CqnggDos.js → index-DSlXL6Ju.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-_FIz-0tp.js → index-DWCJnn2O.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-BKtQyb2o.js → index-DWY7YwDu.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-DfrFNMvz.js → index-DZTwP364.js} +1 -1
  137. package/src/assets/web-panel/assets/{index-BHmdMKYl.js → index-DidrMvOx.js} +1 -1
  138. package/src/assets/web-panel/assets/{index-BO6XvO-C.js → index-Dj3K5kHs.js} +1 -1
  139. package/src/assets/web-panel/assets/{index-iE9tqEN5.js → index-YaeGscSw.js} +1 -1
  140. package/src/assets/web-panel/assets/{index-DI5bRqNG.js → index-YlMnFNOi.js} +1 -1
  141. package/src/assets/web-panel/assets/{index-Cfsn7N18.js → index-asWsB34i.js} +1 -1
  142. package/src/assets/web-panel/assets/{index-CeYP_kT9.js → index-gkjiFjQd.js} +1 -1
  143. package/src/assets/web-panel/assets/{initDefaultProps-DvzKJ6o5.js → initDefaultProps-BOr4igh3.js} +1 -1
  144. package/src/assets/web-panel/assets/{motion-D1yTvmxW.js → motion-CK469n2j.js} +1 -1
  145. package/src/assets/web-panel/assets/{move-DxtSIF8K.js → move-DzjudlYQ.js} +1 -1
  146. package/src/assets/web-panel/assets/{mtc-parser-BDsQgIHY.js → mtc-parser-BQaKUxC6.js} +1 -1
  147. package/src/assets/web-panel/assets/{omit-UVBJW8kh.js → omit-MciovCFD.js} +1 -1
  148. package/src/assets/web-panel/assets/{pickAttrs-D4QqtTyX.js → pickAttrs-DDPJ4zAz.js} +1 -1
  149. package/src/assets/web-panel/assets/{placementArrow-QXmu6vBf.js → placementArrow-Cznyb-jI.js} +1 -1
  150. package/src/assets/web-panel/assets/{responsiveObserve-D-PmXO9M.js → responsiveObserve-AJK3SLzJ.js} +1 -1
  151. package/src/assets/web-panel/assets/{slide-CKbGxEZJ.js → slide-CPQ28wu7.js} +1 -1
  152. package/src/assets/web-panel/assets/{statusUtils-BbgXPkXm.js → statusUtils-CFjzvqf_.js} +1 -1
  153. package/src/assets/web-panel/assets/{styleChecker-DOr9rk68.js → styleChecker-BPyFfTuR.js} +1 -1
  154. package/src/assets/web-panel/assets/{useFlexGapSupport-B2wO2r36.js → useFlexGapSupport-Dq7N6R05.js} +1 -1
  155. package/src/assets/web-panel/assets/{useFs-SeVGBK34.js → useFs-C3GS0uTc.js} +1 -1
  156. package/src/assets/web-panel/assets/{usePersonalDataHub-DUJBCxjD.js → usePersonalDataHub-BhgIVzP_.js} +1 -1
  157. package/src/assets/web-panel/assets/{vnode-CF4EYsig.js → vnode-4ZD9-MDr.js} +1 -1
  158. package/src/assets/web-panel/assets/{zoom-pRUs5pqI.js → zoom-Bx4MRVNW.js} +1 -1
  159. package/src/assets/web-panel/index.html +1 -1
  160. package/src/command-help-index.json +1 -1
  161. package/src/command-manifest.json +1 -1
  162. package/src/commands/checkpoint.js +42 -7
  163. package/src/commands/orchestrate.js +85 -25
  164. package/src/commands/session-location.js +5 -0
  165. package/src/commands/session-show.js +109 -1
  166. package/src/commands/session.js +26 -2
  167. package/src/commands/tokens.js +9 -4
  168. package/src/data/changelog.json +13 -0
  169. package/src/generated/cc-agent-protocol.schema.json +71 -0
  170. package/src/harness/jsonl-session-store.js +357 -114
  171. package/src/harness/mcp-client.js +44 -1
  172. package/src/lib/agent-router.js +35 -7
  173. package/src/lib/app-server/server.js +14 -0
  174. package/src/lib/background-agent-supervisor.js +14 -4
  175. package/src/lib/causal-observability.js +64 -1
  176. package/src/lib/checkpoint-summary-projection.js +98 -0
  177. package/src/lib/checkpoint-timeline-authority.js +15 -51
  178. package/src/lib/claude-code-bridge.js +302 -60
  179. package/src/lib/codex-app-server-adapter.js +161 -35
  180. package/src/lib/cost-budget.js +4 -0
  181. package/src/lib/doctor-checkup.js +31 -2
  182. package/src/lib/durable-security-store.js +6 -1
  183. package/src/lib/evolution/evolution-artifact-identity.js +21 -0
  184. package/src/lib/evolution/evolution-artifact-ports.js +5 -11
  185. package/src/lib/evolution/evolution-eval-cohort-receipt-reconciliation.js +389 -0
  186. package/src/lib/execution-location-failure-site.js +63 -0
  187. package/src/lib/execution-location-target.js +102 -8
  188. package/src/lib/external-agent-adapters.js +2 -0
  189. package/src/lib/image-file-boundary.js +154 -0
  190. package/src/lib/image-input.js +16 -3
  191. package/src/lib/llm-pricing.js +114 -8
  192. package/src/lib/mcp-call-ledger-store.js +7 -2
  193. package/src/lib/model-capabilities.js +21 -10
  194. package/src/lib/model-context-catalog.js +60 -1
  195. package/src/lib/openai-responses.js +7 -1
  196. package/src/lib/orchestrator.js +8 -2
  197. package/src/lib/process-execution-broker/index.js +93 -1
  198. package/src/lib/process-execution-broker/linux-subreaper-artifact.js +120 -0
  199. package/src/lib/process-execution-broker/linux-subreaper-helper.js +344 -0
  200. package/src/lib/process-execution-broker/linux-subreaper-process.js +326 -0
  201. package/src/lib/process-execution-broker/linux-subreaper-supervisor.c +360 -0
  202. package/src/lib/process-execution-broker/owned-posix-process-group-worker.mjs +131 -0
  203. package/src/lib/process-execution-broker/owned-posix-process-group.js +267 -0
  204. package/src/lib/process-execution-broker/process-ownership-journal.js +297 -0
  205. package/src/lib/process-execution-broker/process-ownership-quarantine.js +91 -0
  206. package/src/lib/runtime-usage-ledger.js +3 -0
  207. package/src/lib/secure-fs.js +158 -42
  208. package/src/lib/session-branch-history.js +240 -0
  209. package/src/lib/session-history-origins.js +285 -0
  210. package/src/lib/session-input-receipt.js +110 -0
  211. package/src/lib/session-resource-budget.js +8 -8
  212. package/src/lib/session-transcript-history.js +456 -0
  213. package/src/lib/session-transcript-page.js +164 -0
  214. package/src/lib/session-transcript-reference.js +38 -0
  215. package/src/lib/session-usage.js +8 -0
  216. package/src/lib/token-tracker.js +32 -54
  217. package/src/lib/usage-pricing-context.js +93 -0
  218. package/src/runtime/headless-stream.js +202 -4
  219. package/src/assets/web-panel/assets/EvolutionSettings-CmtU0XmM.js +0 -1
  220. package/src/assets/web-panel/assets/devWarning-CmgDNkoO.js +0 -1
  221. package/src/assets/web-panel/assets/index-BpIZ2S01.js +0 -1
  222. package/src/assets/web-panel/assets/index-C-VmKuyv.js +0 -1
@@ -46,6 +46,14 @@ import {
46
46
  SANDBOX_BOUNDARIES,
47
47
  } from "./platform-sandbox.js";
48
48
  import { normalizeLinuxCgroupPolicy } from "./linux-cgroup-v2.js";
49
+ import { acquireLinuxSubreaperHelper } from "./linux-subreaper-helper.js";
50
+ import { spawnLinuxSubreaperChild } from "./linux-subreaper-process.js";
51
+ import {
52
+ assertProcessOwnershipAvailable,
53
+ getProcessOwnershipStatus,
54
+ observeProcessOwnership,
55
+ prepareProcessOwnership,
56
+ } from "./process-ownership-quarantine.js";
49
57
  import {
50
58
  MACOS_MCP_LAUNCHER_INPUTS,
51
59
  isMacosMcpLauncherPackageVersion,
@@ -1187,6 +1195,7 @@ class ProcessExecutionBroker extends EventEmitter {
1187
1195
  _sanitizeOptions(options) {
1188
1196
  if (!options) return {};
1189
1197
  const safe = { ...options };
1198
+ delete safe.linuxSubreaper;
1190
1199
  if (process.platform === "win32" && safe.shell === true) {
1191
1200
  safe.windowsHide = true;
1192
1201
  }
@@ -4479,6 +4488,7 @@ class ProcessExecutionBroker extends EventEmitter {
4479
4488
  * and durable evidence APIs.
4480
4489
  */
4481
4490
  beginWorkspaceTransaction(options = {}) {
4491
+ assertProcessOwnershipAvailable();
4482
4492
  return this._workspaceTransactionManager(
4483
4493
  options.stateDir,
4484
4494
  options.lockDir,
@@ -4486,6 +4496,7 @@ class ProcessExecutionBroker extends EventEmitter {
4486
4496
  }
4487
4497
 
4488
4498
  recoverWorkspaceTransactions(options = {}) {
4499
+ assertProcessOwnershipAvailable();
4489
4500
  return this._workspaceTransactionManager(
4490
4501
  options.stateDir,
4491
4502
  options.lockDir,
@@ -4499,6 +4510,10 @@ class ProcessExecutionBroker extends EventEmitter {
4499
4510
  ).inspect(id);
4500
4511
  }
4501
4512
 
4513
+ getProcessOwnershipStatus() {
4514
+ return getProcessOwnershipStatus();
4515
+ }
4516
+
4502
4517
  listWorkspaceTransactions(options = {}) {
4503
4518
  return this._workspaceTransactionManager(
4504
4519
  options.stateDir,
@@ -4507,6 +4522,7 @@ class ProcessExecutionBroker extends EventEmitter {
4507
4522
  }
4508
4523
 
4509
4524
  restoreWorkspaceTransaction(id, options = {}) {
4525
+ assertProcessOwnershipAvailable();
4510
4526
  return this._workspaceTransactionManager(
4511
4527
  options.stateDir,
4512
4528
  options.lockDir,
@@ -4514,6 +4530,7 @@ class ProcessExecutionBroker extends EventEmitter {
4514
4530
  }
4515
4531
 
4516
4532
  undoWorkspaceTransactionRestore(id, options = {}) {
4533
+ assertProcessOwnershipAvailable();
4517
4534
  return this._workspaceTransactionManager(
4518
4535
  options.stateDir,
4519
4536
  options.lockDir,
@@ -4569,6 +4586,7 @@ class ProcessExecutionBroker extends EventEmitter {
4569
4586
  }
4570
4587
 
4571
4588
  spawn(command, args, options = {}) {
4589
+ assertProcessOwnershipAvailable();
4572
4590
  options = this._withAmbientProcessContext(command, options);
4573
4591
  const executionId = crypto.randomUUID();
4574
4592
  const startTime = Date.now();
@@ -4800,7 +4818,71 @@ class ProcessExecutionBroker extends EventEmitter {
4800
4818
  );
4801
4819
  auditEntry.mcpStdioExecutableIdentityDigest = admitted.identityDigest;
4802
4820
  }
4803
- proc = nativeSpawnFn(command, args, optsForSpawn);
4821
+ if (
4822
+ process.platform === "linux" &&
4823
+ options.linuxSubreaper &&
4824
+ !sandboxPlan.guarantees.includes(SANDBOX_BOUNDARIES.PROCESS_TREE)
4825
+ ) {
4826
+ const request = options.linuxSubreaper;
4827
+ const stdio = optsForSpawn.stdio;
4828
+ if (
4829
+ !request ||
4830
+ typeof request !== "object" ||
4831
+ Array.isArray(request) ||
4832
+ Object.keys(request).some((key) => key !== "graceMs") ||
4833
+ !Number.isSafeInteger(request.graceMs) ||
4834
+ request.graceMs < 0 ||
4835
+ request.graceMs > 2147483647 ||
4836
+ sandboxPlan.postSpawn.required ||
4837
+ options.shell ||
4838
+ optsForSpawn.shell ||
4839
+ optsForSpawn.detached ||
4840
+ (stdio !== undefined && stdio !== "pipe") ||
4841
+ ["uid", "gid", "signal", "timeout", "input", "argv0"].some(
4842
+ (key) => optsForSpawn[key] !== undefined,
4843
+ ) ||
4844
+ (sandboxPlan.applied && sandboxPlan.backend !== "linux-prlimit")
4845
+ ) {
4846
+ const error = new Error(
4847
+ "Linux external-agent supervision cannot preserve this launch plan",
4848
+ );
4849
+ error.code = "EXTERNAL_AGENT_SUPERVISION_UNSUPPORTED_PLAN";
4850
+ throw error;
4851
+ }
4852
+ const ownershipLease = prepareProcessOwnership(executionId);
4853
+ let nativeEntered = false;
4854
+ try {
4855
+ const helper = acquireLinuxSubreaperHelper({
4856
+ spawnSync: this._native?.spawnSync || nativeSpawnSync,
4857
+ });
4858
+ proc = spawnLinuxSubreaperChild(
4859
+ command,
4860
+ args,
4861
+ {
4862
+ cwd: path.resolve(optsForSpawn.cwd || cwd),
4863
+ env: optsForSpawn.env || process.env,
4864
+ graceMs: request.graceMs,
4865
+ helper,
4866
+ },
4867
+ {
4868
+ spawn: (...nativeArgs) => {
4869
+ nativeEntered = true;
4870
+ return nativeSpawnFn(...nativeArgs);
4871
+ },
4872
+ },
4873
+ );
4874
+ } catch (error) {
4875
+ // Before native entry no process could exist. Once entered, retain
4876
+ // the durable record even if a synchronous exception hides its handle.
4877
+ if (!nativeEntered) ownershipLease?.settle();
4878
+ else ownershipLease?.retain();
4879
+ throw error;
4880
+ }
4881
+ auditEntry.processLifecycleOwner = "linux-subreaper";
4882
+ observeProcessOwnership(proc, executionId, ownershipLease);
4883
+ } else {
4884
+ proc = nativeSpawnFn(command, args, optsForSpawn);
4885
+ }
4804
4886
  if (builtInMacMcpPlan) {
4805
4887
  const callerLifeline = proc?.stdio?.[8];
4806
4888
  if (
@@ -4912,6 +4994,10 @@ class ProcessExecutionBroker extends EventEmitter {
4912
4994
 
4913
4995
  proc.on("exit", (code, signal) => {
4914
4996
  const endTime = Date.now();
4997
+ if (proc.ownedProcessTreeEvidence) {
4998
+ auditEntry.processLifecycleReceipt = proc.ownedProcessTreeEvidence;
4999
+ auditEntry.sandboxTargetPid = proc.sandboxTargetPid;
5000
+ }
4915
5001
  auditEntry.exitCode = code;
4916
5002
  auditEntry.signal = signal;
4917
5003
  auditEntry.endTime = endTime;
@@ -4929,6 +5015,10 @@ class ProcessExecutionBroker extends EventEmitter {
4929
5015
  this.emit("exit", auditEntry);
4930
5016
  });
4931
5017
  proc.on("error", (err) => {
5018
+ if (proc.ownedProcessTreeEvidence) {
5019
+ auditEntry.processLifecycleReceipt = proc.ownedProcessTreeEvidence;
5020
+ auditEntry.sandboxTargetPid = proc.sandboxTargetPid;
5021
+ }
4932
5022
  auditEntry.error = err.message;
4933
5023
  auditEntry.endTime = Date.now();
4934
5024
  auditEntry.durationMs = auditEntry.endTime - startTime;
@@ -4957,6 +5047,7 @@ class ProcessExecutionBroker extends EventEmitter {
4957
5047
  }
4958
5048
 
4959
5049
  spawnSync(command, args, options = {}) {
5050
+ assertProcessOwnershipAvailable();
4960
5051
  options = this._withAmbientProcessContext(command, options);
4961
5052
  const executionId = crypto.randomUUID();
4962
5053
  const startTime = Date.now();
@@ -5203,6 +5294,7 @@ class ProcessExecutionBroker extends EventEmitter {
5203
5294
  * together with the descriptor-pinned generic bwrap plan.
5204
5295
  */
5205
5296
  spawnPty(ptyModule, command, args = [], options = {}) {
5297
+ assertProcessOwnershipAvailable();
5206
5298
  if (!ptyModule || typeof ptyModule.spawn !== "function") {
5207
5299
  throw new TypeError("pty_module_spawn_unavailable");
5208
5300
  }
@@ -0,0 +1,120 @@
1
+ import crypto from "node:crypto";
2
+
3
+ export const LINUX_SUBREAPER_SOURCE_DIGEST =
4
+ "sha256:e920e24b4a79121484f2e8e97886755f88eaa1af93b55326dfa68c7a7f571424";
5
+ export const LINUX_SUBREAPER_ARCHITECTURES = Object.freeze(["x64", "arm64"]);
6
+ export const MAX_SUBREAPER_IMAGE_BYTES = 4 * 1024 * 1024;
7
+ export const MAX_SUBREAPER_MANIFEST_BYTES = 4096;
8
+
9
+ export function subreaperDigest(bytes) {
10
+ return "sha256:" + crypto.createHash("sha256").update(bytes).digest("hex");
11
+ }
12
+
13
+ function invalid(reason) {
14
+ const error = new Error(
15
+ `Linux process supervision helper unavailable: ${reason}`,
16
+ );
17
+ error.code = "EXTERNAL_AGENT_HELPER_UNAVAILABLE";
18
+ return error;
19
+ }
20
+
21
+ /** Bounded ELF64 inspection; release images have no dynamic loader dependency. */
22
+ export function validateLinuxSubreaperElf(bytes, { arch, staticOnly = false }) {
23
+ const machine = arch === "x64" ? 62 : arch === "arm64" ? 183 : null;
24
+ if (
25
+ !machine ||
26
+ !Buffer.isBuffer(bytes) ||
27
+ bytes.length < 64 ||
28
+ bytes.length > MAX_SUBREAPER_IMAGE_BYTES ||
29
+ !bytes.subarray(0, 4).equals(Buffer.from([0x7f, 0x45, 0x4c, 0x46])) ||
30
+ bytes[4] !== 2 ||
31
+ bytes[5] !== 1 ||
32
+ bytes[6] !== 1 ||
33
+ bytes.readUInt16LE(18) !== machine ||
34
+ ![2, 3].includes(bytes.readUInt16LE(16)) ||
35
+ bytes.readUInt32LE(20) !== 1 ||
36
+ bytes.readUInt16LE(52) !== 64 ||
37
+ bytes.readUInt16LE(54) !== 56
38
+ )
39
+ throw invalid("unexpected-helper-image");
40
+ const offset = bytes.readBigUInt64LE(32);
41
+ const count = bytes.readUInt16LE(56);
42
+ if (
43
+ offset < 64n ||
44
+ count < 1 ||
45
+ count > 128 ||
46
+ offset + BigInt(count * 56) > BigInt(bytes.length)
47
+ )
48
+ throw invalid("invalid-helper-program-headers");
49
+ const entry = bytes.readBigUInt64LE(24);
50
+ let executableEntry = false;
51
+ for (let index = 0; index < count; index++) {
52
+ const at = Number(offset) + index * 56;
53
+ const type = bytes.readUInt32LE(at);
54
+ if (staticOnly && [2, 3].includes(type))
55
+ throw invalid("helper-is-not-static");
56
+ if (type !== 1) continue;
57
+ const fileOffset = bytes.readBigUInt64LE(at + 8);
58
+ const address = bytes.readBigUInt64LE(at + 16);
59
+ const fileSize = bytes.readBigUInt64LE(at + 32);
60
+ const memorySize = bytes.readBigUInt64LE(at + 40);
61
+ if (fileSize > memorySize || fileOffset + fileSize > BigInt(bytes.length))
62
+ throw invalid("invalid-helper-load-segment");
63
+ if (
64
+ bytes.readUInt32LE(at + 4) & 1 &&
65
+ entry >= address &&
66
+ entry < address + fileSize
67
+ )
68
+ executableEntry = true;
69
+ }
70
+ if (!executableEntry || (staticOnly && bytes.readUInt16LE(16) !== 2))
71
+ throw invalid("invalid-helper-entry");
72
+ }
73
+
74
+ export function validateLinuxSubreaperArtifact(
75
+ manifestBytes,
76
+ imageBytes,
77
+ { arch, commit } = {},
78
+ ) {
79
+ if (
80
+ !Buffer.isBuffer(manifestBytes) ||
81
+ manifestBytes.length > MAX_SUBREAPER_MANIFEST_BYTES
82
+ )
83
+ throw invalid("invalid-packaged-manifest");
84
+ let manifest;
85
+ try {
86
+ manifest = JSON.parse(manifestBytes.toString("utf8"));
87
+ } catch {
88
+ throw invalid("invalid-packaged-manifest");
89
+ }
90
+ const keys = [
91
+ "schema",
92
+ "platform",
93
+ "arch",
94
+ "sourceDigest",
95
+ "imageDigest",
96
+ "bytes",
97
+ "linkage",
98
+ "commit",
99
+ ];
100
+ if (
101
+ !manifest ||
102
+ typeof manifest !== "object" ||
103
+ Array.isArray(manifest) ||
104
+ Object.keys(manifest).length !== keys.length ||
105
+ Object.keys(manifest).some((key) => !keys.includes(key)) ||
106
+ manifest.schema !== "chainlesschain.linux-subreaper-artifact/v1" ||
107
+ manifest.platform !== "linux" ||
108
+ !LINUX_SUBREAPER_ARCHITECTURES.includes(arch) ||
109
+ manifest.arch !== arch ||
110
+ manifest.sourceDigest !== LINUX_SUBREAPER_SOURCE_DIGEST ||
111
+ manifest.linkage !== "static" ||
112
+ !/^[a-f0-9]{40}$/.test(manifest.commit) ||
113
+ (commit !== undefined && manifest.commit !== commit) ||
114
+ manifest.bytes !== imageBytes.length ||
115
+ manifest.imageDigest !== subreaperDigest(imageBytes)
116
+ )
117
+ throw invalid("packaged-identity-mismatch");
118
+ validateLinuxSubreaperElf(imageBytes, { arch, staticOnly: true });
119
+ return Object.freeze({ ...manifest });
120
+ }
@@ -0,0 +1,344 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import crypto from "node:crypto";
5
+ import { fileURLToPath } from "node:url";
6
+ import {
7
+ LINUX_SUBREAPER_SOURCE_DIGEST,
8
+ MAX_SUBREAPER_IMAGE_BYTES,
9
+ MAX_SUBREAPER_MANIFEST_BYTES,
10
+ validateLinuxSubreaperArtifact,
11
+ validateLinuxSubreaperElf,
12
+ } from "./linux-subreaper-artifact.js";
13
+ export { LINUX_SUBREAPER_SOURCE_DIGEST } from "./linux-subreaper-artifact.js";
14
+
15
+ const MAX_SOURCE_BYTES = 128 * 1024;
16
+ const MAX_IMAGE_BYTES = MAX_SUBREAPER_IMAGE_BYTES;
17
+ const images = new Map();
18
+ const leases = new WeakMap();
19
+ const sha = (bytes) =>
20
+ "sha256:" + crypto.createHash("sha256").update(bytes).digest("hex");
21
+
22
+ function failure(reason) {
23
+ const error = new Error(
24
+ `Linux process supervision helper unavailable: ${reason}`,
25
+ );
26
+ error.code = "EXTERNAL_AGENT_HELPER_UNAVAILABLE";
27
+ return error;
28
+ }
29
+
30
+ function readDescriptor(fd, maximum) {
31
+ const before = fs.fstatSync(fd, { bigint: true });
32
+ if (!before.isFile() || before.size < 1n || before.size > BigInt(maximum))
33
+ throw failure("invalid-file");
34
+ const bytes = Buffer.alloc(Number(before.size));
35
+ let offset = 0;
36
+ while (offset < bytes.length) {
37
+ const count = fs.readSync(fd, bytes, offset, bytes.length - offset, offset);
38
+ if (count <= 0) throw failure("short-file-read");
39
+ offset += count;
40
+ }
41
+ const after = fs.fstatSync(fd, { bigint: true });
42
+ if (
43
+ before.dev !== after.dev ||
44
+ before.ino !== after.ino ||
45
+ before.size !== after.size ||
46
+ before.mtimeNs !== after.mtimeNs ||
47
+ before.ctimeNs !== after.ctimeNs
48
+ )
49
+ throw failure("file-changed");
50
+ return { bytes, stat: after };
51
+ }
52
+
53
+ function compilerPath() {
54
+ // Only the system toolchain is eligible. Do not consult PATH, CC, loader,
55
+ // include-path, or plugin-provided compiler settings.
56
+ const compiler = fs.realpathSync("/usr/bin/cc");
57
+ let current = compiler;
58
+ for (;;) {
59
+ const info = fs.lstatSync(current);
60
+ if (info.isSymbolicLink() || info.uid !== 0 || (info.mode & 0o022) !== 0)
61
+ throw failure("untrusted-system-compiler");
62
+ if (current === compiler && (!info.isFile() || (info.mode & 0o111) === 0))
63
+ throw failure("invalid-system-compiler");
64
+ if (current === "/") break;
65
+ current = path.dirname(current);
66
+ }
67
+ return compiler;
68
+ }
69
+
70
+ function packagedImage() {
71
+ const root = fileURLToPath(
72
+ new URL("../../assets/linux-subreaper/", import.meta.url),
73
+ );
74
+ // Only source checkouts with no packaged directory may use the development
75
+ // compiler path. A partial/corrupt installed payload must never fall back.
76
+ try {
77
+ if (!fs.lstatSync(root).isDirectory())
78
+ throw failure("invalid-packaged-directory");
79
+ } catch (error) {
80
+ if (error.code === "ENOENT") return null;
81
+ throw error;
82
+ }
83
+ let rootFd = null;
84
+ let dirFd = null;
85
+ const read = (name, maximum) => {
86
+ const fd = fs.openSync(
87
+ `/proc/self/fd/${dirFd}/${name}`,
88
+ fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW,
89
+ );
90
+ try {
91
+ const snapshot = readDescriptor(fd, maximum);
92
+ if (snapshot.stat.nlink !== 1n) throw failure("invalid-packaged-file");
93
+ return snapshot.bytes;
94
+ } finally {
95
+ fs.closeSync(fd);
96
+ }
97
+ };
98
+ try {
99
+ rootFd = fs.openSync(
100
+ root,
101
+ fs.constants.O_RDONLY |
102
+ fs.constants.O_DIRECTORY |
103
+ fs.constants.O_NOFOLLOW,
104
+ );
105
+ dirFd = fs.openSync(
106
+ `/proc/self/fd/${rootFd}/linux-${process.arch}`,
107
+ fs.constants.O_RDONLY |
108
+ fs.constants.O_DIRECTORY |
109
+ fs.constants.O_NOFOLLOW,
110
+ );
111
+ const manifest = read("manifest.json", MAX_SUBREAPER_MANIFEST_BYTES);
112
+ const bytes = read("supervisor", MAX_IMAGE_BYTES);
113
+ const identity = validateLinuxSubreaperArtifact(manifest, bytes, {
114
+ arch: process.arch,
115
+ });
116
+ return { bytes, identity };
117
+ } catch (error) {
118
+ if (error.code === "EXTERNAL_AGENT_HELPER_UNAVAILABLE") throw error;
119
+ throw failure("packaged-helper-unavailable");
120
+ } finally {
121
+ if (dirFd !== null) fs.closeSync(dirFd);
122
+ if (rootFd !== null) fs.closeSync(rootFd);
123
+ }
124
+ }
125
+
126
+ function compileImage(spawnSync) {
127
+ let sourceFd = null;
128
+ let directoryFd = null;
129
+ let imageFd = null;
130
+ let temporaryRoot = null;
131
+ let imagePath = null;
132
+ try {
133
+ // Vite may import the Broker through an http: module URL on non-Linux
134
+ // hosts. Resolve this Linux-only asset only when native supervision runs.
135
+ const source = fileURLToPath(
136
+ new URL("./linux-subreaper-supervisor.c", import.meta.url),
137
+ );
138
+ sourceFd = fs.openSync(
139
+ source,
140
+ fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW,
141
+ );
142
+ const snapshot = readDescriptor(sourceFd, MAX_SOURCE_BYTES);
143
+ // npm/git may transport text with CRLF. Compile the exact canonical bytes
144
+ // that the source digest commits to, passed on stdin rather than reopened.
145
+ const sourceBytes = Buffer.from(
146
+ snapshot.bytes.toString("utf8").replace(/\r\n/g, "\n"),
147
+ );
148
+ if (
149
+ snapshot.stat.nlink !== 1n ||
150
+ sha(sourceBytes) !== LINUX_SUBREAPER_SOURCE_DIGEST
151
+ )
152
+ throw failure("source-digest-mismatch");
153
+ fs.closeSync(sourceFd);
154
+ sourceFd = null;
155
+ const packaged = packagedImage();
156
+ const compiler = packaged ? null : compilerPath();
157
+ temporaryRoot = fs.mkdtempSync(
158
+ path.join(os.tmpdir(), "cc-linux-subreaper-build-"),
159
+ );
160
+ fs.chmodSync(temporaryRoot, 0o700);
161
+ directoryFd = fs.openSync(
162
+ temporaryRoot,
163
+ fs.constants.O_RDONLY |
164
+ fs.constants.O_DIRECTORY |
165
+ fs.constants.O_NOFOLLOW,
166
+ );
167
+ const directory = fs.fstatSync(directoryFd);
168
+ if (
169
+ !directory.isDirectory() ||
170
+ directory.uid !== process.getuid() ||
171
+ (directory.mode & 0o777) !== 0o700
172
+ )
173
+ throw failure("untrusted-build-directory");
174
+ imagePath = path.join(temporaryRoot, "supervisor");
175
+ // The compiler writes through its inherited directory handle. An ancestor
176
+ // rename cannot redirect the build to a caller-supplied executable path.
177
+ if (packaged) {
178
+ fs.writeFileSync(
179
+ `/proc/self/fd/${directoryFd}/supervisor`,
180
+ packaged.bytes,
181
+ { flag: "wx", mode: 0o500 },
182
+ );
183
+ } else {
184
+ const built = spawnSync(
185
+ compiler,
186
+ [
187
+ "-std=c11",
188
+ "-Wall",
189
+ "-Wextra",
190
+ "-Werror",
191
+ "-O2",
192
+ "-fstack-protector-strong",
193
+ "-D_FORTIFY_SOURCE=2",
194
+ "-x",
195
+ "c",
196
+ "-",
197
+ "-o",
198
+ "/proc/self/fd/3/supervisor",
199
+ ],
200
+ {
201
+ cwd: temporaryRoot,
202
+ env: { PATH: "/usr/bin:/bin", LC_ALL: "C" },
203
+ shell: false,
204
+ input: sourceBytes,
205
+ timeout: 30000,
206
+ maxBuffer: 1024 * 1024,
207
+ stdio: ["pipe", "pipe", "pipe", directoryFd],
208
+ },
209
+ );
210
+ if (built.error || built.status !== 0 || built.signal)
211
+ throw failure("native-build-failed");
212
+ }
213
+ imageFd = fs.openSync(
214
+ `/proc/self/fd/${directoryFd}/supervisor`,
215
+ fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW,
216
+ );
217
+ fs.fchmodSync(imageFd, 0o500);
218
+ const image = readDescriptor(imageFd, MAX_IMAGE_BYTES);
219
+ if (
220
+ image.stat.uid !== BigInt(process.getuid()) ||
221
+ image.stat.nlink !== 1n ||
222
+ (image.stat.mode & 0o777n) !== 0o500n
223
+ )
224
+ throw failure("untrusted-helper-image");
225
+ validateLinuxSubreaperElf(image.bytes, {
226
+ arch: process.arch,
227
+ staticOnly: Boolean(packaged),
228
+ });
229
+ if (packaged && sha(image.bytes) !== packaged.identity.imageDigest)
230
+ throw failure("packaged-copy-changed");
231
+ // Remove the name before granting a launch lease. The executable can only
232
+ // be reached through the held descriptor; a later pathname swap is inert.
233
+ fs.unlinkSync(`/proc/self/fd/${directoryFd}/supervisor`);
234
+ imagePath = null;
235
+ const held = fs.fstatSync(imageFd, { bigint: true });
236
+ if (
237
+ held.nlink !== 0n ||
238
+ held.dev !== image.stat.dev ||
239
+ held.ino !== image.stat.ino
240
+ )
241
+ throw failure("helper-unlink-unconfirmed");
242
+ const entry = {
243
+ fd: imageFd,
244
+ dev: held.dev,
245
+ ino: held.ino,
246
+ digest: sha(image.bytes),
247
+ distribution: packaged ? "packaged-static" : "local-build",
248
+ };
249
+ imageFd = null;
250
+ return entry;
251
+ } catch (error) {
252
+ if (error.code === "EXTERNAL_AGENT_HELPER_UNAVAILABLE") throw error;
253
+ // Do not expose compiler stdout/stderr, paths, environment, or native argv.
254
+ throw failure(
255
+ error.code === "ENOENT"
256
+ ? "system-compiler-or-source-missing"
257
+ : "native-build-setup-failed",
258
+ );
259
+ } finally {
260
+ if (sourceFd !== null) fs.closeSync(sourceFd);
261
+ if (imageFd !== null) fs.closeSync(imageFd);
262
+ if (imagePath && directoryFd !== null) {
263
+ try {
264
+ fs.unlinkSync(`/proc/self/fd/${directoryFd}/supervisor`);
265
+ } catch {
266
+ /* Preserve the admission failure. */
267
+ }
268
+ }
269
+ if (directoryFd !== null) fs.closeSync(directoryFd);
270
+ if (temporaryRoot) {
271
+ try {
272
+ fs.rmdirSync(temporaryRoot);
273
+ } catch {
274
+ /* Never recursively remove an unexpected build entry. */
275
+ }
276
+ }
277
+ }
278
+ }
279
+
280
+ /** Acquire a one-use descriptor lease from trusted packaged source. */
281
+ export function acquireLinuxSubreaperHelper({ spawnSync }) {
282
+ if (process.platform !== "linux" || typeof spawnSync !== "function")
283
+ throw failure("unsupported-host");
284
+ let entry = images.get(spawnSync);
285
+ if (!entry) {
286
+ entry = compileImage(spawnSync);
287
+ images.set(spawnSync, entry);
288
+ // Outstanding leases hold their own duplicated descriptor. Bound cached
289
+ // native-seam variants without invalidating already-started children.
290
+ if (images.size > 4) {
291
+ const oldest = images.keys().next().value;
292
+ fs.closeSync(images.get(oldest).fd);
293
+ images.delete(oldest);
294
+ }
295
+ }
296
+ const held = readDescriptor(entry.fd, MAX_IMAGE_BYTES);
297
+ if (
298
+ held.stat.dev !== entry.dev ||
299
+ held.stat.ino !== entry.ino ||
300
+ held.stat.nlink !== 0n ||
301
+ sha(held.bytes) !== entry.digest
302
+ )
303
+ throw failure("cached-helper-changed");
304
+ const descriptor = fs.openSync(
305
+ `/proc/self/fd/${entry.fd}`,
306
+ fs.constants.O_RDONLY,
307
+ );
308
+ try {
309
+ const borrowed = fs.fstatSync(descriptor, { bigint: true });
310
+ if (
311
+ borrowed.dev !== entry.dev ||
312
+ borrowed.ino !== entry.ino ||
313
+ borrowed.nlink !== 0n
314
+ )
315
+ throw failure("helper-lease-changed");
316
+ } catch (error) {
317
+ fs.closeSync(descriptor);
318
+ throw error;
319
+ }
320
+ const lease = Object.freeze({ kind: "linux-subreaper-helper-lease/v1" });
321
+ leases.set(lease, {
322
+ descriptor,
323
+ sourceDigest: LINUX_SUBREAPER_SOURCE_DIGEST,
324
+ imageDigest: entry.digest,
325
+ distribution: entry.distribution,
326
+ });
327
+ return lease;
328
+ }
329
+
330
+ export function consumeLinuxSubreaperHelper(lease) {
331
+ const entry = leases.get(lease);
332
+ if (!entry) throw failure("invalid-or-consumed-helper-lease");
333
+ leases.delete(lease);
334
+ let released = false;
335
+ return Object.freeze({
336
+ ...entry,
337
+ release() {
338
+ if (!released) {
339
+ released = true;
340
+ fs.closeSync(entry.descriptor);
341
+ }
342
+ },
343
+ });
344
+ }