chainlesschain 0.165.6 → 0.165.8

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 (238) hide show
  1. package/package.json +2 -1
  2. package/src/assets/web-panel/assets/{AIOps-vfoDb6HZ.js → AIOps-B3gWmXjo.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-Cm5f7p93.js → ActionButton-G9pdT-0e.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-yRuvgWxa.js → Analytics-Ca30J7m2.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-BROsC4h1.js → AppLayout-BtVTm8PU.js} +5 -5
  6. package/src/assets/web-panel/assets/{Artifacts-CimHApb1.js → Artifacts-BhViNa6u.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-DI8kr8zI.js → Audit-DhKq-FnY.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-DSLzKy-n.js → BackgroundAgents-BL0SVbnE.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-DkH_n2r1.js → Backup-BWkblnFi.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-CKSrUoRA.js → BaseInput-ClaRNrF8.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-ClwfMXUS.js → Chat-sZE2Z77o.js} +4 -4
  12. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CjMaqfL7.js → ChatBubbleRenderer-BAfKOnRe.js} +1 -1
  13. package/src/assets/web-panel/assets/{Checkbox-BYTehcQG.js → Checkbox-Cvhay5WM.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-B8AMcp6J.js → Codegen-BpejL-4N.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-BNSogPo3.js → Col-g2Ki6g_1.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-JxPvGb8O.js → Community-D2xKbNo9.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-DF7bFAgE.js → Compact-DbL1Pds3.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-Bvhqnwrq.js → Compliance-DGtZCV4c.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-BDS0CJvM.js → Cowork-4kQpoNsI.js} +3 -3
  20. package/src/assets/web-panel/assets/{Cron-DqvRfxoQ.js → Cron-BxTYXXAN.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-CDcIvnqS.js → Crosschain-k0J0LT2N.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-D7jaUxU3.js → DID-BaqhoPgN.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-B5A18wEV.js → Dashboard-T4RVPIM1.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-_6IVkGag.js → Dropdown-DszOToWq.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-C9PeiKCG.js → EmailListRenderer-C9KJU7HF.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DXjuEHrX.js → FamilyGuardDashboard-Cmr0JnsA.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-B4IAR9zv.js → Federation-BI-_2xZX.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-CxQeSNx1.js → FormItemContext-DsnDEPsl.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-B8GS-Y3N.js → GenericCardRenderer-BLncAKKK.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-BS8SouUX.js → Git-BPQhGXDn.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-Dq9aYb5Q.js → Governance-CyElbUQW.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-BrCEe9AJ.js → Inference-CcSntBQD.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-DybOpiY2.js → KnowledgeGraph-p6e7HZ2r.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-DBpzbRfx.js → Logs-CNEtr-wz.js} +2 -2
  35. package/src/assets/web-panel/assets/MarkdownRenderer-Bj9xI0YH.js +1 -0
  36. package/src/assets/web-panel/assets/{Marketplace-Cc7CCSCu.js → Marketplace-Dd2notAJ.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-DFaIhOfu.js → McpTools-BBsN2CSW.js} +4 -4
  38. package/src/assets/web-panel/assets/{Memory-KCqlp9ol.js → Memory-Dg2uTvwx.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-Bys84ySN.js → MobileBridge-r1YMRiJV.js} +1 -1
  40. package/src/assets/web-panel/assets/{MobileProjects-B-6qU-je.js → MobileProjects-C-89kSm4.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-BgY-fvCq.js → Mtc-CrPZcVgf.js} +5 -5
  42. package/src/assets/web-panel/assets/{MtcAudit-B8pCmqQJ.js → MtcAudit-sxi7hqJb.js} +4 -4
  43. package/src/assets/web-panel/assets/{Multisig-BbOmYutA.js → Multisig-CAgOMfF1.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-BocLQz_M.js → NLProgramming-DafaPts3.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-CSwbxEop.js → Notes-CJM-xUW_.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-CqFNSYG3.js → NotificationSettings-L0ZjfAh_.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-C6gMfAk7.js → OrderTableRenderer-BB1CvCK0.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-QrDXVdMJ.js → Organization-DeLtgAD8.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-Cxntotjt.js → Overflow-CKC2b10z.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-CIdBOwNq.js → P2P-eyf2rzY1.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-CT5aP8rD.js → PdhVaultBrowser-5upNIOW8.js} +3 -3
  52. package/src/assets/web-panel/assets/{Permissions-DH7OM8XU.js → Permissions-B8p3W6JK.js} +4 -4
  53. package/src/assets/web-panel/assets/{PersonalDataHub-CnJqbWce.js → PersonalDataHub-BnRMxTq3.js} +5 -5
  54. package/src/assets/web-panel/assets/{Pipeline-5C3HG1kH.js → Pipeline-DjCNI1li.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-B4yIp7xK.js → Privacy-u6gXLbWT.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-BMvt-2M0.js → ProjectInit-BZAw4tkM.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-CvSTEMRG.js → ProjectSettings-B1Tr72q7.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-BKBJxEek.js → Projects-DO7HFuBQ.js} +1 -1
  59. package/src/assets/web-panel/assets/{Providers-BdwUqFWN.js → Providers-BjCztyhj.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-DtnCKlTm.js → QrScannerModal-ZWyCUbR1.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-sTbgwyNr.js → QuickAsk-DhDjeW4G.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-Bzr14gSb.js → Recommend-R_CN2MuU.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-C_TF5IaJ.js → RemoteSession-uxFcujeu.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-GCAM4H2K.js → Reputation-DX8D7rks.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-Dir0r6OQ.js → Row-BYahQILD.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-CpGnlecX.js → RssFeed-CUSQ2tm-.js} +3 -3
  67. package/src/assets/web-panel/assets/{Search-DMMamC6u.js → Search-CnN_S8Cs.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-yqay5yG-.js → Security-DcZlh-O4.js} +4 -4
  69. package/src/assets/web-panel/assets/{Services-C5i2wh9G.js → Services-ZhBOjzIX.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-vUqk35yj.js → Skeleton-D5Qnq_lI.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-DzcSkhot.js → Skills-BC9cZ3Be.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-CB6qbYNr.js → Sla-DauJ3E8_.js} +1 -1
  73. package/src/assets/web-panel/assets/SpeechSettings-DbNeZ_fh.js +1 -0
  74. package/src/assets/web-panel/assets/{SyncSettings-D-RrsxTJ.js → SyncSettings-DUvJbSct.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-DFxdOJiq.js → Tasks-BXa-5noQ.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-SKAob_Aq.js → Templates-JxaiUt_3.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-BPfsfHQ-.js → Tenant-BW4ERQN8.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-8iw7FpUf.js → Terminal-DltUbdtv.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-C4Gjj5Su.js → TimelineRenderer-CMoZz0Tc.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-COYhN18e.js → Tokens-D_VEV60K.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-B-JzXcf6.js → Trigger-CCXTCs0R.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-BJ5bg0nI.js → Trust-lkGRIPcG.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-BG_ByRMf.js → UkeySign-BfGeQ9HX.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-B3kOnSiU.js → VideoEditing-BEC7pYvc.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-CcoGFnK7.js → Wallet-BZdG24o0.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-DdT8vRC_.js → WebAuthn-yoEddedp.js} +4 -4
  87. package/src/assets/web-panel/assets/{WorkflowEditor-CZu3M9N8.js → WorkflowEditor-BXZEprOW.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-DxJt3Qba.js → chat-gg0bzZal.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-DdYfwJaB.js → colors-DjRVRuin.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-BG3SUzwj.js → compact-item-su-dieAc.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-By51z2-1.js → createContext-Ci3S8oKF.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-CxbFX9uH.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-B0apZ3KJ.js → hasIn-D8F10heH.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-DE76D-kA.js → index-11wtYQiF.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-BkvcEo4p.js → index-1IgxgALJ.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-Bos5_aMV.js → index-1agckWSq.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BfWYsB9t.js → index-5JqhujnR.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CAhHirVH.js → index-6Tniqk1s.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BYINoRLK.js → index-8Z-8BIlN.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-B5rLiEo0.js → index-BCI5v0yB.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BZ_0qm4g.js → index-BDJntYmJ.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CWEuZWCK.js → index-BGzixOGZ.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BLIbGOLX.js → index-BMMOVoLD.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-bP_VlDb4.js → index-BTFpdBtt.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-B3rWuPMW.js → index-Ba_HyPnE.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-Da_WBdLX.js → index-BbF1IHof.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-RD6O-0C6.js → index-BgT9su_e.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CpjZhgNd.js → index-BzPB6kGZ.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Q2SCX-MI.js → index-C6ygzplr.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-BIrJfqO4.js → index-CC3ZDjzY.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BBPf3TpM.js → index-CEmXRhAE.js} +1 -1
  112. package/src/assets/web-panel/assets/index-CJGOlduY.js +1 -0
  113. package/src/assets/web-panel/assets/{index-Cp6e-hGw.js → index-CMPqd5Cv.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-kf57LJ93.js → index-COWd8uGx.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CW93tZDv.js → index-CPIYSp4H.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-BewKYrX9.js → index-CR0h6seT.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-p1_8SbI1.js → index-CUmDhC4j.js} +1 -1
  118. package/src/assets/web-panel/assets/index-CkBCN5yH.js +1 -0
  119. package/src/assets/web-panel/assets/{index-ZxtP8jG7.js → index-CusgZPtc.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BWF8_mkx.js → index-DBAETXft.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BP94CrBV.js → index-DIJ2qFOC.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CNIxXMmN.js → index-Dbq4NMET.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CzmQElZy.js → index-DkMEF5VT.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-ZFbps9po.js → index-DkfQR3hM.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-Dz49VOyQ.js → index-DnLucOn9.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-oxRrmFO9.js → index-DugB_aKa.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-Bissefox.js → index-DyLUarhZ.js} +3 -3
  128. package/src/assets/web-panel/assets/{index-DaIz0NAW.js → index-T6_6ygJZ.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-SQqOlR3d.js → index-Tu8eWqh-.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-DCn8IcxV.js → index-W7XUgdVL.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-3jWkIu5j.js → index-dHZinfko.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-C1C9i79A.js → index-jyNgp5FI.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-BWJktcg8.js → initDefaultProps-Cv4p8e4w.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-BEXBzUFV.js → motion-B8EwmMOw.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-BUKwn2sx.js → move-B8R9F8TK.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-FTI7btqQ.js → mtc-parser-DoFYz5Bp.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-CsLtSPH3.js → omit-CHWYLBjI.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-DWZxsT_S.js → pickAttrs-CXuPDO77.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-Bcfs43CX.js → placementArrow-BaAtUUon.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-a9bcC1p-.js → responsiveObserve-DCc4zcDD.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-BDTzgOXN.js → slide-B_lx89oZ.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-Iq1j_HUg.js → statusUtils-DE8DPmR0.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-DAZEYxeh.js → styleChecker-1ktXOsL_.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-DVkjyDrh.js → useFlexGapSupport-xH89-wjh.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-wXTpNTHt.js → useFs-DscvfW5p.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-CtQM_aZr.js → usePersonalDataHub-RdMKQta7.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-hjEoG85v.js → vnode-Z3wTni2T.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-BHVpyKg_.js → zoom-B0iChCsm.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/command-help-index.json +3 -3
  151. package/src/commands/agent.js +91 -60
  152. package/src/commands/git.js +39 -0
  153. package/src/commands/plugin.js +17 -2
  154. package/src/commands/session-group.js +131 -0
  155. package/src/commands/session-location.js +48 -0
  156. package/src/commands/session.js +11 -0
  157. package/src/commands/sync-providers.js +4 -1
  158. package/src/commands/update.js +1 -0
  159. package/src/data/changelog.json +27 -1
  160. package/src/gateways/ws/ws-agent-handler.js +20 -12
  161. package/src/harness/jsonl-session-store.js +279 -37
  162. package/src/harness/mcp-client.js +701 -91
  163. package/src/harness/session-index.js +15 -4
  164. package/src/lib/agent-worktree.js +8 -1
  165. package/src/lib/auto-mode-safety-classifier.js +3 -17
  166. package/src/lib/background-agent-keeper-protocol.js +26 -6
  167. package/src/lib/background-agent-supervisor.js +17 -1
  168. package/src/lib/browser-evidence.js +1405 -0
  169. package/src/lib/chrome-connector.js +465 -79
  170. package/src/lib/claude-project-auto-memory.js +481 -0
  171. package/src/lib/claude-project-storage-layout.js +104 -0
  172. package/src/lib/cloud/cloud-client.js +40 -0
  173. package/src/lib/execution-location-local-supervisor.mjs +226 -0
  174. package/src/lib/execution-location-runner-lifecycle.js +991 -0
  175. package/src/lib/execution-location-target-preflight.js +333 -0
  176. package/src/lib/execution-location-target.js +783 -13
  177. package/src/lib/file-lines.js +6 -1
  178. package/src/lib/gateway-client-resilience.js +571 -0
  179. package/src/lib/gitlab-mr-worktree.js +176 -0
  180. package/src/lib/hooks-v2-producers.js +119 -15
  181. package/src/lib/hooks-v2-workspace-context.js +44 -1
  182. package/src/lib/host-resource-budget.js +295 -0
  183. package/src/lib/ide-context.js +15 -2
  184. package/src/lib/llm-config-defaults.js +43 -0
  185. package/src/lib/mcp-lifecycle-authority.js +887 -0
  186. package/src/lib/mcp-oauth.js +101 -20
  187. package/src/lib/mcp-tls.js +103 -3
  188. package/src/lib/paths.js +260 -32
  189. package/src/lib/permission-request.js +48 -0
  190. package/src/lib/plugin-runtime/bin.js +3 -1
  191. package/src/lib/plugin-runtime/hooks.js +3 -1
  192. package/src/lib/plugin-runtime/install.js +117 -1
  193. package/src/lib/plugin-runtime/lsp.js +4 -4
  194. package/src/lib/plugin-runtime/marketplace-archive-source.js +40 -5
  195. package/src/lib/plugin-runtime/marketplace-catalog.js +13 -2
  196. package/src/lib/plugin-runtime/marketplace-command-descriptor.js +343 -0
  197. package/src/lib/plugin-runtime/marketplace-command-source.js +580 -0
  198. package/src/lib/plugin-runtime/marketplace-source-adapter.js +33 -8
  199. package/src/lib/plugin-runtime/mcp.js +3 -1
  200. package/src/lib/plugin-runtime/monitors.js +3 -1
  201. package/src/lib/plugin-runtime/remote-source.js +151 -6
  202. package/src/lib/plugin-runtime/settings.js +3 -1
  203. package/src/lib/plugin-runtime/trust.js +274 -13
  204. package/src/lib/process-execution-broker/credential-agent.js +210 -41
  205. package/src/lib/process-execution-broker/index.js +15 -1
  206. package/src/lib/process-execution-broker/linux-cgroup-v2.js +391 -0
  207. package/src/lib/process-execution-broker/platform-sandbox.js +50 -28
  208. package/src/lib/project-mcp-trust.js +165 -10
  209. package/src/lib/resume-session.js +9 -6
  210. package/src/lib/session-core-singletons.js +26 -11
  211. package/src/lib/session-host-lease.js +52 -16
  212. package/src/lib/session-lifecycle-scope.js +153 -0
  213. package/src/lib/session-message-fabric.js +168 -21
  214. package/src/lib/session-projection.js +244 -4
  215. package/src/lib/session-store-guard.js +3 -1
  216. package/src/lib/session-workbench-store.js +466 -0
  217. package/src/lib/spellcheck.js +211 -0
  218. package/src/lib/sub-agent-context.js +9 -9
  219. package/src/lib/sync-cli-db.js +485 -129
  220. package/src/lib/sync-credentials.js +31 -20
  221. package/src/lib/web-fetch.js +112 -40
  222. package/src/lib/web-search.js +127 -61
  223. package/src/lib/workspace-trust.js +793 -0
  224. package/src/repl/agent-repl.js +124 -5
  225. package/src/repl/permission-prompt.js +10 -12
  226. package/src/runtime/agent-core.js +311 -18
  227. package/src/runtime/bootstrap.js +37 -13
  228. package/src/runtime/coding-agent-contract-shared.cjs +11 -4
  229. package/src/runtime/headless-runner.js +234 -36
  230. package/src/runtime/headless-stream.js +181 -6
  231. package/src/runtime/mcp-config.js +298 -8
  232. package/src/runtime/policies/agent-policy.js +8 -0
  233. package/src/runtime/status-diagnostics-lite.js +9 -1
  234. package/src/assets/web-panel/assets/MarkdownRenderer-CFyt8iUd.js +0 -1
  235. package/src/assets/web-panel/assets/SpeechSettings-BHUI7cox.js +0 -1
  236. package/src/assets/web-panel/assets/devWarning-DorRZcI9.js +0 -1
  237. package/src/assets/web-panel/assets/index-BETiL0a3.js +0 -1
  238. package/src/assets/web-panel/assets/index-BhAVHuW8.js +0 -1
@@ -0,0 +1,466 @@
1
+ /**
2
+ * Durable, CLI-owned Sessions Workbench grouping authority.
3
+ *
4
+ * IDE windows only render this state through `cc session projection`. Every
5
+ * mutation is an exact revision CAS under the shared cross-process file lock,
6
+ * so two IDE windows cannot silently overwrite each other's group changes.
7
+ */
8
+
9
+ import { randomUUID } from "node:crypto";
10
+ import {
11
+ mutateSecurityStore,
12
+ readSecurityStore,
13
+ } from "./durable-security-store.js";
14
+ import { projectionRevision } from "./session-projection.js";
15
+ import {
16
+ ensureTrustedSessionLifecycleScope,
17
+ resolveTrustedSessionLifecycleScope,
18
+ } from "./session-lifecycle-scope.js";
19
+
20
+ export const SESSION_WORKBENCH_STATE_SCHEMA =
21
+ "chainlesschain.session-workbench-state/v1";
22
+ export const MAX_SESSION_GROUPS = 128;
23
+ export const MAX_SESSION_GROUP_NAME_CHARS = 80;
24
+ export const MAX_SESSION_GROUP_MEMBERSHIPS = 4096;
25
+
26
+ export function defaultSessionWorkbenchStatePath(options = {}) {
27
+ return resolveTrustedSessionLifecycleScope(options).workbenchStatePath;
28
+ }
29
+
30
+ function stateError(code, message, details = {}) {
31
+ const error = new Error(message);
32
+ error.code = code;
33
+ Object.assign(error, details);
34
+ return error;
35
+ }
36
+
37
+ function cleanText(value, label, maxChars) {
38
+ const text = String(value ?? "").trim();
39
+ if (!text || text.length > maxChars || /[\u0000-\u001f\u007f]/u.test(text)) {
40
+ throw stateError(
41
+ "SESSION_GROUP_INVALID_ARGUMENT",
42
+ `${label} must be 1-${maxChars} characters without control characters`,
43
+ );
44
+ }
45
+ return text;
46
+ }
47
+
48
+ function cleanGroupId(value) {
49
+ const id = cleanText(value, "group id", 128);
50
+ if (!/^group-[a-zA-Z0-9_-]+$/u.test(id)) {
51
+ throw stateError(
52
+ "SESSION_GROUP_INVALID_ARGUMENT",
53
+ "group id has an unsupported format",
54
+ );
55
+ }
56
+ return id;
57
+ }
58
+
59
+ function cleanSessionId(value) {
60
+ const id = cleanText(value, "canonical session id", 512);
61
+ if (!/^[a-z_]+:[^\s]+$/u.test(id)) {
62
+ throw stateError(
63
+ "SESSION_GROUP_INVALID_ARGUMENT",
64
+ "session id must be a canonical kind-prefixed projection id",
65
+ );
66
+ }
67
+ return id;
68
+ }
69
+
70
+ function emptyState() {
71
+ return {
72
+ schema: SESSION_WORKBENCH_STATE_SCHEMA,
73
+ generation: 0,
74
+ groups: [],
75
+ memberships: {},
76
+ };
77
+ }
78
+
79
+ function groupSort(left, right) {
80
+ return (
81
+ left.order - right.order ||
82
+ left.name.localeCompare(right.name) ||
83
+ left.id.localeCompare(right.id)
84
+ );
85
+ }
86
+
87
+ function normalizeState(raw) {
88
+ if (
89
+ raw &&
90
+ typeof raw === "object" &&
91
+ !Array.isArray(raw) &&
92
+ Object.keys(raw).length === 0
93
+ ) {
94
+ return emptyState();
95
+ }
96
+ if (
97
+ !raw ||
98
+ typeof raw !== "object" ||
99
+ Array.isArray(raw) ||
100
+ raw.schema !== SESSION_WORKBENCH_STATE_SCHEMA ||
101
+ !Number.isSafeInteger(raw.generation) ||
102
+ raw.generation < 0 ||
103
+ !Array.isArray(raw.groups) ||
104
+ !raw.memberships ||
105
+ typeof raw.memberships !== "object" ||
106
+ Array.isArray(raw.memberships)
107
+ ) {
108
+ throw stateError(
109
+ "SESSION_GROUP_STORE_CORRUPT",
110
+ "session workbench state is malformed",
111
+ );
112
+ }
113
+ if (raw.groups.length > MAX_SESSION_GROUPS) {
114
+ throw stateError(
115
+ "SESSION_GROUP_STORE_CORRUPT",
116
+ "session workbench state exceeds the group limit",
117
+ );
118
+ }
119
+ const ids = new Set();
120
+ const names = new Set();
121
+ const groups = raw.groups.map((entry) => {
122
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
123
+ throw stateError(
124
+ "SESSION_GROUP_STORE_CORRUPT",
125
+ "session group entry is malformed",
126
+ );
127
+ }
128
+ const id = cleanGroupId(entry.id);
129
+ const name = cleanText(
130
+ entry.name,
131
+ "group name",
132
+ MAX_SESSION_GROUP_NAME_CHARS,
133
+ );
134
+ const order = Number(entry.order);
135
+ if (!Number.isSafeInteger(order) || order < 0 || order > 100_000) {
136
+ throw stateError(
137
+ "SESSION_GROUP_STORE_CORRUPT",
138
+ "session group order is malformed",
139
+ );
140
+ }
141
+ if (ids.has(id) || names.has(name.toLowerCase())) {
142
+ throw stateError(
143
+ "SESSION_GROUP_STORE_CORRUPT",
144
+ "session group ids and names must be unique",
145
+ );
146
+ }
147
+ ids.add(id);
148
+ names.add(name.toLowerCase());
149
+ return { id, name, order };
150
+ });
151
+ const membershipEntries = Object.entries(raw.memberships);
152
+ if (membershipEntries.length > MAX_SESSION_GROUP_MEMBERSHIPS) {
153
+ throw stateError(
154
+ "SESSION_GROUP_STORE_CORRUPT",
155
+ "session workbench state exceeds the membership limit",
156
+ );
157
+ }
158
+ const memberships = {};
159
+ for (const [rawSessionId, rawGroupId] of membershipEntries) {
160
+ const sessionId = cleanSessionId(rawSessionId);
161
+ const groupId = cleanGroupId(rawGroupId);
162
+ if (!ids.has(groupId)) {
163
+ throw stateError(
164
+ "SESSION_GROUP_STORE_CORRUPT",
165
+ `session membership references missing group ${groupId}`,
166
+ );
167
+ }
168
+ memberships[sessionId] = groupId;
169
+ }
170
+ return {
171
+ schema: SESSION_WORKBENCH_STATE_SCHEMA,
172
+ generation: raw.generation,
173
+ groups: groups.sort(groupSort),
174
+ memberships: Object.fromEntries(
175
+ Object.entries(memberships).sort(([left], [right]) =>
176
+ left.localeCompare(right),
177
+ ),
178
+ ),
179
+ };
180
+ }
181
+
182
+ function revisionFor(state) {
183
+ return projectionRevision({
184
+ schema: state.schema,
185
+ generation: state.generation,
186
+ groups: state.groups,
187
+ memberships: state.memberships,
188
+ });
189
+ }
190
+
191
+ function publicProjection(state) {
192
+ const normalized = normalizeState(state);
193
+ return {
194
+ authority: "cli",
195
+ connected: true,
196
+ revision: revisionFor(normalized),
197
+ generation: normalized.generation,
198
+ items: normalized.groups.map((group) => ({ ...group })),
199
+ assignments: Object.entries(normalized.memberships).map(
200
+ ([sessionId, groupId]) => ({ sessionId, groupId }),
201
+ ),
202
+ };
203
+ }
204
+
205
+ function requireRevision(state, expectedRevision) {
206
+ const currentRevision = revisionFor(state);
207
+ if (
208
+ typeof expectedRevision !== "string" ||
209
+ !expectedRevision ||
210
+ expectedRevision !== currentRevision
211
+ ) {
212
+ throw stateError(
213
+ "SESSION_GROUP_STALE",
214
+ "session group revision changed; refresh before retrying",
215
+ { expectedRevision: expectedRevision || null, currentRevision },
216
+ );
217
+ }
218
+ }
219
+
220
+ function reindex(groups) {
221
+ return [...groups]
222
+ .sort(groupSort)
223
+ .map((group, order) => ({ ...group, order }));
224
+ }
225
+
226
+ export class SessionWorkbenchStore {
227
+ constructor(options = {}) {
228
+ const {
229
+ filePath: configuredFilePath,
230
+ launchEnv,
231
+ cwd,
232
+ uuid = randomUUID,
233
+ lockOptions,
234
+ } = options;
235
+ const usesDefaultFilePath = configuredFilePath === undefined;
236
+ this._lifecycleScope = usesDefaultFilePath
237
+ ? resolveTrustedSessionLifecycleScope({ launchEnv, cwd })
238
+ : null;
239
+ this.filePath = usesDefaultFilePath
240
+ ? this._lifecycleScope.workbenchStatePath
241
+ : configuredFilePath;
242
+ this.uuid = uuid;
243
+ this.lockOptions = lockOptions;
244
+ }
245
+
246
+ _prepareStorage() {
247
+ if (this._lifecycleScope?.kind === "project") {
248
+ ensureTrustedSessionLifecycleScope(this._lifecycleScope);
249
+ }
250
+ }
251
+
252
+ projection() {
253
+ this._prepareStorage();
254
+ return publicProjection(
255
+ normalizeState(readSecurityStore(this.filePath, "session workbench")),
256
+ );
257
+ }
258
+
259
+ _mutate(expectedRevision, mutator) {
260
+ this._prepareStorage();
261
+ return mutateSecurityStore(
262
+ this.filePath,
263
+ "session workbench",
264
+ (draft) => {
265
+ const current = normalizeState(draft);
266
+ requireRevision(current, expectedRevision);
267
+ const next = normalizeState(mutator(structuredClone(current)));
268
+ next.generation = current.generation + 1;
269
+ for (const key of Object.keys(draft)) delete draft[key];
270
+ Object.assign(draft, next);
271
+ return publicProjection(next);
272
+ },
273
+ this.lockOptions,
274
+ );
275
+ }
276
+
277
+ createGroup({ name, order = null, expectedRevision } = {}) {
278
+ const normalizedName = cleanText(
279
+ name,
280
+ "group name",
281
+ MAX_SESSION_GROUP_NAME_CHARS,
282
+ );
283
+ return this._mutate(expectedRevision, (state) => {
284
+ if (state.groups.length >= MAX_SESSION_GROUPS) {
285
+ throw stateError(
286
+ "SESSION_GROUP_LIMIT",
287
+ `session groups are limited to ${MAX_SESSION_GROUPS}`,
288
+ );
289
+ }
290
+ if (
291
+ state.groups.some(
292
+ (group) => group.name.toLowerCase() === normalizedName.toLowerCase(),
293
+ )
294
+ ) {
295
+ throw stateError(
296
+ "SESSION_GROUP_CONFLICT",
297
+ "session group name already exists",
298
+ );
299
+ }
300
+ const requestedOrder =
301
+ order == null ? state.groups.length : Number(order);
302
+ if (
303
+ !Number.isSafeInteger(requestedOrder) ||
304
+ requestedOrder < 0 ||
305
+ requestedOrder > state.groups.length
306
+ ) {
307
+ throw stateError(
308
+ "SESSION_GROUP_INVALID_ARGUMENT",
309
+ "group order must be within the current group list",
310
+ );
311
+ }
312
+ state.groups = state.groups.map((group) =>
313
+ group.order >= requestedOrder
314
+ ? { ...group, order: group.order + 1 }
315
+ : group,
316
+ );
317
+ state.groups.push({
318
+ id: `group-${this.uuid().replaceAll("-", "")}`,
319
+ name: normalizedName,
320
+ order: requestedOrder,
321
+ });
322
+ state.groups = reindex(state.groups);
323
+ return state;
324
+ });
325
+ }
326
+
327
+ renameGroup({ groupId, name, expectedRevision } = {}) {
328
+ const id = cleanGroupId(groupId);
329
+ const normalizedName = cleanText(
330
+ name,
331
+ "group name",
332
+ MAX_SESSION_GROUP_NAME_CHARS,
333
+ );
334
+ return this._mutate(expectedRevision, (state) => {
335
+ const group = state.groups.find((entry) => entry.id === id);
336
+ if (!group) {
337
+ throw stateError(
338
+ "SESSION_GROUP_NOT_FOUND",
339
+ `session group ${id} not found`,
340
+ );
341
+ }
342
+ if (
343
+ state.groups.some(
344
+ (entry) =>
345
+ entry.id !== id &&
346
+ entry.name.toLowerCase() === normalizedName.toLowerCase(),
347
+ )
348
+ ) {
349
+ throw stateError(
350
+ "SESSION_GROUP_CONFLICT",
351
+ "session group name already exists",
352
+ );
353
+ }
354
+ group.name = normalizedName;
355
+ return state;
356
+ });
357
+ }
358
+
359
+ deleteGroup({ groupId, expectedRevision } = {}) {
360
+ const id = cleanGroupId(groupId);
361
+ return this._mutate(expectedRevision, (state) => {
362
+ if (!state.groups.some((entry) => entry.id === id)) {
363
+ throw stateError(
364
+ "SESSION_GROUP_NOT_FOUND",
365
+ `session group ${id} not found`,
366
+ );
367
+ }
368
+ state.groups = reindex(state.groups.filter((entry) => entry.id !== id));
369
+ state.memberships = Object.fromEntries(
370
+ Object.entries(state.memberships).filter(
371
+ ([, groupId]) => groupId !== id,
372
+ ),
373
+ );
374
+ return state;
375
+ });
376
+ }
377
+
378
+ setGroupOrder({ groupId, order, expectedRevision } = {}) {
379
+ const id = cleanGroupId(groupId);
380
+ const requestedOrder = Number(order);
381
+ return this._mutate(expectedRevision, (state) => {
382
+ const current = state.groups.find((entry) => entry.id === id);
383
+ if (!current) {
384
+ throw stateError(
385
+ "SESSION_GROUP_NOT_FOUND",
386
+ `session group ${id} not found`,
387
+ );
388
+ }
389
+ if (
390
+ !Number.isSafeInteger(requestedOrder) ||
391
+ requestedOrder < 0 ||
392
+ requestedOrder >= state.groups.length
393
+ ) {
394
+ throw stateError(
395
+ "SESSION_GROUP_INVALID_ARGUMENT",
396
+ "group order must identify an existing position",
397
+ );
398
+ }
399
+ const without = state.groups.filter((entry) => entry.id !== id);
400
+ without.splice(requestedOrder, 0, current);
401
+ state.groups = without.map((entry, index) => ({
402
+ ...entry,
403
+ order: index,
404
+ }));
405
+ return state;
406
+ });
407
+ }
408
+
409
+ moveSessions({ groupId = null, sessionIds, expectedRevision } = {}) {
410
+ const target =
411
+ groupId == null || groupId === "" || groupId === "ungrouped"
412
+ ? null
413
+ : cleanGroupId(groupId);
414
+ if (!Array.isArray(sessionIds) || sessionIds.length === 0) {
415
+ throw stateError(
416
+ "SESSION_GROUP_INVALID_ARGUMENT",
417
+ "at least one canonical session id is required",
418
+ );
419
+ }
420
+ const ids = [...new Set(sessionIds.map(cleanSessionId))];
421
+ if (ids.length > 256) {
422
+ throw stateError(
423
+ "SESSION_GROUP_INVALID_ARGUMENT",
424
+ "one batch move is limited to 256 sessions",
425
+ );
426
+ }
427
+ return this._mutate(expectedRevision, (state) => {
428
+ if (target && !state.groups.some((entry) => entry.id === target)) {
429
+ throw stateError(
430
+ "SESSION_GROUP_NOT_FOUND",
431
+ `session group ${target} not found`,
432
+ );
433
+ }
434
+ const nextCount = new Set([
435
+ ...Object.keys(state.memberships),
436
+ ...(target ? ids : []),
437
+ ]).size;
438
+ if (nextCount > MAX_SESSION_GROUP_MEMBERSHIPS) {
439
+ throw stateError(
440
+ "SESSION_GROUP_LIMIT",
441
+ `session memberships are limited to ${MAX_SESSION_GROUP_MEMBERSHIPS}`,
442
+ );
443
+ }
444
+ for (const sessionId of ids) {
445
+ if (target) state.memberships[sessionId] = target;
446
+ else delete state.memberships[sessionId];
447
+ }
448
+ return state;
449
+ });
450
+ }
451
+ }
452
+
453
+ export function disconnectedSessionGroups(reasonText) {
454
+ return {
455
+ authority: "cli",
456
+ connected: false,
457
+ revision: null,
458
+ generation: 0,
459
+ reason: String(reasonText || "session group store unavailable").slice(
460
+ 0,
461
+ 240,
462
+ ),
463
+ items: [],
464
+ assignments: [],
465
+ };
466
+ }
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Local spellcheck adapter for REPL text.
3
+ *
4
+ * No dictionary is bundled and no text leaves the machine: a caller may opt
5
+ * into an installed aspell, hunspell, or ispell executable. Fenced code is
6
+ * removed before invocation so identifiers and examples do not become noisy
7
+ * spelling diagnostics.
8
+ */
9
+
10
+ import { executionBroker } from "./process-execution-broker/index.js";
11
+
12
+ export const SPELLCHECK_ADAPTERS = Object.freeze([
13
+ Object.freeze({ command: "aspell", args: Object.freeze(["list"]) }),
14
+ Object.freeze({ command: "hunspell", args: Object.freeze(["list"]) }),
15
+ Object.freeze({ command: "ispell", args: Object.freeze(["-l"]) }),
16
+ ]);
17
+
18
+ export const MAX_SPELLCHECK_INPUT_BYTES = 1024 * 1024;
19
+ export const MAX_SPELLCHECK_WORDS = 200;
20
+
21
+ const defaultDeps = Object.freeze({
22
+ spawnSync(command, args, options) {
23
+ return executionBroker.spawnSync(command, args, {
24
+ origin: "spellcheck:local-adapter",
25
+ scope: "spellcheck",
26
+ policy: "allow",
27
+ ...options,
28
+ });
29
+ },
30
+ });
31
+
32
+ /** Parse the REPL's local-only `/spellcheck` command. */
33
+ export function parseSpellcheckCommand(line) {
34
+ const input = String(line || "").trim();
35
+ if (input !== "/spellcheck" && !input.startsWith("/spellcheck ")) {
36
+ return null;
37
+ }
38
+ const argument = input.slice("/spellcheck".length).trim();
39
+ if (!argument || argument === "status")
40
+ return Object.freeze({ action: "status" });
41
+ if (argument === "on" || argument === "off") {
42
+ return Object.freeze({ action: argument });
43
+ }
44
+ return Object.freeze({ action: "check", text: argument });
45
+ }
46
+
47
+ function bool(value) {
48
+ if (typeof value === "boolean") return value;
49
+ if (typeof value !== "string") return null;
50
+ const normalized = value.trim().toLowerCase();
51
+ if (["1", "true", "yes", "on"].includes(normalized)) return true;
52
+ if (["0", "false", "no", "off"].includes(normalized)) return false;
53
+ return null;
54
+ }
55
+
56
+ function safeCommand(value) {
57
+ if (
58
+ typeof value !== "string" ||
59
+ !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(value)
60
+ ) {
61
+ throw new TypeError("spellcheck command is invalid");
62
+ }
63
+ return value;
64
+ }
65
+
66
+ function spawnOptions(input) {
67
+ return {
68
+ input,
69
+ encoding: "utf8",
70
+ timeout: 2500,
71
+ maxBuffer: 512 * 1024,
72
+ shell: false,
73
+ windowsHide: true,
74
+ };
75
+ }
76
+
77
+ /** Resolve the opt-out policy without treating project text as authority. */
78
+ export function resolveSpellcheckEnabled(options = {}) {
79
+ const explicit = bool(options.enabled);
80
+ if (explicit !== null) return explicit;
81
+ const env = options.env || process.env;
82
+ const environment = bool(env.CC_SPELLCHECK ?? env.CLAUDE_CODE_SPELLCHECK);
83
+ if (environment !== null) return environment;
84
+ const configured = bool(
85
+ options.config?.cli?.spellcheck ?? options.config?.spellcheck,
86
+ );
87
+ return configured ?? true;
88
+ }
89
+
90
+ /** Strip fenced Markdown code while retaining the surrounding prose. */
91
+ export function suppressFencedCodeBlocks(value) {
92
+ const output = [];
93
+ let fence = null;
94
+ for (const line of String(value ?? "")
95
+ .replace(/\r\n?/g, "\n")
96
+ .split("\n")) {
97
+ const marker = line.match(/^\s*(`{3,}|~{3,})/u)?.[1] || null;
98
+ if (fence === null && marker) {
99
+ fence = { character: marker[0], length: marker.length };
100
+ continue;
101
+ }
102
+ if (
103
+ fence !== null &&
104
+ marker &&
105
+ marker[0] === fence.character &&
106
+ marker.length >= fence.length
107
+ ) {
108
+ fence = null;
109
+ continue;
110
+ }
111
+ if (fence === null) output.push(line);
112
+ }
113
+ return output.join("\n");
114
+ }
115
+
116
+ function findAdapter(command, deps) {
117
+ const requested = command == null ? null : safeCommand(command);
118
+ const candidates = requested
119
+ ? SPELLCHECK_ADAPTERS.filter((adapter) => adapter.command === requested)
120
+ : SPELLCHECK_ADAPTERS;
121
+ if (requested && candidates.length === 0) {
122
+ return null;
123
+ }
124
+ for (const adapter of candidates) {
125
+ const probe = deps.spawnSync(
126
+ adapter.command,
127
+ ["--version"],
128
+ spawnOptions(""),
129
+ );
130
+ if (!probe?.error && probe?.status === 0) return adapter;
131
+ }
132
+ return null;
133
+ }
134
+
135
+ function projectWords(output) {
136
+ const words = [];
137
+ const seen = new Set();
138
+ for (const raw of String(output || "").split(/\r?\n/u)) {
139
+ const word = raw.trim();
140
+ if (!word || word.length > 128 || !/^[\p{L}][\p{L}'-]*$/u.test(word))
141
+ continue;
142
+ const key = word.toLocaleLowerCase();
143
+ if (seen.has(key)) continue;
144
+ seen.add(key);
145
+ words.push(word);
146
+ if (words.length >= MAX_SPELLCHECK_WORDS) break;
147
+ }
148
+ return Object.freeze(words);
149
+ }
150
+
151
+ /**
152
+ * Check prose with a local executable. Error objects and tool stderr are never
153
+ * returned because they can expose local paths, dictionary options, or input.
154
+ */
155
+ export function spellcheckText(value, options = {}) {
156
+ const enabled = resolveSpellcheckEnabled(options);
157
+ if (!enabled) {
158
+ return Object.freeze({
159
+ enabled: false,
160
+ available: false,
161
+ adapter: null,
162
+ words: Object.freeze([]),
163
+ reason: "disabled",
164
+ });
165
+ }
166
+ const prose = suppressFencedCodeBlocks(value);
167
+ if (Buffer.byteLength(prose, "utf8") > MAX_SPELLCHECK_INPUT_BYTES) {
168
+ throw new RangeError("spellcheck input exceeds the maximum size");
169
+ }
170
+ if (!prose.trim()) {
171
+ return Object.freeze({
172
+ enabled: true,
173
+ available: true,
174
+ adapter: null,
175
+ words: Object.freeze([]),
176
+ reason: "empty",
177
+ });
178
+ }
179
+ const deps = { ...defaultDeps, ...(options.deps || {}) };
180
+ const adapter = findAdapter(options.command, deps);
181
+ if (!adapter) {
182
+ return Object.freeze({
183
+ enabled: true,
184
+ available: false,
185
+ adapter: null,
186
+ words: Object.freeze([]),
187
+ reason: "unavailable",
188
+ });
189
+ }
190
+ const result = deps.spawnSync(
191
+ adapter.command,
192
+ adapter.args,
193
+ spawnOptions(prose),
194
+ );
195
+ if (result?.error || result?.status !== 0) {
196
+ return Object.freeze({
197
+ enabled: true,
198
+ available: false,
199
+ adapter: adapter.command,
200
+ words: Object.freeze([]),
201
+ reason: "failed",
202
+ });
203
+ }
204
+ return Object.freeze({
205
+ enabled: true,
206
+ available: true,
207
+ adapter: adapter.command,
208
+ words: projectWords(result.stdout),
209
+ reason: null,
210
+ });
211
+ }