chainlesschain 0.166.76 → 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 (230) hide show
  1. package/README.md +19 -8
  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-CNaejClV.js → AIOps-DSyZEY2G.js} +1 -1
  12. package/src/assets/web-panel/assets/{ActionButton-CF_CVKT_.js → ActionButton-DhNyZ577.js} +1 -1
  13. package/src/assets/web-panel/assets/{Analytics-a3Z6J7gv.js → Analytics-HMMpxmyi.js} +3 -3
  14. package/src/assets/web-panel/assets/{AppLayout-BFtWEnct.js → AppLayout-CwKMM5Ie.js} +5 -5
  15. package/src/assets/web-panel/assets/{Artifacts-BQ8oeMvX.js → Artifacts-CNzDmph7.js} +1 -1
  16. package/src/assets/web-panel/assets/{Audit-NOo9bmgk.js → Audit-DxWpUW3V.js} +1 -1
  17. package/src/assets/web-panel/assets/{BackgroundAgents-QRc7F3Tp.js → BackgroundAgents-C1R2ST-P.js} +1 -1
  18. package/src/assets/web-panel/assets/{Backup-UlVgLn2P.js → Backup-B6biTaEV.js} +1 -1
  19. package/src/assets/web-panel/assets/{BaseInput-BER9LJAr.js → BaseInput-CVnkD2Z5.js} +1 -1
  20. package/src/assets/web-panel/assets/{Chat-Z8z2Fdfz.js → Chat-Dbewl4Je.js} +6 -6
  21. package/src/assets/web-panel/assets/{ChatBubbleRenderer-DdmuBrdQ.js → ChatBubbleRenderer-DVZ6SwC5.js} +1 -1
  22. package/src/assets/web-panel/assets/{Checkbox-CXPgyB8L.js → Checkbox-BqqiF1JE.js} +1 -1
  23. package/src/assets/web-panel/assets/{Codegen-D1vOsLJ7.js → Codegen-BVMkGumc.js} +1 -1
  24. package/src/assets/web-panel/assets/{Col-ucLnUJC7.js → Col-DmiRHy96.js} +1 -1
  25. package/src/assets/web-panel/assets/{Community-COsV9n9t.js → Community-BDlpygqA.js} +1 -1
  26. package/src/assets/web-panel/assets/{Compact-D0EkBEYh.js → Compact-B2NME_m-.js} +1 -1
  27. package/src/assets/web-panel/assets/{Compliance-C8w9SUjt.js → Compliance-BlzDLE-R.js} +1 -1
  28. package/src/assets/web-panel/assets/{Cowork-CmVaKEJS.js → Cowork-C8raPybB.js} +3 -3
  29. package/src/assets/web-panel/assets/{Cron-B_FiMMV2.js → Cron-DA8Py0zP.js} +2 -2
  30. package/src/assets/web-panel/assets/{Crosschain-ByO3YL8N.js → Crosschain-DU2XyHqB.js} +1 -1
  31. package/src/assets/web-panel/assets/{DID-DwpsLM9r.js → DID-Df098fT_.js} +2 -2
  32. package/src/assets/web-panel/assets/{Dashboard-B_8IUvM_.js → Dashboard-D1rT702x.js} +2 -2
  33. package/src/assets/web-panel/assets/{Dropdown-Bo6WQkuX.js → Dropdown-BweXGo1O.js} +1 -1
  34. package/src/assets/web-panel/assets/{EmailListRenderer-C9LiQesx.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-Dst6VUnO.js → FamilyGuardDashboard-DrznZFVs.js} +1 -1
  37. package/src/assets/web-panel/assets/{Federation-Ci7CoLkJ.js → Federation-DQZ2adIA.js} +1 -1
  38. package/src/assets/web-panel/assets/{FormItemContext-bdDyUhUM.js → FormItemContext-DN30Dowh.js} +1 -1
  39. package/src/assets/web-panel/assets/{GenericCardRenderer-CrRwOUVi.js → GenericCardRenderer-DRdt0j1e.js} +1 -1
  40. package/src/assets/web-panel/assets/{Git-Dis8h-Z-.js → Git-wwRgStzk.js} +2 -2
  41. package/src/assets/web-panel/assets/{Governance-DX7OH5w2.js → Governance-CI4Uw0Nh.js} +1 -1
  42. package/src/assets/web-panel/assets/{Inference-Cavv_Q_Z.js → Inference-5TuE2AJI.js} +1 -1
  43. package/src/assets/web-panel/assets/{KnowledgeGraph-Cck8tnZn.js → KnowledgeGraph-oXyvmFSR.js} +1 -1
  44. package/src/assets/web-panel/assets/{Logs-BQt3aGMu.js → Logs-ewudSWuv.js} +2 -2
  45. package/src/assets/web-panel/assets/MarkdownRenderer-Cz5nyufm.js +1 -0
  46. package/src/assets/web-panel/assets/{Marketplace-CdmAKNSN.js → Marketplace-DcZeWFrs.js} +1 -1
  47. package/src/assets/web-panel/assets/{McpTools-BUlJdyPY.js → McpTools-BcV9p1RS.js} +3 -3
  48. package/src/assets/web-panel/assets/{Memory-DQRTQDr-.js → Memory-CMhYvugt.js} +2 -2
  49. package/src/assets/web-panel/assets/{MobileBridge-C0dnxgsl.js → MobileBridge-5RP2uwvT.js} +1 -1
  50. package/src/assets/web-panel/assets/{MobileProjects-DQ5Gy7fa.js → MobileProjects-BIuM9Ze4.js} +1 -1
  51. package/src/assets/web-panel/assets/{Mtc-Xl7u2isS.js → Mtc-DmBszTDe.js} +5 -5
  52. package/src/assets/web-panel/assets/{MtcAudit-C3KX0574.js → MtcAudit-Czdp5ZGt.js} +2 -2
  53. package/src/assets/web-panel/assets/{Multisig-CHEhfkn8.js → Multisig-DRWUuNr-.js} +3 -3
  54. package/src/assets/web-panel/assets/{NLProgramming-Ce38mH-8.js → NLProgramming-IRQQN0-c.js} +1 -1
  55. package/src/assets/web-panel/assets/{Notes-C7nuTd7c.js → Notes-CGhD1lW9.js} +4 -4
  56. package/src/assets/web-panel/assets/{NotificationSettings-BcoEcyq8.js → NotificationSettings-BtyPgQAh.js} +1 -1
  57. package/src/assets/web-panel/assets/{OrderTableRenderer-D-t5hKkx.js → OrderTableRenderer-yUaqwCty.js} +1 -1
  58. package/src/assets/web-panel/assets/{Organization-C_BGi4xi.js → Organization-C3kTVn5i.js} +4 -4
  59. package/src/assets/web-panel/assets/{Overflow-BodhraDq.js → Overflow-C2-0iZhq.js} +1 -1
  60. package/src/assets/web-panel/assets/{P2P-BTa3sAIy.js → P2P-CISoEUxA.js} +2 -2
  61. package/src/assets/web-panel/assets/{PdhVaultBrowser-BjZslP9T.js → PdhVaultBrowser-NfTVtvKQ.js} +5 -5
  62. package/src/assets/web-panel/assets/{Permissions-u3UDzGef.js → Permissions-CfK0jJhm.js} +3 -3
  63. package/src/assets/web-panel/assets/{PersonalDataHub-Cb7ybv65.js → PersonalDataHub-OsVxxh_j.js} +4 -4
  64. package/src/assets/web-panel/assets/{Pipeline-CS24k-P7.js → Pipeline-DEmK_Ch2.js} +1 -1
  65. package/src/assets/web-panel/assets/{Privacy-Ddj6Kqs7.js → Privacy-D61s73b0.js} +1 -1
  66. package/src/assets/web-panel/assets/{ProjectInit-Bg5uQIgg.js → ProjectInit-DkLF5gHb.js} +2 -2
  67. package/src/assets/web-panel/assets/{ProjectSettings-AmPR8T12.js → ProjectSettings-BA7odTrI.js} +2 -2
  68. package/src/assets/web-panel/assets/{Projects-DGSbAyTK.js → Projects-CdI1GcAG.js} +1 -1
  69. package/src/assets/web-panel/assets/{Providers-Dc1C3lbB.js → Providers-D9BYyP1r.js} +1 -1
  70. package/src/assets/web-panel/assets/{QrScannerModal-Cv3HXpce.js → QrScannerModal-CXMItUDD.js} +1 -1
  71. package/src/assets/web-panel/assets/{QuickAsk-3dpbXARb.js → QuickAsk-8-tF9ffZ.js} +1 -1
  72. package/src/assets/web-panel/assets/{Recommend-5aGRVnJK.js → Recommend-C2QGWOSi.js} +1 -1
  73. package/src/assets/web-panel/assets/{RemoteSession-CTS2jx0p.js → RemoteSession-B1M_v1lx.js} +2 -2
  74. package/src/assets/web-panel/assets/{Reputation-BxaKI0hY.js → Reputation-D0WZHgv1.js} +1 -1
  75. package/src/assets/web-panel/assets/{Row-C23uQdwd.js → Row-D6nf9-c-.js} +1 -1
  76. package/src/assets/web-panel/assets/{RssFeed-ssX9YOhm.js → RssFeed-ClZ6M-mN.js} +3 -3
  77. package/src/assets/web-panel/assets/{Search-C24GogII.js → Search-ZWkt8vuO.js} +1 -1
  78. package/src/assets/web-panel/assets/{Security-DdAcGKkk.js → Security-BUlQut2m.js} +3 -3
  79. package/src/assets/web-panel/assets/{Services-D0dCiEuq.js → Services-Cd_3xJOc.js} +2 -2
  80. package/src/assets/web-panel/assets/{Skeleton-DEY44o0v.js → Skeleton-C8e2-cHW.js} +1 -1
  81. package/src/assets/web-panel/assets/Skills-DucVRJp1.js +1 -0
  82. package/src/assets/web-panel/assets/{Sla-B_bbo2vB.js → Sla-Csr5pUwI.js} +1 -1
  83. package/src/assets/web-panel/assets/SpeechSettings-CXvyaRAT.js +1 -0
  84. package/src/assets/web-panel/assets/{SyncSettings-CpIXql0Z.js → SyncSettings-KdsIcV5h.js} +2 -2
  85. package/src/assets/web-panel/assets/Tasks-B-eHmJm9.js +1 -0
  86. package/src/assets/web-panel/assets/{Templates-C_44nVPq.js → Templates-BglVeaLK.js} +1 -1
  87. package/src/assets/web-panel/assets/{Tenant-CyZ2ey2P.js → Tenant-BBbQ8qan.js} +1 -1
  88. package/src/assets/web-panel/assets/{Terminal-DwGNHWnp.js → Terminal-Ca_pCVBi.js} +2 -2
  89. package/src/assets/web-panel/assets/{TimelineRenderer-BTAHNkqU.js → TimelineRenderer-YD6XG_vZ.js} +1 -1
  90. package/src/assets/web-panel/assets/{Tokens-DCJWkUwc.js → Tokens-2lRoeVli.js} +1 -1
  91. package/src/assets/web-panel/assets/{Trigger-BCjDO9-E.js → Trigger-C-3XNAU9.js} +1 -1
  92. package/src/assets/web-panel/assets/{Trust-_YS8WbRb.js → Trust-k-1PxdLG.js} +1 -1
  93. package/src/assets/web-panel/assets/{UkeySign-m6R8xGq7.js → UkeySign-FG-qW646.js} +1 -1
  94. package/src/assets/web-panel/assets/{VideoEditing-xOfk29c4.js → VideoEditing-BNOe1cmd.js} +1 -1
  95. package/src/assets/web-panel/assets/{Wallet-B1Gw0awc.js → Wallet-D5C3i2Kw.js} +4 -4
  96. package/src/assets/web-panel/assets/{WebAuthn-CHK5ft18.js → WebAuthn-BOpztqd3.js} +4 -4
  97. package/src/assets/web-panel/assets/{WorkflowEditor-DEp1ukQQ.js → WorkflowEditor-BpVrpUEv.js} +1 -1
  98. package/src/assets/web-panel/assets/{chat-B2sFizun.js → chat-DIuMHb38.js} +1 -1
  99. package/src/assets/web-panel/assets/{colors-DJ17YV1E.js → colors-CTFJPyzQ.js} +1 -1
  100. package/src/assets/web-panel/assets/{compact-item-CBhJJgEC.js → compact-item-CONfmJcW.js} +1 -1
  101. package/src/assets/web-panel/assets/{createContext-BZkpvNJy.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-C0ZKo6Ei.js → hasIn-CW4XOjDC.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-Bc3vVG2X.js → index-7wMSBCU7.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-vFMwiAN4.js → index-Akmg1WdH.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DOBXNMdh.js → index-B54qoVff.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DLo8Ls9u.js → index-B8r2t0Ch.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-C7gv9dvb.js → index-B9XoBoty.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DHtpMr1G.js → index-B9aS2VLu.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Dxe0YlZe.js → index-BFs1Tznc.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DumLgj1t.js → index-BKgaRT0b.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-BNp6HKFh.js → index-BM7bOUvu.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-DM0rWF6z.js → index-BMg2JFmW.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-4oULtRqE.js → index-BRZsPxNn.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-LPPe0val.js → index-Bf19fKef.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-Ctguam0K.js → index-BkAbfBF-.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DrU5xVpF.js → index-CBjb2A5R.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CCOr6Q27.js → index-CEZWQthY.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-C9gYiACH.js → index-CFGLf88d.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CZW84cEf.js → index-CLUa68JH.js} +3 -3
  121. package/src/assets/web-panel/assets/{index-BoDUYyuo.js → index-CM2X25Er.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DyiCbHeL.js → index-CX4T2uKN.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CW5o1Gar.js → index-CixqfdRk.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-5K2z_tgO.js → index-CkRojEip.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BOfPp5OV.js → index-Cvmc3f25.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CdxJm-HB.js → index-D-lpTPS8.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-8ueG48gl.js → index-D59GbWCN.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BMxOoITz.js → index-DAESljiJ.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DLMr5KMd.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-BGIvhCPl.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-DjdSFO0d.js → index-DSlXL6Ju.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-Cn5UzvgR.js → index-DWCJnn2O.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-Chct9tL8.js → index-DWY7YwDu.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-BEnd5fiz.js → index-DZTwP364.js} +1 -1
  137. package/src/assets/web-panel/assets/{index-KzNhWykP.js → index-DidrMvOx.js} +1 -1
  138. package/src/assets/web-panel/assets/{index-BpyrhOeh.js → index-Dj3K5kHs.js} +1 -1
  139. package/src/assets/web-panel/assets/{index-CZlkPrxb.js → index-YaeGscSw.js} +1 -1
  140. package/src/assets/web-panel/assets/{index-Dfgxe-fw.js → index-YlMnFNOi.js} +1 -1
  141. package/src/assets/web-panel/assets/{index-IHgzfc1u.js → index-asWsB34i.js} +1 -1
  142. package/src/assets/web-panel/assets/{index-DJkoJzTU.js → index-gkjiFjQd.js} +1 -1
  143. package/src/assets/web-panel/assets/{initDefaultProps-Cqfoq0TJ.js → initDefaultProps-BOr4igh3.js} +1 -1
  144. package/src/assets/web-panel/assets/{motion-CIiVJHNu.js → motion-CK469n2j.js} +1 -1
  145. package/src/assets/web-panel/assets/{move-CFl1o_A8.js → move-DzjudlYQ.js} +1 -1
  146. package/src/assets/web-panel/assets/{mtc-parser-DYoCxcZ1.js → mtc-parser-BQaKUxC6.js} +1 -1
  147. package/src/assets/web-panel/assets/{omit-C1P2q5TY.js → omit-MciovCFD.js} +1 -1
  148. package/src/assets/web-panel/assets/{pickAttrs-BtTRpJtC.js → pickAttrs-DDPJ4zAz.js} +1 -1
  149. package/src/assets/web-panel/assets/{placementArrow-Cst2PcNM.js → placementArrow-Cznyb-jI.js} +1 -1
  150. package/src/assets/web-panel/assets/{responsiveObserve-CF5kalV2.js → responsiveObserve-AJK3SLzJ.js} +1 -1
  151. package/src/assets/web-panel/assets/{slide-CtHGqpXN.js → slide-CPQ28wu7.js} +1 -1
  152. package/src/assets/web-panel/assets/{statusUtils-N__biHXf.js → statusUtils-CFjzvqf_.js} +1 -1
  153. package/src/assets/web-panel/assets/{styleChecker-DR8V_H-i.js → styleChecker-BPyFfTuR.js} +1 -1
  154. package/src/assets/web-panel/assets/{useFlexGapSupport-D274dqun.js → useFlexGapSupport-Dq7N6R05.js} +1 -1
  155. package/src/assets/web-panel/assets/{useFs-BwHLYU5b.js → useFs-C3GS0uTc.js} +1 -1
  156. package/src/assets/web-panel/assets/{usePersonalDataHub-BiA-hVqt.js → usePersonalDataHub-BhgIVzP_.js} +1 -1
  157. package/src/assets/web-panel/assets/{vnode-Bugl94dy.js → vnode-4ZD9-MDr.js} +1 -1
  158. package/src/assets/web-panel/assets/{zoom-DEFl8GCu.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 +26 -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/decision-layer/providers.js +84 -9
  182. package/src/lib/decision-layer/runtime.js +86 -49
  183. package/src/lib/direct-model-usage.js +14 -3
  184. package/src/lib/doctor-checkup.js +31 -2
  185. package/src/lib/durable-security-store.js +6 -1
  186. package/src/lib/evolution/evolution-artifact-identity.js +21 -0
  187. package/src/lib/evolution/evolution-artifact-ports.js +5 -11
  188. package/src/lib/evolution/evolution-eval-cohort-receipt-reconciliation.js +389 -0
  189. package/src/lib/execution-location-failure-site.js +63 -0
  190. package/src/lib/execution-location-target.js +102 -8
  191. package/src/lib/external-agent-adapters.js +2 -0
  192. package/src/lib/image-file-boundary.js +154 -0
  193. package/src/lib/image-input.js +16 -3
  194. package/src/lib/llm-pricing.js +114 -8
  195. package/src/lib/mcp-call-ledger-store.js +7 -2
  196. package/src/lib/model-capabilities.js +21 -10
  197. package/src/lib/model-context-catalog.js +60 -1
  198. package/src/lib/openai-responses.js +7 -1
  199. package/src/lib/orchestrator.js +8 -2
  200. package/src/lib/process-execution-broker/index.js +93 -1
  201. package/src/lib/process-execution-broker/linux-subreaper-artifact.js +120 -0
  202. package/src/lib/process-execution-broker/linux-subreaper-helper.js +344 -0
  203. package/src/lib/process-execution-broker/linux-subreaper-process.js +326 -0
  204. package/src/lib/process-execution-broker/linux-subreaper-supervisor.c +360 -0
  205. package/src/lib/process-execution-broker/owned-posix-process-group-worker.mjs +131 -0
  206. package/src/lib/process-execution-broker/owned-posix-process-group.js +267 -0
  207. package/src/lib/process-execution-broker/process-ownership-journal.js +297 -0
  208. package/src/lib/process-execution-broker/process-ownership-quarantine.js +91 -0
  209. package/src/lib/runtime-usage-ledger.js +3 -0
  210. package/src/lib/secure-fs.js +158 -42
  211. package/src/lib/session-branch-history.js +240 -0
  212. package/src/lib/session-history-origins.js +285 -0
  213. package/src/lib/session-input-receipt.js +110 -0
  214. package/src/lib/session-resource-budget.js +8 -8
  215. package/src/lib/session-transcript-history.js +456 -0
  216. package/src/lib/session-transcript-page.js +164 -0
  217. package/src/lib/session-transcript-reference.js +38 -0
  218. package/src/lib/session-usage.js +8 -0
  219. package/src/lib/token-tracker.js +32 -54
  220. package/src/lib/usage-pricing-context.js +93 -0
  221. package/src/runtime/headless-runner.js +8 -0
  222. package/src/runtime/headless-stream.js +202 -4
  223. package/src/assets/web-panel/assets/EvolutionSettings-Pc1IpRfk.js +0 -1
  224. package/src/assets/web-panel/assets/MarkdownRenderer-BIUeeiVA.js +0 -1
  225. package/src/assets/web-panel/assets/Skills-CYt0Mu2W.js +0 -1
  226. package/src/assets/web-panel/assets/SpeechSettings-a2BBjtTL.js +0 -1
  227. package/src/assets/web-panel/assets/Tasks-BYQKU-GL.js +0 -1
  228. package/src/assets/web-panel/assets/devWarning-DZhu13vj.js +0 -1
  229. package/src/assets/web-panel/assets/index-C6iFyQYz.js +0 -1
  230. package/src/assets/web-panel/assets/index-CztThH9f.js +0 -1
@@ -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
+ }
@@ -0,0 +1,326 @@
1
+ import { isAbsolute } from "node:path";
2
+ import { EventEmitter } from "node:events";
3
+ import { constants } from "node:os";
4
+ import { consumeLinuxSubreaperHelper } from "./linux-subreaper-helper.js";
5
+
6
+ const MAGIC = Buffer.from("CCSUBR01");
7
+ const MAX_FRAME = 1024 * 1024;
8
+
9
+ export function encodeLinuxSubreaperLaunch(command, args, options) {
10
+ if (
11
+ typeof command !== "string" ||
12
+ !command ||
13
+ command.includes("\0") ||
14
+ !Array.isArray(args) ||
15
+ args.length >= 4096 ||
16
+ args.some((arg) => typeof arg !== "string" || arg.includes("\0")) ||
17
+ typeof options.cwd !== "string" ||
18
+ !isAbsolute(options.cwd) ||
19
+ options.cwd.includes("\0") ||
20
+ !options.env ||
21
+ typeof options.env !== "object" ||
22
+ Array.isArray(options.env)
23
+ )
24
+ throw new TypeError("Invalid Linux subreaper launch");
25
+ const entries = Object.entries(options.env);
26
+ if (
27
+ entries.length > 8192 ||
28
+ entries.some(
29
+ ([key, value]) =>
30
+ !key ||
31
+ key.includes("=") ||
32
+ key.includes("\0") ||
33
+ typeof value !== "string" ||
34
+ value.includes("\0"),
35
+ )
36
+ ) {
37
+ throw new TypeError("Invalid Linux subreaper environment");
38
+ }
39
+ const graceMs = options.graceMs ?? 250;
40
+ if (!Number.isSafeInteger(graceMs) || graceMs < 0 || graceMs > 2147483647)
41
+ throw new TypeError("Invalid Linux subreaper grace period");
42
+ const strings = [
43
+ options.cwd,
44
+ command,
45
+ ...args,
46
+ ...entries.map(([key, value]) => `${key}=${value}`),
47
+ ].map((value) => Buffer.from(value, "utf8"));
48
+ const length = 24 + strings.reduce((sum, value) => sum + 4 + value.length, 0);
49
+ if (length > MAX_FRAME)
50
+ throw new TypeError("Linux subreaper launch exceeds its byte limit");
51
+ const frame = Buffer.alloc(length);
52
+ MAGIC.copy(frame);
53
+ frame.writeUInt32BE(length, 8);
54
+ frame.writeUInt32BE(args.length + 1, 12);
55
+ frame.writeUInt32BE(entries.length, 16);
56
+ frame.writeUInt32BE(graceMs, 20);
57
+ let offset = 24;
58
+ for (const value of strings) {
59
+ frame.writeUInt32BE(value.length, offset);
60
+ offset += 4;
61
+ value.copy(frame, offset);
62
+ offset += value.length;
63
+ }
64
+ return frame;
65
+ }
66
+
67
+ /**
68
+ * Native lifecycle primitive for an admitted Broker launch plan. Production
69
+ * uses a one-use, privately branded helper descriptor. The explicit path seam
70
+ * remains for native build/verification tests, never Broker request options.
71
+ */
72
+ export function spawnLinuxSubreaper(command, args, options, native) {
73
+ // Claim the lease before validating the launch so every rejection closes its
74
+ // descriptor. A bad plan must not strand an otherwise valid installation pin.
75
+ const helper = options.helper
76
+ ? consumeLinuxSubreaperHelper(options.helper)
77
+ : null;
78
+ let launch;
79
+ let child;
80
+ try {
81
+ if (
82
+ (native.platform ?? process.platform) !== "linux" ||
83
+ typeof native.spawn !== "function"
84
+ )
85
+ throw new TypeError("Linux Broker native spawn is required");
86
+ if (
87
+ !options.helper &&
88
+ (typeof options.helperPath !== "string" ||
89
+ !isAbsolute(options.helperPath))
90
+ )
91
+ throw new TypeError(
92
+ "An absolute Linux subreaper helper path is required",
93
+ );
94
+ if (options.helper && options.helperPath)
95
+ throw new TypeError("Ambiguous Linux subreaper helper identity");
96
+ if (
97
+ Object.keys(options).some(
98
+ (key) =>
99
+ !["cwd", "env", "graceMs", "helperPath", "helper"].includes(key),
100
+ )
101
+ )
102
+ throw new TypeError("Unsupported Linux subreaper option");
103
+ launch = encodeLinuxSubreaperLaunch(command, args, options);
104
+ child = native.spawn(helper ? "/proc/self/fd/4" : options.helperPath, [], {
105
+ cwd: options.cwd,
106
+ env: { PATH: "/usr/bin:/bin", LC_ALL: "C" },
107
+ shell: false,
108
+ detached: false,
109
+ stdio: [
110
+ "pipe",
111
+ "pipe",
112
+ "pipe",
113
+ "pipe",
114
+ ...(helper ? [helper.descriptor] : []),
115
+ ],
116
+ });
117
+ } finally {
118
+ // Native spawn duplicates stdio synchronously. Never reopen the verified
119
+ // executable path; the child's descriptor now owns that exact image.
120
+ helper?.release();
121
+ }
122
+ const control = child.stdio[3];
123
+ let closed = false;
124
+ let requestedSignal = null;
125
+ let buffer = "";
126
+ let bytes = 0;
127
+ let targetPid = null;
128
+ let target = null;
129
+ let cleanup = null;
130
+ let protocolError = null;
131
+ const terminate = (signal = "SIGTERM") => {
132
+ if (!["SIGTERM", "SIGKILL"].includes(signal))
133
+ throw new TypeError("Invalid Linux subreaper stop signal");
134
+ if (closed || control.destroyed || !control.writable) return false;
135
+ if (requestedSignal === "SIGKILL" || requestedSignal === signal)
136
+ return true;
137
+ requestedSignal = signal;
138
+ control.write(signal === "SIGKILL" ? "K" : "T");
139
+ return true;
140
+ };
141
+ control.on("error", () => {
142
+ protocolError ??= "control-channel-failed";
143
+ control.destroy();
144
+ });
145
+ control.on("data", (chunk) => {
146
+ bytes += chunk.length;
147
+ if (bytes > 16 * 1024) {
148
+ protocolError = "control-reply-limit";
149
+ control.destroy();
150
+ return;
151
+ }
152
+ buffer += chunk.toString("ascii");
153
+ let newline;
154
+ while ((newline = buffer.indexOf("\n")) >= 0) {
155
+ const line = buffer.slice(0, newline);
156
+ buffer = buffer.slice(newline + 1);
157
+ try {
158
+ const message = JSON.parse(line);
159
+ if (
160
+ message.type === "started" &&
161
+ targetPid === null &&
162
+ Number.isSafeInteger(message.pid) &&
163
+ message.pid > 0
164
+ ) {
165
+ targetPid = message.pid;
166
+ } else if (
167
+ message.type === "target-exit" &&
168
+ target === null &&
169
+ targetPid !== null &&
170
+ Number.isInteger(message.code) &&
171
+ message.code >= -1 &&
172
+ message.code <= 255 &&
173
+ Number.isInteger(message.signal) &&
174
+ message.signal >= 0 &&
175
+ message.signal <= 64 &&
176
+ Number.isInteger(message.spawnErrno) &&
177
+ message.spawnErrno >= -1 &&
178
+ message.spawnErrno <= 4095
179
+ ) {
180
+ target = {
181
+ code: message.code,
182
+ signal: message.signal,
183
+ spawnErrno: message.spawnErrno,
184
+ };
185
+ } else if (
186
+ message.type === "cleanup" &&
187
+ cleanup === null &&
188
+ target !== null &&
189
+ typeof message.confirmed === "boolean" &&
190
+ message.rootReaped === true &&
191
+ Number.isSafeInteger(message.reaped) &&
192
+ message.reaped >= 1
193
+ ) {
194
+ cleanup = message;
195
+ } else if (
196
+ message.type === "error" &&
197
+ ["subreaper-unavailable", "cleanup-unconfirmed"].includes(
198
+ message.code,
199
+ )
200
+ ) {
201
+ protocolError ??= message.code;
202
+ } else throw new Error("invalid reply");
203
+ } catch {
204
+ protocolError = "invalid-control-reply";
205
+ control.destroy();
206
+ return;
207
+ }
208
+ }
209
+ });
210
+ const completion = new Promise((resolve) => {
211
+ child.on("error", () => {
212
+ protocolError ??= "supervisor-spawn-failed";
213
+ });
214
+ child.once("close", (code, signal) => {
215
+ closed = true;
216
+ control.destroy();
217
+ if (buffer) protocolError ??= "truncated-control-reply";
218
+ if (!cleanup) protocolError ??= "missing-cleanup-receipt";
219
+ else if (!cleanup.confirmed)
220
+ protocolError ??= "unconfirmed-cleanup-receipt";
221
+ const confirmed =
222
+ cleanup?.confirmed === true &&
223
+ code === 0 &&
224
+ signal === null &&
225
+ !protocolError;
226
+ resolve({
227
+ targetPid,
228
+ target,
229
+ supervisor: { code, signal, closed: true },
230
+ cleanup: {
231
+ mode: "linux-subreaper",
232
+ confirmed,
233
+ descendantsReaped: confirmed,
234
+ reaped: cleanup?.reaped ?? null,
235
+ protocolError,
236
+ // The zero-child fence is a lifecycle fact, not hostile-code isolation.
237
+ processTreeContained: false,
238
+ },
239
+ ...(helper
240
+ ? {
241
+ helper: {
242
+ sourceDigest: helper.sourceDigest,
243
+ imageDigest: helper.imageDigest,
244
+ binding: "unlinked-inherited-fd",
245
+ distribution: helper.distribution,
246
+ },
247
+ }
248
+ : {}),
249
+ });
250
+ });
251
+ });
252
+ control.write(launch);
253
+ return Object.freeze({ child, terminate, completion });
254
+ }
255
+
256
+ /** Broker-facing process handle: close is fenced by the kernel tree receipt. */
257
+ export function spawnLinuxSubreaperChild(command, args, options, native) {
258
+ const owner = spawnLinuxSubreaper(command, args, options, native);
259
+ const raw = owner.child;
260
+ const child = new EventEmitter();
261
+ Object.assign(child, {
262
+ pid: raw.pid,
263
+ sandboxWrapperPid: raw.pid,
264
+ stdin: raw.stdin,
265
+ stdout: raw.stdout,
266
+ stderr: raw.stderr,
267
+ stdio: raw.stdio,
268
+ exitCode: null,
269
+ signalCode: null,
270
+ killed: false,
271
+ ownedProcessTreeClosed: owner.completion,
272
+ kill(signal = "SIGTERM") {
273
+ const requested = owner.terminate(signal);
274
+ if (requested) child.killed = true;
275
+ return requested;
276
+ },
277
+ ref() {
278
+ raw.ref?.();
279
+ return child;
280
+ },
281
+ unref() {
282
+ raw.unref?.();
283
+ return child;
284
+ },
285
+ });
286
+ raw.once("spawn", () => child.emit("spawn"));
287
+ owner.completion.then((receipt) => {
288
+ child.ownedProcessTreeEvidence = receipt;
289
+ child.sandboxTargetPid = receipt.targetPid;
290
+ if (!receipt.cleanup.confirmed) {
291
+ const error = new Error(
292
+ "Linux external-agent process-tree cleanup is unconfirmed",
293
+ );
294
+ error.code = raw.pid
295
+ ? "EXTERNAL_AGENT_CLEANUP_UNCONFIRMED"
296
+ : "EXTERNAL_AGENT_SPAWN_FAILED";
297
+ // A failed native spawn never created an owner or target. All other
298
+ // losses retain the close fence: helper exit alone cannot release an
299
+ // agent while an unobserved adopted descendant may still be executing.
300
+ child.emit("error", error);
301
+ if (!raw.pid) {
302
+ child.exitCode = -1;
303
+ child.emit("exit", -1, null);
304
+ child.emit("close", -1, null);
305
+ } else {
306
+ child.emit("cleanup:unconfirmed", receipt);
307
+ }
308
+ return;
309
+ }
310
+ if (receipt.target.spawnErrno) {
311
+ const error = new Error("External agent executable could not be started");
312
+ error.code = "EXTERNAL_AGENT_SPAWN_FAILED";
313
+ child.emit("error", error);
314
+ }
315
+ child.exitCode = receipt.target.code < 0 ? null : receipt.target.code;
316
+ child.signalCode =
317
+ receipt.target.signal === 0
318
+ ? null
319
+ : (Object.keys(constants.signals).find(
320
+ (signal) => constants.signals[signal] === receipt.target.signal,
321
+ ) ?? "SIGUNKNOWN");
322
+ child.emit("exit", child.exitCode, child.signalCode);
323
+ child.emit("close", child.exitCode, child.signalCode);
324
+ });
325
+ return child;
326
+ }