chainlesschain 0.162.162 → 0.162.164

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 (237) hide show
  1. package/package.json +3 -1
  2. package/src/assets/web-panel/assets/{AIOps-ClI2ALgv.js → AIOps-BqRkaHGb.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-BDjRcJaK.js → ActionButton-DWO7OZLC.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-DikSRsaT.js → Analytics-C5oaVezM.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-9mLhMFmz.js → AppLayout-CsUESDoZ.js} +3 -3
  6. package/src/assets/web-panel/assets/{Artifacts-BSr88BrH.js → Artifacts-Dragqu5k.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-CdvyimOF.js → Audit-CQsaHctY.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-D3_hCedh.js → BackgroundAgents-DdG1jNSM.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-Cyvv9RHf.js → Backup-DN6sjK4z.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-BZM14kt8.js → BaseInput-Cxm_ZTCl.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-DrQSokVz.js → Chat-DVXGmA56.js} +6 -6
  12. package/src/assets/web-panel/assets/{ChatBubbleRenderer-HwJR-C6B.js → ChatBubbleRenderer-BdaCL_iE.js} +1 -1
  13. package/src/assets/web-panel/assets/{Checkbox-bFLYeWMV.js → Checkbox-DEc4vD_A.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-7mN7xJXT.js → Codegen-CKiTcv36.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-DAB5ZWm7.js → Col-Br9UUNN0.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-B_1TymaK.js → Community-NeUH_70T.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-Bq1uSWLJ.js → Compact-BqR-z2Df.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-CyiE1jEe.js → Compliance-DcWB_SgZ.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-Cpk0D7vm.js → Cowork-BfhgcudF.js} +2 -2
  20. package/src/assets/web-panel/assets/{Cron-d_Lv3rdB.js → Cron-LaU29LgD.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-DMqhHjMR.js → Crosschain-B2ZB9uwW.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-Br-oPuBw.js → DID-BuHl38A2.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-CfLW_RaP.js → Dashboard-m627yqvZ.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-DZnTOExV.js → Dropdown-C7bxF8F5.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-DHIUHDv1.js → EmailListRenderer-DPLPQzLp.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-Bw3t3myu.js → FamilyGuardDashboard-cOiH6ike.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-D9cpQPAY.js → Federation-Bvkzg88z.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-Jdczr9Mr.js → FormItemContext-BTsiA7h_.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-BT8ZMpC5.js → GenericCardRenderer-BGnVE5qu.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-DjARip2b.js → Git-DS_j6r25.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-BgWbSRcj.js → Governance-CKRG3Rsl.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-CfouJciM.js → Inference-DW8INoNQ.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-50l7mrAr.js → KnowledgeGraph-BhEYeFhC.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-rq50H84B.js → Logs-wqi0uxuR.js} +2 -2
  35. package/src/assets/web-panel/assets/{MarkdownRenderer-DUPIEdQH.js → MarkdownRenderer-DS8dE8ty.js} +1 -1
  36. package/src/assets/web-panel/assets/{Marketplace-BYgPDmHU.js → Marketplace-CMlTuPLT.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-5DVgcFdx.js → McpTools-CSx4m5JJ.js} +3 -3
  38. package/src/assets/web-panel/assets/{Memory-B70LPk7f.js → Memory-vnQCUy-_.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-De8ssA5Y.js → MobileBridge-BV2NA742.js} +1 -1
  40. package/src/assets/web-panel/assets/MobileProjects-Bw0k8e1B.js +1 -0
  41. package/src/assets/web-panel/assets/{Mtc-RJsOTsIA.js → Mtc-CzK_FPB1.js} +2 -2
  42. package/src/assets/web-panel/assets/{MtcAudit-Crh-6BEK.js → MtcAudit-Cb7G9oL3.js} +5 -5
  43. package/src/assets/web-panel/assets/{Multisig-wuoR5l3x.js → Multisig-qJxlUyzr.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-U2Mji4fZ.js → NLProgramming-DqaBJ7Te.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-CdTZAyDH.js → Notes-CwhTJkRi.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-C-FucWE7.js → NotificationSettings-YDs4Fal4.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-DCYFTeaI.js → OrderTableRenderer-CvEALpq7.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-an3OF85L.js → Organization-CEmQm9n8.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-C-1vmYFe.js → Overflow-zby_P_LA.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-Cwh47xKg.js → P2P-DsmDNFNT.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-Dm38GT0k.js → PdhVaultBrowser-FWwFlZGF.js} +3 -3
  52. package/src/assets/web-panel/assets/{Permissions-DS2Y8awD.js → Permissions-DuzQ6me5.js} +4 -4
  53. package/src/assets/web-panel/assets/{PersonalDataHub-BQNziA0I.js → PersonalDataHub-DZbeN613.js} +3 -3
  54. package/src/assets/web-panel/assets/{Pipeline-DF85L1ue.js → Pipeline-CoNSVAUS.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-BuLornF-.js → Privacy-OYJEAaMC.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-C3Y31IwX.js → ProjectInit-CWIapV--.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-BCPiI8aD.js → ProjectSettings-CX8xMxZn.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-BZ6s4k6g.js → Projects-BLCN8YyY.js} +1 -1
  59. package/src/assets/web-panel/assets/{Providers-D3Wp022X.js → Providers-BV_sxp75.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-CUJfQkH4.js → QrScannerModal-BTnRrHRp.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-UAc0EO8l.js → QuickAsk-D1KZg018.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-BaxKupcs.js → Recommend-COm5cuNg.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-C75NNnXZ.js → RemoteSession-0saWEkYI.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-BVXynZAk.js → Reputation-Dr7iKLS2.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-C5MRZ0bi.js → Row-C1vpPBcr.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-DAKkEYka.js → RssFeed-CxlWrtNj.js} +3 -3
  67. package/src/assets/web-panel/assets/{Search-DvWv9YOA.js → Search-BT2V8dPN.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-B5peafW1.js → Security-bm9V3c5k.js} +4 -4
  69. package/src/assets/web-panel/assets/{Services-UQmvPEaG.js → Services-CocH1yyX.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-C3bhWpuF.js → Skeleton-DHItlMdd.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-DfkKf9_H.js → Skills-C59sLc4w.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-DqMSjlBM.js → Sla-Crj4BMc8.js} +1 -1
  73. package/src/assets/web-panel/assets/{SpeechSettings-C-WbxWUX.js → SpeechSettings-DX4KFceY.js} +1 -1
  74. package/src/assets/web-panel/assets/{SyncSettings-CYuHZ4N2.js → SyncSettings-BD_iwQLr.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-CyeAyB9d.js → Tasks-BmCTzYsH.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-BTCeQnpq.js → Templates-BGUaxZYl.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-BifQuA9Y.js → Tenant-BS0tJx2O.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-Bx_9Bocf.js → Terminal--tHSAsld.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-BX0RFCOm.js → TimelineRenderer-D9-MFxS4.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-CGHrCmUS.js → Tokens-CiCB485f.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-DlqaY4SO.js → Trigger-SmCFuW_l.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-DfOmj-ay.js → Trust-DkK3Rqe0.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-B72jH5fE.js → UkeySign-CDM4LGdB.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-BT-63fqv.js → VideoEditing-IDB7DJXt.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-Dsul3sHr.js → Wallet-Bikj5cmt.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-Izkwwdgy.js → WebAuthn-C9abWlAw.js} +2 -2
  87. package/src/assets/web-panel/assets/{WorkflowEditor-D3FHSiH1.js → WorkflowEditor-DrbRKVky.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-CmVz5z3U.js → chat-CccCSDQf.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-CuLgyJBp.js → colors-CXObXLhb.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-Ml1YkXpw.js → compact-item-B5kfYAxC.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-BvjJ48bs.js → createContext-DmiPBfip.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-CvKrADNa.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-DVC0157C.js → hasIn-Q6lYteAc.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-C229ABfy.js → index-25Wlqps4.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-Ck_52dz_.js → index-33U29UNV.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-QXzlT9KD.js → index-4oXBDczR.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-4SBta3d7.js → index-BGYXvMc5.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-B0S8NzO6.js → index-BJCCa0s_.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-DJyN28Et.js → index-BJJ5DhKI.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DC_OI9H2.js → index-BLOzViJ6.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-C_XuRgGn.js → index-BRrbUMoG.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-wvb_FtaV.js → index-BUFpT17Q.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-KMqhcF7l.js → index-BkRDiqGc.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-vG4XSJ1d.js → index-BsfvW6my.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DYXHFr4r.js → index-By-kfPED.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DuGszaWY.js → index-BzFTcQsc.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CXkJH-lK.js → index-C2FXdboq.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-Dt5KMjwJ.js → index-C5XOlTHN.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-4wcgvPoF.js → index-CLhBDS2w.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-C_H_S-DY.js → index-CMq7UeoT.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BydjdZnl.js → index-CVMTWNKl.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-BjHBpRYZ.js → index-Caghi-yL.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-Bzr0rB5T.js → index-CdB6FuSH.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BbPtzB8M.js → index-CoK8-kWQ.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-BUt8kTIB.js → index-CsO3GUAY.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-C_vRgTl9.js → index-CwZBa20Z.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DukDVXCv.js → index-D-kASucw.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BbepULSc.js → index-D8eBw7vW.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-BfuKP4qe.js → index-D9wgifk4.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BiC6dQZG.js → index-DAYCTc07.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CmFNvNLZ.js → index-DF6Q8l2h.js} +1 -1
  122. package/src/assets/web-panel/assets/index-DTdFUWc_.js +1 -0
  123. package/src/assets/web-panel/assets/{index-KjgKdZe-.js → index-DgTLApS9.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-BpFJHiTv.js → index-DgxVJ8pg.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-Cw0Rjy87.js → index-DlJvIqoR.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CFYVQMvu.js → index-Dw4eHfsG.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CudmwNBV.js → index-Rh-ytwow.js} +3 -3
  128. package/src/assets/web-panel/assets/{index-DDGaOWBV.js → index-StAEt2pq.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-D3lD5qap.js → index-bzfw951k.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BzG-x9p4.js → index-fSUMbMvv.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-B_EvG_GW.js → index-tFHy5Wol.js} +1 -1
  132. package/src/assets/web-panel/assets/index-zQ0M_kz-.js +1 -0
  133. package/src/assets/web-panel/assets/{initDefaultProps-BDgd2YZ8.js → initDefaultProps-BNq7X72N.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-ErtrXdYe.js → motion-DOf9viTc.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-_GPPNCgs.js → move-CRHTcW4x.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-DRLL-8V2.js → mtc-parser-Cyoozgm2.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-p86sl023.js → omit-6-TjFNru.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-BTu7cMLH.js → pickAttrs-DlUmO1zi.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-BEKz6Isr.js → placementArrow-CFOL8mIR.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-Ck42c9MP.js → responsiveObserve-BtaFK5zd.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-1CEvuPsB.js → slide-BIbc2bur.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-BDfdx1GJ.js → statusUtils-BXX9d6-w.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-B4K46m5w.js → styleChecker-BGv10Bpn.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-DoIVpJNq.js → useFlexGapSupport-bKnKT8tw.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-DdAWi-ln.js → useFs-FY4IL4jn.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-iUu6k8dx.js → usePersonalDataHub-Bwl9TEgu.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-DZz4R6Tw.js → vnode-BM3OHxAT.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-DXlf9sA3.js → zoom-D1fbFiHB.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/commands/agenda.js +320 -32
  151. package/src/commands/agent.js +105 -11
  152. package/src/commands/context.js +125 -14
  153. package/src/commands/doctor.js +85 -1
  154. package/src/commands/hook.js +181 -7
  155. package/src/commands/plugin.js +456 -1
  156. package/src/commands/review.js +363 -2
  157. package/src/commands/session.js +191 -0
  158. package/src/commands/team.js +19 -1
  159. package/src/data/changelog.json +10 -4
  160. package/src/gateways/ws/remote-session-protocol.js +39 -0
  161. package/src/gateways/ws/session-protocol.js +55 -2
  162. package/src/gateways/ws/ws-agent-handler.js +50 -0
  163. package/src/harness/jsonl-session-store.js +60 -0
  164. package/src/harness/worktree-isolator.js +140 -5
  165. package/src/lib/agent-schedule-store.js +318 -10
  166. package/src/lib/agent-team/team-worktree.js +37 -2
  167. package/src/lib/agent-tool-admission.js +125 -0
  168. package/src/lib/app-preview.js +360 -0
  169. package/src/lib/async-hook-supervisor.cjs +54 -0
  170. package/src/lib/capability-manifest.js +319 -0
  171. package/src/lib/capability-negotiation.js +23 -12
  172. package/src/lib/channels/channel-manager.js +54 -2
  173. package/src/lib/cli-context-engineering.js +9 -2
  174. package/src/lib/context-breakdown.js +116 -0
  175. package/src/lib/diagnostic-bundle.js +230 -0
  176. package/src/lib/doctor-checkup.js +275 -4
  177. package/src/lib/execution-location.js +286 -0
  178. package/src/lib/headless-manifest.js +13 -40
  179. package/src/lib/hook-event-log.cjs +193 -0
  180. package/src/lib/hook-stats-store.cjs +197 -0
  181. package/src/lib/idempotency.js +109 -0
  182. package/src/lib/interaction-adapter.js +34 -4
  183. package/src/lib/json-schema-output.js +46 -12
  184. package/src/lib/json-schema-validate.js +143 -3
  185. package/src/lib/jsonl-session-store.js +1 -0
  186. package/src/lib/lsp/__tests__/lsp-manager.test.js +58 -0
  187. package/src/lib/lsp/lsp-manager.js +56 -0
  188. package/src/lib/monitor-event.js +290 -0
  189. package/src/lib/operation-fingerprint.js +217 -0
  190. package/src/lib/plugin-runtime/bin.js +37 -0
  191. package/src/lib/plugin-runtime/capabilities.js +19 -0
  192. package/src/lib/plugin-runtime/capability-consent.js +203 -0
  193. package/src/lib/plugin-runtime/hooks.js +37 -0
  194. package/src/lib/plugin-runtime/lsp.js +38 -0
  195. package/src/lib/plugin-runtime/mcp.js +40 -0
  196. package/src/lib/plugin-runtime/monitors.js +37 -0
  197. package/src/lib/plugin-runtime/plugin-options.js +151 -0
  198. package/src/lib/plugin-runtime/policy.js +62 -0
  199. package/src/lib/plugin-runtime/scopes.js +20 -4
  200. package/src/lib/pr-automation-policy.js +224 -0
  201. package/src/lib/project-instructions.js +128 -0
  202. package/src/lib/remote-approval-bridge.js +66 -13
  203. package/src/lib/repl-goal.js +132 -0
  204. package/src/lib/repl-rewind.js +153 -0
  205. package/src/lib/review-comment-anchor.js +241 -0
  206. package/src/lib/review-pipeline.js +46 -7
  207. package/src/lib/runtime-checkup.js +221 -0
  208. package/src/lib/schedule-planner.js +17 -1
  209. package/src/lib/secret-scan.js +409 -0
  210. package/src/lib/session-branch.js +0 -0
  211. package/src/lib/settings-hook-events.cjs +13 -0
  212. package/src/lib/settings-loader.cjs +42 -0
  213. package/src/lib/side-effect-ledger-store.js +88 -0
  214. package/src/lib/side-effect-ledger.js +401 -0
  215. package/src/lib/skill-loader.js +32 -0
  216. package/src/lib/skill-path-scope.js +63 -0
  217. package/src/lib/sub-agent-context.js +110 -9
  218. package/src/lib/sub-agent-registry.js +19 -0
  219. package/src/lib/subagent-inheritance.js +112 -0
  220. package/src/lib/telemetry/span-recorder.js +17 -4
  221. package/src/lib/terminal-context.js +195 -0
  222. package/src/lib/turn-binding-store.js +119 -0
  223. package/src/lib/unattended-action-policy.js +182 -0
  224. package/src/lib/worktree-cleanup-safety.js +138 -0
  225. package/src/lib/worktree-isolator.js +8 -0
  226. package/src/lib/worktree-sparse.js +131 -0
  227. package/src/repl/agent-repl.js +280 -30
  228. package/src/repl/permission-tier.js +28 -0
  229. package/src/runtime/agent-core.js +565 -21
  230. package/src/runtime/coding-agent-contract-shared.cjs +60 -1
  231. package/src/runtime/diagnostics.js +60 -0
  232. package/src/runtime/headless-runner.js +393 -1
  233. package/src/runtime/headless-stream.js +60 -1
  234. package/src/assets/web-panel/assets/MobileProjects-D10VISps.js +0 -1
  235. package/src/assets/web-panel/assets/devWarning-DhiGrbsh.js +0 -1
  236. package/src/assets/web-panel/assets/index-B7a1TrU6.js +0 -1
  237. package/src/assets/web-panel/assets/index-C2B1KRja.js +0 -1
@@ -0,0 +1,230 @@
1
+ /**
2
+ * De-identified diagnostic bundle assembler + mandatory secret-scan export gate
3
+ * (IDE gap P1-9 "脱敏诊断包" of CLAUDE_CODE_IDE_INCREMENTAL_GAP_ANALYSIS_2026-
4
+ * 07-13.md).
5
+ *
6
+ * When an IDE session misbehaves, a one-click diagnostic export is the fastest
7
+ * path to a fix — but a naive dump of "everything about the session" leaks
8
+ * source, keys and terminal output. The gap doc pins the contract exactly: a
9
+ * bundle carries version, platform, capability, connection state, redaction
10
+ * events, trace, reconnect history, and process/port/lockfile/worktree
11
+ * summaries; it does NOT carry source code, API keys, cookies, full environment
12
+ * variables, or unpermitted terminal output; and "导出前必须运行 Secret Scan".
13
+ *
14
+ * This module assembles that bundle from caller-supplied signals and runs the
15
+ * §8.1 recall-first scanner ([[secret-scan.js]]) as a fail-closed export gate.
16
+ * It reuses the canonical capability projection ([[capability-manifest.js]]) so
17
+ * the bundle never invents a second capability truth.
18
+ *
19
+ * Pure: no fs / process / clock / RNG — the caller collects the raw signals
20
+ * (which processes, which ports, the env object) and this module shapes, de-
21
+ * identifies and gates them. Timestamps, if any, are passed in.
22
+ */
23
+
24
+ import { redactSecrets, scanSecrets, SURFACES } from "./secret-scan.js";
25
+ import { buildCompatFixture } from "./capability-manifest.js";
26
+ import { isSecretEnvName } from "./credential-guard.js";
27
+
28
+ /** The categories deliberately EXCLUDED from every bundle (never assembled). */
29
+ export const EXCLUDED_BY_DEFAULT = Object.freeze([
30
+ "source code body",
31
+ "API keys / tokens",
32
+ "cookies",
33
+ "full environment variable values",
34
+ "unpermitted terminal output",
35
+ ]);
36
+
37
+ /**
38
+ * Summarize an environment WITHOUT any values: variable NAMES only, with the
39
+ * secret-named ones flagged (via isSecretEnvName). Honors the contract "默认不
40
+ * 包含完整环境变量" — a name is metadata, a value may be a credential.
41
+ * @param {object} env
42
+ * @returns {{count:number, names:string[], secretNames:string[]}}
43
+ */
44
+ export function summarizeEnv(env) {
45
+ if (!env || typeof env !== "object") {
46
+ return { count: 0, names: [], secretNames: [] };
47
+ }
48
+ const names = Object.keys(env).sort();
49
+ const secretNames = names.filter((n) => isSecretEnvName(n));
50
+ return { count: names.length, names, secretNames };
51
+ }
52
+
53
+ /** Recursively redact every string in a value (arrays/objects walked). */
54
+ function deepRedact(value, depth = 0) {
55
+ if (depth > 64) return value;
56
+ if (typeof value === "string") return redactSecrets(value);
57
+ if (Array.isArray(value)) return value.map((v) => deepRedact(v, depth + 1));
58
+ if (value && typeof value === "object") {
59
+ const out = {};
60
+ for (const k of Object.keys(value))
61
+ out[k] = deepRedact(value[k], depth + 1);
62
+ return out;
63
+ }
64
+ return value;
65
+ }
66
+
67
+ /**
68
+ * Recursively scan a value for any residual secret, returning findings with a
69
+ * dotted path so the gate can name WHERE a leak survived. Read-only.
70
+ * @returns {Array<{path:string, category:string}>}
71
+ */
72
+ export function scanBundleForSecrets(value, path = "", depth = 0) {
73
+ if (depth > 64) return [];
74
+ const findings = [];
75
+ if (typeof value === "string") {
76
+ for (const f of scanSecrets(value)) {
77
+ findings.push({ path: path || "(root)", category: f.category });
78
+ }
79
+ } else if (Array.isArray(value)) {
80
+ value.forEach((v, i) =>
81
+ findings.push(...scanBundleForSecrets(v, `${path}[${i}]`, depth + 1)),
82
+ );
83
+ } else if (value && typeof value === "object") {
84
+ for (const k of Object.keys(value)) {
85
+ findings.push(
86
+ ...scanBundleForSecrets(value[k], path ? `${path}.${k}` : k, depth + 1),
87
+ );
88
+ }
89
+ }
90
+ return findings;
91
+ }
92
+
93
+ const asArray = (v) => (Array.isArray(v) ? v : []);
94
+ const asString = (v) =>
95
+ typeof v === "string" ? v : v == null ? "" : String(v);
96
+
97
+ /**
98
+ * Assemble the diagnostic bundle from caller-supplied signals, de-identifying
99
+ * as it goes. Free-text fields are secret-redacted; env is reduced to names;
100
+ * terminal output is included ONLY with explicit permission (and still
101
+ * redacted). Excluded categories are never assembled in the first place.
102
+ *
103
+ * @param {object} input
104
+ * @param {string} [input.version]
105
+ * @param {object|string} [input.platform]
106
+ * @param {object} [input.capability] defaults to the canonical compat fixture
107
+ * @param {string} [input.connectionState]
108
+ * @param {Array} [input.reconnectHistory] [{at?, reason?}] — reasons redacted
109
+ * @param {object} [input.trace] {traceId, spanCount} summary (no content)
110
+ * @param {Array} [input.redactionEvents] [{surface, category, count}] — what was scrubbed
111
+ * @param {Array} [input.processes] [{pid, name, cpu?}] metadata
112
+ * @param {Array<number|object>} [input.ports]
113
+ * @param {Array<string>} [input.lockfiles]
114
+ * @param {Array} [input.worktrees] [{path, branch}]
115
+ * @param {object} [input.env] reduced to names only
116
+ * @param {string} [input.terminalOutput] included only when opts.includeTerminalOutput
117
+ * @param {string} [input.notes]
118
+ * @param {object} [opts]
119
+ * @param {boolean} [opts.includeTerminalOutput=false]
120
+ * @returns {object} the assembled (already-redacted) bundle
121
+ */
122
+ export function buildDiagnosticBundle(input = {}, opts = {}) {
123
+ const includeTerminal = opts.includeTerminalOutput === true;
124
+
125
+ const redactionEvents = asArray(input.redactionEvents)
126
+ .map((e) => ({
127
+ surface: SURFACES.includes(e?.surface) ? e.surface : "unknown",
128
+ category: asString(e?.category),
129
+ count: Number(e?.count) || 0,
130
+ }))
131
+ .filter((e) => e.category);
132
+
133
+ const bundle = {
134
+ schema: "cc-diagnostic-bundle/v1",
135
+ meta: {
136
+ version: asString(input.version) || null,
137
+ platform:
138
+ input.platform && typeof input.platform === "object"
139
+ ? input.platform
140
+ : asString(input.platform) || null,
141
+ excluded: [...EXCLUDED_BY_DEFAULT],
142
+ },
143
+ capability:
144
+ input.capability && typeof input.capability === "object"
145
+ ? input.capability
146
+ : buildCompatFixture(),
147
+ connection: {
148
+ state: asString(input.connectionState) || null,
149
+ reconnectHistory: asArray(input.reconnectHistory).map((r) => ({
150
+ at: r?.at ?? null,
151
+ reason: asString(r?.reason),
152
+ })),
153
+ },
154
+ trace: input.trace
155
+ ? {
156
+ traceId: asString(input.trace.traceId) || null,
157
+ spanCount: Number(input.trace.spanCount) || 0,
158
+ }
159
+ : null,
160
+ redactionEvents,
161
+ runtime: {
162
+ processes: asArray(input.processes).map((p) => ({
163
+ pid: p?.pid ?? null,
164
+ name: asString(p?.name),
165
+ cpu: p?.cpu ?? null,
166
+ })),
167
+ ports: asArray(input.ports).map((p) =>
168
+ typeof p === "object" && p
169
+ ? { port: Number(p.port) || null, proto: asString(p.proto) || null }
170
+ : { port: Number(p) || null, proto: null },
171
+ ),
172
+ lockfiles: asArray(input.lockfiles).map((f) => asString(f)),
173
+ worktrees: asArray(input.worktrees).map((w) => ({
174
+ path: asString(w?.path),
175
+ branch: asString(w?.branch) || null,
176
+ })),
177
+ },
178
+ // env is reduced to NAMES only up front (values never enter the bundle).
179
+ env: summarizeEnv(input.env),
180
+ notes: input.notes != null ? asString(input.notes) : null,
181
+ };
182
+
183
+ // Terminal output is unpermitted by default: dropped entirely, with a marker
184
+ // so the reader knows it was withheld (not merely absent).
185
+ if (includeTerminal && input.terminalOutput != null) {
186
+ bundle.terminalOutput = asString(input.terminalOutput);
187
+ } else {
188
+ bundle.terminalOutput = null;
189
+ bundle.terminalOutputWithheld = input.terminalOutput != null;
190
+ }
191
+
192
+ // Single de-identification pass over the WHOLE assembled bundle: every string
193
+ // field is secret-redacted regardless of which section it landed in, so the
194
+ // export gate is guaranteed clean no matter which signal carried a secret.
195
+ // env is already values-free, so its names (metadata) pass through untouched.
196
+ return deepRedact(bundle);
197
+ }
198
+
199
+ /**
200
+ * The mandatory pre-export gate ("导出前必须运行 Secret Scan"). Deep-scans the
201
+ * assembled bundle; fail-closed: if ANY residual secret survives, `ok` is false
202
+ * and `blocked` is true — the caller must NOT export it. On a clean bundle the
203
+ * gate returns it ready for export.
204
+ *
205
+ * @param {object} bundle a buildDiagnosticBundle() result
206
+ * @returns {{ok:boolean, blocked:boolean, findings:Array, bundle:object}}
207
+ */
208
+ export function secretScanGate(bundle) {
209
+ const findings = scanBundleForSecrets(bundle);
210
+ const ok = findings.length === 0;
211
+ return { ok, blocked: !ok, findings, bundle };
212
+ }
213
+
214
+ /**
215
+ * One-call assembly + gate. Builds the de-identified bundle and runs the secret
216
+ * scan. When the gate is clean, returns the exportable bundle; when it is not
217
+ * (should never happen given assembly redacts, but defense-in-depth), returns
218
+ * `ok:false` and the leak locations, and does NOT hand back an exportable body.
219
+ *
220
+ * @returns {{ok:boolean, bundle:(object|null), findings:Array}}
221
+ */
222
+ export function exportDiagnosticBundle(input = {}, opts = {}) {
223
+ const bundle = buildDiagnosticBundle(input, opts);
224
+ const gate = secretScanGate(bundle);
225
+ return {
226
+ ok: gate.ok,
227
+ bundle: gate.ok ? bundle : null,
228
+ findings: gate.findings,
229
+ };
230
+ }
@@ -23,10 +23,18 @@ import {
23
23
  statSync,
24
24
  rmSync,
25
25
  } from "node:fs";
26
- import { execSync } from "node:child_process";
26
+ import { execSync, spawnSync } from "node:child_process";
27
27
  import { join, basename } from "node:path";
28
28
  import { getHomeDir, getConfigPath } from "./paths.js";
29
- import { checkAgenda, checkInstructionFiles } from "./runtime-checkup.js";
29
+ import {
30
+ checkAgenda,
31
+ checkInstructionFiles,
32
+ checkHookConfig,
33
+ checkHooks,
34
+ checkSandbox,
35
+ checkDuplicateSkills,
36
+ DEFAULT_CHECKUP_THRESHOLDS,
37
+ } from "./runtime-checkup.js";
30
38
 
31
39
  export const CHECK_LEVELS = Object.freeze({
32
40
  OK: "ok",
@@ -45,6 +53,7 @@ export const _deps = {
45
53
  statSync,
46
54
  rmSync,
47
55
  execSync,
56
+ spawnSync,
48
57
  now: () => Date.now(),
49
58
  };
50
59
 
@@ -315,6 +324,58 @@ async function pluginSection(opts, _deps2) {
315
324
  } catch (err) {
316
325
  checks.push(failedCheck("plugins", "Installed plugins", err));
317
326
  }
327
+
328
+ // Broken manifests + un-consented capabilities (Phase 3 capability gap).
329
+ // Distinct from the signature-lock check above: re-discover to get each
330
+ // plugin's parsed manifest (listInstalled drops it) so we can flag an invalid
331
+ // manifest and any DECLARED capability set the user has not consented to.
332
+ try {
333
+ const { discoverPlugins } = await import("./plugin-runtime/scopes.js");
334
+ const { isPluginCapabilityConsented } =
335
+ await import("./plugin-runtime/capability-consent.js");
336
+ const { checkPluginsAndLsp } = await import("./runtime-checkup.js");
337
+ const discovered =
338
+ discoverPlugins({ cwd: opts.cwd || process.cwd(), skipPolicy: true }) ||
339
+ [];
340
+ // Broken manifests → warn (shared runtime-checkup evaluator).
341
+ for (const f of checkPluginsAndLsp(
342
+ discovered.map((p) => ({
343
+ id: p.name,
344
+ healthy: p.manifest?.ok !== false,
345
+ kind: "plugin",
346
+ })),
347
+ )) {
348
+ checks.push(
349
+ check(
350
+ f.id,
351
+ `plugin ${f.ref}`,
352
+ CHECK_LEVELS.WARN,
353
+ `${f.message} — ${f.remediation}`,
354
+ ),
355
+ );
356
+ }
357
+ // Declared capabilities not yet consented → warn.
358
+ for (const p of discovered) {
359
+ if (!p.manifest?.capabilitiesDeclared) continue;
360
+ const consented = isPluginCapabilityConsented(
361
+ { name: p.name, scope: p.scope, version: p.version },
362
+ p.manifest.capabilities,
363
+ );
364
+ if (!consented) {
365
+ checks.push(
366
+ check(
367
+ "plugin-capability-unconsented",
368
+ `plugin ${p.name}`,
369
+ CHECK_LEVELS.WARN,
370
+ `declares capabilities not yet consented — run \`cc plugin consent ${p.name}\``,
371
+ ),
372
+ );
373
+ }
374
+ }
375
+ } catch (err) {
376
+ checks.push(failedCheck("plugin-capabilities", "plugin capabilities", err));
377
+ }
378
+
318
379
  return { id: "plugins", title: "Plugin trust", checks };
319
380
  }
320
381
 
@@ -566,7 +627,7 @@ async function runtimeSection(opts, deps) {
566
627
  dueAt: e.kind === "wakeup" ? e.dueAt : e.nextAt,
567
628
  recurring: e.kind !== "wakeup",
568
629
  }));
569
- for (const f of checkAgenda(entries, now)) {
630
+ for (const f of checkAgenda(entries, now, DEFAULT_CHECKUP_THRESHOLDS)) {
570
631
  checks.push(
571
632
  check(
572
633
  f.id,
@@ -595,7 +656,7 @@ async function runtimeSection(opts, deps) {
595
656
  }
596
657
  }
597
658
  }
598
- for (const f of checkInstructionFiles(files)) {
659
+ for (const f of checkInstructionFiles(files, DEFAULT_CHECKUP_THRESHOLDS)) {
599
660
  checks.push(
600
661
  check(
601
662
  f.id,
@@ -609,12 +670,221 @@ async function runtimeSection(opts, deps) {
609
670
  checks.push(failedCheck("instructions", "instruction files", err));
610
671
  }
611
672
 
673
+ // settings.json hook config — statically catch hooks that will silently never
674
+ // fire (unknown event / bad regex matcher / missing command) or are
675
+ // misconfigured (bad timeout). Runtime hook health (slow/circuit-broken) needs
676
+ // live per-process stats and isn't computed here.
677
+ try {
678
+ const settingsHooks = await import("./settings-hooks.cjs");
679
+ const mod = settingsHooks.default || settingsHooks;
680
+ const cwd = opts.cwd || process.cwd();
681
+ const files = mod.settingsFiles(cwd);
682
+ const seen = new Set();
683
+ for (const file of files) {
684
+ if (seen.has(file) || !deps.existsSync(file)) continue;
685
+ seen.add(file);
686
+ let hooksBlock = null;
687
+ try {
688
+ const parsed = JSON.parse(deps.readFileSync(file, "utf-8"));
689
+ hooksBlock = parsed && typeof parsed === "object" ? parsed.hooks : null;
690
+ } catch {
691
+ continue; // malformed settings.json is reported elsewhere (config section)
692
+ }
693
+ if (!hooksBlock) continue;
694
+ for (const f of checkHookConfig(hooksBlock, {
695
+ validEvents: mod.HOOK_EVENTS,
696
+ })) {
697
+ checks.push(
698
+ check(
699
+ f.id,
700
+ `${basename(file)} ${f.ref}`,
701
+ SEVERITY_TO_LEVEL[f.severity] || CHECK_LEVELS.INFO,
702
+ `${f.message} — ${f.remediation}`,
703
+ ),
704
+ );
705
+ }
706
+ }
707
+ } catch (err) {
708
+ checks.push(failedCheck("hook-config", "settings hook config", err));
709
+ }
710
+
711
+ // Async-hook RUNTIME health — the reliability aggregate persisted by
712
+ // AsyncHookSupervisor.stopAll(): hooks that have been repeatedly failing,
713
+ // circuit-broken (N failures in a row), or slow on average. Complements the
714
+ // static config check above (which catches hooks that never fire at all).
715
+ try {
716
+ const store = await import("./hook-stats-store.cjs");
717
+ const mod = store.default || store;
718
+ const statsFs = {
719
+ existsSync: deps.existsSync,
720
+ readFileSync: deps.readFileSync,
721
+ };
722
+ const stats = mod.loadHookStats(mod.defaultHookStatsPath(), statsFs);
723
+ const hooks = mod.toCheckHooksInput(stats, {
724
+ circuitThreshold: DEFAULT_CHECKUP_THRESHOLDS.hookFailureThreshold,
725
+ });
726
+ for (const f of checkHooks(hooks, DEFAULT_CHECKUP_THRESHOLDS)) {
727
+ checks.push(
728
+ check(
729
+ f.id,
730
+ `hook ${f.ref}`,
731
+ SEVERITY_TO_LEVEL[f.severity] || CHECK_LEVELS.INFO,
732
+ `${f.message} — ${f.remediation}`,
733
+ ),
734
+ );
735
+ }
736
+ } catch (err) {
737
+ checks.push(failedCheck("hook-health", "async hook stats", err));
738
+ }
739
+
740
+ // Sandbox real capability — catch the "silent degradation" case where a
741
+ // sandbox is configured in settings.json but its engine (docker/bwrap) isn't
742
+ // actually runnable, so tool subprocesses run UNSANDBOXED without warning.
743
+ try {
744
+ const settingsHooks = await import("./settings-hooks.cjs");
745
+ const shMod = settingsHooks.default || settingsHooks;
746
+ const sandboxMod = await import("./agent-sandbox.js");
747
+ const cwd = opts.cwd || process.cwd();
748
+ let sandboxSettings = null;
749
+ for (const file of shMod.settingsFiles(cwd)) {
750
+ if (!deps.existsSync(file)) continue;
751
+ try {
752
+ const parsed = JSON.parse(deps.readFileSync(file, "utf-8"));
753
+ if (parsed && parsed.sandbox && typeof parsed.sandbox === "object") {
754
+ sandboxSettings = { ...(sandboxSettings || {}), ...parsed.sandbox };
755
+ }
756
+ } catch {
757
+ // malformed settings.json is reported by the config section
758
+ }
759
+ }
760
+ if (sandboxSettings && sandboxSettings.enabled === true) {
761
+ const sandbox = sandboxMod.normalizeAgentSandbox(true, {
762
+ settings: sandboxSettings,
763
+ cwd,
764
+ });
765
+ if (sandbox) {
766
+ const probe = sandboxMod.probeSandboxAvailability(sandbox, {
767
+ spawnSync: deps.spawnSync,
768
+ });
769
+ for (const f of checkSandbox({
770
+ configured: true,
771
+ engine: sandbox.engine,
772
+ available: probe.available,
773
+ reason: probe.reason,
774
+ failIfUnavailable: sandbox.policy?.failIfUnavailable === true,
775
+ isolationLevel: sandboxMod.isolationLevel(sandbox),
776
+ })) {
777
+ checks.push(
778
+ check(
779
+ f.id,
780
+ `sandbox ${f.ref}`,
781
+ SEVERITY_TO_LEVEL[f.severity] || CHECK_LEVELS.INFO,
782
+ f.remediation ? `${f.message} — ${f.remediation}` : f.message,
783
+ ),
784
+ );
785
+ }
786
+ }
787
+ }
788
+ } catch (err) {
789
+ checks.push(failedCheck("sandbox", "sandbox availability", err));
790
+ }
791
+
792
+ // Duplicate skills — an id defined in more than one layer silently shadows
793
+ // (loadAll keeps only the winner), so a user's custom skill can override, or
794
+ // be overridden by, another without any signal. opts.skillLayerEntries lets a
795
+ // caller inject the (un-deduped) entry list; otherwise scan via the loader.
796
+ try {
797
+ let entries = opts.skillLayerEntries;
798
+ if (!entries) {
799
+ const { CLISkillLoader } = await import("./skill-loader.js");
800
+ entries = new CLISkillLoader().listSkillLayerEntries();
801
+ }
802
+ for (const f of checkDuplicateSkills(entries)) {
803
+ checks.push(
804
+ check(
805
+ f.id,
806
+ `skill ${f.ref}`,
807
+ SEVERITY_TO_LEVEL[f.severity] || CHECK_LEVELS.INFO,
808
+ `${f.message} — ${f.remediation}`,
809
+ ),
810
+ );
811
+ }
812
+ } catch (err) {
813
+ checks.push(failedCheck("skill-duplicate", "skill layers", err));
814
+ }
815
+
612
816
  if (checks.length === 0) {
613
817
  checks.push(check("runtime-clean", "runtime hygiene", CHECK_LEVELS.OK, ""));
614
818
  }
615
819
  return { id: "runtime", title: "Runtime checkup", checks };
616
820
  }
617
821
 
822
+ // ── execution context (P1-7) ───────────────────────────────────────────────
823
+ // "任务在哪执行是 Session 一等属性": surface the DETECTED execution location and
824
+ // the fail-closed permission posture it implies. Read-only advisory — it never
825
+ // blocks. A local trusted machine is OK; a remote/unknown environment is a WARN
826
+ // because a session there fails closed to read-only unless powers are granted
827
+ // explicitly (and any policy violation from the pure model is listed).
828
+ async function executionSection(opts, deps) {
829
+ const checks = [];
830
+ try {
831
+ const {
832
+ detectAmbientLocation,
833
+ validateExecutionContext,
834
+ EXECUTION_LOCATION,
835
+ } = await import("./execution-location.js");
836
+ // /.dockerenv is the classic in-container marker; keep it injectable via deps
837
+ // so the section is deterministic under test.
838
+ let dockerEnvFileExists = false;
839
+ try {
840
+ dockerEnvFileExists = deps.existsSync("/.dockerenv") === true;
841
+ } catch {
842
+ // non-POSIX host / unreadable — treat as not-a-container.
843
+ }
844
+ const location = detectAmbientLocation({
845
+ env: opts.env || process.env,
846
+ dockerEnvFileExists,
847
+ });
848
+ // Honest minimal input: just the detected location + the working dir. We do
849
+ // NOT fabricate a return path or granted powers — the validation then flags a
850
+ // real remote box with nowhere to return results, which is a meaningful hint.
851
+ const result = validateExecutionContext({
852
+ location,
853
+ source: { dir: opts.cwd || process.cwd() },
854
+ });
855
+ const isUnknown = location === EXECUTION_LOCATION.UNKNOWN;
856
+ const level =
857
+ isUnknown || result.descriptor.remote
858
+ ? CHECK_LEVELS.WARN
859
+ : CHECK_LEVELS.OK;
860
+ checks.push(
861
+ check(
862
+ "execution-location",
863
+ `Execution location: ${location}`,
864
+ level,
865
+ result.descriptor.remote
866
+ ? "remote/unknown — a session here fails closed to read-only unless powers are granted explicitly"
867
+ : isUnknown
868
+ ? "could not identify the environment — treated as untrusted (read-only floor)"
869
+ : "local trusted machine",
870
+ ),
871
+ );
872
+ if (result.violations.length > 0) {
873
+ checks.push(
874
+ check(
875
+ "execution-policy",
876
+ "Execution policy",
877
+ CHECK_LEVELS.WARN,
878
+ `fail-closed advisories: ${result.violations.join(", ")}`,
879
+ ),
880
+ );
881
+ }
882
+ } catch (err) {
883
+ checks.push(failedCheck("execution-location", "execution context", err));
884
+ }
885
+ return { id: "execution", title: "Execution context", checks };
886
+ }
887
+
618
888
  /**
619
889
  * Collect all checkup sections. Never throws — a failing subsystem becomes an
620
890
  * `err` check inside its section.
@@ -633,6 +903,7 @@ export async function collectCheckupSections(opts = {}) {
633
903
  backgroundSection,
634
904
  worktreeSection,
635
905
  runtimeSection,
906
+ executionSection,
636
907
  ]) {
637
908
  try {
638
909
  sections.push(await build(opts, deps));