chainlesschain 0.162.158 → 0.162.159

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 (201) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AIOps-BwpTJTN_.js → AIOps-ByIiF5bT.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-BtQOoo3l.js → ActionButton-NlgSFZq5.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-Duf_rXZa.js → Analytics-D17cOUcb.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-XQK3wjvB.js → AppLayout-B4mEZcbl.js} +4 -4
  6. package/src/assets/web-panel/assets/Artifacts-CASsmyQw.js +1 -0
  7. package/src/assets/web-panel/assets/{Audit-DNjOGQLh.js → Audit-DYAia2e2.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-FH9RAfB5.js → BackgroundAgents-C1lvYUSu.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-ZIbrR4-U.js → Backup-B6agK6bA.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-DSt3NaND.js → BaseInput-DM43R2vy.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-CY-wvbjv.js → Chat-Dtdp3eXp.js} +5 -5
  12. package/src/assets/web-panel/assets/{ChatBubbleRenderer-BAV9V-t-.js → ChatBubbleRenderer-BL5c_OQ1.js} +1 -1
  13. package/src/assets/web-panel/assets/{Checkbox-8JVadE_B.js → Checkbox-D2xf7uZt.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-CN83nPYI.js → Codegen-D3j45jJL.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-xPSvqdN8.js → Col-voPJ9fUZ.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-D78cnIjG.js → Community-DEsyTESF.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-CSw6Csbp.js → Compact-OHV_QXLD.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-E_HhjcYR.js → Compliance-eDTJWC-J.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-DybeQjmm.js → Cowork-BBvy-6d1.js} +3 -3
  20. package/src/assets/web-panel/assets/{Cron-DS0BJeLY.js → Cron-Dw2eoJxu.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-BOwVgkbs.js → Crosschain-DQHms_Bh.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-DRUr9YuX.js → DID-Cyu7Id1c.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-Cht-yUKW.js → Dashboard-sIDzkG92.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-BLr_EJ9X.js → Dropdown-DUW3T2ey.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-Drexuh5W.js → EmailListRenderer-CECELXW8.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-D9Q2Kq63.js → FamilyGuardDashboard-BIZR37ov.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-C-Z1xI-T.js → Federation-BEZIQX84.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-DLHPMkQF.js → FormItemContext-BcdUMznL.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-DxxEdn2r.js → GenericCardRenderer-DsN_fr5H.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-syATcaBt.js → Git-63LhjBx2.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-CYe_r8Zf.js → Governance-CYtQtIcH.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-GWxErB7k.js → Inference-BwR6UUox.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-qQvVCZoi.js → KnowledgeGraph-D9lVNTUA.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-BenAU2W8.js → Logs-C4q5h7Ut.js} +2 -2
  35. package/src/assets/web-panel/assets/{MarkdownRenderer-7agE3Or1.js → MarkdownRenderer-DexLlXfN.js} +1 -1
  36. package/src/assets/web-panel/assets/{Marketplace-D4Jn5fpD.js → Marketplace-Plksliuw.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-DtAwoqiQ.js → McpTools-DZUFfeuG.js} +4 -4
  38. package/src/assets/web-panel/assets/{Memory-BI_O50I8.js → Memory-NoDYt29V.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-CQWE2lqx.js → MobileBridge-CEXGTkdh.js} +1 -1
  40. package/src/assets/web-panel/assets/{MobileProjects-CVtTqgtg.js → MobileProjects-DnbJkbZo.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-Dnr16qsn.js → Mtc-DTAa0cwy.js} +5 -5
  42. package/src/assets/web-panel/assets/{MtcAudit-CQ5Xe4-a.js → MtcAudit-CVV7LnNS.js} +2 -2
  43. package/src/assets/web-panel/assets/{Multisig-Bjr8O-wy.js → Multisig-BqqGrjt_.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-CEe-KirU.js → NLProgramming-C4WP8DRp.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-spKJIKF9.js → Notes-Zo4DJUVI.js} +4 -4
  46. package/src/assets/web-panel/assets/{NotificationSettings-DRp83LFG.js → NotificationSettings-DBcjRaz2.js} +1 -1
  47. package/src/assets/web-panel/assets/OrderTableRenderer-BCQel9bD.js +1 -0
  48. package/src/assets/web-panel/assets/{Organization-BlgB0IYg.js → Organization-BT9WPBOX.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-a_35HqZI.js → Overflow-D6b4bZ3q.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-CSNHCNPC.js → P2P-Cw3OsYx-.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-C8M1JH-1.js → PdhVaultBrowser-C0nyiK2b.js} +5 -5
  52. package/src/assets/web-panel/assets/{Permissions-DmjJi9Ms.js → Permissions-zVBZEB_C.js} +3 -3
  53. package/src/assets/web-panel/assets/{PersonalDataHub-DfuwRyf4.js → PersonalDataHub-BOspsFew.js} +2 -2
  54. package/src/assets/web-panel/assets/{Pipeline-B2-S4ekE.js → Pipeline-CQWfZ4XH.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-B1dOiBLC.js → Privacy-C2oGJ_WL.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-_pNmc-DX.js → ProjectInit-BZMR4qY1.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-DmwG2Ii1.js → ProjectSettings-DAujoP63.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-COATmHxF.js → Projects-DvH_P2Uq.js} +1 -1
  59. package/src/assets/web-panel/assets/{Providers-C6HSjg1d.js → Providers-D_RGHM-v.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-CrDmS7l1.js → QrScannerModal-Mf6KfL2J.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-CfKvWt-x.js → QuickAsk-5D8URoI_.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-DMa6Kuzv.js → Recommend-Df4kC8Gy.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-DrktUo5x.js → RemoteSession-DGi3f3vO.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-BTPQ1vjL.js → Reputation-jmkGFNWb.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-B6Q7QkMG.js → Row-DP6Pcu3m.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-B1IJhAmX.js → RssFeed-D60hSuPO.js} +3 -3
  67. package/src/assets/web-panel/assets/{Search-xbea1kGD.js → Search-0mf1BQUK.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-7rs0cO3F.js → Security-CfZtLFYV.js} +4 -4
  69. package/src/assets/web-panel/assets/{Services-0fjixK0S.js → Services-D9zpZLWz.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-B_rVq9Cu.js → Skeleton-D1_44eMD.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-C5uM90b9.js → Skills-cVFa8zkz.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-U4pYCIZH.js → Sla-Cinpzc3L.js} +1 -1
  73. package/src/assets/web-panel/assets/{SpeechSettings-Cdz4yTWx.js → SpeechSettings-bqdiJE_P.js} +1 -1
  74. package/src/assets/web-panel/assets/{SyncSettings-Me3aetHv.js → SyncSettings-Dgl_SLgj.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-Cf6aNkL_.js → Tasks-DawWAEhy.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-CYatk4tU.js → Templates-Ca0nY651.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-DIMKLw7o.js → Tenant-CgaGEhLm.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-C_cp-uSJ.js → Terminal-D-9EnpRx.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-cUPVNADp.js → TimelineRenderer-CSOxDHZ6.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-CiaEIXVf.js → Tokens-BpwLZpL3.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-DB1WU5lQ.js → Trigger-DgowwBK5.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-Cfht9Ijy.js → Trust-BZutapjE.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-K3P4Vt9S.js → UkeySign-QZPt8_Sp.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-DWjhjXRh.js → VideoEditing-DlQx5UDJ.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-D9-Q1Kan.js → Wallet-ZfdTgtWA.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-BDszy-oV.js → WebAuthn-CAp0y_Cr.js} +5 -5
  87. package/src/assets/web-panel/assets/{WorkflowEditor-DIhij4rA.js → WorkflowEditor-BVITZEmr.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-D7VCiKbh.js → chat-CC2tPaNg.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-BvOd9pVn.js → colors-31brc9CA.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-DoqXBiAO.js → compact-item-DLMkC9C-.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-CrKRzUtp.js → createContext-BMtveI6F.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-CB8pPOtd.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-BWAev4WC.js → hasIn-DbD6WHW2.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-B30NvR21.js → index-3oBsXZmF.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-Cx7M7PSF.js → index-ALvoNTRF.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-BHOcVYrx.js → index-AaIKG60c.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BXyl8O23.js → index-BFRLmCR3.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-YGDy7nNq.js → index-BKAB6-6V.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BoYrS_L2.js → index-BOM-VFlv.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-Bq_ctRpz.js → index-BPpS-lGb.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-CDGLdn12.js → index-Bbc2JeQG.js} +1 -1
  102. package/src/assets/web-panel/assets/index-BhXiaiev.js +1 -0
  103. package/src/assets/web-panel/assets/{index-ISvPZ05r.js → index-BiRQUoyE.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-B0vGEbJT.js → index-BnFLzejT.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-Bj7EgmOp.js → index-BoO4WEJB.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-BZGk8AbZ.js → index-C-cGlCDW.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BkgnGX7v.js → index-C1PfeI88.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-HwHdTusY.js → index-C21pdBqs.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Bf9YlbDn.js → index-C7LHNw_N.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-oY45XrkG.js → index-CEXa-4zd.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-KR1-Em9C.js → index-CEwjBA9q.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-C5kRmj3P.js → index-CFXKbOek.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BN9m4Ux2.js → index-CJhREOlG.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-PDxGjKRu.js → index-COHHQ9cU.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-D23L1V76.js → index-CUmLMFsy.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-zH-tuuGZ.js → index-CWgfipcC.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CmJ6xKBO.js → index-C_eUKGYP.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CEPHMSih.js → index-CcVszn2b.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DV-Rfmfx.js → index-Cod97Urs.js} +3 -3
  120. package/src/assets/web-panel/assets/{index-BWWsaimP.js → index-Cwbqh0KZ.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-8g5TJCZ3.js → index-D67kIagl.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CEXfKSiI.js → index-D7cV0tu0.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CoD31Ndm.js → index-DJvxFyIz.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CSb-tnIo.js → index-DZl-UXB6.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DvDOpsJB.js → index-Dm0byjm1.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DlGu7As6.js → index-DndNnYc0.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-gmxqu5Kk.js → index-WQUO2vvK.js} +1 -1
  128. package/src/assets/web-panel/assets/index-WpaYaE3D.js +1 -0
  129. package/src/assets/web-panel/assets/{index-ww1QtLnX.js → index-bdaJwTXJ.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-JzUmJMvn.js → index-ep6JchNG.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BCyP071m.js → index-jG6h22Qg.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-1poMpMU0.js → index-ntVQqSML.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-XW-OR3mL.js → initDefaultProps-D5UoBRhN.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-CeuEHh20.js → motion-DltOw0CR.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-Dva79Keg.js → move-_oPkk5zj.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-C0B6bD2j.js → mtc-parser-EES8ROCS.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-AkZvO-a2.js → omit-B-_39x_M.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-B4r55qGc.js → pickAttrs-l6D0yJHz.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-BLH-z7YE.js → placementArrow-DIeUK31L.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-ksEGZ2Wf.js → responsiveObserve-dG4EzUQo.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-Cth4OD1Z.js → slide-DWFzYGdH.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-9S83ezxw.js → statusUtils-CECdTA5H.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-7yQmQGZ4.js → styleChecker-D6kP-mMK.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-DpGnMmPc.js → useFlexGapSupport-BWfna_rd.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-C4zDZIXH.js → useFs-Bb-j6rzo.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-CoLICdUZ.js → usePersonalDataHub-D5OIsYM4.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-CKyH-35X.js → vnode-DNpwzFTM.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-DRDGit17.js → zoom-vNLpFQBW.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/command-manifest.json +17 -3
  151. package/src/commands/agent.js +7 -0
  152. package/src/commands/background-session.js +143 -3
  153. package/src/commands/browse.js +86 -0
  154. package/src/commands/cloud.js +232 -0
  155. package/src/commands/doctor.js +61 -6
  156. package/src/commands/mcp.js +61 -0
  157. package/src/commands/plugin.js +63 -1
  158. package/src/commands/routine.js +367 -0
  159. package/src/commands/session.js +326 -0
  160. package/src/data/changelog.json +7 -2
  161. package/src/harness/jsonl-session-store.js +82 -2
  162. package/src/harness/session-index.js +295 -0
  163. package/src/harness/session-mirror.js +142 -0
  164. package/src/harness/transcript-integrity.js +182 -0
  165. package/src/index.js +8 -0
  166. package/src/lib/background-agent-supervisor.js +126 -2
  167. package/src/lib/channels/channel-manager.js +126 -0
  168. package/src/lib/channels/telegram-channel.js +112 -0
  169. package/src/lib/channels/webhook-channel.js +140 -0
  170. package/src/lib/chrome-connector.js +386 -0
  171. package/src/lib/cloud/bundle.js +110 -0
  172. package/src/lib/cloud/cloud-client.js +152 -0
  173. package/src/lib/computer-use/authorization.js +173 -0
  174. package/src/lib/computer-use/computer-use-server.js +276 -0
  175. package/src/lib/computer-use/control-backend.js +150 -0
  176. package/src/lib/doctor-checkup.js +652 -0
  177. package/src/lib/jsonl-session-store.js +4 -0
  178. package/src/lib/lsp/lsp-server-registry.js +48 -21
  179. package/src/lib/plugin-runtime/governance.js +174 -0
  180. package/src/lib/pr-link-ledger.js +221 -0
  181. package/src/lib/routine-store.js +352 -0
  182. package/src/lib/session-store-guard.js +40 -0
  183. package/src/lib/session-usage.js +318 -2
  184. package/src/lib/sub-agent-context.js +23 -0
  185. package/src/repl/agent-repl.js +361 -3
  186. package/src/repl/bg-dashboard.js +355 -0
  187. package/src/repl/fast-mode.js +103 -0
  188. package/src/repl/fullscreen-tui.js +197 -0
  189. package/src/repl/slash-command-registry.js +11 -3
  190. package/src/repl/voice-dictation.js +132 -0
  191. package/src/runtime/agent-core.js +242 -1
  192. package/src/runtime/coding-agent-contract-shared.cjs +88 -0
  193. package/src/runtime/coding-agent-policy.cjs +17 -0
  194. package/src/runtime/headless-runner.js +71 -7
  195. package/src/runtime/headless-stream.js +14 -8
  196. package/src/runtime/policies/agent-policy.js +3 -0
  197. package/src/assets/web-panel/assets/Artifacts-DQvJoQ6E.js +0 -1
  198. package/src/assets/web-panel/assets/OrderTableRenderer-h1A0XB2a.js +0 -1
  199. package/src/assets/web-panel/assets/devWarning-nDB--2xr.js +0 -1
  200. package/src/assets/web-panel/assets/index-B1_pRTtB.js +0 -1
  201. package/src/assets/web-panel/assets/index-TMM9FuW-.js +0 -1
@@ -538,10 +538,61 @@ export function registerPluginCommand(program) {
538
538
 
539
539
  const counts = summarizeComponents(manifest);
540
540
 
541
+ // Dependency version constraints (gap P2#13): if the manifest declares
542
+ // `dependencies` (plugin name → semver range, plus reserved host/cc),
543
+ // check them against what's installed and the running cc version. Unmet
544
+ // deps are surfaced but do not by themselves fail structural validation —
545
+ // they may simply be absent in this environment.
546
+ let dependencyCheck = null;
547
+ try {
548
+ const rawManifest = manifest.manifestPath
549
+ ? JSON.parse(
550
+ (await import("node:fs")).readFileSync(
551
+ manifest.manifestPath,
552
+ "utf8",
553
+ ),
554
+ )
555
+ : {};
556
+ if (rawManifest && rawManifest.dependencies) {
557
+ const { checkPluginDependencies, formatDependencyIssues } =
558
+ await import("../lib/plugin-runtime/governance.js");
559
+ const { discoverPlugins } =
560
+ await import("../lib/plugin-runtime/scopes.js");
561
+ const { VERSION } = await import("../constants.js");
562
+ const installed = {};
563
+ try {
564
+ for (const p of discoverPlugins({ skipPolicy: true })) {
565
+ installed[p.name] = p.version;
566
+ }
567
+ } catch {
568
+ /* discovery best-effort */
569
+ }
570
+ const result = checkPluginDependencies(rawManifest, {
571
+ installed,
572
+ hostVersion: VERSION,
573
+ });
574
+ dependencyCheck = {
575
+ ok: result.ok,
576
+ issues: formatDependencyIssues(
577
+ manifest.metadata?.name || dir,
578
+ result,
579
+ ),
580
+ ...result,
581
+ };
582
+ }
583
+ } catch {
584
+ /* dependency inspection is best-effort */
585
+ }
586
+
541
587
  if (options.json) {
542
588
  console.log(
543
589
  JSON.stringify(
544
- { ...manifest, componentCounts: counts, verification },
590
+ {
591
+ ...manifest,
592
+ componentCounts: counts,
593
+ verification,
594
+ dependencyCheck,
595
+ },
545
596
  null,
546
597
  2,
547
598
  ),
@@ -570,6 +621,17 @@ export function registerPluginCommand(program) {
570
621
  (verification.ok ? chalk.green("passed") : chalk.red("FAILED")),
571
622
  );
572
623
  }
624
+ if (dependencyCheck) {
625
+ logger.log(
626
+ chalk.bold("\nDependencies: ") +
627
+ (dependencyCheck.ok
628
+ ? chalk.green("satisfied")
629
+ : chalk.yellow("unmet")),
630
+ );
631
+ for (const issue of dependencyCheck.issues) {
632
+ logger.log(chalk.yellow(` ⚠ ${issue}`));
633
+ }
634
+ }
573
635
  for (const w of manifest.warnings) logger.log(chalk.yellow(` ⚠ ${w}`));
574
636
  for (const e of manifest.errors) logger.log(chalk.red(` ✖ ${e}`));
575
637
  if (manifest.ok) {
@@ -0,0 +1,367 @@
1
+ /**
2
+ * `cc routine` — named scheduled/triggered agent tasks with run history
3
+ * (gap-2026-07-11 P1#8; Claude-Code Routines parity, self-hosted).
4
+ *
5
+ * cc routine create "nightly report" --prompt "..." --cron "0 3 * * *"
6
+ * cc routine create "deploy watch" --prompt "..." --github acme/app --events PushEvent
7
+ * cc routine create "one shot" --prompt "..." --at 2026-07-12T09:00:00Z
8
+ * cc routine create "ci hook" --prompt "..." --webhook
9
+ * cc routine list · enable/disable · trigger <id> · run · runs [id] · logs <runId> · remove <id>
10
+ *
11
+ * `cc routine run` is the driver (fire due cron/once + poll github) — run it
12
+ * periodically (`cc loop --every 1m -- cc routine run`, system cron, or an
13
+ * agenda wakeup), exactly like `cc agenda run`.
14
+ */
15
+
16
+ import { spawn, execFile } from "node:child_process";
17
+ import { readFileSync, existsSync } from "node:fs";
18
+ import { fileURLToPath } from "node:url";
19
+ import chalk from "chalk";
20
+ import { logger } from "../lib/logger.js";
21
+
22
+ const BIN_PATH = fileURLToPath(
23
+ new URL("../../bin/chainlesschain.js", import.meta.url),
24
+ );
25
+
26
+ async function loadStore() {
27
+ const { RoutineStore } = await import("../lib/routine-store.js");
28
+ return new RoutineStore();
29
+ }
30
+
31
+ /** Production runner: `cc agent -p <prompt> --output-format json`. */
32
+ function defaultRunAgent({ prompt }) {
33
+ return new Promise((resolve) => {
34
+ const child = spawn(
35
+ process.execPath,
36
+ [BIN_PATH, "agent", "-p", prompt, "--output-format", "json"],
37
+ { windowsHide: true },
38
+ );
39
+ let out = "";
40
+ let err = "";
41
+ child.stdout?.setEncoding("utf8");
42
+ child.stderr?.setEncoding("utf8");
43
+ child.stdout?.on("data", (d) => (out += d));
44
+ child.stderr?.on("data", (d) => (err += d));
45
+ child.on("error", (error) =>
46
+ resolve({ exitCode: -1, output: `spawn error: ${error.message}` }),
47
+ );
48
+ child.on("close", (code) => {
49
+ let usage = null;
50
+ let costUsd;
51
+ let resultText = "";
52
+ try {
53
+ // result envelope is the last JSON line on stdout
54
+ const lines = out.split("\n").filter((l) => l.trim());
55
+ const envelope = JSON.parse(lines[lines.length - 1]);
56
+ usage = envelope.usage || null;
57
+ costUsd = Number(envelope.total_cost_usd ?? envelope.costUsd);
58
+ resultText = envelope.result || "";
59
+ } catch {
60
+ /* non-JSON output still recorded verbatim */
61
+ }
62
+ resolve({
63
+ exitCode: code ?? -1,
64
+ output: resultText || out || err,
65
+ usage,
66
+ costUsd: Number.isFinite(costUsd) ? costUsd : undefined,
67
+ });
68
+ });
69
+ });
70
+ }
71
+
72
+ /** Production github events fetch via gh CLI. */
73
+ function defaultFetchEvents(repo) {
74
+ return new Promise((resolve) => {
75
+ execFile(
76
+ "gh",
77
+ ["api", `repos/${repo}/events`, "--paginate=false"],
78
+ { encoding: "utf8", timeout: 8000, windowsHide: true },
79
+ (err, stdout) => {
80
+ if (err) return resolve([]);
81
+ try {
82
+ const rows = JSON.parse(stdout);
83
+ resolve(
84
+ (Array.isArray(rows) ? rows : []).map((r) => ({
85
+ id: r.id,
86
+ type: r.type,
87
+ })),
88
+ );
89
+ } catch {
90
+ resolve([]);
91
+ }
92
+ },
93
+ );
94
+ });
95
+ }
96
+
97
+ function describeTrigger(routine) {
98
+ const t = routine.trigger || {};
99
+ if (t.kind === "cron") return `cron ${t.cron}`;
100
+ if (t.kind === "once") return `once ${new Date(t.at).toISOString()}`;
101
+ if (t.kind === "github")
102
+ return `github ${t.repo}${t.events?.length ? ` (${t.events.join(",")})` : ""}`;
103
+ return "webhook (cc routine trigger)";
104
+ }
105
+
106
+ export function registerRoutineCommand(program) {
107
+ const routine = program
108
+ .command("routine")
109
+ .description(
110
+ "Named scheduled/triggered agent tasks with run history (cron/once/webhook/github)",
111
+ );
112
+
113
+ routine
114
+ .command("create <name>")
115
+ .description(
116
+ "Create a routine (exactly one of --cron/--at/--webhook/--github)",
117
+ )
118
+ .requiredOption("--prompt <text>", "Agent prompt to run")
119
+ .option("--cron <expr>", "5-field cron schedule (driver-fired)")
120
+ .option("--at <time>", "One-off ISO time / epoch ms (driver-fired)")
121
+ .option("--webhook", "Fire externally via `cc routine trigger <id>`")
122
+ .option(
123
+ "--github <repo>",
124
+ "Fire on new GitHub events for owner/name (driver-polled via gh)",
125
+ )
126
+ .option(
127
+ "--events <list>",
128
+ "GitHub event types filter (e.g. PushEvent,PullRequestEvent)",
129
+ )
130
+ .option("--json", "Output as JSON")
131
+ .action(async (name, options) => {
132
+ try {
133
+ const picked = [
134
+ options.cron && "cron",
135
+ options.at && "once",
136
+ options.webhook && "webhook",
137
+ options.github && "github",
138
+ ].filter(Boolean);
139
+ if (picked.length !== 1) {
140
+ throw new Error(
141
+ "pick exactly one trigger: --cron <expr> | --at <time> | --webhook | --github <repo>",
142
+ );
143
+ }
144
+ const trigger =
145
+ picked[0] === "cron"
146
+ ? { kind: "cron", cron: options.cron }
147
+ : picked[0] === "once"
148
+ ? { kind: "once", at: options.at }
149
+ : picked[0] === "github"
150
+ ? {
151
+ kind: "github",
152
+ repo: options.github,
153
+ events: options.events
154
+ ? options.events.split(",").map((s) => s.trim())
155
+ : [],
156
+ }
157
+ : { kind: "webhook" };
158
+ const store = await loadStore();
159
+ const created = store.create({ name, prompt: options.prompt, trigger });
160
+ if (options.json) return console.log(JSON.stringify(created, null, 2));
161
+ logger.success(
162
+ `Created routine ${created.id} (${describeTrigger(created)})`,
163
+ );
164
+ if (trigger.kind === "webhook") {
165
+ logger.log(
166
+ chalk.gray(` fire it with: cc routine trigger ${created.id}`),
167
+ );
168
+ } else {
169
+ logger.log(chalk.gray(" driver: run `cc routine run` periodically"));
170
+ }
171
+ } catch (err) {
172
+ logger.error(err.message);
173
+ process.exitCode = 1;
174
+ }
175
+ });
176
+
177
+ routine
178
+ .command("list", { isDefault: true })
179
+ .description("List routines with run/cost summaries")
180
+ .option("--json", "Output as JSON")
181
+ .action(async (options) => {
182
+ try {
183
+ const store = await loadStore();
184
+ const routines = store.list().map((r) => ({
185
+ ...r,
186
+ summary: store.summarize(r.id),
187
+ }));
188
+ if (options.json) return console.log(JSON.stringify(routines, null, 2));
189
+ if (routines.length === 0) {
190
+ logger.log(
191
+ chalk.gray("No routines. Create one with `cc routine create`."),
192
+ );
193
+ return;
194
+ }
195
+ for (const r of routines) {
196
+ const state = r.enabled ? chalk.green("on ") : chalk.gray("off");
197
+ const s = r.summary;
198
+ const cost = s.costUsd ? ` $${s.costUsd.toFixed(4)}` : "";
199
+ logger.log(
200
+ `${state} ${r.id} ${chalk.bold(r.name)} ${chalk.gray(describeTrigger(r))}`,
201
+ );
202
+ logger.log(
203
+ chalk.gray(
204
+ ` runs ${s.totalRuns} (${s.ok} ok, ${s.failed} failed${s.running ? `, ${s.running} running` : ""})${cost}`,
205
+ ),
206
+ );
207
+ }
208
+ } catch (err) {
209
+ logger.error(err.message);
210
+ process.exitCode = 1;
211
+ }
212
+ });
213
+
214
+ routine
215
+ .command("enable <id>")
216
+ .description("Enable a routine")
217
+ .action(async (id) => {
218
+ try {
219
+ const store = await loadStore();
220
+ const r = store.setEnabled(id, true);
221
+ logger.success(`Enabled ${r.id} (${r.name})`);
222
+ } catch (err) {
223
+ logger.error(err.message);
224
+ process.exitCode = 1;
225
+ }
226
+ });
227
+
228
+ routine
229
+ .command("disable <id>")
230
+ .description("Disable a routine (kept, never fires)")
231
+ .action(async (id) => {
232
+ try {
233
+ const store = await loadStore();
234
+ const r = store.setEnabled(id, false);
235
+ logger.success(`Disabled ${r.id} (${r.name})`);
236
+ } catch (err) {
237
+ logger.error(err.message);
238
+ process.exitCode = 1;
239
+ }
240
+ });
241
+
242
+ routine
243
+ .command("remove <id>")
244
+ .description("Delete a routine (run history is kept)")
245
+ .action(async (id) => {
246
+ try {
247
+ const store = await loadStore();
248
+ const r = store.remove(id);
249
+ logger.success(`Removed ${r.id} (${r.name})`);
250
+ } catch (err) {
251
+ logger.error(err.message);
252
+ process.exitCode = 1;
253
+ }
254
+ });
255
+
256
+ routine
257
+ .command("trigger <id>")
258
+ .description("Fire a routine NOW (the webhook/API entry point)")
259
+ .option("--json", "Output as JSON")
260
+ .action(async (id, options) => {
261
+ try {
262
+ const store = await loadStore();
263
+ const r = store.get(id);
264
+ if (!r) throw new Error(`routine not found: ${id}`);
265
+ const { fireRoutine } = await import("../lib/routine-store.js");
266
+ const runId = await fireRoutine(store, r, defaultRunAgent, {
267
+ trigger: "manual",
268
+ });
269
+ const run = store.listRuns({ routineId: r.id, limit: 1 })[0];
270
+ if (options.json) return console.log(JSON.stringify(run, null, 2));
271
+ logger.success(`Fired ${r.id} → ${runId} (${run?.status})`);
272
+ logger.log(chalk.gray(` log: cc routine logs ${runId}`));
273
+ } catch (err) {
274
+ logger.error(err.message);
275
+ process.exitCode = 1;
276
+ }
277
+ });
278
+
279
+ routine
280
+ .command("run")
281
+ .description("Driver: fire due cron/once routines and poll github triggers")
282
+ .option("--json", "Output as JSON")
283
+ .action(async (options) => {
284
+ try {
285
+ const store = await loadStore();
286
+ const { fireRoutine, pollGithubRoutine } =
287
+ await import("../lib/routine-store.js");
288
+ const fired = [];
289
+ for (const r of store.due()) {
290
+ fired.push({
291
+ routine: r.id,
292
+ runId: await fireRoutine(store, r, defaultRunAgent, {
293
+ trigger: r.trigger.kind,
294
+ }),
295
+ });
296
+ }
297
+ for (const r of store.githubRoutines()) {
298
+ const runs = await pollGithubRoutine(store, r, {
299
+ fetchEvents: defaultFetchEvents,
300
+ runAgent: defaultRunAgent,
301
+ });
302
+ for (const runId of runs) fired.push({ routine: r.id, runId });
303
+ }
304
+ if (options.json)
305
+ return console.log(JSON.stringify({ fired }, null, 2));
306
+ if (fired.length === 0) {
307
+ logger.log(chalk.gray("Nothing due."));
308
+ } else {
309
+ for (const f of fired) logger.log(`fired ${f.routine} → ${f.runId}`);
310
+ }
311
+ } catch (err) {
312
+ logger.error(err.message);
313
+ process.exitCode = 1;
314
+ }
315
+ });
316
+
317
+ routine
318
+ .command("runs [id]")
319
+ .description("Run history (all routines, or one)")
320
+ .option("-n, --limit <n>", "Max rows", "20")
321
+ .option("--json", "Output as JSON")
322
+ .action(async (id, options) => {
323
+ try {
324
+ const store = await loadStore();
325
+ const routineId = id ? (store.get(id)?.id ?? id) : null;
326
+ const runs = store.listRuns({
327
+ routineId,
328
+ limit: Math.max(1, Number(options.limit) || 20),
329
+ });
330
+ if (options.json) return console.log(JSON.stringify(runs, null, 2));
331
+ if (runs.length === 0) return logger.log(chalk.gray("No runs."));
332
+ for (const run of runs) {
333
+ const color =
334
+ run.status === "ok"
335
+ ? chalk.green
336
+ : run.status === "running"
337
+ ? chalk.cyan
338
+ : chalk.red;
339
+ const cost = Number.isFinite(run.costUsd)
340
+ ? ` $${run.costUsd.toFixed(4)}`
341
+ : "";
342
+ logger.log(
343
+ `${color((run.status || "?").padEnd(8))} ${run.runId} ${run.routineId} ${new Date(run.startedAt).toISOString()}${cost}`,
344
+ );
345
+ if (run.summary) logger.log(chalk.gray(` ${run.summary}`));
346
+ }
347
+ } catch (err) {
348
+ logger.error(err.message);
349
+ process.exitCode = 1;
350
+ }
351
+ });
352
+
353
+ routine
354
+ .command("logs <runId>")
355
+ .description("Print a run's full agent output")
356
+ .action(async (runId) => {
357
+ try {
358
+ const store = await loadStore();
359
+ const file = store.logFile(runId);
360
+ if (!existsSync(file)) throw new Error(`no log for run: ${runId}`);
361
+ process.stdout.write(readFileSync(file, "utf-8"));
362
+ } catch (err) {
363
+ logger.error(err.message);
364
+ process.exitCode = 1;
365
+ }
366
+ });
367
+ }