chainlesschain 0.163.8 → 0.164.0

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 (228) hide show
  1. package/package.json +4 -1
  2. package/scripts/macos-mcp-launcher-build.mjs +317 -0
  3. package/scripts/macos-mcp-launcher-postinstall.sh +54 -0
  4. package/scripts/macos-mcp-launcher-preinstall.sh +61 -0
  5. package/src/assets/web-panel/assets/{AIOps-CavM7W3k.js → AIOps-D2MEn7fI.js} +1 -1
  6. package/src/assets/web-panel/assets/{ActionButton-CUvZGabQ.js → ActionButton-lCW_4Gf0.js} +1 -1
  7. package/src/assets/web-panel/assets/{Analytics-DeBnWnbe.js → Analytics-Bs7i-nsS.js} +3 -3
  8. package/src/assets/web-panel/assets/{AppLayout-DbI5kxvd.js → AppLayout-CK7B6S_j.js} +5 -5
  9. package/src/assets/web-panel/assets/{Artifacts-D93bigKm.js → Artifacts-C8ILjpyo.js} +1 -1
  10. package/src/assets/web-panel/assets/{Audit-CBNvfUZa.js → Audit-Bb9cNaWc.js} +1 -1
  11. package/src/assets/web-panel/assets/{BackgroundAgents-CJLyh_YU.js → BackgroundAgents-sC9ooXIf.js} +1 -1
  12. package/src/assets/web-panel/assets/{Backup-D_0yoehD.js → Backup-D-DrsplT.js} +1 -1
  13. package/src/assets/web-panel/assets/{BaseInput-TJxmbObW.js → BaseInput-uCNZpwSK.js} +1 -1
  14. package/src/assets/web-panel/assets/{Chat-CE0dto1q.js → Chat-CsDK1uE9.js} +6 -6
  15. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CZ5-yYiD.js → ChatBubbleRenderer-OqSDt50w.js} +1 -1
  16. package/src/assets/web-panel/assets/{Checkbox-Ck1RVIVo.js → Checkbox-JhTXM1-K.js} +1 -1
  17. package/src/assets/web-panel/assets/{Codegen-qpoyf6DK.js → Codegen-BbzZLnyD.js} +1 -1
  18. package/src/assets/web-panel/assets/{Col-DUyPWjIE.js → Col-D4VW4m4j.js} +1 -1
  19. package/src/assets/web-panel/assets/{Community-D_S1BemS.js → Community-BXrYawxV.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compact-BjxeK-Gc.js → Compact-DCihGy1u.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compliance-Dd3CEJsu.js → Compliance-DlyZ-lk8.js} +1 -1
  22. package/src/assets/web-panel/assets/{Cowork-B4QG7-ad.js → Cowork-DvGZrhbO.js} +3 -3
  23. package/src/assets/web-panel/assets/{Cron-BtZnids5.js → Cron-DUncZi8h.js} +2 -2
  24. package/src/assets/web-panel/assets/{Crosschain-CHPfCBFD.js → Crosschain-C_hLuUcm.js} +1 -1
  25. package/src/assets/web-panel/assets/{DID-DT8DCEOK.js → DID-b6YSUqxr.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dashboard-COQab5_U.js → Dashboard-uvM15Cfb.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dropdown-BY1PsQuU.js → Dropdown-D1-Nd4qY.js} +1 -1
  28. package/src/assets/web-panel/assets/{EmailListRenderer-CsuAuaq3.js → EmailListRenderer-8ApvL6Zc.js} +1 -1
  29. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BqpinD-j.js → FamilyGuardDashboard-LYJt8811.js} +1 -1
  30. package/src/assets/web-panel/assets/{Federation-D0gkfQFv.js → Federation-BbI3HGpv.js} +1 -1
  31. package/src/assets/web-panel/assets/{FormItemContext-BqgE-axK.js → FormItemContext-DSoEKuFu.js} +1 -1
  32. package/src/assets/web-panel/assets/{GenericCardRenderer-D0hJ2KvC.js → GenericCardRenderer-B0S9OWd5.js} +1 -1
  33. package/src/assets/web-panel/assets/{Git-CmMB0uPY.js → Git-DIs9Zhf3.js} +2 -2
  34. package/src/assets/web-panel/assets/{Governance-BnVEI0Dk.js → Governance-jzZXrxcl.js} +1 -1
  35. package/src/assets/web-panel/assets/{Inference-YTAMihRP.js → Inference-JUPjf2ZI.js} +1 -1
  36. package/src/assets/web-panel/assets/{KnowledgeGraph-0ax7VHop.js → KnowledgeGraph-DxnfJvlP.js} +1 -1
  37. package/src/assets/web-panel/assets/{Logs-B9TRcokL.js → Logs-iXiz8BEE.js} +2 -2
  38. package/src/assets/web-panel/assets/MarkdownRenderer-GmB6DOr6.js +1 -0
  39. package/src/assets/web-panel/assets/{Marketplace-B6CSuD_H.js → Marketplace-Y3Xch312.js} +1 -1
  40. package/src/assets/web-panel/assets/{McpTools-CjMXvOVU.js → McpTools-D7kGGbO7.js} +3 -3
  41. package/src/assets/web-panel/assets/{Memory-CXRF71U3.js → Memory-Do_hVxzh.js} +2 -2
  42. package/src/assets/web-panel/assets/{MobileBridge-DQgNp_oS.js → MobileBridge-CtrR0Tas.js} +1 -1
  43. package/src/assets/web-panel/assets/MobileProjects-BL0Czcoj.js +1 -0
  44. package/src/assets/web-panel/assets/{Mtc-6hDTRPe1.js → Mtc-qo5QCTGd.js} +2 -2
  45. package/src/assets/web-panel/assets/{MtcAudit-BlVHU1DS.js → MtcAudit-cq5mnjYj.js} +2 -2
  46. package/src/assets/web-panel/assets/{Multisig-DP9pzEbV.js → Multisig-Bq0MAQHw.js} +3 -3
  47. package/src/assets/web-panel/assets/{NLProgramming-Djorh8EV.js → NLProgramming-DdWE6Vi2.js} +1 -1
  48. package/src/assets/web-panel/assets/{Notes-oLZ-JkUg.js → Notes-BxMBFcIp.js} +4 -4
  49. package/src/assets/web-panel/assets/{NotificationSettings-Cg288VH3.js → NotificationSettings-RTrAcbUe.js} +1 -1
  50. package/src/assets/web-panel/assets/{OrderTableRenderer-Bb1O3Ofr.js → OrderTableRenderer-DJbpGqzT.js} +1 -1
  51. package/src/assets/web-panel/assets/{Organization-CBdo-bHs.js → Organization-SQzIPdqC.js} +2 -2
  52. package/src/assets/web-panel/assets/{Overflow-qZdnVumx.js → Overflow-02yECh22.js} +1 -1
  53. package/src/assets/web-panel/assets/{P2P-D4kNfGNQ.js → P2P-BNg4pNCM.js} +2 -2
  54. package/src/assets/web-panel/assets/{PdhVaultBrowser-DnlMemM7.js → PdhVaultBrowser-BxPJZsD3.js} +5 -5
  55. package/src/assets/web-panel/assets/{Permissions-DHucHFBJ.js → Permissions-CLnDnPAz.js} +3 -3
  56. package/src/assets/web-panel/assets/{PersonalDataHub-BovlOIPR.js → PersonalDataHub-C5m0AjGf.js} +4 -4
  57. package/src/assets/web-panel/assets/{Pipeline-Deru3CQY.js → Pipeline-VwOf5Dhv.js} +1 -1
  58. package/src/assets/web-panel/assets/{Privacy-Bq5oTTbU.js → Privacy-CC0W2hZd.js} +1 -1
  59. package/src/assets/web-panel/assets/{ProjectInit-BfzxVWAz.js → ProjectInit-Dz893Bob.js} +2 -2
  60. package/src/assets/web-panel/assets/{ProjectSettings-CKC6XBtH.js → ProjectSettings-CxQkvl0k.js} +2 -2
  61. package/src/assets/web-panel/assets/Projects-DDAjkUkT.js +1 -0
  62. package/src/assets/web-panel/assets/{Providers-C_jx4TWX.js → Providers-DeB9IkxK.js} +1 -1
  63. package/src/assets/web-panel/assets/{QrScannerModal-BdIHeVGC.js → QrScannerModal-OCeoaswn.js} +1 -1
  64. package/src/assets/web-panel/assets/{QuickAsk-BwZwAcPD.js → QuickAsk-DenotaAj.js} +1 -1
  65. package/src/assets/web-panel/assets/{Recommend-BNTt0L-m.js → Recommend-Cies_jjI.js} +1 -1
  66. package/src/assets/web-panel/assets/{RemoteSession-Biyn2-Ro.js → RemoteSession-Dxzl5n2T.js} +3 -3
  67. package/src/assets/web-panel/assets/{Reputation-D6VpG32B.js → Reputation-CW0mvxgZ.js} +1 -1
  68. package/src/assets/web-panel/assets/{Row-D_74OvQQ.js → Row-SEd32qZU.js} +1 -1
  69. package/src/assets/web-panel/assets/{RssFeed-BTr0a-BQ.js → RssFeed-BSwnJ3Lm.js} +3 -3
  70. package/src/assets/web-panel/assets/{Search-C3MCFoNU.js → Search-xe2m8bkC.js} +1 -1
  71. package/src/assets/web-panel/assets/{Security-CqW9aJ6s.js → Security-Mq2F9Nro.js} +3 -3
  72. package/src/assets/web-panel/assets/{Services-Cw5GNaHF.js → Services-BKGw2V3P.js} +2 -2
  73. package/src/assets/web-panel/assets/{Skeleton-DZps5qeY.js → Skeleton-DW95-Rxf.js} +1 -1
  74. package/src/assets/web-panel/assets/{Skills-C6NQ1znT.js → Skills-CHgChCv_.js} +1 -1
  75. package/src/assets/web-panel/assets/{Sla-DFP8G2Sh.js → Sla-tKh6k3R7.js} +1 -1
  76. package/src/assets/web-panel/assets/{SpeechSettings-ESt6MB6v.js → SpeechSettings-D6UL3dA5.js} +1 -1
  77. package/src/assets/web-panel/assets/{SyncSettings-BHnN98aM.js → SyncSettings-D0Fw8fVL.js} +2 -2
  78. package/src/assets/web-panel/assets/{Tasks-NiSCaOf-.js → Tasks-20x1GB3D.js} +1 -1
  79. package/src/assets/web-panel/assets/{Templates-DsKFhW2C.js → Templates-DJ-lts-a.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tenant-CQ0E0ze5.js → Tenant-BFdGpbs7.js} +1 -1
  81. package/src/assets/web-panel/assets/{Terminal-D_rBu_by.js → Terminal-Xpx61vHL.js} +2 -2
  82. package/src/assets/web-panel/assets/{TimelineRenderer-D3Vm4Po4.js → TimelineRenderer-C6UIvyZQ.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tokens-DNTxRH6q.js → Tokens-Dellq08f.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trigger-Dgprz1ms.js → Trigger-VKw8d0J-.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trust-B2rUnVBD.js → Trust-DNftdKT5.js} +1 -1
  86. package/src/assets/web-panel/assets/{UkeySign-DEGQNc6_.js → UkeySign-DX9VAKJI.js} +1 -1
  87. package/src/assets/web-panel/assets/{VideoEditing-jlsAx3Eh.js → VideoEditing-B2h3jO8q.js} +1 -1
  88. package/src/assets/web-panel/assets/{Wallet-8jQih1ij.js → Wallet-CjGkof7f.js} +4 -4
  89. package/src/assets/web-panel/assets/{WebAuthn-XLeO6xIB.js → WebAuthn-2Zfcu55P.js} +4 -4
  90. package/src/assets/web-panel/assets/{WorkflowEditor-De_dgDAG.js → WorkflowEditor-B9eZ8UxZ.js} +1 -1
  91. package/src/assets/web-panel/assets/{chat-CI19R_Sk.js → chat-CQNfD-YO.js} +1 -1
  92. package/src/assets/web-panel/assets/{colors-DsYTOYN3.js → colors-D4usyFT2.js} +1 -1
  93. package/src/assets/web-panel/assets/{compact-item-CM3-t_Qr.js → compact-item-s4TpjvjX.js} +1 -1
  94. package/src/assets/web-panel/assets/{createContext-BjxlBRZv.js → createContext-BRCSvYxj.js} +1 -1
  95. package/src/assets/web-panel/assets/devWarning-DKJjSWRn.js +1 -0
  96. package/src/assets/web-panel/assets/{hasIn-RDaWX_4i.js → hasIn-AdkUbkV-.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BN6UPD2E.js → index--00U6vXZ.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CiECJi-Q.js → index-B2V-eKfK.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-CnHH7bnD.js → index-B4JJCfQ2.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CjTrRt13.js → index-BIoG5yYf.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-Dxge-xWl.js → index-BMcimU-2.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-9R6BxAr0.js → index-BPhkFZ1I.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BHNYPO0b.js → index-BQ3DXBtD.js} +3 -3
  104. package/src/assets/web-panel/assets/{index-Cpqm1qfU.js → index-Bad4VNvz.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-B9O9YyWE.js → index-BgiXR_-_.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-B5REnKt8.js → index-BtobShro.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-D6sm5-Xq.js → index-Bw2MEnUk.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DcPFB8qJ.js → index-C1mJtE6q.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-BKJr-TZp.js → index-C484EJiS.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Drlnwr8F.js → index-C5KAQFPQ.js} +1 -1
  111. package/src/assets/web-panel/assets/index-C61cnl3K.js +1 -0
  112. package/src/assets/web-panel/assets/{index-Dsij_KsN.js → index-C7Y8Aluc.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-IeiL9RKc.js → index-CCsM_Ybx.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-B-Z8eFUJ.js → index-CJCFe2Qf.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CyOGN6a5.js → index-CJVEOa4i.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-B0PMlbMs.js → index-CJdQrZth.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-nAH87mQP.js → index-CKC1t3Ic.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BGqqJfL0.js → index-CQhAVU5t.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-Cd9OJhHG.js → index-CYdoQsa1.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-D0zcy54x.js → index-Cduu2Hhr.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DIUnNOjG.js → index-CkwiSLhU.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CVQMeiwH.js → index-Cvyt-zhm.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BlT2VAEK.js → index-D2GjI2oe.js} +1 -1
  124. package/src/assets/web-panel/assets/index-D4XFHxBr.js +1 -0
  125. package/src/assets/web-panel/assets/{index-C0yx-jtQ.js → index-DARsAyUp.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-Bi46Xu4u.js → index-DVKfQ0Ux.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-Cd3euP_4.js → index-DZT36ZYq.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BCnZyIMA.js → index-D_XBHopw.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-C4gkzxkw.js → index-DdCB70SS.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-B7WBt_4T.js → index-DzRjHxEv.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-DX7tuWVJ.js → index-MMN9V6JF.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DoQA0-52.js → index-RfMr79MW.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-DXXtGMUJ.js → index-_IRVsV9X.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-pPL66J85.js → index-nXyk8GZ9.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-DyIWssPC.js → index-s_buFMEG.js} +1 -1
  136. package/src/assets/web-panel/assets/{initDefaultProps-BTL88of4.js → initDefaultProps-Blmpk7HL.js} +1 -1
  137. package/src/assets/web-panel/assets/{motion-BUB2pXwB.js → motion-DPBJMv1n.js} +1 -1
  138. package/src/assets/web-panel/assets/{move-egCkkOMm.js → move-ButdzCM7.js} +1 -1
  139. package/src/assets/web-panel/assets/{mtc-parser-DAWhZC8c.js → mtc-parser-cyRC_QCe.js} +1 -1
  140. package/src/assets/web-panel/assets/{omit-CvOxe_6d.js → omit-1epSV7hz.js} +1 -1
  141. package/src/assets/web-panel/assets/{pickAttrs-DZUSLZ5Z.js → pickAttrs-DuPY8xJs.js} +1 -1
  142. package/src/assets/web-panel/assets/{placementArrow-BERxGNMY.js → placementArrow-6XZqarhe.js} +1 -1
  143. package/src/assets/web-panel/assets/{responsiveObserve-DZuDfZ9n.js → responsiveObserve-B40pXBWM.js} +1 -1
  144. package/src/assets/web-panel/assets/{slide-DO756sgI.js → slide-jbZ9Wu4n.js} +1 -1
  145. package/src/assets/web-panel/assets/{statusUtils-BRQlIz28.js → statusUtils-BKQQcVy4.js} +1 -1
  146. package/src/assets/web-panel/assets/{styleChecker-DCSfdybl.js → styleChecker-NiKfWjUT.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFlexGapSupport-LD8dWVve.js → useFlexGapSupport-bQUCvPeb.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFs-BX9uW2LK.js → useFs-CUGji7ph.js} +1 -1
  149. package/src/assets/web-panel/assets/{usePersonalDataHub-BPSlPuHU.js → usePersonalDataHub-4veyN2N2.js} +1 -1
  150. package/src/assets/web-panel/assets/{vnode-BmOILC9V.js → vnode-1-nLug-Z.js} +1 -1
  151. package/src/assets/web-panel/assets/{zoom-1iKowKGg.js → zoom-dhCeRDMo.js} +1 -1
  152. package/src/assets/web-panel/index.html +1 -1
  153. package/src/command-help-index.json +3 -3
  154. package/src/commands/cowork.js +174 -19
  155. package/src/commands/permissions.js +240 -16
  156. package/src/commands/plugin.js +1293 -56
  157. package/src/commands/session-location.js +276 -0
  158. package/src/commands/session.js +2 -0
  159. package/src/data/changelog.json +15 -2
  160. package/src/gateways/ws/action-protocol.js +35 -10
  161. package/src/gateways/ws/remote-session-protocol.js +24 -1
  162. package/src/gateways/ws/ws-agent-handler.js +12 -0
  163. package/src/gateways/ws/ws-server.js +48 -12
  164. package/src/harness/jsonl-session-store.js +341 -24
  165. package/src/harness/mcp-client.js +8 -1
  166. package/src/harness/remote-session-audit.js +1 -0
  167. package/src/harness/remote-session-crypto.js +210 -2
  168. package/src/harness/remote-session-registry.js +159 -6
  169. package/src/harness/session-list-index.js +233 -14
  170. package/src/lib/agent-authority.js +6 -0
  171. package/src/lib/background-agent-keeper-client.js +248 -0
  172. package/src/lib/background-agent-keeper-protocol.js +147 -0
  173. package/src/lib/background-agent-supervisor.js +520 -40
  174. package/src/lib/background-interaction-resolver.js +12 -0
  175. package/src/lib/background-turn-bootstrap-protocol.js +126 -0
  176. package/src/lib/cowork-workflow.js +336 -16
  177. package/src/lib/dynamic-workflow-facade.js +648 -0
  178. package/src/lib/execution-location-contract.js +551 -0
  179. package/src/lib/execution-location-runtime.js +130 -0
  180. package/src/lib/ide-context.js +94 -6
  181. package/src/lib/mcp-stdio-package-materialization.js +166 -14
  182. package/src/lib/packer/pkg-config-generator.js +2 -0
  183. package/src/lib/permission-authority.js +77 -0
  184. package/src/lib/permission-side-effect-center.js +495 -0
  185. package/src/lib/plugin-runtime/install.js +514 -13
  186. package/src/lib/plugin-runtime/marketplace-artifact-readback.js +900 -0
  187. package/src/lib/plugin-runtime/marketplace-catalog.js +1181 -0
  188. package/src/lib/plugin-runtime/marketplace-impact.js +408 -0
  189. package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +1567 -0
  190. package/src/lib/plugin-security.js +60 -3
  191. package/src/lib/process-execution-broker/index.js +1095 -57
  192. package/src/lib/process-execution-broker/linux-bwrap-descriptor-launch.js +375 -0
  193. package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +90 -16
  194. package/src/lib/process-execution-broker/linux-generic-bwrap.js +159 -18
  195. package/src/lib/process-execution-broker/macos-mcp-launcher-contract.js +278 -0
  196. package/src/lib/process-execution-broker/macos-mcp-launcher-protocol.json +23 -0
  197. package/src/lib/process-execution-broker/macos-mcp-launcher.c +1497 -0
  198. package/src/lib/process-execution-broker/mcp-fd-entry-bootstrap.js +37 -0
  199. package/src/lib/process-execution-broker/platform-sandbox.js +2330 -279
  200. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  201. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  202. package/src/lib/process-execution-broker/windows-sandbox.cs +50 -4
  203. package/src/lib/public-ide-capability-manifest.js +3 -0
  204. package/src/lib/remote-approval-bridge.js +123 -17
  205. package/src/lib/remote-membership-authority.js +632 -0
  206. package/src/lib/remote-membership-coordinator.js +2409 -0
  207. package/src/lib/remote-membership-host-store.js +1750 -0
  208. package/src/lib/scoped-permission-store.js +369 -0
  209. package/src/lib/session-anti-rollback-anchor.js +262 -5
  210. package/src/lib/sub-agent-context.js +4 -0
  211. package/src/lib/workflow-definition-contract.js +149 -0
  212. package/src/repl/agent-repl.js +41 -7
  213. package/src/repl/chat-repl.js +2 -0
  214. package/src/repl/clipboard-image.js +735 -16
  215. package/src/repl/ide-status.js +1 -1
  216. package/src/repl/prompt-interactions.js +59 -6
  217. package/src/runtime/agent-core.js +83 -3
  218. package/src/runtime/headless-runner.js +30 -25
  219. package/src/runtime/headless-stream.js +32 -25
  220. package/src/workers/background-agent-keeper.js +498 -0
  221. package/src/workers/background-agent-worker.js +358 -13
  222. package/src/workers/background-turn-bootstrap.js +143 -0
  223. package/src/assets/web-panel/assets/MarkdownRenderer-yySN5YNM.js +0 -1
  224. package/src/assets/web-panel/assets/MobileProjects-DlPwcCbq.js +0 -1
  225. package/src/assets/web-panel/assets/Projects-CMolGhae.js +0 -1
  226. package/src/assets/web-panel/assets/devWarning-S1ld2LwU.js +0 -1
  227. package/src/assets/web-panel/assets/index-Drz6yq0m.js +0 -1
  228. package/src/assets/web-panel/assets/index-uWiUs7S_.js +0 -1
@@ -0,0 +1,551 @@
1
+ import {
2
+ EXECUTION_LOCATION,
3
+ clampPermissionsForLocation,
4
+ normalizeExecutionLocation,
5
+ redactCredentialRefs,
6
+ } from "./execution-location.js";
7
+
8
+ export const EXECUTION_LOCATION_BINDING_SCHEMA =
9
+ "cc-execution-location-binding/v1";
10
+ export const EXECUTION_LOCATION_CATALOG_SCHEMA =
11
+ "cc-execution-location-catalog/v1";
12
+ export const EXECUTION_LOCATION_HANDOFF_FACTS_SCHEMA =
13
+ "cc-execution-location-handoff-facts/v1";
14
+ export const EXECUTION_LOCATION_HANDOFF_SCHEMA =
15
+ "cc-execution-location-handoff/v1";
16
+
17
+ const FORBIDDEN_SECRET_KEYS = new Set([
18
+ "apikey",
19
+ "credentialvalue",
20
+ "password",
21
+ "privatekey",
22
+ "secret",
23
+ "token",
24
+ "value",
25
+ ]);
26
+ const NETWORK_POLICIES = new Set([
27
+ "offline",
28
+ "restricted",
29
+ "unrestricted",
30
+ "unknown",
31
+ ]);
32
+ const SANDBOX_STRENGTHS = new Set(["strong", "partial", "none", "unknown"]);
33
+ const DATA_BOUNDARY_KINDS = new Set([
34
+ "working-directory",
35
+ "repository",
36
+ "declared",
37
+ "unknown",
38
+ ]);
39
+ const HANDOFF_STRATEGIES = new Set(["commit", "stash", "patch", "none"]);
40
+ const CREDENTIAL_SOURCES = new Set([
41
+ "config",
42
+ "env",
43
+ "environment",
44
+ "keychain",
45
+ "local-provider",
46
+ "managed-secret",
47
+ "none",
48
+ "not-observed",
49
+ "unknown",
50
+ ]);
51
+
52
+ function stringValue(value, { max = 256, nullable = true } = {}) {
53
+ if (value == null && nullable) return null;
54
+ if (typeof value !== "string") throw new TypeError("expected a string");
55
+ const output = value.trim();
56
+ if (!output || output.length > max || /[\u0000-\u001f\u007f]/u.test(output)) {
57
+ throw new TypeError(
58
+ "string is empty, too long, or contains control characters",
59
+ );
60
+ }
61
+ return output;
62
+ }
63
+
64
+ function safeString(value, options) {
65
+ try {
66
+ return stringValue(value, options);
67
+ } catch {
68
+ return null;
69
+ }
70
+ }
71
+
72
+ function enumValue(value, allowed, fallback = "unknown") {
73
+ const normalized = safeString(value)?.toLowerCase();
74
+ return allowed.has(normalized) ? normalized : fallback;
75
+ }
76
+
77
+ function containsForbiddenSecretMaterial(value, seen = new Set()) {
78
+ if (!value || typeof value !== "object") return false;
79
+ if (seen.has(value)) return true;
80
+ seen.add(value);
81
+ if (Array.isArray(value)) {
82
+ return value.some((item) => containsForbiddenSecretMaterial(item, seen));
83
+ }
84
+ for (const [key, child] of Object.entries(value)) {
85
+ if (FORBIDDEN_SECRET_KEYS.has(key.toLowerCase()) && child != null) {
86
+ return true;
87
+ }
88
+ if (containsForbiddenSecretMaterial(child, seen)) return true;
89
+ }
90
+ return false;
91
+ }
92
+
93
+ function normalizeNames(values, { max = 64 } = {}) {
94
+ const output = [];
95
+ for (const value of Array.isArray(values) ? values : []) {
96
+ const name = safeString(value, { max });
97
+ if (name && /^[A-Za-z0-9_.:/@+-]+$/u.test(name) && !output.includes(name)) {
98
+ output.push(name);
99
+ }
100
+ }
101
+ return output.sort();
102
+ }
103
+
104
+ function normalizeDataBoundary(value) {
105
+ const input = value && typeof value === "object" ? value : {};
106
+ return {
107
+ kind: enumValue(input.kind, DATA_BOUNDARY_KINDS),
108
+ root: safeString(input.root, { max: 4096 }),
109
+ };
110
+ }
111
+
112
+ function normalizeGitSource(value) {
113
+ const input = value && typeof value === "object" ? value : {};
114
+ return {
115
+ root: safeString(input.root, { max: 4096 }),
116
+ head: safeString(input.head, { max: 512 }),
117
+ commit: safeString(input.commit, { max: 128 }),
118
+ };
119
+ }
120
+
121
+ function normalizeCredentials(value) {
122
+ if (containsForbiddenSecretMaterial(value)) {
123
+ throw new TypeError(
124
+ "credential values are forbidden in execution-location data",
125
+ );
126
+ }
127
+ return redactCredentialRefs(value).map((credential) =>
128
+ Object.freeze({
129
+ name: safeString(credential.name),
130
+ source: enumValue(credential.source, CREDENTIAL_SOURCES),
131
+ scope: safeString(credential.scope),
132
+ }),
133
+ );
134
+ }
135
+
136
+ export function createExecutionLocationBinding(input = {}) {
137
+ if (!input || typeof input !== "object" || Array.isArray(input)) {
138
+ throw new TypeError("execution location binding input must be an object");
139
+ }
140
+ if (containsForbiddenSecretMaterial(input)) {
141
+ throw new TypeError(
142
+ "secret material is forbidden in execution-location data",
143
+ );
144
+ }
145
+ const location = normalizeExecutionLocation(input.location);
146
+ const requestedPermissions =
147
+ input.permissions && typeof input.permissions === "object"
148
+ ? input.permissions
149
+ : {};
150
+ const permissionGrant = clampPermissionsForLocation(
151
+ location,
152
+ requestedPermissions,
153
+ );
154
+ const cwd = safeString(input.source?.cwd, { max: 4096 });
155
+ const git = normalizeGitSource(input.source?.git);
156
+ const boundary = normalizeDataBoundary(input.policy?.dataBoundary);
157
+ return Object.freeze({
158
+ schema: EXECUTION_LOCATION_BINDING_SCHEMA,
159
+ location,
160
+ observedAt: safeString(input.observedAt, { max: 64 }),
161
+ observed: input.observed === true,
162
+ signals: Object.freeze(normalizeNames(input.signals)),
163
+ source: Object.freeze({ cwd, git: Object.freeze(git) }),
164
+ runtime: Object.freeze({
165
+ platform: safeString(input.runtime?.platform, { max: 64 }),
166
+ arch: safeString(input.runtime?.arch, { max: 64 }),
167
+ nodeVersion: safeString(input.runtime?.nodeVersion, { max: 64 }),
168
+ tools: Object.freeze(normalizeNames(input.runtime?.tools)),
169
+ }),
170
+ model: Object.freeze({
171
+ provider: safeString(input.model?.provider),
172
+ name: safeString(input.model?.name),
173
+ credentialSource: enumValue(
174
+ input.model?.credentialSource,
175
+ CREDENTIAL_SOURCES,
176
+ "not-observed",
177
+ ),
178
+ }),
179
+ credentials: Object.freeze(normalizeCredentials(input.credentials)),
180
+ permissions: Object.freeze({
181
+ status:
182
+ input.permissions?.status === "declared" ? "declared" : "not-observed",
183
+ ...permissionGrant,
184
+ }),
185
+ policy: Object.freeze({
186
+ network: enumValue(input.policy?.network, NETWORK_POLICIES),
187
+ sandbox: enumValue(input.policy?.sandbox, SANDBOX_STRENGTHS),
188
+ dataBoundary: Object.freeze(boundary),
189
+ }),
190
+ extension:
191
+ location === EXECUTION_LOCATION.CONTAINER ? "chainlesschain" : null,
192
+ controlPlane: Object.freeze({
193
+ remoteControl: "controls-local-execution-only",
194
+ }),
195
+ });
196
+ }
197
+
198
+ export function normalizeExecutionLocationBinding(value) {
199
+ if (value?.schema !== EXECUTION_LOCATION_BINDING_SCHEMA) {
200
+ throw new TypeError(
201
+ `execution location binding must use ${EXECUTION_LOCATION_BINDING_SCHEMA}`,
202
+ );
203
+ }
204
+ return createExecutionLocationBinding(value);
205
+ }
206
+
207
+ const LOCATION_PROFILES = Object.freeze({
208
+ [EXECUTION_LOCATION.LOCAL]: {
209
+ label: "Local",
210
+ executor: "local-process",
211
+ launch: "available",
212
+ resume: "available",
213
+ startup: "immediate",
214
+ continuity: "host-process-dependent",
215
+ cost: "local-resource",
216
+ connectors: ["local-files", "local-git"],
217
+ },
218
+ [EXECUTION_LOCATION.WSL]: {
219
+ label: "WSL",
220
+ executor: "ambient-only",
221
+ launch: "not-implemented",
222
+ resume: "not-implemented",
223
+ startup: "requires-existing-wsl-session",
224
+ continuity: "wsl-host-dependent",
225
+ cost: "local-resource",
226
+ connectors: ["wsl-files", "wsl-git"],
227
+ },
228
+ [EXECUTION_LOCATION.SSH]: {
229
+ label: "SSH",
230
+ executor: "ssh-adapter",
231
+ launch: "requires-configuration",
232
+ resume: "requires-configuration",
233
+ startup: "target-and-auth-required",
234
+ continuity: "remote-host-dependent",
235
+ cost: "remote-host-dependent",
236
+ connectors: ["ssh"],
237
+ },
238
+ [EXECUTION_LOCATION.CONTAINER]: {
239
+ label: "Container",
240
+ executor: "docker-adapter",
241
+ launch: "requires-configuration",
242
+ resume: "requires-configuration",
243
+ startup: "image-and-runtime-required",
244
+ continuity: "container-lifecycle-dependent",
245
+ cost: "runtime-dependent",
246
+ connectors: ["docker"],
247
+ extension: "chainlesschain",
248
+ },
249
+ [EXECUTION_LOCATION.CLOUD]: {
250
+ label: "Cloud",
251
+ executor: "self-hosted-handoff",
252
+ launch: "requires-configuration",
253
+ resume: "not-implemented",
254
+ startup: "provider-and-auth-required",
255
+ continuity: "provider-dependent",
256
+ cost: "provider-dependent",
257
+ connectors: ["self-hosted-cloud-handoff"],
258
+ },
259
+ });
260
+
261
+ function catalogEntry(location, current) {
262
+ const profile = LOCATION_PROFILES[location];
263
+ const isCurrent = current.location === location;
264
+ return Object.freeze({
265
+ location,
266
+ label: profile.label,
267
+ availability: isCurrent
268
+ ? "current"
269
+ : profile.launch === "not-implemented"
270
+ ? "unavailable"
271
+ : "requires-configuration",
272
+ current: isCurrent,
273
+ extension: profile.extension || null,
274
+ source: isCurrent ? current.source : null,
275
+ supportedTools: isCurrent ? current.runtime.tools : Object.freeze([]),
276
+ model: isCurrent
277
+ ? current.model
278
+ : Object.freeze({
279
+ provider: null,
280
+ name: null,
281
+ credentialSource: "unknown",
282
+ }),
283
+ permissions: isCurrent
284
+ ? current.permissions
285
+ : Object.freeze({ status: "unknown" }),
286
+ policy: isCurrent
287
+ ? current.policy
288
+ : Object.freeze({
289
+ network: "unknown",
290
+ sandbox: "unknown",
291
+ dataBoundary: Object.freeze({ kind: "unknown", root: null }),
292
+ }),
293
+ startup: profile.startup,
294
+ continuity: profile.continuity,
295
+ cost: profile.cost,
296
+ connectors: Object.freeze([...profile.connectors]),
297
+ capabilities: Object.freeze({
298
+ execute: isCurrent ? "available" : profile.launch,
299
+ launch: profile.launch,
300
+ resume: profile.resume,
301
+ handoffPreview: "available",
302
+ }),
303
+ mechanism: profile.executor,
304
+ });
305
+ }
306
+
307
+ export function buildExecutionLocationCatalog(binding) {
308
+ const current = normalizeExecutionLocationBinding(binding);
309
+ const locations = [
310
+ EXECUTION_LOCATION.LOCAL,
311
+ EXECUTION_LOCATION.WSL,
312
+ EXECUTION_LOCATION.SSH,
313
+ EXECUTION_LOCATION.CONTAINER,
314
+ EXECUTION_LOCATION.CLOUD,
315
+ ];
316
+ return Object.freeze({
317
+ schema: EXECUTION_LOCATION_CATALOG_SCHEMA,
318
+ currentLocation: current.location,
319
+ currentBinding: current,
320
+ controlPlane: Object.freeze({
321
+ remoteControl: Object.freeze({
322
+ executionLocation: false,
323
+ meaning:
324
+ "remote UI control of execution that remains on the local host",
325
+ }),
326
+ }),
327
+ locations: Object.freeze(
328
+ locations.map((location) => catalogEntry(location, current)),
329
+ ),
330
+ });
331
+ }
332
+
333
+ function pushUnique(output, value) {
334
+ if (!output.includes(value)) output.push(value);
335
+ }
336
+
337
+ function validDigest(value) {
338
+ return typeof value === "string" && /^sha256:[a-f0-9]{64}$/u.test(value);
339
+ }
340
+
341
+ function validReference(value) {
342
+ return (
343
+ typeof value === "string" &&
344
+ /^[A-Za-z0-9][A-Za-z0-9._/@:+-]{2,255}$/u.test(value)
345
+ );
346
+ }
347
+
348
+ export function buildExecutionLocationHandoffPreview(input = {}) {
349
+ const source = normalizeExecutionLocationBinding(input.sourceBinding);
350
+ const target = normalizeExecutionLocation(input.target);
351
+ const facts =
352
+ input.facts && typeof input.facts === "object" ? input.facts : {};
353
+ const expectedAuthority =
354
+ input.sourceAuthority && typeof input.sourceAuthority === "object"
355
+ ? input.sourceAuthority
356
+ : {};
357
+ const blockers = [];
358
+ const warnings = [];
359
+
360
+ if (facts.schema !== EXECUTION_LOCATION_HANDOFF_FACTS_SCHEMA) {
361
+ pushUnique(blockers, "handoff-facts-schema-invalid");
362
+ }
363
+ if (target === EXECUTION_LOCATION.UNKNOWN) {
364
+ pushUnique(blockers, "target-location-unknown");
365
+ }
366
+ if (containsForbiddenSecretMaterial(facts)) {
367
+ pushUnique(blockers, "credential-value-present");
368
+ }
369
+
370
+ const factsAuthority =
371
+ facts.authority && typeof facts.authority === "object"
372
+ ? facts.authority
373
+ : {};
374
+ const expectedSessionId = safeString(expectedAuthority.sessionId);
375
+ const expectedHeadHash = safeString(expectedAuthority.headHash, { max: 64 });
376
+ const expectedEventCount = Number(expectedAuthority.eventCount);
377
+ const factsSessionId = safeString(factsAuthority.sessionId);
378
+ const factsHeadHash = safeString(factsAuthority.headHash, { max: 64 });
379
+ const factsEventCount = Number(factsAuthority.eventCount);
380
+ const expectedAuthorityValid =
381
+ expectedSessionId != null &&
382
+ /^[a-f0-9]{64}$/u.test(expectedHeadHash || "") &&
383
+ Number.isSafeInteger(expectedEventCount) &&
384
+ expectedEventCount > 0;
385
+ const factsAuthorityValid =
386
+ factsSessionId != null &&
387
+ /^[a-f0-9]{64}$/u.test(factsHeadHash || "") &&
388
+ Number.isSafeInteger(factsEventCount) &&
389
+ factsEventCount > 0;
390
+ if (!expectedAuthorityValid || !factsAuthorityValid) {
391
+ pushUnique(blockers, "session-authority-evidence-missing");
392
+ } else if (
393
+ factsSessionId !== expectedSessionId ||
394
+ factsHeadHash !== expectedHeadHash ||
395
+ factsEventCount !== expectedEventCount
396
+ ) {
397
+ pushUnique(blockers, "session-authority-evidence-mismatch");
398
+ }
399
+
400
+ const targetEvidence =
401
+ facts.target && typeof facts.target === "object" ? facts.target : {};
402
+ const crossingLocation = target !== source.location;
403
+ if (
404
+ crossingLocation &&
405
+ (targetEvidence.configured !== true ||
406
+ !validReference(targetEvidence.evidenceId))
407
+ ) {
408
+ pushUnique(blockers, "target-configuration-evidence-missing");
409
+ }
410
+ const targetNetwork = enumValue(
411
+ targetEvidence.networkPolicy,
412
+ NETWORK_POLICIES,
413
+ );
414
+ const targetSandbox = enumValue(
415
+ targetEvidence.sandboxStrength,
416
+ SANDBOX_STRENGTHS,
417
+ );
418
+ const targetBoundary = normalizeDataBoundary(targetEvidence.dataBoundary);
419
+ if (crossingLocation && targetNetwork === "unknown") {
420
+ pushUnique(blockers, "target-network-policy-unknown");
421
+ }
422
+ if (crossingLocation && targetSandbox === "unknown") {
423
+ pushUnique(blockers, "target-sandbox-strength-unknown");
424
+ }
425
+ if (crossingLocation && targetBoundary.kind === "unknown") {
426
+ pushUnique(blockers, "target-data-boundary-unknown");
427
+ }
428
+
429
+ const git = facts.git && typeof facts.git === "object" ? facts.git : {};
430
+ const gitStatus = ["clean", "dirty"].includes(git.status)
431
+ ? git.status
432
+ : "unknown";
433
+ const sourceCommit = safeString(source.source.git.commit, { max: 128 });
434
+ const baseCommit = safeString(git.baseCommit, { max: 128 });
435
+ const strategy = HANDOFF_STRATEGIES.has(facts.strategy?.kind)
436
+ ? facts.strategy.kind
437
+ : "none";
438
+ const strategyRef = safeString(facts.strategy?.ref, { max: 256 });
439
+ const strategyDigest = safeString(facts.strategy?.artifactDigest, {
440
+ max: 80,
441
+ });
442
+ if (gitStatus === "unknown") {
443
+ pushUnique(blockers, "git-state-unknown");
444
+ } else if (!sourceCommit || baseCommit !== sourceCommit) {
445
+ pushUnique(blockers, "git-base-commit-mismatch");
446
+ } else if (gitStatus === "clean") {
447
+ if (strategy !== "commit" || strategyRef !== sourceCommit) {
448
+ pushUnique(blockers, "clean-worktree-commit-missing");
449
+ }
450
+ } else if (!(
451
+ (strategy === "stash" && validReference(strategyRef)) ||
452
+ (strategy === "patch" && validDigest(strategyDigest))
453
+ )) {
454
+ pushUnique(blockers, "dirty-worktree-without-stash-or-patch");
455
+ }
456
+
457
+ if (facts.summary?.included !== true || !validDigest(facts.summary?.digest)) {
458
+ pushUnique(blockers, "session-summary-missing");
459
+ }
460
+ if (
461
+ facts.permissions?.included !== true ||
462
+ !validDigest(facts.permissions?.digest)
463
+ ) {
464
+ pushUnique(blockers, "permission-handoff-missing");
465
+ }
466
+
467
+ const artifacts = [];
468
+ if (!Array.isArray(facts.artifacts)) {
469
+ pushUnique(blockers, "artifact-inventory-missing");
470
+ }
471
+ for (const item of Array.isArray(facts.artifacts) ? facts.artifacts : []) {
472
+ const name = safeString(item?.name);
473
+ const digest = safeString(item?.digest, { max: 80 });
474
+ if (name && validDigest(digest)) {
475
+ artifacts.push(Object.freeze({ name, digest }));
476
+ } else pushUnique(blockers, "artifact-evidence-invalid");
477
+ }
478
+ if (
479
+ strategy === "patch" &&
480
+ validDigest(strategyDigest) &&
481
+ !artifacts.some((artifact) => artifact.digest === strategyDigest)
482
+ ) {
483
+ pushUnique(blockers, "patch-artifact-not-in-inventory");
484
+ }
485
+ if (!Array.isArray(facts.credentials)) {
486
+ pushUnique(blockers, "credential-inventory-missing");
487
+ }
488
+ const credentials = containsForbiddenSecretMaterial(facts.credentials)
489
+ ? []
490
+ : normalizeCredentials(facts.credentials);
491
+ const requiredCapabilities = normalizeNames(facts.requiredCapabilities);
492
+ const evidencedCapabilities = normalizeNames(targetEvidence.capabilities);
493
+ for (const capability of requiredCapabilities) {
494
+ if (!evidencedCapabilities.includes(capability)) {
495
+ pushUnique(blockers, `target-capability-unavailable:${capability}`);
496
+ }
497
+ }
498
+ if (credentials.length > 0) {
499
+ warnings.push(
500
+ "credential references require target-side re-authorization; values are never transferred",
501
+ );
502
+ }
503
+
504
+ return Object.freeze({
505
+ schema: EXECUTION_LOCATION_HANDOFF_SCHEMA,
506
+ allowed: blockers.length === 0,
507
+ source: Object.freeze({
508
+ location: source.location,
509
+ sessionBindingSchema: source.schema,
510
+ authority: Object.freeze({
511
+ sessionId: expectedSessionId,
512
+ headHash: expectedHeadHash,
513
+ eventCount: Number.isSafeInteger(expectedEventCount)
514
+ ? expectedEventCount
515
+ : null,
516
+ }),
517
+ git: source.source.git,
518
+ policy: source.policy,
519
+ }),
520
+ target: Object.freeze({
521
+ location: target,
522
+ configured: targetEvidence.configured === true,
523
+ evidenceId: safeString(targetEvidence.evidenceId),
524
+ networkPolicy: targetNetwork,
525
+ sandboxStrength: targetSandbox,
526
+ dataBoundary: Object.freeze(targetBoundary),
527
+ capabilities: Object.freeze(evidencedCapabilities),
528
+ evidenceAuthority: "operator-supplied-facts",
529
+ }),
530
+ transfer: Object.freeze({
531
+ git: Object.freeze({
532
+ status: gitStatus,
533
+ baseCommit,
534
+ strategy,
535
+ ref: strategyRef,
536
+ artifactDigest: strategyDigest,
537
+ }),
538
+ summaryDigest: validDigest(facts.summary?.digest)
539
+ ? facts.summary.digest
540
+ : null,
541
+ permissionDigest: validDigest(facts.permissions?.digest)
542
+ ? facts.permissions.digest
543
+ : null,
544
+ artifacts: Object.freeze(artifacts),
545
+ credentialRefs: Object.freeze(credentials),
546
+ credentialValuesTransferred: false,
547
+ }),
548
+ blockers: Object.freeze(blockers),
549
+ warnings: Object.freeze(warnings),
550
+ });
551
+ }
@@ -0,0 +1,130 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { createExecutionLocationBinding } from "./execution-location-contract.js";
4
+ import { detectAmbientLocation } from "./execution-location.js";
5
+
6
+ const LOCATION_SIGNAL_NAMES = Object.freeze([
7
+ "CODESPACES",
8
+ "GITHUB_CODESPACE_TOKEN",
9
+ "SSH_CONNECTION",
10
+ "SSH_CLIENT",
11
+ "SSH_TTY",
12
+ "container",
13
+ "KUBERNETES_SERVICE_HOST",
14
+ "WSL_DISTRO_NAME",
15
+ "WSL_INTEROP",
16
+ ]);
17
+
18
+ function readSmallUtf8(runtimeFs, filePath, maxBytes = 4096) {
19
+ try {
20
+ const stat = runtimeFs.lstatSync(filePath);
21
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > maxBytes) {
22
+ return null;
23
+ }
24
+ return runtimeFs.readFileSync(filePath, "utf8");
25
+ } catch {
26
+ return null;
27
+ }
28
+ }
29
+
30
+ function resolveGitDirectory(runtimeFs, markerPath) {
31
+ try {
32
+ const stat = runtimeFs.lstatSync(markerPath);
33
+ if (stat.isSymbolicLink()) return null;
34
+ if (stat.isDirectory()) return markerPath;
35
+ if (!stat.isFile() || stat.size > 4096) return null;
36
+ const marker = runtimeFs.readFileSync(markerPath, "utf8").trim();
37
+ const match = /^gitdir:\s*(.+)$/iu.exec(marker);
38
+ return match ? path.resolve(path.dirname(markerPath), match[1]) : null;
39
+ } catch {
40
+ return null;
41
+ }
42
+ }
43
+
44
+ function discoverGit(runtimeFs, cwd) {
45
+ let cursor = path.resolve(cwd);
46
+ while (true) {
47
+ const marker = path.join(cursor, ".git");
48
+ const gitDirectory = resolveGitDirectory(runtimeFs, marker);
49
+ if (gitDirectory) {
50
+ const rawHead = readSmallUtf8(
51
+ runtimeFs,
52
+ path.join(gitDirectory, "HEAD"),
53
+ 1024,
54
+ )?.trim();
55
+ let head = null;
56
+ let commit = null;
57
+ if (rawHead && /^[a-f0-9]{40,64}$/iu.test(rawHead)) {
58
+ head = "detached";
59
+ commit = rawHead.toLowerCase();
60
+ } else {
61
+ const match = /^ref:\s*(refs\/[A-Za-z0-9._\/-]+)$/u.exec(rawHead || "");
62
+ if (match && !match[1].includes("..")) {
63
+ head = match[1];
64
+ const loose = readSmallUtf8(
65
+ runtimeFs,
66
+ path.join(gitDirectory, ...match[1].split("/")),
67
+ 256,
68
+ )?.trim();
69
+ if (loose && /^[a-f0-9]{40,64}$/iu.test(loose)) {
70
+ commit = loose.toLowerCase();
71
+ }
72
+ }
73
+ }
74
+ return { root: cursor, head, commit };
75
+ }
76
+ const parent = path.dirname(cursor);
77
+ if (parent === cursor) return { root: null, head: null, commit: null };
78
+ cursor = parent;
79
+ }
80
+ }
81
+
82
+ export function captureAmbientExecutionLocation(options = {}, deps = {}) {
83
+ const runtimeFs = deps.fs || fs;
84
+ const env = deps.env || process.env;
85
+ const cwd = path.resolve(deps.cwd ? deps.cwd() : process.cwd());
86
+ const dockerEnvFileExists = (() => {
87
+ try {
88
+ return runtimeFs.existsSync("/.dockerenv");
89
+ } catch {
90
+ return false;
91
+ }
92
+ })();
93
+ const location = detectAmbientLocation({ env, dockerEnvFileExists });
94
+ const git = discoverGit(runtimeFs, cwd);
95
+ const signals = LOCATION_SIGNAL_NAMES.filter(
96
+ (name) => typeof env[name] === "string" && env[name].trim() !== "",
97
+ );
98
+ const observedAt = deps.now ? deps.now() : new Date().toISOString();
99
+ return createExecutionLocationBinding({
100
+ location,
101
+ observedAt,
102
+ observed: true,
103
+ signals,
104
+ source: { cwd, git },
105
+ runtime: {
106
+ platform: deps.platform || process.platform,
107
+ arch: deps.arch || process.arch,
108
+ nodeVersion: deps.nodeVersion || process.version,
109
+ tools: ["chainlesschain-cli", "node"],
110
+ },
111
+ model: {
112
+ provider: options.provider,
113
+ name: options.model,
114
+ credentialSource: options.credentialSource || "not-observed",
115
+ },
116
+ credentials: options.credentials,
117
+ permissions: {
118
+ status: options.permissions ? "declared" : "not-observed",
119
+ ...(options.permissions || {}),
120
+ },
121
+ policy: {
122
+ network: options.networkPolicy || "unknown",
123
+ sandbox: options.sandboxStrength || "unknown",
124
+ dataBoundary: {
125
+ kind: git.root ? "repository" : "working-directory",
126
+ root: git.root || cwd,
127
+ },
128
+ },
129
+ });
130
+ }