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
@@ -7,20 +7,26 @@
7
7
  * cc agenda list [--json] show all scheduled entries
8
8
  * cc agenda run [--json] [--dry-run] fire everything due right now
9
9
  * cc agenda cancel <id> remove one entry
10
+ * cc agenda prune [--older-than N] drop finished entries
10
11
  *
11
12
  * `run` for each due entry:
12
13
  * - wakeup → spawn `cc agent -p <prompt>`, mark fired
13
14
  * - cron → spawn `cc agent -p <prompt>`, advance to next fire time
14
- * - monitor → run <command>; if output matches stop_when, send the
15
- * notification and stop; else re-arm for the next interval
15
+ * - monitor → check its source (a shell <command>'s output, a <watchFile>'s
16
+ * content / appearance / modification, or a <watchUrl>'s response
17
+ * body / 2xx); if it matches stop_when, send the notification and
18
+ * stop; else re-arm for the next interval
16
19
  */
17
20
 
18
21
  import { spawn, execSync } from "node:child_process";
22
+ import { readFileSync, statSync } from "node:fs";
19
23
  import { fileURLToPath } from "node:url";
20
24
  import chalk from "chalk";
21
25
  import { AgentScheduleStore } from "../lib/agent-schedule-store.js";
22
26
  import { sendAgentNotification } from "../lib/agent-notify.js";
23
- import { nextWakeupAt } from "../lib/schedule-planner.js";
27
+ import { nextWakeupAt, partitionSchedule } from "../lib/schedule-planner.js";
28
+ import { monitorEventEnvelope, capEventPayload } from "../lib/monitor-event.js";
29
+ import { unattendedDisallowedTools } from "../lib/unattended-action-policy.js";
24
30
 
25
31
  const BIN_PATH = fileURLToPath(
26
32
  new URL("../../bin/chainlesschain.js", import.meta.url),
@@ -58,6 +64,20 @@ export function registerAgendaCommand(program) {
58
64
  .action((id, options) => {
59
65
  process.exitCode = runAgendaCancel(id, options);
60
66
  });
67
+
68
+ cmd
69
+ .command("prune")
70
+ .description(
71
+ "Remove finished entries (fired / matched / exhausted / expired)",
72
+ )
73
+ .option(
74
+ "--older-than <seconds>",
75
+ "Only prune entries that finished more than N seconds ago",
76
+ )
77
+ .option("--json", "Machine-readable JSON output")
78
+ .action((options) => {
79
+ process.exitCode = runAgendaPrune(options);
80
+ });
61
81
  }
62
82
 
63
83
  export function runAgendaList(options = {}, _deps = {}) {
@@ -80,17 +100,30 @@ export function runAgendaList(options = {}, _deps = {}) {
80
100
  log("");
81
101
  log(chalk.bold(" Agenda:\n"));
82
102
  for (const e of entries) {
103
+ const monitorWhat =
104
+ e.source === "file"
105
+ ? `file ${e.watchFile}`
106
+ : e.source === "http"
107
+ ? `url ${e.watchUrl}`
108
+ : `every ${Math.round(e.intervalMs / 1000)}s`;
83
109
  const when =
84
110
  e.kind === "wakeup"
85
111
  ? new Date(e.dueAt).toISOString()
86
112
  : e.kind === "cron"
87
113
  ? `${e.cron} (next ${new Date(e.nextAt).toISOString()})`
88
- : `every ${Math.round(e.intervalMs / 1000)}s (next ${new Date(e.nextAt).toISOString()})`;
114
+ : `${monitorWhat} (next ${new Date(e.nextAt).toISOString()})`;
115
+ const expiry =
116
+ e.expiresAt != null
117
+ ? chalk.dim(` · expires ${new Date(e.expiresAt).toISOString()}`)
118
+ : "";
119
+ const policy = e.runPolicy
120
+ ? chalk.dim(` · ${describePolicy(e.runPolicy)}`)
121
+ : "";
89
122
  log(
90
123
  ` ${chalk.cyan(e.kind.padEnd(8))} ${chalk.dim(e.id.slice(0, 8))} ` +
91
- `${statusBadge(e.status)} ${e.label || truncate(e.prompt || e.command, 40)}`,
124
+ `${statusBadge(e.status)} ${e.label || truncate(e.prompt || e.command || e.watchFile || e.watchUrl, 40)}`,
92
125
  );
93
- log(` ${chalk.dim(when)}`);
126
+ log(` ${chalk.dim(when)}${expiry}${policy}`);
94
127
  }
95
128
  if (nextAt != null) {
96
129
  const rel = Math.max(0, Math.round((nextAt - now) / 1000));
@@ -120,6 +153,54 @@ export function runAgendaCancel(id, options = {}, _deps = {}) {
120
153
  return 2;
121
154
  }
122
155
 
156
+ /**
157
+ * Remove finished (terminal) entries so the store does not grow without bound.
158
+ * `--older-than <seconds>` keeps entries that finished more recently.
159
+ */
160
+ export function runAgendaPrune(options = {}, _deps = {}) {
161
+ const log = _deps.log || ((m) => console.log(m));
162
+ const store = _deps.store || new AgentScheduleStore();
163
+ const now = _deps.now ? _deps.now() : Date.now();
164
+
165
+ let before = Infinity;
166
+ if (options.olderThan != null) {
167
+ const secs = Number(options.olderThan);
168
+ if (!Number.isFinite(secs) || secs < 0) {
169
+ log(chalk.red(`\n ✖ invalid --older-than: ${options.olderThan}\n`));
170
+ return 2;
171
+ }
172
+ before = now - secs * 1000;
173
+ }
174
+
175
+ const removed = store.pruneTerminal({ before });
176
+ if (options.json) {
177
+ log(
178
+ JSON.stringify(
179
+ {
180
+ pruned: removed.map((e) => ({
181
+ id: e.id,
182
+ kind: e.kind,
183
+ status: e.status,
184
+ })),
185
+ },
186
+ null,
187
+ 2,
188
+ ),
189
+ );
190
+ return 0;
191
+ }
192
+ if (removed.length === 0) {
193
+ log(chalk.gray("\n No finished entries to prune.\n"));
194
+ return 0;
195
+ }
196
+ log(
197
+ chalk.green(
198
+ `\n ✓ Pruned ${removed.length} finished entr${removed.length === 1 ? "y" : "ies"}\n`,
199
+ ),
200
+ );
201
+ return 0;
202
+ }
203
+
123
204
  /**
124
205
  * Fire due entries. Returns 0 unless a monitor command / agent spawn failed in
125
206
  * a way worth signalling; JSON summary lists every action taken.
@@ -129,8 +210,16 @@ export async function runAgendaRun(options = {}, _deps = {}) {
129
210
  const store = _deps.store || new AgentScheduleStore();
130
211
  const spawnAgent = _deps.spawnAgent || defaultSpawnAgent;
131
212
  const runCommand = _deps.runCommand || defaultRunCommand;
213
+ const readWatchedFile = _deps.readWatchedFile || defaultReadWatchedFile;
214
+ const fetchUrl = _deps.fetchUrl || defaultFetchUrl;
132
215
  const notify = _deps.notify || sendAgentNotification;
133
- const due = store.due(null, _deps.now ? _deps.now() : null);
216
+ const now = _deps.now ? _deps.now() : Date.now();
217
+ // Retire expired entries BEFORE firing due ones — an expired task never gets
218
+ // a final fire (schedule-planner semantics). Dry-run inspects without mutating.
219
+ const retired = options.dryRun
220
+ ? partitionSchedule(store.list(), { now }).expired
221
+ : store.retireExpired(now);
222
+ const due = store.due(null, now);
134
223
  const actions = [];
135
224
 
136
225
  for (const entry of due) {
@@ -140,32 +229,112 @@ export async function runAgendaRun(options = {}, _deps = {}) {
140
229
  }
141
230
  try {
142
231
  if (entry.kind === "wakeup") {
143
- await spawnAgent(entry.prompt);
232
+ await spawnAgent(entry.prompt, entry.runPolicy);
144
233
  store.markWakeupFired(entry.id);
145
234
  actions.push({ id: entry.id, kind: "wakeup", action: "fired" });
146
235
  } else if (entry.kind === "cron") {
147
- await spawnAgent(entry.prompt);
236
+ await spawnAgent(entry.prompt, entry.runPolicy);
148
237
  store.advanceCron(entry.id);
149
238
  actions.push({ id: entry.id, kind: "cron", action: "fired" });
150
239
  } else if (entry.kind === "monitor") {
151
- const output = await runCommand(entry.command);
152
- const matched = entry.stopWhen
153
- ? new RegExp(entry.stopWhen).test(output)
154
- : false;
240
+ // Three sources: a shell command (match its output), a watched file
241
+ // (match its content, or — with no stopWhen — fire when it appears),
242
+ // or an HTTP endpoint (match its response body, or fire on 2xx).
243
+ let output = "";
244
+ let matched = false;
245
+ let mtimeMs = null;
246
+ if (entry.source === "file") {
247
+ const file = await readWatchedFile(entry.watchFile);
248
+ output = file.content;
249
+ mtimeMs = file.mtimeMs ?? null;
250
+ if (entry.watchChange) {
251
+ // Fire once the file's mtime advances past the baseline recorded on
252
+ // the first check. The first check only establishes the baseline.
253
+ matched =
254
+ entry.lastMtimeMs != null &&
255
+ mtimeMs != null &&
256
+ mtimeMs > entry.lastMtimeMs;
257
+ } else {
258
+ matched = entry.stopWhen
259
+ ? new RegExp(entry.stopWhen).test(file.content)
260
+ : file.exists; // no pattern → the file appearing is the signal
261
+ }
262
+ } else if (entry.source === "http") {
263
+ const res = await fetchUrl(entry.watchUrl);
264
+ output = res.body;
265
+ matched = entry.stopWhen
266
+ ? new RegExp(entry.stopWhen).test(res.body)
267
+ : res.ok; // no pattern → a 2xx response is the signal
268
+ } else {
269
+ output = await runCommand(entry.command);
270
+ matched = entry.stopWhen
271
+ ? new RegExp(entry.stopWhen).test(output)
272
+ : false;
273
+ }
155
274
  if (matched) {
156
- await notify({
157
- title: entry.notify?.title || `Monitor matched: ${entry.command}`,
158
- body: truncate(output, 500),
159
- level: "success",
275
+ const what =
276
+ entry.source === "file"
277
+ ? entry.watchFile
278
+ : entry.source === "http"
279
+ ? entry.watchUrl
280
+ : entry.command;
281
+ // Stamp the firing with the shared delivery guarantees (monitor-event.js):
282
+ // a deterministic event_id (audit identity, RNG-free) + a SYSTEM
283
+ // authority envelope (steer only — a monitor firing can NEVER answer a
284
+ // permission gate) + a byte-safe payload cap.
285
+ const envelope = monitorEventEnvelope(
286
+ entry.id,
287
+ { what, output },
288
+ { at: now, source: entry.source },
289
+ );
290
+ // At-most-once dedup: a persisted lastEventId equal to this event_id
291
+ // means this exact observation already fired (e.g. a resident daemon
292
+ // re-observing the same state) — record but do not re-notify.
293
+ const duplicate =
294
+ entry.lastEventId != null &&
295
+ entry.lastEventId === envelope.event_id;
296
+ // Persist the firing (status→matched + event_id + authority audit)
297
+ // BEFORE the notification side-effect so the record is durable even if
298
+ // the alert delivery fails; delivery itself is best-effort.
299
+ const updated = store.recordMonitorCheck(entry.id, {
300
+ matched: true,
301
+ mtimeMs,
302
+ eventId: envelope.event_id,
303
+ authority: envelope.authority,
304
+ });
305
+ const action = {
306
+ id: entry.id,
307
+ kind: "monitor",
308
+ action: duplicate ? "duplicate" : "matched",
309
+ status: updated?.status,
310
+ event_id: envelope.event_id,
311
+ authority: envelope.authority,
312
+ };
313
+ if (envelope.truncated) action.truncated = true;
314
+ if (!duplicate) {
315
+ try {
316
+ await notify({
317
+ title: entry.notify?.title || `Monitor matched: ${what}`,
318
+ body: capEventPayload(output, 500).value,
319
+ level: "success",
320
+ });
321
+ } catch (notifyErr) {
322
+ action.notifyError = notifyErr.message;
323
+ }
324
+ }
325
+ actions.push(action);
326
+ } else {
327
+ const updated = store.recordMonitorCheck(entry.id, {
328
+ matched: false,
329
+ mtimeMs,
330
+ });
331
+ actions.push({
332
+ id: entry.id,
333
+ kind: "monitor",
334
+ action: "checked",
335
+ status: updated?.status,
160
336
  });
161
337
  }
162
- const updated = store.recordMonitorCheck(entry.id, { matched });
163
- actions.push({
164
- id: entry.id,
165
- kind: "monitor",
166
- action: matched ? "matched" : "checked",
167
- status: updated?.status,
168
- });
169
338
  }
170
339
  } catch (err) {
171
340
  actions.push({
@@ -177,11 +346,25 @@ export async function runAgendaRun(options = {}, _deps = {}) {
177
346
  }
178
347
  }
179
348
 
349
+ const retiredSummary = retired.map((e) => ({ id: e.id, kind: e.kind }));
180
350
  if (options.json) {
181
- log(JSON.stringify({ due: due.length, actions }, null, 2));
182
- } else if (actions.length === 0) {
351
+ log(
352
+ JSON.stringify(
353
+ { due: due.length, retired: retiredSummary, actions },
354
+ null,
355
+ 2,
356
+ ),
357
+ );
358
+ } else if (actions.length === 0 && retired.length === 0) {
183
359
  log(chalk.gray(" Nothing due.\n"));
184
360
  } else {
361
+ for (const e of retired) {
362
+ log(
363
+ chalk.gray(
364
+ ` ${e.kind} ${e.id.slice(0, 8)}: ${options.dryRun ? "would-expire" : "expired"}`,
365
+ ),
366
+ );
367
+ }
185
368
  for (const a of actions) {
186
369
  const colour = a.action === "error" ? chalk.red : chalk.green;
187
370
  log(colour(` ${a.kind} ${a.id.slice(0, 8)}: ${a.action}`));
@@ -192,13 +375,72 @@ export async function runAgendaRun(options = {}, _deps = {}) {
192
375
 
193
376
  // ─── default effectful deps (overridable in tests) ─────────────────────────
194
377
 
195
- function defaultSpawnAgent(prompt) {
378
+ /**
379
+ * Build the `cc agent` argv for a scheduled prompt, appending the entry's
380
+ * per-task run policy as real `cc agent` flags. A missing / empty policy adds
381
+ * nothing, so an unpolicied task spawns exactly `cc agent -p <prompt>` as
382
+ * before (byte-identical). Exported for unit tests.
383
+ */
384
+ export function buildAgentArgs(prompt, policy = null) {
385
+ const args = ["agent", "-p", prompt];
386
+ // P1-8: a scheduled run is UNATTENDED — deny high-risk external tools
387
+ // (publish_artifact / notify) by default so no timer-fired agent can publish
388
+ // or message outward on its own. A task opts specific action classes back in
389
+ // via runPolicy.unattendedAllowlist; those tools are then NOT disallowed.
390
+ const disallow = unattendedDisallowedTools({
391
+ attended: false,
392
+ allowlist:
393
+ policy && Array.isArray(policy.unattendedAllowlist)
394
+ ? policy.unattendedAllowlist
395
+ : [],
396
+ });
397
+ if (disallow.length > 0) {
398
+ args.push("--disallowed-tools", disallow.join(","));
399
+ }
400
+ if (policy && typeof policy === "object") {
401
+ if (
402
+ typeof policy.permissionMode === "string" &&
403
+ policy.permissionMode.length > 0
404
+ ) {
405
+ args.push("--permission-mode", policy.permissionMode);
406
+ }
407
+ if (policy.worktree === true) args.push("--worktree");
408
+ if (Number.isFinite(policy.maxTurns) && policy.maxTurns > 0) {
409
+ args.push("--max-turns", String(policy.maxTurns));
410
+ }
411
+ if (
412
+ typeof policy.goalCondition === "string" &&
413
+ policy.goalCondition.length > 0
414
+ ) {
415
+ args.push("--goal-condition", policy.goalCondition);
416
+ if (Number.isFinite(policy.maxOuterTurns) && policy.maxOuterTurns > 0) {
417
+ args.push("--max-outer-turns", String(policy.maxOuterTurns));
418
+ }
419
+ if (Number.isFinite(policy.goalMaxTokens) && policy.goalMaxTokens > 0) {
420
+ args.push("--goal-max-tokens", String(policy.goalMaxTokens));
421
+ }
422
+ if (Number.isFinite(policy.goalMaxCost) && policy.goalMaxCost > 0) {
423
+ args.push("--goal-max-cost", String(policy.goalMaxCost));
424
+ }
425
+ if (Number.isFinite(policy.goalMaxTime) && policy.goalMaxTime > 0) {
426
+ args.push("--goal-max-time", String(policy.goalMaxTime));
427
+ }
428
+ }
429
+ }
430
+ return args;
431
+ }
432
+
433
+ function defaultSpawnAgent(prompt, policy = null) {
196
434
  return new Promise((resolve, reject) => {
197
- const child = spawn(process.execPath, [BIN_PATH, "agent", "-p", prompt], {
198
- stdio: "ignore",
199
- detached: false,
200
- env: process.env,
201
- });
435
+ const child = spawn(
436
+ process.execPath,
437
+ [BIN_PATH, ...buildAgentArgs(prompt, policy)],
438
+ {
439
+ stdio: "ignore",
440
+ detached: false,
441
+ env: process.env,
442
+ },
443
+ );
202
444
  child.on("error", reject);
203
445
  child.on("close", (code) =>
204
446
  code === 0 || code == null
@@ -221,6 +463,40 @@ function defaultRunCommand(command) {
221
463
  }
222
464
  }
223
465
 
466
+ /**
467
+ * Read a watched file → { exists, content, mtimeMs }. A missing file is not an
468
+ * error. mtimeMs feeds watchChange monitors (fire when the file is modified).
469
+ */
470
+ function defaultReadWatchedFile(filePath) {
471
+ try {
472
+ const content = readFileSync(filePath, "utf-8");
473
+ let mtimeMs = null;
474
+ try {
475
+ mtimeMs = statSync(filePath).mtimeMs;
476
+ } catch {
477
+ /* content read but stat failed — treat mtime as unknown */
478
+ }
479
+ return { exists: true, content, mtimeMs };
480
+ } catch {
481
+ return { exists: false, content: "", mtimeMs: null };
482
+ }
483
+ }
484
+
485
+ /**
486
+ * GET a watched URL → { ok, status, body }. Any failure (network, timeout,
487
+ * non-2xx) is not an error here — it just yields ok:false so the monitor
488
+ * re-arms and tries again next interval.
489
+ */
490
+ async function defaultFetchUrl(url) {
491
+ try {
492
+ const res = await fetch(url, { signal: AbortSignal.timeout(30000) });
493
+ const body = await res.text();
494
+ return { ok: res.ok, status: res.status, body };
495
+ } catch {
496
+ return { ok: false, status: 0, body: "" };
497
+ }
498
+ }
499
+
224
500
  function statusBadge(status) {
225
501
  switch (status) {
226
502
  case "pending":
@@ -231,6 +507,8 @@ function statusBadge(status) {
231
507
  return chalk.cyan(status);
232
508
  case "exhausted":
233
509
  return chalk.yellow(status);
510
+ case "expired":
511
+ return chalk.gray(status);
234
512
  default:
235
513
  return status;
236
514
  }
@@ -240,3 +518,13 @@ function truncate(text, n) {
240
518
  const s = String(text || "");
241
519
  return s.length > n ? s.slice(0, n) + "…" : s;
242
520
  }
521
+
522
+ /** Compact human summary of a scheduled entry's per-task run policy. */
523
+ function describePolicy(policy) {
524
+ const parts = [];
525
+ if (policy.permissionMode) parts.push(policy.permissionMode);
526
+ if (policy.worktree === true) parts.push("worktree");
527
+ if (Number.isFinite(policy.maxTurns)) parts.push(`≤${policy.maxTurns} turns`);
528
+ if (policy.goalCondition) parts.push(`goal: ${policy.goalCondition}`);
529
+ return parts.join(", ");
530
+ }
@@ -204,6 +204,10 @@ export function registerAgentCommand(program) {
204
204
  "--otlp <file>",
205
205
  "Write the agent run's OpenTelemetry spans (model/tool/retry) as OTLP/JSON to <file>",
206
206
  )
207
+ .option(
208
+ "--otlp-content",
209
+ "Include prompt/response CONTENT in --otlp spans (off by default; content is redacted unless this is set)",
210
+ )
207
211
  .option(
208
212
  "--auto-rewake",
209
213
  "When an async `asyncRewake` hook (e.g. a background test) fails at turn end, re-engage the agent to fix it (bounded by --max-rewakes)",
@@ -311,6 +315,30 @@ export function registerAgentCommand(program) {
311
315
  "--goal-assess",
312
316
  "After the run, ask the model to assess goal progress and persist it (opt-in; costs one extra completion; requires --goal)",
313
317
  )
318
+ .option(
319
+ "--goal-condition <spec>",
320
+ "Session completion condition; re-drives outer turns until met. Prefix exit-zero:/file-exists:/contains:/regex: (deterministic) or model:<desc> (model-judged)",
321
+ )
322
+ .option(
323
+ "--max-outer-turns <n>",
324
+ "Max outer re-drive turns for --goal-condition (default 10, hard cap 100)",
325
+ (v) => parseInt(v, 10),
326
+ )
327
+ .option(
328
+ "--goal-max-tokens <n>",
329
+ "Token budget across --goal-condition outer turns",
330
+ (v) => parseInt(v, 10),
331
+ )
332
+ .option(
333
+ "--goal-max-cost <usd>",
334
+ "Cost budget (USD) across --goal-condition outer turns",
335
+ (v) => parseFloat(v),
336
+ )
337
+ .option(
338
+ "--goal-max-time <ms>",
339
+ "Wall-clock budget (ms) across --goal-condition outer turns",
340
+ (v) => parseInt(v, 10),
341
+ )
314
342
  .option(
315
343
  "--mcp-config <file>",
316
344
  "Load ad-hoc MCP servers from a JSON file for this run (headless); their tools become callable (mcp__<server>__<tool>)",
@@ -871,6 +899,11 @@ export function registerAgentCommand(program) {
871
899
  maxCostUsd,
872
900
  priceTable,
873
901
  chatFn: fallbackChatFn,
902
+ // --json-schema: structured output for stream-INPUT mode. The schema
903
+ // is resolved + meta-validated up front, its output contract injected
904
+ // into the system prompt, and a per-turn `structured_result` event is
905
+ // appended after each turn (parity with single-prompt --json-schema).
906
+ jsonSchema: options.jsonSchema || null,
874
907
  });
875
908
  } catch (err) {
876
909
  process.stderr.write(`Error: ${err.message}\n`);
@@ -1001,6 +1034,19 @@ export function registerAgentCommand(program) {
1001
1034
  }
1002
1035
  const { runAgentHeadless, parseToolList } =
1003
1036
  await import("../runtime/headless-runner.js");
1037
+ // --goal-condition: validate the spec up front so a bad prefix fails
1038
+ // fast (before any model call) with a clear message.
1039
+ if (options.goalCondition) {
1040
+ try {
1041
+ const { parseGoalCondition } =
1042
+ await import("../lib/goal-condition-engine.js");
1043
+ parseGoalCondition(options.goalCondition);
1044
+ } catch (e) {
1045
+ process.stderr.write(`--goal-condition: ${e.message}\n`);
1046
+ await _finishWorktree();
1047
+ process.exit(1);
1048
+ }
1049
+ }
1004
1050
  const maxTurns = options.maxTurns
1005
1051
  ? parseInt(options.maxTurns, 10)
1006
1052
  : undefined;
@@ -1027,6 +1073,9 @@ export function registerAgentCommand(program) {
1027
1073
  autoCheckpoint,
1028
1074
  // --otlp <file>: capture + export the run's OTel spans as OTLP/JSON.
1029
1075
  otlp: options.otlp || null,
1076
+ // --otlp-content: opt in to emitting prompt/response CONTENT in those
1077
+ // spans. Default false → content stays redacted (privacy by default).
1078
+ otlpContent: options.otlpContent === true,
1030
1079
  // --auto-rewake / --max-rewakes: bounded re-drive on async-hook failure.
1031
1080
  // --max-rewakes implies --auto-rewake (a positive budget turns it on).
1032
1081
  autoRewake:
@@ -1052,6 +1101,21 @@ export function registerAgentCommand(program) {
1052
1101
  goal: options.goal,
1053
1102
  // --goal-assess: run-end LLM progress assessment (Phase 2)
1054
1103
  goalAssess: options.goalAssess === true,
1104
+ // --goal-condition: session-level completion-condition engine — drives
1105
+ // outer turns until the condition is met or a budget is exhausted.
1106
+ goalCondition: options.goalCondition || null,
1107
+ maxOuterTurns: Number.isFinite(options.maxOuterTurns)
1108
+ ? options.maxOuterTurns
1109
+ : undefined,
1110
+ goalMaxTokens: Number.isFinite(options.goalMaxTokens)
1111
+ ? options.goalMaxTokens
1112
+ : undefined,
1113
+ goalMaxCostUsd: Number.isFinite(options.goalMaxCost)
1114
+ ? options.goalMaxCost
1115
+ : undefined,
1116
+ goalMaxTimeMs: Number.isFinite(options.goalMaxTime)
1117
+ ? options.goalMaxTime
1118
+ : undefined,
1055
1119
  // --mcp-config: connect ad-hoc MCP servers + expose their tools
1056
1120
  mcpConfig: options.mcpConfig || null,
1057
1121
  // --no-mcp: skip registered (cc mcp add) auto-connect servers
@@ -1081,21 +1145,51 @@ export function registerAgentCommand(program) {
1081
1145
  chatFn: fallbackChatFn,
1082
1146
  };
1083
1147
 
1084
- // --json-schema: structured output 鈥?wrap the runner with capture +
1085
- // validate + retry (json-schema-output.js); prints only the
1086
- // validated JSON. Incompatible with stream-json (event stream and a
1087
- // single JSON contract don't mix).
1148
+ // --json-schema: structured output. Accepts a file path OR inline JSON.
1149
+ // - text/json output: wrap the runner with capture + validate + retry
1150
+ // (json-schema-output.js); prints only the validated JSON.
1151
+ // - stream-json output: stream events normally, then emit a terminal
1152
+ // `structured_result` event (schema_digest + valid + value/errors) as
1153
+ // the last NDJSON line, so the two protocols are now compatible.
1088
1154
  if (options.jsonSchema) {
1155
+ const jso = await import("../lib/json-schema-output.js");
1089
1156
  if (options.outputFormat === "stream-json") {
1090
- process.stderr.write(
1091
- "--json-schema is incompatible with --output-format stream-json.\n",
1092
- );
1093
- process.exit(1);
1157
+ try {
1158
+ const schema = jso.loadSchemaFile(
1159
+ jso._deps.fs,
1160
+ options.jsonSchema,
1161
+ );
1162
+ const instruction = jso.buildSchemaInstruction(schema);
1163
+ const outcome = await runAgentHeadless({
1164
+ ...headlessOptions,
1165
+ appendSystemPrompt: [
1166
+ headlessOptions.appendSystemPrompt,
1167
+ instruction,
1168
+ ]
1169
+ .filter(Boolean)
1170
+ .join("\n\n"),
1171
+ });
1172
+ // The normal stream (init … result) has already been written to
1173
+ // stdout by the runner. Append the structured verdict as the final
1174
+ // NDJSON line, built from the run's final text.
1175
+ const parsed = jso.extractJsonPayload(
1176
+ String(outcome?.result ?? ""),
1177
+ );
1178
+ const evt = jso.buildStructuredResult(
1179
+ schema,
1180
+ parsed.ok ? parsed.value : null,
1181
+ );
1182
+ process.stdout.write(JSON.stringify(evt) + "\n");
1183
+ await _finishWorktree();
1184
+ process.exit(evt.valid ? 0 : 1);
1185
+ } catch (err) {
1186
+ process.stderr.write(`Error: ${err.message}\n`);
1187
+ await _finishWorktree();
1188
+ process.exit(1);
1189
+ }
1094
1190
  }
1095
1191
  try {
1096
- const { runJsonSchemaConstrained } =
1097
- await import("../lib/json-schema-output.js");
1098
- const code = await runJsonSchemaConstrained({
1192
+ const code = await jso.runJsonSchemaConstrained({
1099
1193
  schemaFile: options.jsonSchema,
1100
1194
  baseOptions: headlessOptions,
1101
1195
  runHeadless: runAgentHeadless,