@cleocode/cleo 2026.4.161 → 2026.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (857) hide show
  1. package/dist/backfill/audit-columns.d.ts +105 -0
  2. package/dist/backfill/audit-columns.d.ts.map +1 -0
  3. package/dist/backfill/audit-columns.js +258 -0
  4. package/dist/backfill/audit-columns.js.map +1 -0
  5. package/dist/cli/commands/adapter.d.ts +28 -0
  6. package/dist/cli/commands/adapter.d.ts.map +1 -0
  7. package/dist/cli/commands/adapter.js +119 -0
  8. package/dist/cli/commands/adapter.js.map +1 -0
  9. package/dist/cli/commands/add-batch.d.ts +33 -0
  10. package/dist/cli/commands/add-batch.d.ts.map +1 -0
  11. package/dist/cli/commands/add-batch.js +148 -0
  12. package/dist/cli/commands/add-batch.js.map +1 -0
  13. package/dist/cli/commands/add.d.ts +162 -0
  14. package/dist/cli/commands/add.d.ts.map +1 -0
  15. package/dist/cli/commands/add.js +279 -0
  16. package/dist/cli/commands/add.js.map +1 -0
  17. package/dist/cli/commands/admin.d.ts +24 -0
  18. package/dist/cli/commands/admin.d.ts.map +1 -0
  19. package/dist/cli/commands/admin.js +283 -0
  20. package/dist/cli/commands/admin.js.map +1 -0
  21. package/dist/cli/commands/adr.d.ts +33 -0
  22. package/dist/cli/commands/adr.d.ts.map +1 -0
  23. package/dist/cli/commands/adr.js +147 -0
  24. package/dist/cli/commands/adr.js.map +1 -0
  25. package/dist/cli/commands/agent-profile-status.d.ts +98 -0
  26. package/dist/cli/commands/agent-profile-status.d.ts.map +1 -0
  27. package/dist/cli/commands/agent-profile-status.js +71 -0
  28. package/dist/cli/commands/agent-profile-status.js.map +1 -0
  29. package/dist/cli/commands/agent.d.ts +47 -0
  30. package/dist/cli/commands/agent.d.ts.map +1 -0
  31. package/dist/cli/commands/agent.js +2976 -0
  32. package/dist/cli/commands/agent.js.map +1 -0
  33. package/dist/cli/commands/analyze.d.ts +21 -0
  34. package/dist/cli/commands/analyze.d.ts.map +1 -0
  35. package/dist/cli/commands/analyze.js +32 -0
  36. package/dist/cli/commands/analyze.js.map +1 -0
  37. package/dist/cli/commands/archive-stats.d.ts +66 -0
  38. package/dist/cli/commands/archive-stats.d.ts.map +1 -0
  39. package/dist/cli/commands/archive-stats.js +93 -0
  40. package/dist/cli/commands/archive-stats.js.map +1 -0
  41. package/dist/cli/commands/archive.d.ts +42 -0
  42. package/dist/cli/commands/archive.d.ts.map +1 -0
  43. package/dist/cli/commands/archive.js +59 -0
  44. package/dist/cli/commands/archive.js.map +1 -0
  45. package/dist/cli/commands/audit.d.ts +22 -0
  46. package/dist/cli/commands/audit.d.ts.map +1 -0
  47. package/dist/cli/commands/audit.js +137 -0
  48. package/dist/cli/commands/audit.js.map +1 -0
  49. package/dist/cli/commands/backfill.d.ts +56 -0
  50. package/dist/cli/commands/backfill.d.ts.map +1 -0
  51. package/dist/cli/commands/backfill.js +161 -0
  52. package/dist/cli/commands/backfill.js.map +1 -0
  53. package/dist/cli/commands/backup-inspect.d.ts +33 -0
  54. package/dist/cli/commands/backup-inspect.d.ts.map +1 -0
  55. package/dist/cli/commands/backup-inspect.js +430 -0
  56. package/dist/cli/commands/backup-inspect.js.map +1 -0
  57. package/dist/cli/commands/backup.d.ts +23 -0
  58. package/dist/cli/commands/backup.d.ts.map +1 -0
  59. package/dist/cli/commands/backup.js +564 -0
  60. package/dist/cli/commands/backup.js.map +1 -0
  61. package/dist/cli/commands/blockers.d.ts +20 -0
  62. package/dist/cli/commands/blockers.d.ts.map +1 -0
  63. package/dist/cli/commands/blockers.js +31 -0
  64. package/dist/cli/commands/blockers.js.map +1 -0
  65. package/dist/cli/commands/brain.d.ts +37 -0
  66. package/dist/cli/commands/brain.d.ts.map +1 -0
  67. package/dist/cli/commands/brain.js +445 -0
  68. package/dist/cli/commands/brain.js.map +1 -0
  69. package/dist/cli/commands/briefing.d.ts +52 -0
  70. package/dist/cli/commands/briefing.d.ts.map +1 -0
  71. package/dist/cli/commands/briefing.js +69 -0
  72. package/dist/cli/commands/briefing.js.map +1 -0
  73. package/dist/cli/commands/bug.d.ts +61 -0
  74. package/dist/cli/commands/bug.d.ts.map +1 -0
  75. package/dist/cli/commands/bug.js +198 -0
  76. package/dist/cli/commands/bug.js.map +1 -0
  77. package/dist/cli/commands/cancel.d.ts +26 -0
  78. package/dist/cli/commands/cancel.d.ts.map +1 -0
  79. package/dist/cli/commands/cancel.js +40 -0
  80. package/dist/cli/commands/cancel.js.map +1 -0
  81. package/dist/cli/commands/cant.d.ts +13 -0
  82. package/dist/cli/commands/cant.d.ts.map +1 -0
  83. package/dist/cli/commands/cant.js +245 -0
  84. package/dist/cli/commands/cant.js.map +1 -0
  85. package/dist/cli/commands/chain.d.ts +24 -0
  86. package/dist/cli/commands/chain.d.ts.map +1 -0
  87. package/dist/cli/commands/chain.js +116 -0
  88. package/dist/cli/commands/chain.js.map +1 -0
  89. package/dist/cli/commands/check.d.ts +18 -0
  90. package/dist/cli/commands/check.d.ts.map +1 -0
  91. package/dist/cli/commands/check.js +280 -0
  92. package/dist/cli/commands/check.js.map +1 -0
  93. package/dist/cli/commands/checkpoint.d.ts +27 -0
  94. package/dist/cli/commands/checkpoint.d.ts.map +1 -0
  95. package/dist/cli/commands/checkpoint.js +105 -0
  96. package/dist/cli/commands/checkpoint.js.map +1 -0
  97. package/dist/cli/commands/claim.d.ts +35 -0
  98. package/dist/cli/commands/claim.d.ts.map +1 -0
  99. package/dist/cli/commands/claim.js +35 -0
  100. package/dist/cli/commands/claim.js.map +1 -0
  101. package/dist/cli/commands/code.d.ts +22 -0
  102. package/dist/cli/commands/code.d.ts.map +1 -0
  103. package/dist/cli/commands/code.js +161 -0
  104. package/dist/cli/commands/code.js.map +1 -0
  105. package/dist/cli/commands/complete.d.ts +49 -0
  106. package/dist/cli/commands/complete.d.ts.map +1 -0
  107. package/dist/cli/commands/complete.js +83 -0
  108. package/dist/cli/commands/complete.js.map +1 -0
  109. package/dist/cli/commands/complexity.d.ts +13 -0
  110. package/dist/cli/commands/complexity.d.ts.map +1 -0
  111. package/dist/cli/commands/complexity.js +32 -0
  112. package/dist/cli/commands/complexity.js.map +1 -0
  113. package/dist/cli/commands/compliance.d.ts +27 -0
  114. package/dist/cli/commands/compliance.d.ts.map +1 -0
  115. package/dist/cli/commands/compliance.js +233 -0
  116. package/dist/cli/commands/compliance.js.map +1 -0
  117. package/dist/cli/commands/conduit.d.ts +28 -0
  118. package/dist/cli/commands/conduit.d.ts.map +1 -0
  119. package/dist/cli/commands/conduit.js +279 -0
  120. package/dist/cli/commands/conduit.js.map +1 -0
  121. package/dist/cli/commands/config.d.ts +25 -0
  122. package/dist/cli/commands/config.d.ts.map +1 -0
  123. package/dist/cli/commands/config.js +132 -0
  124. package/dist/cli/commands/config.js.map +1 -0
  125. package/dist/cli/commands/consensus.d.ts +21 -0
  126. package/dist/cli/commands/consensus.d.ts.map +1 -0
  127. package/dist/cli/commands/consensus.js +100 -0
  128. package/dist/cli/commands/consensus.js.map +1 -0
  129. package/dist/cli/commands/context.d.ts +19 -0
  130. package/dist/cli/commands/context.d.ts.map +1 -0
  131. package/dist/cli/commands/context.js +111 -0
  132. package/dist/cli/commands/context.js.map +1 -0
  133. package/dist/cli/commands/contribution.d.ts +21 -0
  134. package/dist/cli/commands/contribution.d.ts.map +1 -0
  135. package/dist/cli/commands/contribution.js +90 -0
  136. package/dist/cli/commands/contribution.js.map +1 -0
  137. package/dist/cli/commands/current.d.ts +18 -0
  138. package/dist/cli/commands/current.d.ts.map +1 -0
  139. package/dist/cli/commands/current.js +28 -0
  140. package/dist/cli/commands/current.js.map +1 -0
  141. package/dist/cli/commands/daemon.d.ts +36 -0
  142. package/dist/cli/commands/daemon.d.ts.map +1 -0
  143. package/dist/cli/commands/daemon.js +223 -0
  144. package/dist/cli/commands/daemon.js.map +1 -0
  145. package/dist/cli/commands/dash.d.ts +23 -0
  146. package/dist/cli/commands/dash.d.ts.map +1 -0
  147. package/dist/cli/commands/dash.js +38 -0
  148. package/dist/cli/commands/dash.js.map +1 -0
  149. package/dist/cli/commands/decomposition.d.ts +13 -0
  150. package/dist/cli/commands/decomposition.d.ts.map +1 -0
  151. package/dist/cli/commands/decomposition.js +92 -0
  152. package/dist/cli/commands/decomposition.js.map +1 -0
  153. package/dist/cli/commands/delete.d.ts +29 -0
  154. package/dist/cli/commands/delete.d.ts.map +1 -0
  155. package/dist/cli/commands/delete.js +55 -0
  156. package/dist/cli/commands/delete.js.map +1 -0
  157. package/dist/cli/commands/deps.d.ts +45 -0
  158. package/dist/cli/commands/deps.d.ts.map +1 -0
  159. package/dist/cli/commands/deps.js +170 -0
  160. package/dist/cli/commands/deps.js.map +1 -0
  161. package/dist/cli/commands/detect-drift.d.ts +23 -0
  162. package/dist/cli/commands/detect-drift.d.ts.map +1 -0
  163. package/dist/cli/commands/detect-drift.js +440 -0
  164. package/dist/cli/commands/detect-drift.js.map +1 -0
  165. package/dist/cli/commands/detect.d.ts +3 -0
  166. package/dist/cli/commands/detect.d.ts.map +1 -0
  167. package/dist/cli/commands/detect.js +14 -0
  168. package/dist/cli/commands/detect.js.map +1 -0
  169. package/dist/cli/commands/diagnostics.d.ts +19 -0
  170. package/dist/cli/commands/diagnostics.d.ts.map +1 -0
  171. package/dist/cli/commands/diagnostics.js +109 -0
  172. package/dist/cli/commands/diagnostics.js.map +1 -0
  173. package/dist/cli/commands/docs.d.ts +25 -0
  174. package/dist/cli/commands/docs.d.ts.map +1 -0
  175. package/dist/cli/commands/docs.js +798 -0
  176. package/dist/cli/commands/docs.js.map +1 -0
  177. package/dist/cli/commands/doctor-projects.d.ts +101 -0
  178. package/dist/cli/commands/doctor-projects.d.ts.map +1 -0
  179. package/dist/cli/commands/doctor-projects.js +188 -0
  180. package/dist/cli/commands/doctor-projects.js.map +1 -0
  181. package/dist/cli/commands/doctor.d.ts +66 -0
  182. package/dist/cli/commands/doctor.d.ts.map +1 -0
  183. package/dist/cli/commands/doctor.js +178 -0
  184. package/dist/cli/commands/doctor.js.map +1 -0
  185. package/dist/cli/commands/dynamic.d.ts +15 -0
  186. package/dist/cli/commands/dynamic.d.ts.map +1 -0
  187. package/dist/cli/commands/dynamic.js +21 -0
  188. package/dist/cli/commands/dynamic.js.map +1 -0
  189. package/dist/cli/commands/exists.d.ts +13 -0
  190. package/dist/cli/commands/exists.d.ts.map +1 -0
  191. package/dist/cli/commands/exists.js +40 -0
  192. package/dist/cli/commands/exists.js.map +1 -0
  193. package/dist/cli/commands/export-tasks.d.ts +46 -0
  194. package/dist/cli/commands/export-tasks.d.ts.map +1 -0
  195. package/dist/cli/commands/export-tasks.js +81 -0
  196. package/dist/cli/commands/export-tasks.js.map +1 -0
  197. package/dist/cli/commands/export.d.ts +35 -0
  198. package/dist/cli/commands/export.d.ts.map +1 -0
  199. package/dist/cli/commands/export.js +68 -0
  200. package/dist/cli/commands/export.js.map +1 -0
  201. package/dist/cli/commands/find.d.ts +54 -0
  202. package/dist/cli/commands/find.d.ts.map +1 -0
  203. package/dist/cli/commands/find.js +92 -0
  204. package/dist/cli/commands/find.js.map +1 -0
  205. package/dist/cli/commands/gc.d.ts +25 -0
  206. package/dist/cli/commands/gc.d.ts.map +1 -0
  207. package/dist/cli/commands/gc.js +165 -0
  208. package/dist/cli/commands/gc.js.map +1 -0
  209. package/dist/cli/commands/generate-changelog.d.ts +30 -0
  210. package/dist/cli/commands/generate-changelog.d.ts.map +1 -0
  211. package/dist/cli/commands/generate-changelog.js +270 -0
  212. package/dist/cli/commands/generate-changelog.js.map +1 -0
  213. package/dist/cli/commands/grade.d.ts +13 -0
  214. package/dist/cli/commands/grade.d.ts.map +1 -0
  215. package/dist/cli/commands/grade.js +27 -0
  216. package/dist/cli/commands/grade.js.map +1 -0
  217. package/dist/cli/commands/history.d.ts +13 -0
  218. package/dist/cli/commands/history.d.ts.map +1 -0
  219. package/dist/cli/commands/history.js +65 -0
  220. package/dist/cli/commands/history.js.map +1 -0
  221. package/dist/cli/commands/import-tasks.d.ts +60 -0
  222. package/dist/cli/commands/import-tasks.d.ts.map +1 -0
  223. package/dist/cli/commands/import-tasks.js +83 -0
  224. package/dist/cli/commands/import-tasks.js.map +1 -0
  225. package/dist/cli/commands/import.d.ts +42 -0
  226. package/dist/cli/commands/import.d.ts.map +1 -0
  227. package/dist/cli/commands/import.js +64 -0
  228. package/dist/cli/commands/import.js.map +1 -0
  229. package/dist/cli/commands/init.d.ts +65 -0
  230. package/dist/cli/commands/init.d.ts.map +1 -0
  231. package/dist/cli/commands/init.js +122 -0
  232. package/dist/cli/commands/init.js.map +1 -0
  233. package/dist/cli/commands/inject.d.ts +41 -0
  234. package/dist/cli/commands/inject.d.ts.map +1 -0
  235. package/dist/cli/commands/inject.js +56 -0
  236. package/dist/cli/commands/inject.js.map +1 -0
  237. package/dist/cli/commands/install-global.d.ts +48 -0
  238. package/dist/cli/commands/install-global.d.ts.map +1 -0
  239. package/dist/cli/commands/install-global.js +104 -0
  240. package/dist/cli/commands/install-global.js.map +1 -0
  241. package/dist/cli/commands/intelligence.d.ts +21 -0
  242. package/dist/cli/commands/intelligence.d.ts.map +1 -0
  243. package/dist/cli/commands/intelligence.js +145 -0
  244. package/dist/cli/commands/intelligence.js.map +1 -0
  245. package/dist/cli/commands/issue.d.ts +23 -0
  246. package/dist/cli/commands/issue.d.ts.map +1 -0
  247. package/dist/cli/commands/issue.js +152 -0
  248. package/dist/cli/commands/issue.js.map +1 -0
  249. package/dist/cli/commands/labels.d.ts +21 -0
  250. package/dist/cli/commands/labels.d.ts.map +1 -0
  251. package/dist/cli/commands/labels.js +65 -0
  252. package/dist/cli/commands/labels.js.map +1 -0
  253. package/dist/cli/commands/lifecycle.d.ts +25 -0
  254. package/dist/cli/commands/lifecycle.d.ts.map +1 -0
  255. package/dist/cli/commands/lifecycle.js +221 -0
  256. package/dist/cli/commands/lifecycle.js.map +1 -0
  257. package/dist/cli/commands/list.d.ts +28 -0
  258. package/dist/cli/commands/list.d.ts.map +1 -0
  259. package/dist/cli/commands/list.js +81 -0
  260. package/dist/cli/commands/list.js.map +1 -0
  261. package/dist/cli/commands/log.d.ts +36 -0
  262. package/dist/cli/commands/log.d.ts.map +1 -0
  263. package/dist/cli/commands/log.js +50 -0
  264. package/dist/cli/commands/log.js.map +1 -0
  265. package/dist/cli/commands/manifest.d.ts +15 -0
  266. package/dist/cli/commands/manifest.d.ts.map +1 -0
  267. package/dist/cli/commands/manifest.js +334 -0
  268. package/dist/cli/commands/manifest.js.map +1 -0
  269. package/dist/cli/commands/map.d.ts +25 -0
  270. package/dist/cli/commands/map.d.ts.map +1 -0
  271. package/dist/cli/commands/map.js +37 -0
  272. package/dist/cli/commands/map.js.map +1 -0
  273. package/dist/cli/commands/memory.d.ts +48 -0
  274. package/dist/cli/commands/memory.d.ts.map +1 -0
  275. package/dist/cli/commands/memory.js +2439 -0
  276. package/dist/cli/commands/memory.js.map +1 -0
  277. package/dist/cli/commands/migrate-claude-mem.d.ts +23 -0
  278. package/dist/cli/commands/migrate-claude-mem.d.ts.map +1 -0
  279. package/dist/cli/commands/migrate-claude-mem.js +181 -0
  280. package/dist/cli/commands/migrate-claude-mem.js.map +1 -0
  281. package/dist/cli/commands/next.d.ts +27 -0
  282. package/dist/cli/commands/next.d.ts.map +1 -0
  283. package/dist/cli/commands/next.js +40 -0
  284. package/dist/cli/commands/next.js.map +1 -0
  285. package/dist/cli/commands/nexus.d.ts +15 -0
  286. package/dist/cli/commands/nexus.d.ts.map +1 -0
  287. package/dist/cli/commands/nexus.js +3377 -0
  288. package/dist/cli/commands/nexus.js.map +1 -0
  289. package/dist/cli/commands/ops.d.ts +23 -0
  290. package/dist/cli/commands/ops.d.ts.map +1 -0
  291. package/dist/cli/commands/ops.js +35 -0
  292. package/dist/cli/commands/ops.js.map +1 -0
  293. package/dist/cli/commands/orchestrate.d.ts +48 -0
  294. package/dist/cli/commands/orchestrate.d.ts.map +1 -0
  295. package/dist/cli/commands/orchestrate.js +774 -0
  296. package/dist/cli/commands/orchestrate.js.map +1 -0
  297. package/dist/cli/commands/otel.d.ts +30 -0
  298. package/dist/cli/commands/otel.d.ts.map +1 -0
  299. package/dist/cli/commands/otel.js +193 -0
  300. package/dist/cli/commands/otel.js.map +1 -0
  301. package/dist/cli/commands/phase.d.ts +29 -0
  302. package/dist/cli/commands/phase.d.ts.map +1 -0
  303. package/dist/cli/commands/phase.js +189 -0
  304. package/dist/cli/commands/phase.js.map +1 -0
  305. package/dist/cli/commands/pivot.d.ts +34 -0
  306. package/dist/cli/commands/pivot.d.ts.map +1 -0
  307. package/dist/cli/commands/pivot.js +50 -0
  308. package/dist/cli/commands/pivot.js.map +1 -0
  309. package/dist/cli/commands/plan.d.ts +17 -0
  310. package/dist/cli/commands/plan.d.ts.map +1 -0
  311. package/dist/cli/commands/plan.js +27 -0
  312. package/dist/cli/commands/plan.js.map +1 -0
  313. package/dist/cli/commands/playbook.d.ts +26 -0
  314. package/dist/cli/commands/playbook.d.ts.map +1 -0
  315. package/dist/cli/commands/playbook.js +220 -0
  316. package/dist/cli/commands/playbook.js.map +1 -0
  317. package/dist/cli/commands/promote.d.ts +19 -0
  318. package/dist/cli/commands/promote.d.ts.map +1 -0
  319. package/dist/cli/commands/promote.js +27 -0
  320. package/dist/cli/commands/promote.js.map +1 -0
  321. package/dist/cli/commands/provider.d.ts +23 -0
  322. package/dist/cli/commands/provider.d.ts.map +1 -0
  323. package/dist/cli/commands/provider.js +168 -0
  324. package/dist/cli/commands/provider.js.map +1 -0
  325. package/dist/cli/commands/reason.d.ts +18 -0
  326. package/dist/cli/commands/reason.d.ts.map +1 -0
  327. package/dist/cli/commands/reason.js +102 -0
  328. package/dist/cli/commands/reason.js.map +1 -0
  329. package/dist/cli/commands/reconcile.d.ts +35 -0
  330. package/dist/cli/commands/reconcile.d.ts.map +1 -0
  331. package/dist/cli/commands/reconcile.js +102 -0
  332. package/dist/cli/commands/reconcile.js.map +1 -0
  333. package/dist/cli/commands/refresh-memory.d.ts +16 -0
  334. package/dist/cli/commands/refresh-memory.d.ts.map +1 -0
  335. package/dist/cli/commands/refresh-memory.js +34 -0
  336. package/dist/cli/commands/refresh-memory.js.map +1 -0
  337. package/dist/cli/commands/relates.d.ts +19 -0
  338. package/dist/cli/commands/relates.d.ts.map +1 -0
  339. package/dist/cli/commands/relates.js +129 -0
  340. package/dist/cli/commands/relates.js.map +1 -0
  341. package/dist/cli/commands/release.d.ts +27 -0
  342. package/dist/cli/commands/release.d.ts.map +1 -0
  343. package/dist/cli/commands/release.js +300 -0
  344. package/dist/cli/commands/release.js.map +1 -0
  345. package/dist/cli/commands/remote.d.ts +49 -0
  346. package/dist/cli/commands/remote.d.ts.map +1 -0
  347. package/dist/cli/commands/remote.js +265 -0
  348. package/dist/cli/commands/remote.js.map +1 -0
  349. package/dist/cli/commands/reorder.d.ts +31 -0
  350. package/dist/cli/commands/reorder.d.ts.map +1 -0
  351. package/dist/cli/commands/reorder.js +57 -0
  352. package/dist/cli/commands/reorder.js.map +1 -0
  353. package/dist/cli/commands/reparent.d.ts +27 -0
  354. package/dist/cli/commands/reparent.d.ts.map +1 -0
  355. package/dist/cli/commands/reparent.js +36 -0
  356. package/dist/cli/commands/reparent.js.map +1 -0
  357. package/dist/cli/commands/req.d.ts +37 -0
  358. package/dist/cli/commands/req.d.ts.map +1 -0
  359. package/dist/cli/commands/req.js +121 -0
  360. package/dist/cli/commands/req.js.map +1 -0
  361. package/dist/cli/commands/research.d.ts +25 -0
  362. package/dist/cli/commands/research.d.ts.map +1 -0
  363. package/dist/cli/commands/research.js +327 -0
  364. package/dist/cli/commands/research.js.map +1 -0
  365. package/dist/cli/commands/restore.d.ts +64 -0
  366. package/dist/cli/commands/restore.d.ts.map +1 -0
  367. package/dist/cli/commands/restore.js +539 -0
  368. package/dist/cli/commands/restore.js.map +1 -0
  369. package/dist/cli/commands/revert.d.ts +79 -0
  370. package/dist/cli/commands/revert.d.ts.map +1 -0
  371. package/dist/cli/commands/revert.js +300 -0
  372. package/dist/cli/commands/revert.js.map +1 -0
  373. package/dist/cli/commands/roadmap.d.ts +29 -0
  374. package/dist/cli/commands/roadmap.d.ts.map +1 -0
  375. package/dist/cli/commands/roadmap.js +43 -0
  376. package/dist/cli/commands/roadmap.js.map +1 -0
  377. package/dist/cli/commands/safestop.d.ts +41 -0
  378. package/dist/cli/commands/safestop.d.ts.map +1 -0
  379. package/dist/cli/commands/safestop.js +62 -0
  380. package/dist/cli/commands/safestop.js.map +1 -0
  381. package/dist/cli/commands/schema.d.ts +44 -0
  382. package/dist/cli/commands/schema.d.ts.map +1 -0
  383. package/dist/cli/commands/schema.js +177 -0
  384. package/dist/cli/commands/schema.js.map +1 -0
  385. package/dist/cli/commands/self-update.d.ts +81 -0
  386. package/dist/cli/commands/self-update.d.ts.map +1 -0
  387. package/dist/cli/commands/self-update.js +483 -0
  388. package/dist/cli/commands/self-update.js.map +1 -0
  389. package/dist/cli/commands/sentient.d.ts +44 -0
  390. package/dist/cli/commands/sentient.d.ts.map +1 -0
  391. package/dist/cli/commands/sentient.js +687 -0
  392. package/dist/cli/commands/sentient.js.map +1 -0
  393. package/dist/cli/commands/sequence.d.ts +15 -0
  394. package/dist/cli/commands/sequence.d.ts.map +1 -0
  395. package/dist/cli/commands/sequence.js +68 -0
  396. package/dist/cli/commands/sequence.js.map +1 -0
  397. package/dist/cli/commands/session.d.ts +32 -0
  398. package/dist/cli/commands/session.d.ts.map +1 -0
  399. package/dist/cli/commands/session.js +583 -0
  400. package/dist/cli/commands/session.js.map +1 -0
  401. package/dist/cli/commands/show.d.ts +21 -0
  402. package/dist/cli/commands/show.d.ts.map +1 -0
  403. package/dist/cli/commands/show.js +37 -0
  404. package/dist/cli/commands/show.js.map +1 -0
  405. package/dist/cli/commands/skills.d.ts +31 -0
  406. package/dist/cli/commands/skills.d.ts.map +1 -0
  407. package/dist/cli/commands/skills.js +303 -0
  408. package/dist/cli/commands/skills.js.map +1 -0
  409. package/dist/cli/commands/snapshot.d.ts +17 -0
  410. package/dist/cli/commands/snapshot.d.ts.map +1 -0
  411. package/dist/cli/commands/snapshot.js +95 -0
  412. package/dist/cli/commands/snapshot.js.map +1 -0
  413. package/dist/cli/commands/start.d.ts +21 -0
  414. package/dist/cli/commands/start.d.ts.map +1 -0
  415. package/dist/cli/commands/start.js +32 -0
  416. package/dist/cli/commands/start.js.map +1 -0
  417. package/dist/cli/commands/stats.d.ts +30 -0
  418. package/dist/cli/commands/stats.d.ts.map +1 -0
  419. package/dist/cli/commands/stats.js +71 -0
  420. package/dist/cli/commands/stats.js.map +1 -0
  421. package/dist/cli/commands/sticky.d.ts +23 -0
  422. package/dist/cli/commands/sticky.d.ts.map +1 -0
  423. package/dist/cli/commands/sticky.js +315 -0
  424. package/dist/cli/commands/sticky.js.map +1 -0
  425. package/dist/cli/commands/stop.d.ts +15 -0
  426. package/dist/cli/commands/stop.d.ts.map +1 -0
  427. package/dist/cli/commands/stop.js +25 -0
  428. package/dist/cli/commands/stop.js.map +1 -0
  429. package/dist/cli/commands/sync.d.ts +25 -0
  430. package/dist/cli/commands/sync.d.ts.map +1 -0
  431. package/dist/cli/commands/sync.js +125 -0
  432. package/dist/cli/commands/sync.js.map +1 -0
  433. package/dist/cli/commands/testing.d.ts +22 -0
  434. package/dist/cli/commands/testing.d.ts.map +1 -0
  435. package/dist/cli/commands/testing.js +111 -0
  436. package/dist/cli/commands/testing.js.map +1 -0
  437. package/dist/cli/commands/token.d.ts +22 -0
  438. package/dist/cli/commands/token.d.ts.map +1 -0
  439. package/dist/cli/commands/token.js +197 -0
  440. package/dist/cli/commands/token.js.map +1 -0
  441. package/dist/cli/commands/transcript.d.ts +32 -0
  442. package/dist/cli/commands/transcript.d.ts.map +1 -0
  443. package/dist/cli/commands/transcript.js +526 -0
  444. package/dist/cli/commands/transcript.js.map +1 -0
  445. package/dist/cli/commands/update.d.ts +164 -0
  446. package/dist/cli/commands/update.d.ts.map +1 -0
  447. package/dist/cli/commands/update.js +234 -0
  448. package/dist/cli/commands/update.js.map +1 -0
  449. package/dist/cli/commands/upgrade.d.ts +76 -0
  450. package/dist/cli/commands/upgrade.d.ts.map +1 -0
  451. package/dist/cli/commands/upgrade.js +154 -0
  452. package/dist/cli/commands/upgrade.js.map +1 -0
  453. package/dist/cli/commands/verify.d.ts +83 -0
  454. package/dist/cli/commands/verify.d.ts.map +1 -0
  455. package/dist/cli/commands/verify.js +108 -0
  456. package/dist/cli/commands/verify.js.map +1 -0
  457. package/dist/cli/commands/web.d.ts +27 -0
  458. package/dist/cli/commands/web.d.ts.map +1 -0
  459. package/dist/cli/commands/web.js +414 -0
  460. package/dist/cli/commands/web.js.map +1 -0
  461. package/dist/cli/field-context.d.ts +32 -0
  462. package/dist/cli/field-context.d.ts.map +1 -0
  463. package/dist/cli/field-context.js +47 -0
  464. package/dist/cli/field-context.js.map +1 -0
  465. package/dist/cli/format-context.d.ts +32 -0
  466. package/dist/cli/format-context.d.ts.map +1 -0
  467. package/dist/cli/format-context.js +50 -0
  468. package/dist/cli/format-context.js.map +1 -0
  469. package/dist/cli/help-renderer.d.ts +40 -0
  470. package/dist/cli/help-renderer.d.ts.map +1 -0
  471. package/dist/cli/help-renderer.js +325 -0
  472. package/dist/cli/help-renderer.js.map +1 -0
  473. package/dist/cli/index.d.ts +14 -0
  474. package/dist/cli/index.d.ts.map +1 -0
  475. package/dist/cli/index.js +1561 -9748
  476. package/dist/cli/index.js.map +4 -4
  477. package/dist/cli/infer-files-via-gitnexus.d.ts +12 -0
  478. package/dist/cli/infer-files-via-gitnexus.d.ts.map +1 -0
  479. package/dist/cli/infer-files-via-gitnexus.js +12 -0
  480. package/dist/cli/infer-files-via-gitnexus.js.map +1 -0
  481. package/dist/cli/lib/did-you-mean.d.ts +30 -0
  482. package/dist/cli/lib/did-you-mean.d.ts.map +1 -0
  483. package/dist/cli/lib/did-you-mean.js +63 -0
  484. package/dist/cli/lib/did-you-mean.js.map +1 -0
  485. package/dist/cli/lib/registry-args.d.ts +36 -0
  486. package/dist/cli/lib/registry-args.d.ts.map +1 -0
  487. package/dist/cli/lib/registry-args.js +37 -0
  488. package/dist/cli/lib/registry-args.js.map +1 -0
  489. package/dist/cli/lib/subcommand-guard.d.ts +45 -0
  490. package/dist/cli/lib/subcommand-guard.d.ts.map +1 -0
  491. package/dist/cli/lib/subcommand-guard.js +55 -0
  492. package/dist/cli/lib/subcommand-guard.js.map +1 -0
  493. package/dist/cli/logger-bootstrap.d.ts +6 -0
  494. package/dist/cli/logger-bootstrap.d.ts.map +1 -0
  495. package/dist/cli/logger-bootstrap.js +10 -0
  496. package/dist/cli/logger-bootstrap.js.map +1 -0
  497. package/dist/cli/middleware/output-format.d.ts +30 -0
  498. package/dist/cli/middleware/output-format.d.ts.map +1 -0
  499. package/dist/cli/middleware/output-format.js +35 -0
  500. package/dist/cli/middleware/output-format.js.map +1 -0
  501. package/dist/cli/paths.d.ts +85 -0
  502. package/dist/cli/paths.d.ts.map +1 -0
  503. package/dist/cli/paths.js +108 -0
  504. package/dist/cli/paths.js.map +1 -0
  505. package/dist/cli/progress.d.ts +89 -0
  506. package/dist/cli/progress.d.ts.map +1 -0
  507. package/dist/cli/progress.js +185 -0
  508. package/dist/cli/progress.js.map +1 -0
  509. package/dist/cli/renderers/colors.d.ts +32 -0
  510. package/dist/cli/renderers/colors.d.ts.map +1 -0
  511. package/dist/cli/renderers/colors.js +141 -0
  512. package/dist/cli/renderers/colors.js.map +1 -0
  513. package/dist/cli/renderers/error.d.ts +13 -0
  514. package/dist/cli/renderers/error.d.ts.map +1 -0
  515. package/dist/cli/renderers/error.js +42 -0
  516. package/dist/cli/renderers/error.js.map +1 -0
  517. package/dist/cli/renderers/index.d.ts +90 -0
  518. package/dist/cli/renderers/index.d.ts.map +1 -0
  519. package/dist/cli/renderers/index.js +268 -0
  520. package/dist/cli/renderers/index.js.map +1 -0
  521. package/dist/cli/renderers/lafs-validator.d.ts +91 -0
  522. package/dist/cli/renderers/lafs-validator.d.ts.map +1 -0
  523. package/dist/cli/renderers/lafs-validator.js +176 -0
  524. package/dist/cli/renderers/lafs-validator.js.map +1 -0
  525. package/dist/cli/renderers/normalizer.d.ts +21 -0
  526. package/dist/cli/renderers/normalizer.d.ts.map +1 -0
  527. package/dist/cli/renderers/normalizer.js +106 -0
  528. package/dist/cli/renderers/normalizer.js.map +1 -0
  529. package/dist/cli/renderers/system.d.ts +110 -0
  530. package/dist/cli/renderers/system.d.ts.map +1 -0
  531. package/dist/cli/renderers/system.js +662 -0
  532. package/dist/cli/renderers/system.js.map +1 -0
  533. package/dist/cli/renderers/tasks.d.ts +28 -0
  534. package/dist/cli/renderers/tasks.d.ts.map +1 -0
  535. package/dist/cli/renderers/tasks.js +306 -0
  536. package/dist/cli/renderers/tasks.js.map +1 -0
  537. package/dist/cli/tree-context.d.ts +53 -0
  538. package/dist/cli/tree-context.d.ts.map +1 -0
  539. package/dist/cli/tree-context.js +43 -0
  540. package/dist/cli/tree-context.js.map +1 -0
  541. package/dist/dispatch/adapters/cli.d.ts +67 -0
  542. package/dist/dispatch/adapters/cli.d.ts.map +1 -0
  543. package/dist/dispatch/adapters/cli.js +331 -0
  544. package/dist/dispatch/adapters/cli.js.map +1 -0
  545. package/dist/dispatch/adapters/typed.d.ts +362 -0
  546. package/dist/dispatch/adapters/typed.d.ts.map +1 -0
  547. package/dist/dispatch/adapters/typed.js +278 -0
  548. package/dist/dispatch/adapters/typed.js.map +1 -0
  549. package/dist/dispatch/context/session-context.d.ts +108 -0
  550. package/dist/dispatch/context/session-context.d.ts.map +1 -0
  551. package/dist/dispatch/context/session-context.js +111 -0
  552. package/dist/dispatch/context/session-context.js.map +1 -0
  553. package/dist/dispatch/dispatcher.d.ts +37 -0
  554. package/dist/dispatch/dispatcher.d.ts.map +1 -0
  555. package/dist/dispatch/dispatcher.js +172 -0
  556. package/dist/dispatch/dispatcher.js.map +1 -0
  557. package/dist/dispatch/domains/_base.d.ts +104 -0
  558. package/dist/dispatch/domains/_base.d.ts.map +1 -0
  559. package/dist/dispatch/domains/_base.js +147 -0
  560. package/dist/dispatch/domains/_base.js.map +1 -0
  561. package/dist/dispatch/domains/_meta.d.ts +23 -0
  562. package/dist/dispatch/domains/_meta.d.ts.map +1 -0
  563. package/dist/dispatch/domains/_meta.js +25 -0
  564. package/dist/dispatch/domains/_meta.js.map +1 -0
  565. package/dist/dispatch/domains/_routing.d.ts +8 -0
  566. package/dist/dispatch/domains/_routing.d.ts.map +1 -0
  567. package/dist/dispatch/domains/_routing.js +20 -0
  568. package/dist/dispatch/domains/_routing.js.map +1 -0
  569. package/dist/dispatch/domains/admin/smoke-provider.d.ts +54 -0
  570. package/dist/dispatch/domains/admin/smoke-provider.d.ts.map +1 -0
  571. package/dist/dispatch/domains/admin/smoke-provider.js +309 -0
  572. package/dist/dispatch/domains/admin/smoke-provider.js.map +1 -0
  573. package/dist/dispatch/domains/admin.d.ts +51 -0
  574. package/dist/dispatch/domains/admin.d.ts.map +1 -0
  575. package/dist/dispatch/domains/admin.js +1163 -0
  576. package/dist/dispatch/domains/admin.js.map +1 -0
  577. package/dist/dispatch/domains/check/canon.d.ts +65 -0
  578. package/dist/dispatch/domains/check/canon.d.ts.map +1 -0
  579. package/dist/dispatch/domains/check/canon.js +193 -0
  580. package/dist/dispatch/domains/check/canon.js.map +1 -0
  581. package/dist/dispatch/domains/check.d.ts +37 -0
  582. package/dist/dispatch/domains/check.d.ts.map +1 -0
  583. package/dist/dispatch/domains/check.js +562 -0
  584. package/dist/dispatch/domains/check.js.map +1 -0
  585. package/dist/dispatch/domains/conduit.d.ts +61 -0
  586. package/dist/dispatch/domains/conduit.d.ts.map +1 -0
  587. package/dist/dispatch/domains/conduit.js +609 -0
  588. package/dist/dispatch/domains/conduit.js.map +1 -0
  589. package/dist/dispatch/domains/diagnostics.d.ts +25 -0
  590. package/dist/dispatch/domains/diagnostics.d.ts.map +1 -0
  591. package/dist/dispatch/domains/diagnostics.js +82 -0
  592. package/dist/dispatch/domains/diagnostics.js.map +1 -0
  593. package/dist/dispatch/domains/docs.d.ts +63 -0
  594. package/dist/dispatch/domains/docs.d.ts.map +1 -0
  595. package/dist/dispatch/domains/docs.js +539 -0
  596. package/dist/dispatch/domains/docs.js.map +1 -0
  597. package/dist/dispatch/domains/index.d.ts +33 -0
  598. package/dist/dispatch/domains/index.d.ts.map +1 -0
  599. package/dist/dispatch/domains/index.js +58 -0
  600. package/dist/dispatch/domains/index.js.map +1 -0
  601. package/dist/dispatch/domains/intelligence.d.ts +26 -0
  602. package/dist/dispatch/domains/intelligence.d.ts.map +1 -0
  603. package/dist/dispatch/domains/intelligence.js +154 -0
  604. package/dist/dispatch/domains/intelligence.js.map +1 -0
  605. package/dist/dispatch/domains/ivtr.d.ts +182 -0
  606. package/dist/dispatch/domains/ivtr.d.ts.map +1 -0
  607. package/dist/dispatch/domains/ivtr.js +430 -0
  608. package/dist/dispatch/domains/ivtr.js.map +1 -0
  609. package/dist/dispatch/domains/memory.d.ts +22 -0
  610. package/dist/dispatch/domains/memory.d.ts.map +1 -0
  611. package/dist/dispatch/domains/memory.js +1281 -0
  612. package/dist/dispatch/domains/memory.js.map +1 -0
  613. package/dist/dispatch/domains/nexus.d.ts +78 -0
  614. package/dist/dispatch/domains/nexus.d.ts.map +1 -0
  615. package/dist/dispatch/domains/nexus.js +938 -0
  616. package/dist/dispatch/domains/nexus.js.map +1 -0
  617. package/dist/dispatch/domains/orchestrate.d.ts +307 -0
  618. package/dist/dispatch/domains/orchestrate.d.ts.map +1 -0
  619. package/dist/dispatch/domains/orchestrate.js +986 -0
  620. package/dist/dispatch/domains/orchestrate.js.map +1 -0
  621. package/dist/dispatch/domains/pipeline.d.ts +276 -0
  622. package/dist/dispatch/domains/pipeline.d.ts.map +1 -0
  623. package/dist/dispatch/domains/pipeline.js +689 -0
  624. package/dist/dispatch/domains/pipeline.js.map +1 -0
  625. package/dist/dispatch/domains/playbook.d.ts +131 -0
  626. package/dist/dispatch/domains/playbook.d.ts.map +1 -0
  627. package/dist/dispatch/domains/playbook.js +633 -0
  628. package/dist/dispatch/domains/playbook.js.map +1 -0
  629. package/dist/dispatch/domains/release.d.ts +97 -0
  630. package/dist/dispatch/domains/release.d.ts.map +1 -0
  631. package/dist/dispatch/domains/release.js +177 -0
  632. package/dist/dispatch/domains/release.js.map +1 -0
  633. package/dist/dispatch/domains/sentient.d.ts +60 -0
  634. package/dist/dispatch/domains/sentient.d.ts.map +1 -0
  635. package/dist/dispatch/domains/sentient.js +270 -0
  636. package/dist/dispatch/domains/sentient.js.map +1 -0
  637. package/dist/dispatch/domains/session.d.ts +49 -0
  638. package/dist/dispatch/domains/session.d.ts.map +1 -0
  639. package/dist/dispatch/domains/session.js +459 -0
  640. package/dist/dispatch/domains/session.js.map +1 -0
  641. package/dist/dispatch/domains/sticky.d.ts +82 -0
  642. package/dist/dispatch/domains/sticky.d.ts.map +1 -0
  643. package/dist/dispatch/domains/sticky.js +287 -0
  644. package/dist/dispatch/domains/sticky.js.map +1 -0
  645. package/dist/dispatch/domains/tasks.d.ts +58 -0
  646. package/dist/dispatch/domains/tasks.d.ts.map +1 -0
  647. package/dist/dispatch/domains/tasks.js +497 -0
  648. package/dist/dispatch/domains/tasks.js.map +1 -0
  649. package/dist/dispatch/domains/tools.d.ts +37 -0
  650. package/dist/dispatch/domains/tools.d.ts.map +1 -0
  651. package/dist/dispatch/domains/tools.js +481 -0
  652. package/dist/dispatch/domains/tools.js.map +1 -0
  653. package/dist/dispatch/engines/_error.d.ts +114 -0
  654. package/dist/dispatch/engines/_error.d.ts.map +1 -0
  655. package/dist/dispatch/engines/_error.js +290 -0
  656. package/dist/dispatch/engines/_error.js.map +1 -0
  657. package/dist/dispatch/engines/admin-engine.d.ts +386 -0
  658. package/dist/dispatch/engines/admin-engine.d.ts.map +1 -0
  659. package/dist/dispatch/engines/admin-engine.js +270 -0
  660. package/dist/dispatch/engines/admin-engine.js.map +1 -0
  661. package/dist/dispatch/engines/code-engine.d.ts +14 -0
  662. package/dist/dispatch/engines/code-engine.d.ts.map +1 -0
  663. package/dist/dispatch/engines/code-engine.js +14 -0
  664. package/dist/dispatch/engines/code-engine.js.map +1 -0
  665. package/dist/dispatch/engines/codebase-map-engine.d.ts +31 -0
  666. package/dist/dispatch/engines/codebase-map-engine.d.ts.map +1 -0
  667. package/dist/dispatch/engines/codebase-map-engine.js +43 -0
  668. package/dist/dispatch/engines/codebase-map-engine.js.map +1 -0
  669. package/dist/dispatch/engines/config-engine.d.ts +14 -0
  670. package/dist/dispatch/engines/config-engine.d.ts.map +1 -0
  671. package/dist/dispatch/engines/config-engine.js +14 -0
  672. package/dist/dispatch/engines/config-engine.js.map +1 -0
  673. package/dist/dispatch/engines/diagnostics-engine.d.ts +13 -0
  674. package/dist/dispatch/engines/diagnostics-engine.d.ts.map +1 -0
  675. package/dist/dispatch/engines/diagnostics-engine.js +12 -0
  676. package/dist/dispatch/engines/diagnostics-engine.js.map +1 -0
  677. package/dist/dispatch/engines/hooks-engine.d.ts +13 -0
  678. package/dist/dispatch/engines/hooks-engine.d.ts.map +1 -0
  679. package/dist/dispatch/engines/hooks-engine.js +12 -0
  680. package/dist/dispatch/engines/hooks-engine.js.map +1 -0
  681. package/dist/dispatch/engines/init-engine.d.ts +14 -0
  682. package/dist/dispatch/engines/init-engine.d.ts.map +1 -0
  683. package/dist/dispatch/engines/init-engine.js +14 -0
  684. package/dist/dispatch/engines/init-engine.js.map +1 -0
  685. package/dist/dispatch/engines/lifecycle-engine.d.ts +13 -0
  686. package/dist/dispatch/engines/lifecycle-engine.d.ts.map +1 -0
  687. package/dist/dispatch/engines/lifecycle-engine.js +12 -0
  688. package/dist/dispatch/engines/lifecycle-engine.js.map +1 -0
  689. package/dist/dispatch/engines/memory-engine.d.ts +10 -0
  690. package/dist/dispatch/engines/memory-engine.d.ts.map +1 -0
  691. package/dist/dispatch/engines/memory-engine.js +10 -0
  692. package/dist/dispatch/engines/memory-engine.js.map +1 -0
  693. package/dist/dispatch/engines/nexus-engine.d.ts +603 -0
  694. package/dist/dispatch/engines/nexus-engine.d.ts.map +1 -0
  695. package/dist/dispatch/engines/nexus-engine.js +1438 -0
  696. package/dist/dispatch/engines/nexus-engine.js.map +1 -0
  697. package/dist/dispatch/engines/orchestrate-engine.d.ts +252 -0
  698. package/dist/dispatch/engines/orchestrate-engine.d.ts.map +1 -0
  699. package/dist/dispatch/engines/orchestrate-engine.js +1526 -0
  700. package/dist/dispatch/engines/orchestrate-engine.js.map +1 -0
  701. package/dist/dispatch/engines/pipeline-engine.d.ts +13 -0
  702. package/dist/dispatch/engines/pipeline-engine.d.ts.map +1 -0
  703. package/dist/dispatch/engines/pipeline-engine.js +12 -0
  704. package/dist/dispatch/engines/pipeline-engine.js.map +1 -0
  705. package/dist/dispatch/engines/release-engine.d.ts +13 -0
  706. package/dist/dispatch/engines/release-engine.d.ts.map +1 -0
  707. package/dist/dispatch/engines/release-engine.js +13 -0
  708. package/dist/dispatch/engines/release-engine.js.map +1 -0
  709. package/dist/dispatch/engines/session-engine.d.ts +15 -0
  710. package/dist/dispatch/engines/session-engine.d.ts.map +1 -0
  711. package/dist/dispatch/engines/session-engine.js +12 -0
  712. package/dist/dispatch/engines/session-engine.js.map +1 -0
  713. package/dist/dispatch/engines/sticky-engine.d.ts +13 -0
  714. package/dist/dispatch/engines/sticky-engine.d.ts.map +1 -0
  715. package/dist/dispatch/engines/sticky-engine.js +12 -0
  716. package/dist/dispatch/engines/sticky-engine.js.map +1 -0
  717. package/dist/dispatch/engines/system-engine.d.ts +543 -0
  718. package/dist/dispatch/engines/system-engine.d.ts.map +1 -0
  719. package/dist/dispatch/engines/system-engine.js +1278 -0
  720. package/dist/dispatch/engines/system-engine.js.map +1 -0
  721. package/dist/dispatch/engines/task-engine.d.ts +1161 -0
  722. package/dist/dispatch/engines/task-engine.d.ts.map +1 -0
  723. package/dist/dispatch/engines/task-engine.js +1599 -0
  724. package/dist/dispatch/engines/task-engine.js.map +1 -0
  725. package/dist/dispatch/engines/template-parser.d.ts +85 -0
  726. package/dist/dispatch/engines/template-parser.d.ts.map +1 -0
  727. package/dist/dispatch/engines/template-parser.js +114 -0
  728. package/dist/dispatch/engines/template-parser.js.map +1 -0
  729. package/dist/dispatch/engines/tools-engine.d.ts +13 -0
  730. package/dist/dispatch/engines/tools-engine.d.ts.map +1 -0
  731. package/dist/dispatch/engines/tools-engine.js +12 -0
  732. package/dist/dispatch/engines/tools-engine.js.map +1 -0
  733. package/dist/dispatch/engines/validate-engine.d.ts +13 -0
  734. package/dist/dispatch/engines/validate-engine.d.ts.map +1 -0
  735. package/dist/dispatch/engines/validate-engine.js +13 -0
  736. package/dist/dispatch/engines/validate-engine.js.map +1 -0
  737. package/dist/dispatch/index.d.ts +20 -0
  738. package/dist/dispatch/index.d.ts.map +1 -0
  739. package/dist/dispatch/index.js +19 -0
  740. package/dist/dispatch/index.js.map +1 -0
  741. package/dist/dispatch/lib/background-jobs.d.ts +162 -0
  742. package/dist/dispatch/lib/background-jobs.d.ts.map +1 -0
  743. package/dist/dispatch/lib/background-jobs.js +360 -0
  744. package/dist/dispatch/lib/background-jobs.js.map +1 -0
  745. package/dist/dispatch/lib/budget.d.ts +36 -0
  746. package/dist/dispatch/lib/budget.d.ts.map +1 -0
  747. package/dist/dispatch/lib/budget.js +109 -0
  748. package/dist/dispatch/lib/budget.js.map +1 -0
  749. package/dist/dispatch/lib/capability-matrix.d.ts +11 -0
  750. package/dist/dispatch/lib/capability-matrix.d.ts.map +1 -0
  751. package/dist/dispatch/lib/capability-matrix.js +10 -0
  752. package/dist/dispatch/lib/capability-matrix.js.map +1 -0
  753. package/dist/dispatch/lib/config-loader.d.ts +42 -0
  754. package/dist/dispatch/lib/config-loader.d.ts.map +1 -0
  755. package/dist/dispatch/lib/config-loader.js +218 -0
  756. package/dist/dispatch/lib/config-loader.js.map +1 -0
  757. package/dist/dispatch/lib/config.d.ts +11 -0
  758. package/dist/dispatch/lib/config.d.ts.map +1 -0
  759. package/dist/dispatch/lib/config.js +10 -0
  760. package/dist/dispatch/lib/config.js.map +1 -0
  761. package/dist/dispatch/lib/defaults.d.ts +115 -0
  762. package/dist/dispatch/lib/defaults.d.ts.map +1 -0
  763. package/dist/dispatch/lib/defaults.js +61 -0
  764. package/dist/dispatch/lib/defaults.js.map +1 -0
  765. package/dist/dispatch/lib/engine.d.ts +17 -0
  766. package/dist/dispatch/lib/engine.d.ts.map +1 -0
  767. package/dist/dispatch/lib/engine.js +36 -0
  768. package/dist/dispatch/lib/engine.js.map +1 -0
  769. package/dist/dispatch/lib/exit-codes.d.ts +35 -0
  770. package/dist/dispatch/lib/exit-codes.d.ts.map +1 -0
  771. package/dist/dispatch/lib/exit-codes.js +60 -0
  772. package/dist/dispatch/lib/exit-codes.js.map +1 -0
  773. package/dist/dispatch/lib/gateway-meta.d.ts +37 -0
  774. package/dist/dispatch/lib/gateway-meta.d.ts.map +1 -0
  775. package/dist/dispatch/lib/gateway-meta.js +50 -0
  776. package/dist/dispatch/lib/gateway-meta.js.map +1 -0
  777. package/dist/dispatch/lib/job-manager-accessor.d.ts +9 -0
  778. package/dist/dispatch/lib/job-manager-accessor.d.ts.map +1 -0
  779. package/dist/dispatch/lib/job-manager-accessor.js +13 -0
  780. package/dist/dispatch/lib/job-manager-accessor.js.map +1 -0
  781. package/dist/dispatch/lib/meta.d.ts +26 -0
  782. package/dist/dispatch/lib/meta.d.ts.map +1 -0
  783. package/dist/dispatch/lib/meta.js +37 -0
  784. package/dist/dispatch/lib/meta.js.map +1 -0
  785. package/dist/dispatch/lib/param-utils.d.ts +11 -0
  786. package/dist/dispatch/lib/param-utils.d.ts.map +1 -0
  787. package/dist/dispatch/lib/param-utils.js +10 -0
  788. package/dist/dispatch/lib/param-utils.js.map +1 -0
  789. package/dist/dispatch/lib/projections.d.ts +56 -0
  790. package/dist/dispatch/lib/projections.d.ts.map +1 -0
  791. package/dist/dispatch/lib/projections.js +65 -0
  792. package/dist/dispatch/lib/projections.js.map +1 -0
  793. package/dist/dispatch/lib/proto-envelope.d.ts +56 -0
  794. package/dist/dispatch/lib/proto-envelope.d.ts.map +1 -0
  795. package/dist/dispatch/lib/proto-envelope.js +17 -0
  796. package/dist/dispatch/lib/proto-envelope.js.map +1 -0
  797. package/dist/dispatch/lib/schema-utils.d.ts +39 -0
  798. package/dist/dispatch/lib/schema-utils.d.ts.map +1 -0
  799. package/dist/dispatch/lib/schema-utils.js +88 -0
  800. package/dist/dispatch/lib/schema-utils.js.map +1 -0
  801. package/dist/dispatch/lib/security.d.ts +11 -0
  802. package/dist/dispatch/lib/security.d.ts.map +1 -0
  803. package/dist/dispatch/lib/security.js +10 -0
  804. package/dist/dispatch/lib/security.js.map +1 -0
  805. package/dist/dispatch/middleware/audit.d.ts +23 -0
  806. package/dist/dispatch/middleware/audit.d.ts.map +1 -0
  807. package/dist/dispatch/middleware/audit.js +169 -0
  808. package/dist/dispatch/middleware/audit.js.map +1 -0
  809. package/dist/dispatch/middleware/field-filter.d.ts +25 -0
  810. package/dist/dispatch/middleware/field-filter.d.ts.map +1 -0
  811. package/dist/dispatch/middleware/field-filter.js +70 -0
  812. package/dist/dispatch/middleware/field-filter.js.map +1 -0
  813. package/dist/dispatch/middleware/pipeline.d.ts +33 -0
  814. package/dist/dispatch/middleware/pipeline.d.ts.map +1 -0
  815. package/dist/dispatch/middleware/pipeline.js +60 -0
  816. package/dist/dispatch/middleware/pipeline.js.map +1 -0
  817. package/dist/dispatch/middleware/projection.d.ts +35 -0
  818. package/dist/dispatch/middleware/projection.d.ts.map +1 -0
  819. package/dist/dispatch/middleware/projection.js +146 -0
  820. package/dist/dispatch/middleware/projection.js.map +1 -0
  821. package/dist/dispatch/middleware/protocol-enforcement.d.ts +30 -0
  822. package/dist/dispatch/middleware/protocol-enforcement.d.ts.map +1 -0
  823. package/dist/dispatch/middleware/protocol-enforcement.js +56 -0
  824. package/dist/dispatch/middleware/protocol-enforcement.js.map +1 -0
  825. package/dist/dispatch/middleware/rate-limiter.d.ts +72 -0
  826. package/dist/dispatch/middleware/rate-limiter.d.ts.map +1 -0
  827. package/dist/dispatch/middleware/rate-limiter.js +127 -0
  828. package/dist/dispatch/middleware/rate-limiter.js.map +1 -0
  829. package/dist/dispatch/middleware/sanitizer.d.ts +24 -0
  830. package/dist/dispatch/middleware/sanitizer.d.ts.map +1 -0
  831. package/dist/dispatch/middleware/sanitizer.js +56 -0
  832. package/dist/dispatch/middleware/sanitizer.js.map +1 -0
  833. package/dist/dispatch/middleware/session-resolver.d.ts +26 -0
  834. package/dist/dispatch/middleware/session-resolver.d.ts.map +1 -0
  835. package/dist/dispatch/middleware/session-resolver.js +65 -0
  836. package/dist/dispatch/middleware/session-resolver.js.map +1 -0
  837. package/dist/dispatch/middleware/telemetry.d.ts +21 -0
  838. package/dist/dispatch/middleware/telemetry.d.ts.map +1 -0
  839. package/dist/dispatch/middleware/telemetry.js +50 -0
  840. package/dist/dispatch/middleware/telemetry.js.map +1 -0
  841. package/dist/dispatch/middleware/verification-gates.d.ts +22 -0
  842. package/dist/dispatch/middleware/verification-gates.d.ts.map +1 -0
  843. package/dist/dispatch/middleware/verification-gates.js +59 -0
  844. package/dist/dispatch/middleware/verification-gates.js.map +1 -0
  845. package/dist/dispatch/registry.d.ts +91 -0
  846. package/dist/dispatch/registry.d.ts.map +1 -0
  847. package/dist/dispatch/registry.js +6430 -0
  848. package/dist/dispatch/registry.js.map +1 -0
  849. package/dist/dispatch/types.d.ts +150 -0
  850. package/dist/dispatch/types.d.ts.map +1 -0
  851. package/dist/dispatch/types.js +38 -0
  852. package/dist/dispatch/types.js.map +1 -0
  853. package/dist/migrations/2026-04-25-t991-parent-link-repair.d.ts +88 -0
  854. package/dist/migrations/2026-04-25-t991-parent-link-repair.d.ts.map +1 -0
  855. package/dist/migrations/2026-04-25-t991-parent-link-repair.js +76 -0
  856. package/dist/migrations/2026-04-25-t991-parent-link-repair.js.map +1 -0
  857. package/package.json +9 -9
@@ -0,0 +1,2976 @@
1
+ /**
2
+ * CLI agent command group — agent credential management (unified registry).
3
+ *
4
+ * Provides:
5
+ * cleo agent register — register a new agent credential
6
+ * cleo agent list — list all registered agent credentials
7
+ * cleo agent get <id> — get a specific agent credential
8
+ * cleo agent remove <id> — remove an agent credential
9
+ * cleo agent rotate-key <id> — rotate an agent's API key
10
+ * cleo agent poll — one-shot message check
11
+ * cleo agent send — send a message to an agent or conversation
12
+ * cleo agent start — start the daemon poller for an agent
13
+ * cleo agent install — install an agent from .cantz archive or directory
14
+ * cleo agent pack — package an agent directory as .cantz archive
15
+ * cleo agent create — scaffold a new agent package with persona.cant and manifest.json
16
+ *
17
+ * **Daemon vs. Pi session — important distinction.** The daemon spawned
18
+ * by `cleo agent start` ONLY polls SignalDock for inbound messages and
19
+ * keeps the cloud status indicator green. It does NOT execute CANT
20
+ * workflow profiles inside the daemon process. CANT workflow execution
21
+ * (sessions, parallel arms, conditionals, approval gates, discretion
22
+ * evaluation, etc.) lives entirely inside the
23
+ * `cant-bridge.ts` Pi extension at
24
+ * `packages/cleo/templates/cleoos-hub/pi-extensions/cant-bridge.ts`,
25
+ * which interprets `.cant` files via shell-out to the `cleo cant`
26
+ * command family. Operators who want profile-driven behaviour should
27
+ * start a Pi session and use `/cant:load <file>` followed by
28
+ * `/cant:run <file> <workflowName>`. The daemon and the Pi session are
29
+ * distinct runtimes with distinct purposes, by design (see ADR-035 §D5
30
+ * "Option Y" addendum).
31
+ *
32
+ * @see docs/specs/SIGNALDOCK-UNIFIED-AGENT-REGISTRY.md Section 3.4
33
+ * @see .cleo/adrs/ADR-035-pi-v2-v3-harness.md §D5 + Addendum
34
+ * @task T178
35
+ */
36
+ import { checkAgentHealth, detectCrashedAgents, detectStaleAgents, getHealthReport, STALE_THRESHOLD_MS, } from '@cleocode/core/internal';
37
+ import { defineCommand, showUsage } from 'citty';
38
+ import { AGENTS_SUBDIR, CANT_AGENTS_SUBDIR, CLEO_DIR_NAME } from '../paths.js';
39
+ import { cliOutput } from '../renderers/index.js';
40
+ import { computeProfileStatus } from './agent-profile-status.js';
41
+ /** cleo agent register — register a new agent credential in the local registry */
42
+ const registerCommand = defineCommand({
43
+ meta: {
44
+ name: 'register',
45
+ description: 'Register a new agent credential in the local registry',
46
+ },
47
+ args: {
48
+ id: {
49
+ type: 'string',
50
+ description: 'Unique agent identifier',
51
+ required: true,
52
+ },
53
+ name: {
54
+ type: 'string',
55
+ description: 'Human-readable display name',
56
+ required: true,
57
+ },
58
+ 'api-key': {
59
+ type: 'string',
60
+ description: 'API key (sk_live_...)',
61
+ required: true,
62
+ },
63
+ 'api-url': {
64
+ type: 'string',
65
+ description: 'API base URL',
66
+ default: 'https://api.signaldock.io',
67
+ },
68
+ classification: {
69
+ type: 'string',
70
+ description: 'Agent classification (e.g. code_dev, orchestrator)',
71
+ },
72
+ privacy: {
73
+ type: 'string',
74
+ description: 'Privacy tier: public, discoverable, private',
75
+ default: 'public',
76
+ },
77
+ },
78
+ async run({ args }) {
79
+ try {
80
+ const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
81
+ await getDb();
82
+ const registry = new AgentRegistryAccessor(process.cwd());
83
+ const agentId = args.id;
84
+ const displayName = args.name;
85
+ const classification = args.classification;
86
+ const credential = await registry.register({
87
+ agentId,
88
+ displayName,
89
+ apiKey: args['api-key'],
90
+ apiBaseUrl: args['api-url'] ?? 'https://api.signaldock.io',
91
+ classification,
92
+ privacyTier: args.privacy ?? 'public',
93
+ capabilities: [],
94
+ skills: [],
95
+ transportType: 'http',
96
+ transportConfig: {},
97
+ isActive: true,
98
+ });
99
+ // Scaffold .cant persona file if it doesn't exist
100
+ const { existsSync, mkdirSync, writeFileSync } = await import('node:fs');
101
+ const { join } = await import('node:path');
102
+ const cantDir = join(CLEO_DIR_NAME, AGENTS_SUBDIR);
103
+ const cantPath = join(cantDir, `${agentId}.cant`);
104
+ let cantScaffolded = false;
105
+ if (!existsSync(cantPath)) {
106
+ mkdirSync(cantDir, { recursive: true });
107
+ const role = classification ?? 'specialist';
108
+ const cantContent = `---
109
+ kind: agent
110
+ version: 2
111
+ ---
112
+
113
+ agent ${agentId}:
114
+ house: none
115
+ allegiance: canon
116
+ role: ${role}
117
+ parent: project-orchestrator
118
+ description: "${displayName}"
119
+
120
+ tone:
121
+ |
122
+ TODO: Describe how this agent communicates.
123
+
124
+ prompt:
125
+ |
126
+ TODO: Write the core behavioral instruction.
127
+
128
+ skills: [ct-cleo]
129
+
130
+ permissions:
131
+ tasks: read
132
+ session: read
133
+ memory: read
134
+
135
+ transport:
136
+ primary: local
137
+ fallback: sse
138
+ cloud: http
139
+ apiBaseUrl: https://api.signaldock.io
140
+
141
+ lifecycle:
142
+ start: cleo agent start ${agentId}
143
+ stop: cleo agent stop ${agentId}
144
+ status: cleo agent status ${agentId}
145
+
146
+ context:
147
+ active-tasks
148
+ memory-bridge
149
+
150
+ on SessionStart:
151
+ /checkin @all #online
152
+
153
+ enforcement:
154
+ 1: TODO — what does this agent push back on?
155
+ `;
156
+ writeFileSync(cantPath, cantContent, 'utf-8');
157
+ cantScaffolded = true;
158
+ }
159
+ cliOutput({
160
+ success: true,
161
+ data: {
162
+ agentId: credential.agentId,
163
+ displayName: credential.displayName,
164
+ cantFile: cantScaffolded ? cantPath : existsSync(cantPath) ? cantPath : null,
165
+ cantScaffolded,
166
+ },
167
+ }, { command: 'agent register' });
168
+ }
169
+ catch (err) {
170
+ cliOutput({ success: false, error: { code: 'E_REGISTER', message: String(err) } }, { command: 'agent register' });
171
+ process.exitCode = 1;
172
+ }
173
+ },
174
+ });
175
+ /** cleo agent signin <agentId> — sign in as an agent */
176
+ const signinCommand = defineCommand({
177
+ meta: {
178
+ name: 'signin',
179
+ description: 'Sign in as an agent — marks active, caches credentials for session',
180
+ },
181
+ args: {
182
+ agentId: {
183
+ type: 'positional',
184
+ description: 'Agent ID to sign in as',
185
+ required: true,
186
+ },
187
+ 'api-url': {
188
+ type: 'string',
189
+ description: 'Override API base URL for cloud status update',
190
+ },
191
+ },
192
+ async run({ args }) {
193
+ try {
194
+ const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
195
+ await getDb();
196
+ const registry = new AgentRegistryAccessor(process.cwd());
197
+ // Look up the credential
198
+ const credential = await registry.get(args.agentId);
199
+ if (!credential) {
200
+ cliOutput({
201
+ success: false,
202
+ error: {
203
+ code: 'E_NOT_FOUND',
204
+ message: `Agent '${args.agentId}' not registered. Run: cleo agent register --id ${args.agentId} --name "..." --api-key sk_live_...`,
205
+ },
206
+ }, { command: 'agent signin' });
207
+ process.exitCode = 1;
208
+ return;
209
+ }
210
+ // Mark as active + update lastUsedAt
211
+ await registry.update(args.agentId, { isActive: true });
212
+ await registry.markUsed(args.agentId);
213
+ // Attempt to set online status on cloud (best-effort, don't fail if offline)
214
+ const apiUrl = args['api-url'] ?? credential.apiBaseUrl;
215
+ try {
216
+ await fetch(`${apiUrl}/agents/${args.agentId}/status`, {
217
+ method: 'PUT',
218
+ headers: {
219
+ 'Content-Type': 'application/json',
220
+ Authorization: `Bearer ${credential.apiKey}`,
221
+ 'X-Agent-Id': args.agentId,
222
+ },
223
+ body: JSON.stringify({ status: 'online' }),
224
+ signal: AbortSignal.timeout(5000),
225
+ });
226
+ }
227
+ catch {
228
+ // Offline is fine — LocalTransport works without cloud
229
+ }
230
+ cliOutput({
231
+ success: true,
232
+ data: {
233
+ agentId: credential.agentId,
234
+ displayName: credential.displayName,
235
+ apiBaseUrl: apiUrl,
236
+ status: 'online',
237
+ transport: 'local',
238
+ },
239
+ }, { command: 'agent signin' });
240
+ }
241
+ catch (err) {
242
+ cliOutput({ success: false, error: { code: 'E_SIGNIN', message: String(err) } }, { command: 'agent signin' });
243
+ process.exitCode = 1;
244
+ }
245
+ },
246
+ });
247
+ /**
248
+ * cleo agent start <agentId> — start the SignalDock-poller daemon.
249
+ *
250
+ * Profile handling:
251
+ * The `--cant <file>` option (or the default
252
+ * `.cleo/agents/<agentId>.cant` lookup) is read for two reasons:
253
+ *
254
+ * 1. **Fail-fast validation**: if the file exists and the optional
255
+ * `@cleocode/cant` validator is available in this build, the
256
+ * file is parsed so malformed profiles surface as a status
257
+ * string rather than blowing up later.
258
+ * 2. **Status surface**: the resulting status (`validated`,
259
+ * `invalid (N errors)`, `loaded (unvalidated)`, or `none`) is
260
+ * reported in the LAFS envelope so operators know the daemon
261
+ * saw the file they expected.
262
+ *
263
+ * The profile string is then DROPPED. The daemon does NOT execute
264
+ * workflow profiles. Profile-driven behaviour runs inside Pi sessions
265
+ * through the `cant-bridge.ts` Pi extension.
266
+ * See ADR-035 §D5 (Option Y addendum) for the architectural rationale.
267
+ */
268
+ const startCommand = defineCommand({
269
+ meta: {
270
+ name: 'start',
271
+ description: 'Start an agent daemon — polls SignalDock for messages. Profile is validated for fail-fast feedback only; CANT execution lives in Pi via cant-bridge.ts.',
272
+ },
273
+ args: {
274
+ agentId: {
275
+ type: 'positional',
276
+ description: 'Agent ID to start',
277
+ required: true,
278
+ },
279
+ cant: {
280
+ type: 'string',
281
+ description: 'Path to .cant persona file (validated only, NOT executed by the daemon)',
282
+ },
283
+ 'poll-interval': {
284
+ type: 'string',
285
+ description: 'Poll interval in milliseconds',
286
+ default: '5000',
287
+ },
288
+ heartbeat: {
289
+ type: 'boolean',
290
+ description: 'Enable heartbeat service (default: true)',
291
+ default: true,
292
+ },
293
+ },
294
+ async run({ args }) {
295
+ try {
296
+ const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
297
+ const { createRuntime } = await import('@cleocode/runtime');
298
+ const { existsSync, readFileSync } = await import('node:fs');
299
+ const { join } = await import('node:path');
300
+ await getDb();
301
+ const registry = new AgentRegistryAccessor(process.cwd());
302
+ // 1. Look up credential
303
+ const credential = await registry.get(args.agentId);
304
+ if (!credential) {
305
+ cliOutput({
306
+ success: false,
307
+ error: {
308
+ code: 'E_NOT_FOUND',
309
+ message: `Agent '${args.agentId}' not registered. Run: cleo agent register --id ${args.agentId} --name "..." --api-key sk_live_...`,
310
+ },
311
+ }, { command: 'agent start' });
312
+ process.exitCode = 1;
313
+ return;
314
+ }
315
+ // 2. Read and (best-effort) validate the .cant profile.
316
+ // This is FAIL-FAST GUARDING ONLY. The profile string is
317
+ // used to compute a status field below, then dropped. The
318
+ // daemon does not interpret the workflow body.
319
+ let profile = null;
320
+ let cantValidation = null;
321
+ const cantPath = args.cant ?? join(CLEO_DIR_NAME, AGENTS_SUBDIR, `${args.agentId}.cant`);
322
+ if (existsSync(cantPath)) {
323
+ profile = readFileSync(cantPath, 'utf-8');
324
+ try {
325
+ const cantModule = await import('@cleocode/cant');
326
+ // validate() may not be available in all builds of @cleocode/cant
327
+ const validate = 'validate' in cantModule
328
+ ? cantModule.validate
329
+ : null;
330
+ if (validate) {
331
+ const result = validate(profile);
332
+ cantValidation = {
333
+ valid: result.valid,
334
+ errors: result.diagnostics?.map((d) => d.message) ?? [],
335
+ };
336
+ }
337
+ }
338
+ catch {
339
+ // cant-napi not available — profile loaded but unvalidated
340
+ cantValidation = null;
341
+ }
342
+ }
343
+ // 3. Mark active + update lastUsedAt
344
+ await registry.update(args.agentId, { isActive: true });
345
+ await registry.markUsed(args.agentId);
346
+ // 4. Set cloud status (best-effort)
347
+ try {
348
+ await fetch(`${credential.apiBaseUrl}/agents/${args.agentId}/status`, {
349
+ method: 'PUT',
350
+ headers: {
351
+ 'Content-Type': 'application/json',
352
+ Authorization: `Bearer ${credential.apiKey}`,
353
+ 'X-Agent-Id': args.agentId,
354
+ },
355
+ body: JSON.stringify({ status: 'online' }),
356
+ signal: AbortSignal.timeout(5000),
357
+ });
358
+ }
359
+ catch {
360
+ // Offline is fine — LocalTransport works without cloud
361
+ }
362
+ // 5. Start runtime services (transport auto-resolved: Local > SSE > HTTP).
363
+ // Note: createRuntime() does NOT receive the profile. The
364
+ // daemon's job is purely SignalDock polling + cloud status.
365
+ const pollInterval = Number.parseInt(args['poll-interval'], 10);
366
+ const runtime = await createRuntime(registry, {
367
+ agentId: args.agentId,
368
+ pollIntervalMs: pollInterval,
369
+ heartbeatIntervalMs: args.heartbeat === false ? 0 : 30000,
370
+ groupConversationIds: [],
371
+ });
372
+ runtime.poller.start();
373
+ cliOutput({
374
+ success: true,
375
+ data: {
376
+ agentId: args.agentId,
377
+ displayName: credential.displayName,
378
+ status: 'online',
379
+ transport: runtime.transport.name,
380
+ // Surfaced for operator visibility only — see
381
+ // computeProfileStatus tsdoc for the four possible values.
382
+ profile: computeProfileStatus(profile, cantValidation),
383
+ services: {
384
+ poller: 'running',
385
+ heartbeat: runtime.heartbeat ? 'running' : 'disabled',
386
+ keyRotation: runtime.keyRotation ? 'running' : 'disabled',
387
+ },
388
+ },
389
+ }, { command: 'agent start' });
390
+ // 6. Keep process alive until shutdown signal (cross-platform)
391
+ const shutdown = () => {
392
+ runtime.stop();
393
+ void registry.update(args.agentId, { isActive: false }).catch(() => { });
394
+ process.exit(0);
395
+ };
396
+ process.on('SIGINT', shutdown);
397
+ process.on('SIGTERM', shutdown);
398
+ // Windows: listen for 'message' from parent process managers (PM2, etc.)
399
+ if (process.platform === 'win32') {
400
+ process.on('message', (msg) => {
401
+ if (msg === 'shutdown')
402
+ shutdown();
403
+ });
404
+ }
405
+ // Keep alive
406
+ await new Promise(() => { });
407
+ }
408
+ catch (err) {
409
+ cliOutput({ success: false, error: { code: 'E_START', message: String(err) } }, { command: 'agent start' });
410
+ process.exitCode = 1;
411
+ }
412
+ },
413
+ });
414
+ /** cleo agent stop <agentId> — stop an agent and mark it offline */
415
+ const stopCommand = defineCommand({
416
+ meta: {
417
+ name: 'stop',
418
+ description: 'Stop an agent — mark offline and deactivate',
419
+ },
420
+ args: {
421
+ agentId: {
422
+ type: 'positional',
423
+ description: 'Agent ID to stop',
424
+ required: true,
425
+ },
426
+ },
427
+ async run({ args }) {
428
+ try {
429
+ const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
430
+ await getDb();
431
+ const registry = new AgentRegistryAccessor(process.cwd());
432
+ const credential = await registry.get(args.agentId);
433
+ if (!credential) {
434
+ cliOutput({
435
+ success: false,
436
+ error: { code: 'E_NOT_FOUND', message: `Agent '${args.agentId}' not registered.` },
437
+ }, { command: 'agent stop' });
438
+ process.exitCode = 1;
439
+ return;
440
+ }
441
+ // Mark inactive
442
+ await registry.update(args.agentId, { isActive: false });
443
+ // Set cloud status offline (best-effort)
444
+ try {
445
+ await fetch(`${credential.apiBaseUrl}/agents/${args.agentId}/status`, {
446
+ method: 'PUT',
447
+ headers: {
448
+ 'Content-Type': 'application/json',
449
+ Authorization: `Bearer ${credential.apiKey}`,
450
+ 'X-Agent-Id': args.agentId,
451
+ },
452
+ body: JSON.stringify({ status: 'offline' }),
453
+ signal: AbortSignal.timeout(5000),
454
+ });
455
+ }
456
+ catch {
457
+ // Offline is fine
458
+ }
459
+ cliOutput({ success: true, data: { agentId: args.agentId, status: 'offline' } }, { command: 'agent stop' });
460
+ }
461
+ catch (err) {
462
+ cliOutput({ success: false, error: { code: 'E_STOP', message: String(err) } }, { command: 'agent stop' });
463
+ process.exitCode = 1;
464
+ }
465
+ },
466
+ });
467
+ /** cleo agent status [agentId] — show agent status for all or a specific agent */
468
+ const statusCommand = defineCommand({
469
+ meta: {
470
+ name: 'status',
471
+ description: 'Show agent status — all agents or specific agent',
472
+ },
473
+ args: {
474
+ agentId: {
475
+ type: 'positional',
476
+ description: 'Agent ID to check (optional — omit for all)',
477
+ required: false,
478
+ },
479
+ },
480
+ async run({ args }) {
481
+ try {
482
+ const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
483
+ await getDb();
484
+ const registry = new AgentRegistryAccessor(process.cwd());
485
+ if (args.agentId) {
486
+ const credential = await registry.get(args.agentId);
487
+ if (!credential) {
488
+ cliOutput({
489
+ success: false,
490
+ error: { code: 'E_NOT_FOUND', message: `Agent '${args.agentId}' not registered.` },
491
+ }, { command: 'agent status' });
492
+ process.exitCode = 1;
493
+ return;
494
+ }
495
+ cliOutput({
496
+ success: true,
497
+ data: {
498
+ agentId: credential.agentId,
499
+ displayName: credential.displayName,
500
+ active: credential.isActive,
501
+ lastUsedAt: credential.lastUsedAt,
502
+ transport: credential.transportType,
503
+ },
504
+ }, { command: 'agent status' });
505
+ }
506
+ else {
507
+ const agents = await registry.list();
508
+ cliOutput({
509
+ success: true,
510
+ data: {
511
+ agents: agents.map((a) => ({
512
+ agentId: a.agentId,
513
+ displayName: a.displayName,
514
+ active: a.isActive,
515
+ lastUsedAt: a.lastUsedAt,
516
+ })),
517
+ total: agents.length,
518
+ },
519
+ }, { command: 'agent status' });
520
+ }
521
+ }
522
+ catch (err) {
523
+ cliOutput({ success: false, error: { code: 'E_STATUS', message: String(err) } }, { command: 'agent status' });
524
+ process.exitCode = 1;
525
+ }
526
+ },
527
+ });
528
+ /** cleo agent assign <agentId> <taskId> — assign a task to an agent via messaging */
529
+ const assignCommand = defineCommand({
530
+ meta: {
531
+ name: 'assign',
532
+ description: 'Assign a task to an agent via messaging',
533
+ },
534
+ args: {
535
+ agentId: {
536
+ type: 'positional',
537
+ description: 'Target agent ID',
538
+ required: true,
539
+ },
540
+ taskId: {
541
+ type: 'positional',
542
+ description: 'Task ID to assign',
543
+ required: true,
544
+ },
545
+ },
546
+ async run({ args }) {
547
+ try {
548
+ const { AgentRegistryAccessor, getDb, createConduit } = await import('@cleocode/core/internal');
549
+ await getDb();
550
+ const registry = new AgentRegistryAccessor(process.cwd());
551
+ const active = await registry.getActive();
552
+ if (!active) {
553
+ cliOutput({
554
+ success: false,
555
+ error: {
556
+ code: 'E_NO_ACTIVE',
557
+ message: 'No active agent. Run: cleo agent signin <id>',
558
+ },
559
+ }, { command: 'agent assign' });
560
+ process.exitCode = 1;
561
+ return;
562
+ }
563
+ const conduit = await createConduit(registry);
564
+ await conduit.send(args.agentId, `/action @${args.agentId} #task-assignment\n\nAssigned task ${args.taskId}. Run: cleo show ${args.taskId} && cleo start ${args.taskId}`);
565
+ await conduit.disconnect();
566
+ cliOutput({
567
+ success: true,
568
+ data: { agentId: args.agentId, taskId: args.taskId, assignedBy: active.agentId },
569
+ }, { command: 'agent assign' });
570
+ }
571
+ catch (err) {
572
+ cliOutput({ success: false, error: { code: 'E_ASSIGN', message: String(err) } }, { command: 'agent assign' });
573
+ process.exitCode = 1;
574
+ }
575
+ },
576
+ });
577
+ /** cleo agent wake <agentId> — wake an idle agent by sending a prod message */
578
+ const wakeCommand = defineCommand({
579
+ meta: {
580
+ name: 'wake',
581
+ description: 'Wake an idle agent — send a prod message',
582
+ },
583
+ args: {
584
+ agentId: {
585
+ type: 'positional',
586
+ description: 'Agent ID to wake',
587
+ required: true,
588
+ },
589
+ },
590
+ async run({ args }) {
591
+ try {
592
+ const { AgentRegistryAccessor, getDb, createConduit } = await import('@cleocode/core/internal');
593
+ await getDb();
594
+ const registry = new AgentRegistryAccessor(process.cwd());
595
+ const active = await registry.getActive();
596
+ if (!active) {
597
+ cliOutput({
598
+ success: false,
599
+ error: {
600
+ code: 'E_NO_ACTIVE',
601
+ message: 'No active agent. Run: cleo agent signin <id>',
602
+ },
603
+ }, { command: 'agent wake' });
604
+ process.exitCode = 1;
605
+ return;
606
+ }
607
+ const conduit = await createConduit(registry);
608
+ await conduit.send(args.agentId, `/action @${args.agentId} #wake #prod\n\nYou are idle. Check your queue: cleo current || cleo next. Report status immediately.`);
609
+ await conduit.disconnect();
610
+ cliOutput({ success: true, data: { agentId: args.agentId, prodBy: active.agentId } }, { command: 'agent wake' });
611
+ }
612
+ catch (err) {
613
+ cliOutput({ success: false, error: { code: 'E_WAKE', message: String(err) } }, { command: 'agent wake' });
614
+ process.exitCode = 1;
615
+ }
616
+ },
617
+ });
618
+ /** cleo agent spawn — spawn a new ephemeral agent for a specific task */
619
+ const spawnCommand = defineCommand({
620
+ meta: {
621
+ name: 'spawn',
622
+ description: 'Spawn a new ephemeral agent for a specific task',
623
+ },
624
+ args: {
625
+ role: {
626
+ type: 'string',
627
+ description: 'Agent role (e.g. code_dev, research, security)',
628
+ required: true,
629
+ },
630
+ task: {
631
+ type: 'string',
632
+ description: 'Task to assign to the spawned agent',
633
+ },
634
+ model: {
635
+ type: 'string',
636
+ description: 'Model to use (e.g. opus, sonnet)',
637
+ },
638
+ name: {
639
+ type: 'string',
640
+ description: 'Display name for the agent',
641
+ },
642
+ },
643
+ async run({ args }) {
644
+ try {
645
+ const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
646
+ await getDb();
647
+ const registry = new AgentRegistryAccessor(process.cwd());
648
+ const role = args.role;
649
+ const taskId = args.task;
650
+ const model = args.model ?? 'sonnet';
651
+ const displayName = args.name ?? `ephemeral-${role}-${Date.now().toString(36)}`;
652
+ const agentId = displayName;
653
+ // Register the ephemeral agent locally (no cloud registration)
654
+ await registry.register({
655
+ agentId,
656
+ displayName,
657
+ apiKey: 'ephemeral-local-only',
658
+ apiBaseUrl: 'local',
659
+ classification: role,
660
+ privacyTier: 'private',
661
+ capabilities: ['chat', 'tools'],
662
+ skills: [role],
663
+ transportType: 'http',
664
+ transportConfig: {},
665
+ isActive: true,
666
+ });
667
+ cliOutput({
668
+ success: true,
669
+ data: {
670
+ agentId,
671
+ displayName,
672
+ role,
673
+ model,
674
+ taskId: taskId ?? null,
675
+ transport: 'local',
676
+ lifecycle: 'ephemeral',
677
+ },
678
+ }, { command: 'agent spawn' });
679
+ }
680
+ catch (err) {
681
+ cliOutput({ success: false, error: { code: 'E_SPAWN', message: String(err) } }, { command: 'agent spawn' });
682
+ process.exitCode = 1;
683
+ }
684
+ },
685
+ });
686
+ /** cleo agent reassign <taskId> <agentId> — reassign a task to another agent via conduit */
687
+ const reassignCommand = defineCommand({
688
+ meta: {
689
+ name: 'reassign',
690
+ description: 'Reassign a task to another agent via conduit message',
691
+ },
692
+ args: {
693
+ taskId: {
694
+ type: 'positional',
695
+ description: 'Task ID to reassign',
696
+ required: true,
697
+ },
698
+ agentId: {
699
+ type: 'positional',
700
+ description: 'Target agent ID',
701
+ required: true,
702
+ },
703
+ },
704
+ async run({ args }) {
705
+ try {
706
+ const { AgentRegistryAccessor, getDb, createConduit } = await import('@cleocode/core/internal');
707
+ await getDb();
708
+ const registry = new AgentRegistryAccessor(process.cwd());
709
+ const active = await registry.getActive();
710
+ if (!active) {
711
+ cliOutput({ success: false, error: { code: 'E_NO_ACTIVE', message: 'No active agent.' } }, { command: 'agent reassign' });
712
+ process.exitCode = 1;
713
+ return;
714
+ }
715
+ const conduit = await createConduit(registry);
716
+ await conduit.send(args.agentId, `/action @${args.agentId} #task-reassignment\n\nTask ${args.taskId} reassigned to you by ${active.agentId}. Run: cleo show ${args.taskId} && cleo start ${args.taskId}`);
717
+ await conduit.disconnect();
718
+ cliOutput({
719
+ success: true,
720
+ data: { taskId: args.taskId, newOwner: args.agentId, reassignedBy: active.agentId },
721
+ }, { command: 'agent reassign' });
722
+ }
723
+ catch (err) {
724
+ cliOutput({ success: false, error: { code: 'E_REASSIGN', message: String(err) } }, { command: 'agent reassign' });
725
+ process.exitCode = 1;
726
+ }
727
+ },
728
+ });
729
+ /** cleo agent stop-all — stop all active agents and mark them offline */
730
+ const stopAllCommand = defineCommand({
731
+ meta: {
732
+ name: 'stop-all',
733
+ description: 'Stop all active agents — mark all offline',
734
+ },
735
+ async run() {
736
+ try {
737
+ const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
738
+ await getDb();
739
+ const registry = new AgentRegistryAccessor(process.cwd());
740
+ const agents = await registry.list({ active: true });
741
+ let stopped = 0;
742
+ for (const a of agents) {
743
+ await registry.update(a.agentId, { isActive: false });
744
+ try {
745
+ await fetch(`${a.apiBaseUrl}/agents/${a.agentId}/status`, {
746
+ method: 'PUT',
747
+ headers: {
748
+ 'Content-Type': 'application/json',
749
+ Authorization: `Bearer ${a.apiKey}`,
750
+ 'X-Agent-Id': a.agentId,
751
+ },
752
+ body: JSON.stringify({ status: 'offline' }),
753
+ signal: AbortSignal.timeout(3000),
754
+ });
755
+ }
756
+ catch {
757
+ /* best-effort */
758
+ }
759
+ stopped++;
760
+ }
761
+ cliOutput({ success: true, data: { stopped, total: agents.length } }, { command: 'agent stop-all' });
762
+ }
763
+ catch (err) {
764
+ cliOutput({ success: false, error: { code: 'E_STOP_ALL', message: String(err) } }, { command: 'agent stop-all' });
765
+ process.exitCode = 1;
766
+ }
767
+ },
768
+ });
769
+ /**
770
+ * cleo agent work <agentId> — enter autonomous work loop.
771
+ *
772
+ * Phase 3: --execute enables the Conductor Loop, which autonomously
773
+ * dispatches ready tasks via orchestrate.spawn.execute.
774
+ */
775
+ const workCommand = defineCommand({
776
+ meta: {
777
+ name: 'work',
778
+ description: 'Enter autonomous work loop — poll tasks, report, optionally execute. --execute enables the Conductor Loop.',
779
+ },
780
+ args: {
781
+ agentId: {
782
+ type: 'positional',
783
+ description: 'Agent ID to run the work loop as',
784
+ required: true,
785
+ },
786
+ 'poll-interval': {
787
+ type: 'string',
788
+ description: 'Task check interval in milliseconds',
789
+ default: '30000',
790
+ },
791
+ execute: {
792
+ type: 'boolean',
793
+ description: 'Autonomously execute ready tasks via orchestrate.spawn.execute (Phase 3 Conductor Loop)',
794
+ },
795
+ adapter: {
796
+ type: 'string',
797
+ description: 'Adapter id to route spawns through (default: auto-detect from capabilities)',
798
+ },
799
+ epic: {
800
+ type: 'string',
801
+ description: 'Restrict autonomous execution to a specific epic (default: any ready task)',
802
+ },
803
+ },
804
+ async run({ args }) {
805
+ try {
806
+ const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
807
+ const { createRuntime } = await import('@cleocode/runtime');
808
+ const { existsSync } = await import('node:fs');
809
+ const { join } = await import('node:path');
810
+ const { execFile } = await import('node:child_process');
811
+ const { promisify } = await import('node:util');
812
+ const execFileAsync = promisify(execFile);
813
+ await getDb();
814
+ const registry = new AgentRegistryAccessor(process.cwd());
815
+ const credential = await registry.get(args.agentId);
816
+ if (!credential) {
817
+ cliOutput({
818
+ success: false,
819
+ error: { code: 'E_NOT_FOUND', message: `Agent '${args.agentId}' not registered.` },
820
+ }, { command: 'agent work' });
821
+ process.exitCode = 1;
822
+ return;
823
+ }
824
+ await registry.update(args.agentId, { isActive: true });
825
+ await registry.markUsed(args.agentId);
826
+ const cantPath = join(CLEO_DIR_NAME, AGENTS_SUBDIR, `${args.agentId}.cant`);
827
+ const hasProfile = existsSync(cantPath);
828
+ const runtime = await createRuntime(registry, {
829
+ agentId: args.agentId,
830
+ pollIntervalMs: 5000,
831
+ heartbeatIntervalMs: 30000,
832
+ });
833
+ runtime.poller.start();
834
+ const executeMode = args.execute === true;
835
+ const epicRestrict = args.epic;
836
+ const adapterRestrict = args.adapter;
837
+ cliOutput({
838
+ success: true,
839
+ data: {
840
+ agentId: args.agentId,
841
+ mode: executeMode ? 'conductor-loop' : 'watch-only',
842
+ profile: hasProfile ? 'loaded' : 'none',
843
+ status: 'running',
844
+ epic: epicRestrict ?? 'any',
845
+ adapter: adapterRestrict ?? 'auto',
846
+ },
847
+ }, { command: 'agent work' });
848
+ // Parse LAFS envelope from CLI stdout (handles both minimal and full shapes)
849
+ const parseLafs = (raw) => {
850
+ const lines = raw.trim().split('\n');
851
+ const envLine = [...lines].reverse().find((l) => l.startsWith('{'));
852
+ if (!envLine)
853
+ return undefined;
854
+ try {
855
+ const env = JSON.parse(envLine);
856
+ if (env.ok === true)
857
+ return env.r;
858
+ if (env.success === true)
859
+ return (env.result ?? env.data);
860
+ return undefined;
861
+ }
862
+ catch {
863
+ return undefined;
864
+ }
865
+ };
866
+ const runCleo = async (cleoArgs, timeoutMs = 15000) => {
867
+ const { stdout } = await execFileAsync('cleo', cleoArgs, {
868
+ encoding: 'utf-8',
869
+ timeout: timeoutMs,
870
+ });
871
+ return stdout;
872
+ };
873
+ const taskInterval = Number.parseInt(args['poll-interval'], 10);
874
+ let inFlight = false;
875
+ let iterations = 0;
876
+ const workLoop = setInterval(async () => {
877
+ if (inFlight)
878
+ return;
879
+ inFlight = true;
880
+ iterations += 1;
881
+ try {
882
+ const currentRaw = await runCleo(['current']).catch(() => '');
883
+ if (currentRaw.trim()) {
884
+ // A task is already in progress — skip
885
+ return;
886
+ }
887
+ // Resolve next ready task (respect epic restriction when set)
888
+ const nextArgs = epicRestrict ? ['orchestrate', 'next', epicRestrict] : ['next'];
889
+ const nextRaw = await runCleo(nextArgs).catch(() => '');
890
+ if (!nextRaw.trim())
891
+ return;
892
+ const nextData = parseLafs(nextRaw);
893
+ const taskId = nextData?.nextTask?.id ?? (typeof nextData?.id === 'string' ? nextData.id : undefined);
894
+ if (!taskId)
895
+ return;
896
+ if (!executeMode) {
897
+ // Watch-only legacy behaviour: advertise availability
898
+ console.log(`[${args.agentId}] Task available: ${taskId}. Pass --execute to run autonomously.`);
899
+ return;
900
+ }
901
+ // Phase 3 Conductor Loop: actually execute via orchestrate.spawn.execute
902
+ const spawnArgs = ['orchestrate', 'spawn', taskId];
903
+ if (adapterRestrict) {
904
+ spawnArgs.push('--adapter', adapterRestrict);
905
+ }
906
+ const spawnRaw = await runCleo(spawnArgs, 60000).catch((e) => {
907
+ console.error(`[${args.agentId}] conductor-loop: spawn failed for ${taskId}: ${String(e)}`);
908
+ return '';
909
+ });
910
+ const spawnData = parseLafs(spawnRaw);
911
+ if (spawnData?.instanceId) {
912
+ console.log(`[${args.agentId}] conductor-loop spawned task=${taskId} instance=${spawnData.instanceId} status=${spawnData.status ?? 'unknown'}`);
913
+ }
914
+ }
915
+ catch {
916
+ /* non-fatal — loop continues */
917
+ }
918
+ finally {
919
+ inFlight = false;
920
+ }
921
+ }, taskInterval);
922
+ const shutdown = () => {
923
+ clearInterval(workLoop);
924
+ runtime.stop();
925
+ void registry.update(args.agentId, { isActive: false }).catch(() => { });
926
+ if (executeMode) {
927
+ console.log(`[${args.agentId}] conductor-loop shutdown after ${iterations} iterations.`);
928
+ }
929
+ process.exit(0);
930
+ };
931
+ process.on('SIGINT', shutdown);
932
+ process.on('SIGTERM', shutdown);
933
+ if (process.platform === 'win32') {
934
+ process.on('message', (msg) => {
935
+ if (msg === 'shutdown')
936
+ shutdown();
937
+ });
938
+ }
939
+ await new Promise(() => { });
940
+ }
941
+ catch (err) {
942
+ cliOutput({ success: false, error: { code: 'E_WORK', message: String(err) } }, { command: 'agent work' });
943
+ process.exitCode = 1;
944
+ }
945
+ },
946
+ });
947
+ /**
948
+ * cleo agent list — list registered agent credentials.
949
+ *
950
+ * Default: project-scoped INNER JOIN. Use --global for full cross-project scan
951
+ * (ADR-037 §4 Q1=B).
952
+ *
953
+ * @task T362 @epic T310
954
+ */
955
+ const listCommand = defineCommand({
956
+ meta: {
957
+ name: 'list',
958
+ description: 'List registered agent credentials',
959
+ },
960
+ args: {
961
+ active: {
962
+ type: 'boolean',
963
+ description: 'Show only active agents (project-scoped mode only)',
964
+ },
965
+ global: {
966
+ type: 'boolean',
967
+ description: 'Show all global agents regardless of project attachment (ADR-037 §4 Q1=B)',
968
+ },
969
+ 'include-disabled': {
970
+ type: 'boolean',
971
+ description: 'Include detached/disabled agents (enabled=0)',
972
+ },
973
+ },
974
+ async run({ args }) {
975
+ try {
976
+ const { listAgentsForProject, getDb } = await import('@cleocode/core/internal');
977
+ await getDb();
978
+ const includeGlobal = args.global === true;
979
+ const includeDisabled = args['include-disabled'] === true;
980
+ const agents = listAgentsForProject(process.cwd(), {
981
+ includeGlobal,
982
+ includeDisabled,
983
+ });
984
+ // Apply legacy --active filter only when NOT in global mode
985
+ const filtered = !includeGlobal && args.active ? agents.filter((a) => a.isActive) : agents;
986
+ cliOutput({
987
+ success: true,
988
+ data: filtered.map((a) => ({
989
+ agentId: a.agentId,
990
+ name: a.displayName,
991
+ classification: a.classification ?? null,
992
+ transportType: a.transportType,
993
+ isActive: a.isActive,
994
+ lastUsedAt: a.lastUsedAt ?? null,
995
+ attachment: a.projectRef
996
+ ? a.projectRef.enabled === 1
997
+ ? '[attached]'
998
+ : '[disabled]'
999
+ : '[global]',
1000
+ })),
1001
+ }, { command: 'agent list' });
1002
+ }
1003
+ catch (err) {
1004
+ cliOutput({ success: false, error: { code: 'E_LIST', message: String(err) } }, { command: 'agent list' });
1005
+ process.exitCode = 1;
1006
+ }
1007
+ },
1008
+ });
1009
+ /**
1010
+ * cleo agent get <agentId> — get details for a specific agent credential.
1011
+ *
1012
+ * Default: project-scoped lookup. With --global: cross-project identity lookup
1013
+ * (ADR-037 §4).
1014
+ *
1015
+ * @task T362 @epic T310
1016
+ */
1017
+ const getCommand = defineCommand({
1018
+ meta: {
1019
+ name: 'get',
1020
+ description: 'Get details for a specific agent credential',
1021
+ },
1022
+ args: {
1023
+ agentId: {
1024
+ type: 'positional',
1025
+ description: 'Agent ID to look up',
1026
+ required: true,
1027
+ },
1028
+ global: {
1029
+ type: 'boolean',
1030
+ description: 'Perform global identity lookup — returns agent even if not attached to current project',
1031
+ },
1032
+ },
1033
+ async run({ args }) {
1034
+ try {
1035
+ const { lookupAgent, getDb } = await import('@cleocode/core/internal');
1036
+ await getDb();
1037
+ const includeGlobal = args.global === true;
1038
+ const agent = lookupAgent(process.cwd(), args.agentId, { includeGlobal });
1039
+ if (!agent) {
1040
+ cliOutput({
1041
+ success: false,
1042
+ error: { code: 'E_NOT_FOUND', message: `Agent not found: ${args.agentId}` },
1043
+ }, { command: 'agent get' });
1044
+ process.exitCode = 4;
1045
+ return;
1046
+ }
1047
+ // Redact API key in output
1048
+ const redactedKey = agent.apiKey.length > 16
1049
+ ? `${agent.apiKey.substring(0, 12)}...${agent.apiKey.substring(agent.apiKey.length - 4)}`
1050
+ : '***redacted***';
1051
+ cliOutput({
1052
+ success: true,
1053
+ data: {
1054
+ agentId: agent.agentId,
1055
+ displayName: agent.displayName,
1056
+ apiKey: redactedKey,
1057
+ apiBaseUrl: agent.apiBaseUrl,
1058
+ classification: agent.classification ?? null,
1059
+ transportType: agent.transportType,
1060
+ isActive: agent.isActive,
1061
+ lastUsedAt: agent.lastUsedAt ?? null,
1062
+ createdAt: agent.createdAt,
1063
+ updatedAt: agent.updatedAt,
1064
+ projectRef: agent.projectRef ?? 'not attached to current project',
1065
+ },
1066
+ }, { command: 'agent get' });
1067
+ }
1068
+ catch (err) {
1069
+ cliOutput({ success: false, error: { code: 'E_GET', message: String(err) } }, { command: 'agent get' });
1070
+ process.exitCode = 1;
1071
+ }
1072
+ },
1073
+ });
1074
+ /**
1075
+ * cleo agent attach <agentId> — attach a global agent to the current project.
1076
+ *
1077
+ * @task T364 @epic T310
1078
+ * @why ADR-037 §3 — project_agent_refs override table allows per-project
1079
+ * agents to be attached/detached without touching global identity.
1080
+ */
1081
+ const attachCommand = defineCommand({
1082
+ meta: {
1083
+ name: 'attach',
1084
+ description: 'Attach a global agent to the current project',
1085
+ },
1086
+ args: {
1087
+ agentId: {
1088
+ type: 'positional',
1089
+ description: 'Agent ID to attach',
1090
+ required: true,
1091
+ },
1092
+ role: {
1093
+ type: 'string',
1094
+ description: 'Per-project role override',
1095
+ },
1096
+ 'capabilities-override': {
1097
+ type: 'string',
1098
+ description: 'JSON blob of capability overrides',
1099
+ },
1100
+ },
1101
+ async run({ args }) {
1102
+ try {
1103
+ const { AgentRegistryAccessor, attachAgentToProject, lookupAgent, getDb } = await import('@cleocode/core/internal');
1104
+ await getDb();
1105
+ const projectRoot = process.cwd();
1106
+ // Ensure both DBs initialised before any cross-DB operation
1107
+ const _registry = new AgentRegistryAccessor(projectRoot);
1108
+ void _registry;
1109
+ // Verify agent exists globally
1110
+ const globalAgent = lookupAgent(projectRoot, args.agentId, { includeGlobal: true });
1111
+ if (!globalAgent) {
1112
+ cliOutput({
1113
+ success: false,
1114
+ error: { code: 'E_NOT_FOUND', message: `Agent not found: ${args.agentId}` },
1115
+ }, { command: 'agent attach' });
1116
+ process.exitCode = 4;
1117
+ return;
1118
+ }
1119
+ attachAgentToProject(projectRoot, args.agentId, {
1120
+ role: typeof args.role === 'string' ? args.role : null,
1121
+ capabilitiesOverride: typeof args['capabilities-override'] === 'string' ? args['capabilities-override'] : null,
1122
+ });
1123
+ cliOutput({
1124
+ success: true,
1125
+ data: {
1126
+ attached: args.agentId,
1127
+ projectRoot,
1128
+ role: typeof args.role === 'string' ? args.role : null,
1129
+ },
1130
+ }, { command: 'agent attach' });
1131
+ }
1132
+ catch (err) {
1133
+ cliOutput({ success: false, error: { code: 'E_ATTACH', message: String(err) } }, { command: 'agent attach' });
1134
+ process.exitCode = 1;
1135
+ }
1136
+ },
1137
+ });
1138
+ /**
1139
+ * cleo agent detach <agentId> — detach an agent from the current project.
1140
+ *
1141
+ * @task T364 @epic T310
1142
+ * @why ADR-037 §3 — soft-delete via project_agent_refs.enabled=0 preserves
1143
+ * global agent identity while removing it from the project view.
1144
+ */
1145
+ const detachCommand = defineCommand({
1146
+ meta: {
1147
+ name: 'detach',
1148
+ description: 'Detach an agent from the current project (preserves global identity)',
1149
+ },
1150
+ args: {
1151
+ agentId: {
1152
+ type: 'positional',
1153
+ description: 'Agent ID to detach',
1154
+ required: true,
1155
+ },
1156
+ },
1157
+ async run({ args }) {
1158
+ try {
1159
+ const { AgentRegistryAccessor, detachAgentFromProject, getProjectAgentRef, getDb } = await import('@cleocode/core/internal');
1160
+ await getDb();
1161
+ const projectRoot = process.cwd();
1162
+ // Ensure both DBs initialised
1163
+ const _registry = new AgentRegistryAccessor(projectRoot);
1164
+ void _registry;
1165
+ const ref = getProjectAgentRef(projectRoot, args.agentId);
1166
+ if (!ref) {
1167
+ cliOutput({
1168
+ success: false,
1169
+ error: {
1170
+ code: 'E_NOT_FOUND',
1171
+ message: `Agent ${args.agentId} not attached to current project`,
1172
+ },
1173
+ }, { command: 'agent detach' });
1174
+ process.exitCode = 4;
1175
+ return;
1176
+ }
1177
+ detachAgentFromProject(projectRoot, args.agentId);
1178
+ cliOutput({ success: true, data: { detached: args.agentId, projectRoot } }, { command: 'agent detach' });
1179
+ }
1180
+ catch (err) {
1181
+ cliOutput({ success: false, error: { code: 'E_DETACH', message: String(err) } }, { command: 'agent detach' });
1182
+ process.exitCode = 1;
1183
+ }
1184
+ },
1185
+ });
1186
+ /**
1187
+ * cleo agent remove <agentId> — detach agent from project or remove from global registry.
1188
+ *
1189
+ * Default (no --global): sets enabled=0 in conduit.db:project_agent_refs only.
1190
+ * --global: calls AgentRegistryAccessor.removeGlobal() (destructive). Pre-check
1191
+ * scans the current project's conduit.db for an active reference.
1192
+ *
1193
+ * @task T366 @epic T310
1194
+ * @why ADR-037 §6 — never-auto-delete semantics; --global flag required for
1195
+ * destructive removal; best-effort cross-project scan with documented
1196
+ * limitation (current project only for v1).
1197
+ */
1198
+ const removeCommand = defineCommand({
1199
+ meta: {
1200
+ name: 'remove',
1201
+ description: 'Detach agent from current project (default) or remove global identity with --global',
1202
+ },
1203
+ args: {
1204
+ agentId: {
1205
+ type: 'positional',
1206
+ description: 'Agent ID to remove',
1207
+ required: true,
1208
+ },
1209
+ global: {
1210
+ type: 'boolean',
1211
+ description: 'Remove from global signaldock.db (destructive, irreversible)',
1212
+ },
1213
+ 'force-global': {
1214
+ type: 'boolean',
1215
+ description: 'Force global removal even when the current project still has an active reference',
1216
+ },
1217
+ },
1218
+ async run({ args }) {
1219
+ try {
1220
+ const { AgentRegistryAccessor, detachAgentFromProject, getProjectAgentRef, getDb } = await import('@cleocode/core/internal');
1221
+ await getDb();
1222
+ const projectRoot = process.cwd();
1223
+ if (!args.global) {
1224
+ // Project-scoped detach (default post-T310) — mirrors `cleo agent detach`
1225
+ // Ensure both DBs initialised
1226
+ const _registry = new AgentRegistryAccessor(projectRoot);
1227
+ void _registry;
1228
+ const ref = getProjectAgentRef(projectRoot, args.agentId);
1229
+ if (!ref) {
1230
+ cliOutput({
1231
+ success: false,
1232
+ error: {
1233
+ code: 'E_NOT_FOUND',
1234
+ message: `Agent ${args.agentId} not attached to current project`,
1235
+ },
1236
+ }, { command: 'agent remove' });
1237
+ process.exitCode = 4;
1238
+ return;
1239
+ }
1240
+ detachAgentFromProject(projectRoot, args.agentId);
1241
+ cliOutput({ success: true, data: { removed: args.agentId, scope: 'project', projectRoot } }, { command: 'agent remove' });
1242
+ return;
1243
+ }
1244
+ // --global: destructive removal from signaldock.db
1245
+ // Safety scan — limited to current project (ADR-037 §6 known limitation).
1246
+ const _registry2 = new AgentRegistryAccessor(projectRoot);
1247
+ void _registry2;
1248
+ const activeRef = getProjectAgentRef(projectRoot, args.agentId);
1249
+ if (activeRef && !args['force-global']) {
1250
+ console.warn(`NOTE: Safety scan is limited to the current project. Other projects may have ` +
1251
+ `dangling references after global removal.`);
1252
+ cliOutput({
1253
+ success: false,
1254
+ error: {
1255
+ code: 'E_VALIDATION',
1256
+ message: `Agent "${args.agentId}" is still attached to current project. ` +
1257
+ `Detach first or pass --force-global to proceed anyway.`,
1258
+ fix: `cleo agent detach ${args.agentId} # detach first, then retry` +
1259
+ ` OR cleo agent remove ${args.agentId} --global --force-global`,
1260
+ },
1261
+ }, { command: 'agent remove' });
1262
+ process.exitCode = 6;
1263
+ return;
1264
+ }
1265
+ console.warn(`NOTE: Safety scan is limited to the current project. Other projects may have ` +
1266
+ `dangling references after global removal.`);
1267
+ const registry = new AgentRegistryAccessor(projectRoot);
1268
+ await registry.removeGlobal(args.agentId, { force: args['force-global'] === true });
1269
+ cliOutput({ success: true, data: { removed: args.agentId, scope: 'global' } }, { command: 'agent remove' });
1270
+ }
1271
+ catch (err) {
1272
+ cliOutput({ success: false, error: { code: 'E_REMOVE', message: String(err) } }, { command: 'agent remove' });
1273
+ process.exitCode = 1;
1274
+ }
1275
+ },
1276
+ });
1277
+ /** cleo agent rotate-key <agentId> — rotate an agent API key */
1278
+ const rotateKeyCommand = defineCommand({
1279
+ meta: {
1280
+ name: 'rotate-key',
1281
+ description: 'Rotate an agent API key (generates new key on cloud, re-encrypts locally)',
1282
+ },
1283
+ args: {
1284
+ agentId: {
1285
+ type: 'positional',
1286
+ description: 'Agent ID whose key should be rotated',
1287
+ required: true,
1288
+ },
1289
+ },
1290
+ async run({ args }) {
1291
+ try {
1292
+ const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
1293
+ await getDb();
1294
+ const registry = new AgentRegistryAccessor(process.cwd());
1295
+ const result = await registry.rotateKey(args.agentId);
1296
+ cliOutput({
1297
+ success: true,
1298
+ data: {
1299
+ agentId: result.agentId,
1300
+ newApiKey: `${result.newApiKey.substring(0, 12)}...`,
1301
+ message: 'API key rotated. Old key is invalidated.',
1302
+ },
1303
+ }, { command: 'agent rotate-key' });
1304
+ }
1305
+ catch (err) {
1306
+ cliOutput({ success: false, error: { code: 'E_ROTATE', message: String(err) } }, { command: 'agent rotate-key' });
1307
+ process.exitCode = 1;
1308
+ }
1309
+ },
1310
+ });
1311
+ /** cleo agent claim-code <agentId> — generate a claim code for human ownership verification */
1312
+ const claimCodeCommand = defineCommand({
1313
+ meta: {
1314
+ name: 'claim-code',
1315
+ description: 'Generate a claim code for human ownership of an agent',
1316
+ },
1317
+ args: {
1318
+ agentId: {
1319
+ type: 'positional',
1320
+ description: 'Agent ID to generate a claim code for',
1321
+ required: true,
1322
+ },
1323
+ },
1324
+ async run({ args }) {
1325
+ try {
1326
+ const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
1327
+ await getDb();
1328
+ const registry = new AgentRegistryAccessor(process.cwd());
1329
+ const credential = await registry.get(args.agentId);
1330
+ if (!credential) {
1331
+ cliOutput({
1332
+ success: false,
1333
+ error: { code: 'E_NOT_FOUND', message: `Agent not found: ${args.agentId}` },
1334
+ }, { command: 'agent claim-code' });
1335
+ process.exitCode = 4;
1336
+ return;
1337
+ }
1338
+ const response = await fetch(`${credential.apiBaseUrl}/agents/${args.agentId}/claim-code`, {
1339
+ method: 'POST',
1340
+ headers: {
1341
+ 'Content-Type': 'application/json',
1342
+ Authorization: `Bearer ${credential.apiKey}`,
1343
+ 'X-Agent-Id': args.agentId,
1344
+ },
1345
+ });
1346
+ if (!response.ok) {
1347
+ const text = await response.text().catch(() => '');
1348
+ throw new Error(`Failed to generate claim code: ${response.status} ${text}`);
1349
+ }
1350
+ const data = (await response.json());
1351
+ cliOutput({
1352
+ success: true,
1353
+ data: {
1354
+ agentId: args.agentId,
1355
+ claimCode: data.data?.claimCode,
1356
+ claimUrl: data.data?.claimUrl ?? `https://signaldock.io/claim/${data.data?.claimCode}`,
1357
+ expiresAt: data.data?.expiresAt,
1358
+ message: 'Share this claim code with the human owner to verify agent ownership.',
1359
+ },
1360
+ }, { command: 'agent claim-code' });
1361
+ }
1362
+ catch (err) {
1363
+ cliOutput({ success: false, error: { code: 'E_CLAIM', message: String(err) } }, { command: 'agent claim-code' });
1364
+ process.exitCode = 1;
1365
+ }
1366
+ },
1367
+ });
1368
+ /** cleo agent watch — start continuous message polling for the active agent */
1369
+ const watchCommand = defineCommand({
1370
+ meta: {
1371
+ name: 'watch',
1372
+ description: 'Start continuous message polling for the active agent (long-running)',
1373
+ },
1374
+ args: {
1375
+ agent: {
1376
+ type: 'string',
1377
+ description: 'Agent ID to watch as (defaults to most recently used)',
1378
+ alias: 'a',
1379
+ },
1380
+ interval: {
1381
+ type: 'string',
1382
+ description: 'Poll interval in milliseconds',
1383
+ default: '5000',
1384
+ },
1385
+ group: {
1386
+ type: 'string',
1387
+ description: 'Comma-separated group conversation IDs to monitor',
1388
+ },
1389
+ },
1390
+ async run({ args }) {
1391
+ try {
1392
+ const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
1393
+ const { createRuntime } = await import('@cleocode/runtime');
1394
+ await getDb();
1395
+ const registry = new AgentRegistryAccessor(process.cwd());
1396
+ const groupIds = args.group ? args.group.split(',').map((s) => s.trim()) : undefined;
1397
+ const handle = await createRuntime(registry, {
1398
+ agentId: args.agent,
1399
+ pollIntervalMs: Number(args.interval) || 5000,
1400
+ groupConversationIds: groupIds,
1401
+ });
1402
+ handle.poller.onMessage((msg) => {
1403
+ cliOutput({
1404
+ success: true,
1405
+ data: {
1406
+ event: 'message',
1407
+ id: msg.id,
1408
+ from: msg.from,
1409
+ content: msg.content,
1410
+ threadId: msg.threadId,
1411
+ timestamp: msg.timestamp,
1412
+ },
1413
+ }, { command: 'agent watch' });
1414
+ });
1415
+ handle.poller.start();
1416
+ cliOutput({
1417
+ success: true,
1418
+ data: {
1419
+ event: 'started',
1420
+ agentId: handle.agentId,
1421
+ pollIntervalMs: Number(args.interval) || 5000,
1422
+ groupConversationIds: groupIds ?? [],
1423
+ message: 'Watching for messages. Press Ctrl+C to stop.',
1424
+ },
1425
+ }, { command: 'agent watch' });
1426
+ // Keep alive until SIGINT/SIGTERM
1427
+ const shutdown = () => {
1428
+ handle.stop();
1429
+ cliOutput({ success: true, data: { event: 'stopped', agentId: handle.agentId } }, { command: 'agent watch' });
1430
+ process.exit(0);
1431
+ };
1432
+ process.on('SIGINT', shutdown);
1433
+ process.on('SIGTERM', shutdown);
1434
+ if (process.platform === 'win32') {
1435
+ process.on('message', (msg) => {
1436
+ if (msg === 'shutdown')
1437
+ shutdown();
1438
+ });
1439
+ }
1440
+ }
1441
+ catch (err) {
1442
+ cliOutput({ success: false, error: { code: 'E_WATCH', message: String(err) } }, { command: 'agent watch' });
1443
+ process.exitCode = 1;
1444
+ }
1445
+ },
1446
+ });
1447
+ /** cleo agent poll — one-shot message check for the active agent */
1448
+ const pollCommand = defineCommand({
1449
+ meta: {
1450
+ name: 'poll',
1451
+ description: 'One-shot message check for the active agent',
1452
+ },
1453
+ args: {
1454
+ agent: {
1455
+ type: 'string',
1456
+ description: 'Agent ID to poll as (defaults to most recently used)',
1457
+ alias: 'a',
1458
+ },
1459
+ limit: {
1460
+ type: 'string',
1461
+ description: 'Max messages to fetch',
1462
+ default: '20',
1463
+ },
1464
+ },
1465
+ async run({ args }) {
1466
+ try {
1467
+ const { AgentRegistryAccessor, createConduit, getDb } = await import('@cleocode/core/internal');
1468
+ await getDb();
1469
+ const registry = new AgentRegistryAccessor(process.cwd());
1470
+ const agentId = args.agent;
1471
+ const conduit = await createConduit(registry, agentId);
1472
+ const limit = Number(args.limit) || 20;
1473
+ const messages = await conduit.poll({ limit });
1474
+ cliOutput({
1475
+ success: true,
1476
+ data: { agentId: conduit.agentId, messages, count: messages.length, limit },
1477
+ }, { command: 'agent poll' });
1478
+ await conduit.disconnect();
1479
+ }
1480
+ catch (err) {
1481
+ cliOutput({ success: false, error: { code: 'E_POLL', message: String(err) } }, { command: 'agent poll' });
1482
+ process.exitCode = 1;
1483
+ }
1484
+ },
1485
+ });
1486
+ /** cleo agent send <message> — send a message to an agent or conversation */
1487
+ const sendCommand = defineCommand({
1488
+ meta: {
1489
+ name: 'send',
1490
+ description: 'Send a message to an agent or conversation',
1491
+ },
1492
+ args: {
1493
+ message: {
1494
+ type: 'positional',
1495
+ description: 'Message content to send',
1496
+ required: true,
1497
+ },
1498
+ to: {
1499
+ type: 'string',
1500
+ description: 'Target agent ID',
1501
+ },
1502
+ conv: {
1503
+ type: 'string',
1504
+ description: 'Target conversation ID',
1505
+ },
1506
+ agent: {
1507
+ type: 'string',
1508
+ description: 'Send as this agent (defaults to most recently used)',
1509
+ alias: 'a',
1510
+ },
1511
+ },
1512
+ async run({ args }) {
1513
+ try {
1514
+ const { AgentRegistryAccessor, createConduit, getDb } = await import('@cleocode/core/internal');
1515
+ await getDb();
1516
+ const registry = new AgentRegistryAccessor(process.cwd());
1517
+ const agentId = args.agent;
1518
+ const to = args.to;
1519
+ const conv = args.conv;
1520
+ if (!to && !conv) {
1521
+ cliOutput({ success: false, error: { code: 'E_ARGS', message: 'Must specify --to or --conv' } }, { command: 'agent send' });
1522
+ process.exitCode = 1;
1523
+ return;
1524
+ }
1525
+ const conduit = await createConduit(registry, agentId);
1526
+ const result = await conduit.send(to ?? conv ?? '', args.message, {
1527
+ threadId: conv,
1528
+ });
1529
+ cliOutput({ success: true, data: { messageId: result.messageId, deliveredAt: result.deliveredAt } }, { command: 'agent send' });
1530
+ await conduit.disconnect();
1531
+ }
1532
+ catch (err) {
1533
+ cliOutput({ success: false, error: { code: 'E_SEND', message: String(err) } }, { command: 'agent send' });
1534
+ process.exitCode = 1;
1535
+ }
1536
+ },
1537
+ });
1538
+ /** cleo agent health — check agent health and detect stale or crashed agents */
1539
+ const healthCommand = defineCommand({
1540
+ meta: {
1541
+ name: 'health',
1542
+ description: 'Check agent health and detect stale or crashed agents',
1543
+ },
1544
+ args: {
1545
+ id: {
1546
+ type: 'string',
1547
+ description: 'Check health for a specific agent ID',
1548
+ },
1549
+ threshold: {
1550
+ type: 'string',
1551
+ description: 'Staleness threshold in milliseconds (default: 180000 = 3 minutes)',
1552
+ default: String(STALE_THRESHOLD_MS),
1553
+ },
1554
+ 'detect-crashed': {
1555
+ type: 'boolean',
1556
+ description: 'Detect and mark crashed agents (write operation)',
1557
+ },
1558
+ },
1559
+ async run({ args }) {
1560
+ const thresholdMs = Number(args.threshold);
1561
+ const agentId = args.id;
1562
+ const detectCrashed = args['detect-crashed'] === true;
1563
+ if (agentId) {
1564
+ const health = await checkAgentHealth(agentId, thresholdMs);
1565
+ if (!health) {
1566
+ cliOutput({
1567
+ success: false,
1568
+ error: { code: 'E_NOT_FOUND', message: `Agent not found: ${agentId}` },
1569
+ }, { command: 'agent health' });
1570
+ process.exitCode = 4;
1571
+ return;
1572
+ }
1573
+ cliOutput({ success: true, data: health }, { command: 'agent health' });
1574
+ return;
1575
+ }
1576
+ if (detectCrashed) {
1577
+ const crashed = await detectCrashedAgents(thresholdMs);
1578
+ cliOutput({
1579
+ success: true,
1580
+ data: {
1581
+ detectedCrashed: crashed.length,
1582
+ agents: crashed.map((a) => ({
1583
+ id: a.id,
1584
+ agentType: a.agentType,
1585
+ lastHeartbeat: a.lastHeartbeat,
1586
+ status: a.status,
1587
+ })),
1588
+ },
1589
+ }, { command: 'agent health' });
1590
+ return;
1591
+ }
1592
+ const [report, stale] = await Promise.all([
1593
+ getHealthReport(thresholdMs),
1594
+ detectStaleAgents(thresholdMs),
1595
+ ]);
1596
+ cliOutput({
1597
+ success: true,
1598
+ data: {
1599
+ summary: {
1600
+ total: report.total,
1601
+ active: report.active,
1602
+ idle: report.idle,
1603
+ starting: report.starting,
1604
+ error: report.error,
1605
+ crashed: report.crashed,
1606
+ stopped: report.stopped,
1607
+ totalErrors: report.totalErrors,
1608
+ },
1609
+ staleAgents: stale.map((s) => ({
1610
+ id: s.agentId,
1611
+ status: s.status,
1612
+ heartbeatAgeMs: s.heartbeatAgeMs,
1613
+ lastHeartbeat: s.lastHeartbeat,
1614
+ thresholdMs: s.thresholdMs,
1615
+ })),
1616
+ thresholdMs,
1617
+ },
1618
+ }, { command: 'agent health' });
1619
+ },
1620
+ });
1621
+ /**
1622
+ * cleo agent install <path> — install an agent from a `.cant` manifest or
1623
+ * `.cantz` archive (ZIP) using the T889 / W2-3 {@link installAgentFromCant}
1624
+ * pipeline.
1625
+ *
1626
+ * - `.cant` file: fed directly to the pipeline; copied to the tier directory
1627
+ * and the `agents` row + `agent_skills` junctions are written atomically.
1628
+ * - `.cantz` archive: extracted to a temp dir, `persona.cant` is located and
1629
+ * renamed to `<agentId>.cant` before being passed to the pipeline.
1630
+ * - Agent-directory (legacy): same path as `.cantz` — looks for
1631
+ * `persona.cant` inside and feeds a renamed copy to the pipeline.
1632
+ *
1633
+ * Flags:
1634
+ * - `--global`: install to global tier ({@link getCleoGlobalAgentsDir}).
1635
+ * - `--strict`: fail with `E_VALIDATION` when the pipeline reports warnings
1636
+ * (e.g. unknown skill slugs).
1637
+ * - `--attach`: after install, also attach the agent to the current project
1638
+ * via {@link attachAgentToProject} (conduit.db:project_agent_refs).
1639
+ * - `--force`: overwrite an existing row / file instead of throwing
1640
+ * `E_AGENT_ALREADY_INSTALLED`.
1641
+ * - `--resync`: drop the existing `agents` row (keep the `.cant` on disk)
1642
+ * then re-install; combines `force: true` with a pre-flight row delete.
1643
+ *
1644
+ * On success, emits a LAFS envelope of shape `{ agentId, tier, cantPath,
1645
+ * cantSha256, inserted, skillsAttached, warnings, attached }`.
1646
+ *
1647
+ * @task T889 / W2-6
1648
+ * @epic T889
1649
+ * @see docs/specs/CANTZ-PACKAGE-STANDARD.md
1650
+ */
1651
+ const installCommand = defineCommand({
1652
+ meta: {
1653
+ name: 'install',
1654
+ description: 'Install an agent from a .cant file or .cantz archive',
1655
+ },
1656
+ args: {
1657
+ path: {
1658
+ type: 'positional',
1659
+ description: 'Path to the .cant file, .cantz archive, or agent directory',
1660
+ required: true,
1661
+ },
1662
+ global: {
1663
+ type: 'boolean',
1664
+ description: 'Install to global tier (~/.local/share/cleo/cant/agents/)',
1665
+ },
1666
+ strict: {
1667
+ type: 'boolean',
1668
+ description: 'Fail on warnings (e.g. unknown skill slugs)',
1669
+ },
1670
+ attach: {
1671
+ type: 'boolean',
1672
+ description: 'Attach to the current project after install',
1673
+ },
1674
+ force: {
1675
+ type: 'boolean',
1676
+ description: 'Overwrite existing agent row / file',
1677
+ },
1678
+ resync: {
1679
+ type: 'boolean',
1680
+ description: 'Drop + reinstall the agents row, keeping the on-disk .cant',
1681
+ },
1682
+ },
1683
+ async run({ args }) {
1684
+ let tempDir = null;
1685
+ try {
1686
+ const { existsSync, mkdirSync, statSync, readdirSync, copyFileSync } = await import('node:fs');
1687
+ const { join, basename, resolve, extname } = await import('node:path');
1688
+ const { tmpdir } = await import('node:os');
1689
+ const resolvedPath = resolve(args.path);
1690
+ if (!existsSync(resolvedPath)) {
1691
+ cliOutput({
1692
+ success: false,
1693
+ error: {
1694
+ code: 'E_NOT_FOUND',
1695
+ message: `Path does not exist: ${resolvedPath}`,
1696
+ },
1697
+ }, { command: 'agent install' });
1698
+ process.exitCode = 4;
1699
+ return;
1700
+ }
1701
+ // Resolve the eventual `.cant` path that will be handed to the install
1702
+ // pipeline. Three input shapes are accepted:
1703
+ // 1. <id>.cant — used as-is.
1704
+ // 2. <pkg>.cantz — extracted; persona.cant inside is renamed
1705
+ // to `<agentId>.cant` in the temp tree.
1706
+ // 3. <dir>/persona.cant — same flow as .cantz; rename into tmp.
1707
+ let cantPath;
1708
+ const stat = statSync(resolvedPath);
1709
+ const ext = extname(resolvedPath);
1710
+ if (stat.isFile() && ext === '.cant') {
1711
+ cantPath = resolvedPath;
1712
+ }
1713
+ else if (stat.isFile() && ext === '.cantz') {
1714
+ const { execFileSync } = await import('node:child_process');
1715
+ tempDir = join(tmpdir(), `cleo-agent-install-${Date.now()}`);
1716
+ mkdirSync(tempDir, { recursive: true });
1717
+ try {
1718
+ execFileSync('unzip', ['-o', '-q', resolvedPath, '-d', tempDir], {
1719
+ encoding: 'utf-8',
1720
+ timeout: 30_000,
1721
+ });
1722
+ }
1723
+ catch (unzipErr) {
1724
+ cliOutput({
1725
+ success: false,
1726
+ error: {
1727
+ code: 'E_VALIDATION',
1728
+ message: `Failed to extract .cantz archive: ${String(unzipErr)}`,
1729
+ },
1730
+ }, { command: 'agent install' });
1731
+ process.exitCode = 6;
1732
+ return;
1733
+ }
1734
+ const topLevel = readdirSync(tempDir).filter((entry) => statSync(join(tempDir, entry)).isDirectory());
1735
+ if (topLevel.length !== 1) {
1736
+ cliOutput({
1737
+ success: false,
1738
+ error: {
1739
+ code: 'E_VALIDATION',
1740
+ message: `Archive must contain exactly one top-level directory, found ${topLevel.length}`,
1741
+ },
1742
+ }, { command: 'agent install' });
1743
+ process.exitCode = 6;
1744
+ return;
1745
+ }
1746
+ const agentName = topLevel[0];
1747
+ const personaPath = join(tempDir, agentName, 'persona.cant');
1748
+ if (!existsSync(personaPath)) {
1749
+ cliOutput({
1750
+ success: false,
1751
+ error: {
1752
+ code: 'E_VALIDATION',
1753
+ message: `Archive must contain persona.cant: ${personaPath}`,
1754
+ },
1755
+ }, { command: 'agent install' });
1756
+ process.exitCode = 6;
1757
+ return;
1758
+ }
1759
+ // The pipeline requires filename base === agent name; materialize a
1760
+ // renamed copy into the temp dir so the check passes.
1761
+ cantPath = join(tempDir, `${agentName}.cant`);
1762
+ copyFileSync(personaPath, cantPath);
1763
+ }
1764
+ else if (stat.isDirectory()) {
1765
+ const agentName = basename(resolvedPath);
1766
+ const personaPath = join(resolvedPath, 'persona.cant');
1767
+ if (!existsSync(personaPath)) {
1768
+ cliOutput({
1769
+ success: false,
1770
+ error: {
1771
+ code: 'E_VALIDATION',
1772
+ message: `Agent directory must contain persona.cant: ${personaPath}`,
1773
+ },
1774
+ }, { command: 'agent install' });
1775
+ process.exitCode = 6;
1776
+ return;
1777
+ }
1778
+ tempDir = join(tmpdir(), `cleo-agent-install-${Date.now()}`);
1779
+ mkdirSync(tempDir, { recursive: true });
1780
+ cantPath = join(tempDir, `${agentName}.cant`);
1781
+ copyFileSync(personaPath, cantPath);
1782
+ }
1783
+ else {
1784
+ cliOutput({
1785
+ success: false,
1786
+ error: {
1787
+ code: 'E_VALIDATION',
1788
+ message: `Path must be a .cant, .cantz, or agent directory: ${resolvedPath}`,
1789
+ },
1790
+ }, { command: 'agent install' });
1791
+ process.exitCode = 6;
1792
+ return;
1793
+ }
1794
+ // Lazy-import the core facade so test mocks can intercept these symbols.
1795
+ const { ensureGlobalSignaldockDb, getGlobalSignaldockDbPath, installAgentFromCant, attachAgentToProject, } = await import('@cleocode/core/internal');
1796
+ const { DatabaseSync } = (await import('node:sqlite'));
1797
+ ensureGlobalSignaldockDb();
1798
+ const dbPath = getGlobalSignaldockDbPath();
1799
+ const db = new DatabaseSync(dbPath);
1800
+ db.exec('PRAGMA foreign_keys = ON');
1801
+ db.exec('PRAGMA journal_mode = WAL');
1802
+ const isGlobal = args.global === true;
1803
+ const targetTier = isGlobal ? 'global' : 'project';
1804
+ const projectRoot = process.cwd();
1805
+ try {
1806
+ // `--resync`: drop+reinstall the registry row but preserve the
1807
+ // on-disk `.cant`. Implementation: delete the existing row BEFORE
1808
+ // calling the pipeline, then let the pipeline handle it as a fresh
1809
+ // insert. The file copy over itself is still atomic.
1810
+ if (args.resync) {
1811
+ const parsedName = basename(cantPath, '.cant');
1812
+ const row = db.prepare('SELECT id FROM agents WHERE agent_id = ?').get(parsedName);
1813
+ if (row) {
1814
+ db.exec('BEGIN IMMEDIATE TRANSACTION');
1815
+ try {
1816
+ db.prepare('DELETE FROM agent_skills WHERE agent_id = ?').run(row.id);
1817
+ db.prepare('DELETE FROM agents WHERE id = ?').run(row.id);
1818
+ db.exec('COMMIT');
1819
+ }
1820
+ catch (resyncErr) {
1821
+ db.exec('ROLLBACK');
1822
+ throw resyncErr;
1823
+ }
1824
+ }
1825
+ }
1826
+ const result = installAgentFromCant(db, {
1827
+ cantSource: cantPath,
1828
+ targetTier,
1829
+ installedFrom: 'user',
1830
+ projectRoot: targetTier === 'project' ? projectRoot : undefined,
1831
+ force: args.force === true || args.resync === true,
1832
+ });
1833
+ if (args.strict && result.warnings.length > 0) {
1834
+ cliOutput({
1835
+ success: false,
1836
+ error: {
1837
+ code: 'E_VALIDATION',
1838
+ message: `Install produced warnings in --strict mode: ${result.warnings.join('; ')}`,
1839
+ },
1840
+ data: {
1841
+ agentId: result.agentId,
1842
+ tier: result.tier,
1843
+ warnings: result.warnings,
1844
+ },
1845
+ }, { command: 'agent install' });
1846
+ process.exitCode = 6;
1847
+ return;
1848
+ }
1849
+ let attached = false;
1850
+ if (args.attach && targetTier === 'global') {
1851
+ attachAgentToProject(projectRoot, result.agentId);
1852
+ attached = true;
1853
+ }
1854
+ cliOutput({
1855
+ success: true,
1856
+ data: {
1857
+ agentId: result.agentId,
1858
+ tier: result.tier,
1859
+ cantPath: result.cantPath,
1860
+ cantSha256: result.cantSha256,
1861
+ inserted: result.inserted,
1862
+ skillsAttached: result.skillsAttached,
1863
+ warnings: result.warnings,
1864
+ attached,
1865
+ },
1866
+ }, { command: 'agent install' });
1867
+ }
1868
+ finally {
1869
+ db.close();
1870
+ }
1871
+ }
1872
+ catch (err) {
1873
+ const message = err instanceof Error ? err.message : String(err);
1874
+ const code = /E_AGENT_ALREADY_INSTALLED/.test(message)
1875
+ ? 'E_AGENT_ALREADY_INSTALLED'
1876
+ : 'E_INSTALL';
1877
+ cliOutput({ success: false, error: { code, message } }, { command: 'agent install' });
1878
+ process.exitCode = 1;
1879
+ }
1880
+ finally {
1881
+ if (tempDir) {
1882
+ try {
1883
+ const { rmSync } = await import('node:fs');
1884
+ rmSync(tempDir, { recursive: true, force: true });
1885
+ }
1886
+ catch {
1887
+ // best-effort cleanup — don't mask the primary error
1888
+ }
1889
+ }
1890
+ }
1891
+ },
1892
+ });
1893
+ /**
1894
+ * cleo agent pack <dir> — package an agent directory into a .cantz ZIP archive.
1895
+ *
1896
+ * Validates that the source directory contains `persona.cant`, then creates a
1897
+ * ZIP archive named `<dirname>.cantz` in the current working directory.
1898
+ *
1899
+ * @task T438 @epic T250
1900
+ * @see docs/specs/CANTZ-PACKAGE-STANDARD.md
1901
+ */
1902
+ const packCommand = defineCommand({
1903
+ meta: {
1904
+ name: 'pack',
1905
+ description: 'Package an agent directory as a .cantz archive',
1906
+ },
1907
+ args: {
1908
+ dir: {
1909
+ type: 'positional',
1910
+ description: 'Agent directory to package',
1911
+ required: true,
1912
+ },
1913
+ },
1914
+ async run({ args }) {
1915
+ try {
1916
+ const { existsSync, statSync } = await import('node:fs');
1917
+ const { resolve, basename, dirname } = await import('node:path');
1918
+ const { execFileSync } = await import('node:child_process');
1919
+ const resolvedDir = resolve(args.dir);
1920
+ if (!existsSync(resolvedDir) || !statSync(resolvedDir).isDirectory()) {
1921
+ cliOutput({
1922
+ success: false,
1923
+ error: {
1924
+ code: 'E_NOT_FOUND',
1925
+ message: `Directory does not exist: ${resolvedDir}`,
1926
+ },
1927
+ }, { command: 'agent pack' });
1928
+ process.exitCode = 4;
1929
+ return;
1930
+ }
1931
+ // Validate persona.cant exists
1932
+ const { join } = await import('node:path');
1933
+ const personaPath = join(resolvedDir, 'persona.cant');
1934
+ if (!existsSync(personaPath)) {
1935
+ cliOutput({
1936
+ success: false,
1937
+ error: {
1938
+ code: 'E_VALIDATION',
1939
+ message: `Agent directory must contain persona.cant: ${personaPath}`,
1940
+ },
1941
+ }, { command: 'agent pack' });
1942
+ process.exitCode = 6;
1943
+ return;
1944
+ }
1945
+ const agentName = basename(resolvedDir);
1946
+ const archiveName = `${agentName}.cantz`;
1947
+ const archivePath = resolve(archiveName);
1948
+ const parentDir = dirname(resolvedDir);
1949
+ // Create ZIP archive — run zip from parent directory so the
1950
+ // archive contains agentName/ as the top-level directory
1951
+ try {
1952
+ execFileSync('zip', ['-r', archivePath, agentName], {
1953
+ cwd: parentDir,
1954
+ encoding: 'utf-8',
1955
+ timeout: 30000,
1956
+ });
1957
+ }
1958
+ catch (zipErr) {
1959
+ cliOutput({
1960
+ success: false,
1961
+ error: {
1962
+ code: 'E_PACK',
1963
+ message: `Failed to create archive: ${String(zipErr)}`,
1964
+ },
1965
+ }, { command: 'agent pack' });
1966
+ process.exitCode = 1;
1967
+ return;
1968
+ }
1969
+ // Get file count and archive size
1970
+ const archiveStats = statSync(archivePath);
1971
+ const { readdirSync } = await import('node:fs');
1972
+ let fileCount = 0;
1973
+ const countFiles = (dirPath) => {
1974
+ const entries = readdirSync(dirPath, { withFileTypes: true });
1975
+ for (const entry of entries) {
1976
+ if (entry.isFile()) {
1977
+ fileCount++;
1978
+ }
1979
+ else if (entry.isDirectory()) {
1980
+ countFiles(join(dirPath, entry.name));
1981
+ }
1982
+ }
1983
+ };
1984
+ countFiles(resolvedDir);
1985
+ cliOutput({
1986
+ success: true,
1987
+ data: {
1988
+ archive: archivePath,
1989
+ agent: agentName,
1990
+ files: fileCount,
1991
+ size: archiveStats.size,
1992
+ },
1993
+ }, { command: 'agent pack' });
1994
+ }
1995
+ catch (err) {
1996
+ cliOutput({ success: false, error: { code: 'E_PACK', message: String(err) } }, { command: 'agent pack' });
1997
+ process.exitCode = 1;
1998
+ }
1999
+ },
2000
+ });
2001
+ /**
2002
+ * cleo agent create — scaffold a complete agent package.
2003
+ *
2004
+ * Creates a directory structure conforming to the CANTZ package standard
2005
+ * (docs/specs/CANTZ-PACKAGE-STANDARD.md) with role-based persona templates
2006
+ * derived from the starter-bundle canonical agents.
2007
+ *
2008
+ * Template roles:
2009
+ * - **orchestrator**: read-only tools, high tier, dispatch-focused
2010
+ * - **lead**: read-only tools, mid tier, task decomposition
2011
+ * - **worker**: full tool access, mid tier, code execution
2012
+ * - **docs-worker**: documentation-focused worker variant
2013
+ *
2014
+ * @task T439 @epic T250
2015
+ * @see docs/specs/CANTZ-PACKAGE-STANDARD.md
2016
+ * @see packages/cleo-os/starter-bundle/agents/ — canonical format reference
2017
+ */
2018
+ const createCommand = defineCommand({
2019
+ meta: {
2020
+ name: 'create',
2021
+ description: 'Scaffold a new agent package with persona.cant and manifest.json',
2022
+ },
2023
+ args: {
2024
+ name: {
2025
+ type: 'string',
2026
+ description: 'Agent name (kebab-case)',
2027
+ required: true,
2028
+ },
2029
+ role: {
2030
+ type: 'string',
2031
+ description: 'Agent role: orchestrator, lead, worker, or docs-worker',
2032
+ required: true,
2033
+ },
2034
+ tier: {
2035
+ type: 'string',
2036
+ description: 'Agent tier: low, mid, or high (defaults based on role)',
2037
+ },
2038
+ team: {
2039
+ type: 'string',
2040
+ description: 'Team this agent belongs to',
2041
+ },
2042
+ domain: {
2043
+ type: 'string',
2044
+ description: 'Domain description for file permissions and context',
2045
+ },
2046
+ global: {
2047
+ type: 'boolean',
2048
+ description: 'Create in global tier (~/.local/share/cleo/cant/agents/)',
2049
+ },
2050
+ 'seed-brain': {
2051
+ type: 'boolean',
2052
+ description: 'Create expertise/mental-model-seed.md and seed a BRAIN observation',
2053
+ },
2054
+ parent: {
2055
+ type: 'string',
2056
+ description: 'Parent agent name in the hierarchy',
2057
+ },
2058
+ },
2059
+ async run({ args }) {
2060
+ try {
2061
+ const { existsSync, mkdirSync, writeFileSync } = await import('node:fs');
2062
+ const { join } = await import('node:path');
2063
+ const { homedir } = await import('node:os');
2064
+ const name = args.name;
2065
+ const role = args.role;
2066
+ const tier = args.tier ?? inferTierFromRole(role);
2067
+ const team = args.team;
2068
+ const domain = args.domain;
2069
+ const isGlobal = args.global === true;
2070
+ const seedBrain = args['seed-brain'] === true;
2071
+ const parent = args.parent;
2072
+ // Validate role
2073
+ const validRoles = ['orchestrator', 'lead', 'worker', 'docs-worker'];
2074
+ if (!validRoles.includes(role)) {
2075
+ cliOutput({
2076
+ success: false,
2077
+ error: {
2078
+ code: 'E_VALIDATION',
2079
+ message: `Invalid role "${role}". Must be one of: ${validRoles.join(', ')}`,
2080
+ fix: `cleo agent create --name ${name} --role worker`,
2081
+ },
2082
+ }, { command: 'agent create' });
2083
+ process.exitCode = 6;
2084
+ return;
2085
+ }
2086
+ // Validate tier
2087
+ const validTiers = ['low', 'mid', 'high'];
2088
+ if (!validTiers.includes(tier)) {
2089
+ cliOutput({
2090
+ success: false,
2091
+ error: {
2092
+ code: 'E_VALIDATION',
2093
+ message: `Invalid tier "${tier}". Must be one of: ${validTiers.join(', ')}`,
2094
+ fix: `cleo agent create --name ${name} --role ${role} --tier mid`,
2095
+ },
2096
+ }, { command: 'agent create' });
2097
+ process.exitCode = 6;
2098
+ return;
2099
+ }
2100
+ // Validate name is kebab-case
2101
+ if (!/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(name)) {
2102
+ cliOutput({
2103
+ success: false,
2104
+ error: {
2105
+ code: 'E_VALIDATION',
2106
+ message: `Agent name must be kebab-case: "${name}"`,
2107
+ fix: 'Use lowercase letters, numbers, and hyphens. Must start with a letter.',
2108
+ },
2109
+ }, { command: 'agent create' });
2110
+ process.exitCode = 6;
2111
+ return;
2112
+ }
2113
+ // Determine target directory
2114
+ let targetRoot;
2115
+ if (isGlobal) {
2116
+ const home = homedir();
2117
+ const xdgData = process.env['XDG_DATA_HOME'] ?? join(home, '.local', 'share');
2118
+ targetRoot = join(xdgData, 'cleo', 'cant', 'agents');
2119
+ }
2120
+ else {
2121
+ targetRoot = join(process.cwd(), CLEO_DIR_NAME, CANT_AGENTS_SUBDIR);
2122
+ }
2123
+ const agentDir = join(targetRoot, name);
2124
+ // Check if agent directory already exists
2125
+ if (existsSync(agentDir)) {
2126
+ cliOutput({
2127
+ success: false,
2128
+ error: {
2129
+ code: 'E_VALIDATION',
2130
+ message: `Agent directory already exists: ${agentDir}`,
2131
+ fix: 'Remove the existing directory or choose a different name.',
2132
+ },
2133
+ }, { command: 'agent create' });
2134
+ process.exitCode = 6;
2135
+ return;
2136
+ }
2137
+ // Create directory structure
2138
+ mkdirSync(agentDir, { recursive: true });
2139
+ // Generate persona.cant from role template
2140
+ const personaContent = generatePersonaCant({
2141
+ name,
2142
+ role,
2143
+ tier,
2144
+ team,
2145
+ domain,
2146
+ parent,
2147
+ });
2148
+ writeFileSync(join(agentDir, 'persona.cant'), personaContent, 'utf-8');
2149
+ // Generate manifest.json
2150
+ const manifest = generateManifest({ name, role, tier, domain });
2151
+ writeFileSync(join(agentDir, 'manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`, 'utf-8');
2152
+ // Track created files for summary
2153
+ const createdFiles = [
2154
+ join(agentDir, 'persona.cant'),
2155
+ join(agentDir, 'manifest.json'),
2156
+ ];
2157
+ // Generate team config if team specified
2158
+ if (team) {
2159
+ const teamConfigContent = generateTeamConfig(name, role, team);
2160
+ writeFileSync(join(agentDir, 'team-config.cant'), teamConfigContent, 'utf-8');
2161
+ createdFiles.push(join(agentDir, 'team-config.cant'));
2162
+ }
2163
+ // Seed brain expertise if requested
2164
+ if (seedBrain) {
2165
+ const expertiseDir = join(agentDir, 'expertise');
2166
+ mkdirSync(expertiseDir, { recursive: true });
2167
+ const seedContent = generateMentalModelSeed(name, role, domain);
2168
+ writeFileSync(join(expertiseDir, 'mental-model-seed.md'), seedContent, 'utf-8');
2169
+ createdFiles.push(join(expertiseDir, 'mental-model-seed.md'));
2170
+ // Best-effort BRAIN observation via CLI
2171
+ try {
2172
+ const { execFile } = await import('node:child_process');
2173
+ const { promisify } = await import('node:util');
2174
+ const execFileAsync = promisify(execFile);
2175
+ await execFileAsync('cleo', [
2176
+ 'observe',
2177
+ `Agent ${name} created with role ${role}`,
2178
+ '--title',
2179
+ `Agent creation: ${name}`,
2180
+ ], { encoding: 'utf-8', timeout: 10000 }).catch(() => {
2181
+ // Best-effort — do not fail create if observe fails
2182
+ });
2183
+ }
2184
+ catch {
2185
+ // Best-effort — do not fail create if observe fails
2186
+ }
2187
+ }
2188
+ // Best-effort agent registration in signaldock.db
2189
+ let registered = false;
2190
+ try {
2191
+ const { AgentRegistryAccessor, getDb } = await import('@cleocode/core/internal');
2192
+ await getDb();
2193
+ const registry = new AgentRegistryAccessor(process.cwd());
2194
+ const existing = await registry.get(name);
2195
+ if (!existing) {
2196
+ const descMatch = personaContent.match(/description:\s*"([^"]+)"/);
2197
+ const displayName = descMatch?.[1] ?? name;
2198
+ await registry.register({
2199
+ agentId: name,
2200
+ displayName,
2201
+ apiKey: 'local-created',
2202
+ apiBaseUrl: 'local',
2203
+ classification: role,
2204
+ privacyTier: 'private',
2205
+ capabilities: [],
2206
+ skills: [],
2207
+ transportType: 'http',
2208
+ transportConfig: {},
2209
+ isActive: false,
2210
+ });
2211
+ registered = true;
2212
+ }
2213
+ }
2214
+ catch {
2215
+ // Registration is best-effort — do not fail the create
2216
+ }
2217
+ cliOutput({
2218
+ success: true,
2219
+ data: {
2220
+ agent: name,
2221
+ role,
2222
+ tier,
2223
+ directory: agentDir,
2224
+ scope: isGlobal ? 'global' : 'project',
2225
+ files: createdFiles,
2226
+ registered,
2227
+ brainSeeded: seedBrain,
2228
+ },
2229
+ }, { command: 'agent create' });
2230
+ }
2231
+ catch (err) {
2232
+ cliOutput({ success: false, error: { code: 'E_CREATE', message: String(err) } }, { command: 'agent create' });
2233
+ process.exitCode = 1;
2234
+ }
2235
+ },
2236
+ });
2237
+ /**
2238
+ * cleo agent doctor — reconcile `.cant` files on disk vs the registry DB.
2239
+ *
2240
+ * Walks the tier filesystems (global + the current project, if any) against
2241
+ * `signaldock.db:agents` and emits typed D-code findings. With `--repair`
2242
+ * the doctor applies safe, idempotent remediations (delete orphan rows,
2243
+ * refresh drifting SHA-256 digests). Exits non-zero when any
2244
+ * error-severity finding is present so CI can gate on a clean report.
2245
+ *
2246
+ * @task T889 / T901 / W2-7
2247
+ * @epic T889
2248
+ */
2249
+ /**
2250
+ * cleo agent mint — invoke agent-architect meta-agent to synthesize a project-specific
2251
+ * agent from a .cant spec file and project context.
2252
+ *
2253
+ * Semantic distinction from `cleo agent create`:
2254
+ * - `create` — static scaffold from role templates (no AI synthesis)
2255
+ * - `mint` — meta-agent-driven synthesis from a spec file + project context (AC8)
2256
+ *
2257
+ * @task T1276 v2026.4.127 T1259 E2 cleo agent mint CLI verb
2258
+ */
2259
+ const mintCommand = defineCommand({
2260
+ meta: {
2261
+ name: 'mint',
2262
+ description: 'Synthesize a project-specific agent from a .cant spec using agent-architect meta-agent',
2263
+ },
2264
+ args: {
2265
+ spec: {
2266
+ type: 'positional',
2267
+ description: 'Path to the .cant spec file describing the agent to synthesize',
2268
+ required: true,
2269
+ },
2270
+ 'output-dir': {
2271
+ type: 'string',
2272
+ description: 'Directory to write synthesized .cant files (defaults to .cleo/cant/agents/)',
2273
+ },
2274
+ 'dry-run': {
2275
+ type: 'boolean',
2276
+ description: 'Preview invocation tokens without invoking agent-architect',
2277
+ default: false,
2278
+ },
2279
+ json: {
2280
+ type: 'boolean',
2281
+ description: 'Emit result as LAFS JSON envelope',
2282
+ default: false,
2283
+ },
2284
+ },
2285
+ async run({ args }) {
2286
+ try {
2287
+ const { existsSync, readFileSync, mkdirSync } = await import('node:fs');
2288
+ const { resolve, join } = await import('node:path');
2289
+ const specPath = resolve(args.spec);
2290
+ if (!existsSync(specPath)) {
2291
+ const errEnv = {
2292
+ success: false,
2293
+ error: { code: 'E_NOT_FOUND', message: `spec file not found: ${specPath}` },
2294
+ meta: { operation: 'agent.mint', timestamp: new Date().toISOString() },
2295
+ };
2296
+ if (args.json) {
2297
+ process.stdout.write(JSON.stringify(errEnv, null, 2) + '\n');
2298
+ }
2299
+ else {
2300
+ process.stderr.write(`error: spec file not found: ${specPath}\n`);
2301
+ }
2302
+ process.exitCode = 4;
2303
+ return;
2304
+ }
2305
+ const specContent = readFileSync(specPath, 'utf-8');
2306
+ const projectRoot = process.cwd();
2307
+ const outputDir = args['output-dir']
2308
+ ? resolve(args['output-dir'])
2309
+ : join(projectRoot, '.cleo', 'cant', 'agents');
2310
+ mkdirSync(outputDir, { recursive: true });
2311
+ if (args['dry-run']) {
2312
+ const preview = {
2313
+ success: true,
2314
+ data: {
2315
+ dryRun: true,
2316
+ agentName: 'agent-architect',
2317
+ specPath,
2318
+ outputDir,
2319
+ projectRoot,
2320
+ message: 'Dry-run: would invoke agent-architect with the above tokens',
2321
+ },
2322
+ meta: { operation: 'agent.mint', timestamp: new Date().toISOString() },
2323
+ };
2324
+ process.stdout.write(JSON.stringify(preview, null, 2) + '\n');
2325
+ return;
2326
+ }
2327
+ const { invokeMetaAgent } = await import('@cleocode/core/agents/invoke-meta-agent');
2328
+ const result = await invokeMetaAgent({
2329
+ agentName: 'agent-architect',
2330
+ projectRoot,
2331
+ tokens: {
2332
+ CANT_AGENTS_DIR: outputDir,
2333
+ // Pass spec content as PROJECT_CONTEXT to let agent-architect read it
2334
+ PROJECT_CONTEXT: specContent,
2335
+ },
2336
+ });
2337
+ if (result.invoked) {
2338
+ const envelope = {
2339
+ success: true,
2340
+ data: {
2341
+ invoked: true,
2342
+ outputs: result.outputs ?? [],
2343
+ outputDir,
2344
+ message: `agent-architect synthesized ${result.outputs?.length ?? 0} agent(s)`,
2345
+ },
2346
+ meta: { operation: 'agent.mint', timestamp: new Date().toISOString() },
2347
+ };
2348
+ if (args.json) {
2349
+ process.stdout.write(JSON.stringify(envelope, null, 2) + '\n');
2350
+ }
2351
+ else {
2352
+ process.stdout.write(`minted ${result.outputs?.length ?? 0} agent(s) to ${outputDir}\n`);
2353
+ for (const out of result.outputs ?? []) {
2354
+ process.stdout.write(` + ${out}\n`);
2355
+ }
2356
+ }
2357
+ }
2358
+ else {
2359
+ const fallbackMsg = `agent-architect unavailable: ${result.reason ?? 'unknown'}. Run 'cleo agent create' for static scaffolding.`;
2360
+ const envelope = {
2361
+ success: false,
2362
+ error: { code: 'E_META_AGENT_UNAVAILABLE', message: fallbackMsg },
2363
+ meta: { operation: 'agent.mint', timestamp: new Date().toISOString() },
2364
+ };
2365
+ if (args.json) {
2366
+ process.stdout.write(JSON.stringify(envelope, null, 2) + '\n');
2367
+ }
2368
+ else {
2369
+ process.stderr.write(`warn: ${fallbackMsg}\n`);
2370
+ }
2371
+ process.exitCode = 1;
2372
+ }
2373
+ }
2374
+ catch (err) {
2375
+ const message = err instanceof Error ? err.message : String(err);
2376
+ process.stderr.write(`error: agent mint failed: ${message}\n`);
2377
+ process.exitCode = 1;
2378
+ }
2379
+ },
2380
+ });
2381
+ const doctorCommand = defineCommand({
2382
+ meta: {
2383
+ name: 'doctor',
2384
+ description: 'Reconcile .cant files on disk against the registry and report drift',
2385
+ },
2386
+ args: {
2387
+ repair: {
2388
+ type: 'boolean',
2389
+ description: 'Apply safe repairs (D-002 orphan-row delete, D-003 hash refresh)',
2390
+ },
2391
+ 'import-legacy-json': {
2392
+ type: 'boolean',
2393
+ description: 'When used with --repair, import a discovered ~/.cleo/agent-registry.json',
2394
+ },
2395
+ 'migrate-path': {
2396
+ type: 'boolean',
2397
+ description: 'When used with --repair, migrate legacy .cleo/agents/ rows to .cleo/cant/agents/',
2398
+ },
2399
+ json: {
2400
+ type: 'boolean',
2401
+ description: 'Emit the raw DoctorReport envelope as JSON instead of a human table',
2402
+ },
2403
+ },
2404
+ async run({ args }) {
2405
+ try {
2406
+ const { buildDoctorReport, reconcileDoctor, ensureGlobalSignaldockDb, getGlobalSignaldockDbPath, } = await import('@cleocode/core/internal');
2407
+ const { createRequire } = await import('node:module');
2408
+ const nodeSqlite = createRequire(import.meta.url)('node:sqlite');
2409
+ const { DatabaseSync } = nodeSqlite;
2410
+ await ensureGlobalSignaldockDb();
2411
+ const dbPath = getGlobalSignaldockDbPath();
2412
+ const db = new DatabaseSync(dbPath);
2413
+ db.exec('PRAGMA foreign_keys = ON');
2414
+ try {
2415
+ const report = await buildDoctorReport(db, { projectRoot: process.cwd() });
2416
+ const repairFlag = args.repair === true;
2417
+ let reconciled;
2418
+ if (repairFlag) {
2419
+ reconciled = await reconcileDoctor(db, report.findings, {
2420
+ importLegacyJson: args['import-legacy-json'] === true,
2421
+ allowPathMigration: args['migrate-path'] === true,
2422
+ });
2423
+ }
2424
+ if (args.json === true) {
2425
+ cliOutput({ success: true, data: { report, reconciled: reconciled ?? null } }, { command: 'agent doctor' });
2426
+ }
2427
+ else {
2428
+ const lines = [];
2429
+ if (report.findings.length === 0) {
2430
+ lines.push('No drift detected — registry and filesystem are in sync.');
2431
+ }
2432
+ else {
2433
+ lines.push(`Findings: ${report.summary.error} error(s), ${report.summary.warn} warning(s), ${report.summary.info} info`);
2434
+ lines.push('');
2435
+ for (const f of report.findings) {
2436
+ lines.push(`[${f.code}] ${f.severity.toUpperCase()} ${f.subject} — ${f.message}`);
2437
+ if (f.fixCommand)
2438
+ lines.push(` fix: ${f.fixCommand}`);
2439
+ }
2440
+ if (reconciled) {
2441
+ lines.push('');
2442
+ lines.push(`Repaired: ${reconciled.repaired.length > 0 ? reconciled.repaired.join(', ') : '(none)'}`);
2443
+ lines.push(`Skipped: ${reconciled.skipped.length > 0 ? reconciled.skipped.join(', ') : '(none)'}`);
2444
+ }
2445
+ }
2446
+ cliOutput({
2447
+ success: true,
2448
+ data: {
2449
+ message: lines.join('\n'),
2450
+ summary: report.summary,
2451
+ generatedAt: report.generatedAt,
2452
+ findings: report.findings.length,
2453
+ repaired: reconciled?.repaired.length ?? 0,
2454
+ skipped: reconciled?.skipped.length ?? 0,
2455
+ },
2456
+ }, { command: 'agent doctor' });
2457
+ }
2458
+ if (report.summary.error > 0) {
2459
+ process.exitCode = 1;
2460
+ }
2461
+ }
2462
+ finally {
2463
+ db.close();
2464
+ }
2465
+ }
2466
+ catch (err) {
2467
+ cliOutput({ success: false, error: { code: 'E_DOCTOR', message: String(err) } }, { command: 'agent doctor' });
2468
+ process.exitCode = 1;
2469
+ }
2470
+ },
2471
+ });
2472
+ /**
2473
+ * Root agent command group — agent lifecycle, credentials, and messaging.
2474
+ *
2475
+ * Registers all agent subcommands. See file-level TSDoc for the full
2476
+ * command surface and daemon vs. Pi session architectural distinction.
2477
+ *
2478
+ * @see docs/specs/SIGNALDOCK-UNIFIED-AGENT-REGISTRY.md Section 3.4
2479
+ * @see .cleo/adrs/ADR-035-pi-v2-v3-harness.md §D5
2480
+ * @task T178
2481
+ */
2482
+ export const agentCommand = defineCommand({
2483
+ meta: { name: 'agent', description: 'Agent lifecycle, credentials, and messaging' },
2484
+ subCommands: {
2485
+ doctor: doctorCommand,
2486
+ register: registerCommand,
2487
+ signin: signinCommand,
2488
+ start: startCommand,
2489
+ stop: stopCommand,
2490
+ status: statusCommand,
2491
+ assign: assignCommand,
2492
+ wake: wakeCommand,
2493
+ spawn: spawnCommand,
2494
+ reassign: reassignCommand,
2495
+ 'stop-all': stopAllCommand,
2496
+ work: workCommand,
2497
+ list: listCommand,
2498
+ get: getCommand,
2499
+ attach: attachCommand,
2500
+ detach: detachCommand,
2501
+ remove: removeCommand,
2502
+ 'rotate-key': rotateKeyCommand,
2503
+ 'claim-code': claimCodeCommand,
2504
+ watch: watchCommand,
2505
+ poll: pollCommand,
2506
+ send: sendCommand,
2507
+ health: healthCommand,
2508
+ install: installCommand,
2509
+ pack: packCommand,
2510
+ create: createCommand,
2511
+ mint: mintCommand,
2512
+ },
2513
+ async run({ cmd, rawArgs }) {
2514
+ const firstArg = rawArgs?.find((a) => !a.startsWith('-'));
2515
+ if (firstArg && cmd.subCommands && firstArg in cmd.subCommands)
2516
+ return;
2517
+ await showUsage(cmd);
2518
+ },
2519
+ });
2520
+ /**
2521
+ * Infer the default tier from the agent role.
2522
+ *
2523
+ * - orchestrator -> high
2524
+ * - lead -> mid
2525
+ * - worker -> mid
2526
+ * - docs-worker -> mid
2527
+ *
2528
+ * @param role - The agent role string.
2529
+ * @returns The inferred tier string.
2530
+ */
2531
+ function inferTierFromRole(role) {
2532
+ if (role === 'orchestrator')
2533
+ return 'high';
2534
+ return 'mid';
2535
+ }
2536
+ /**
2537
+ * Generate a `persona.cant` file from role-based templates.
2538
+ *
2539
+ * Templates are derived from the canonical starter-bundle agents at
2540
+ * `packages/cleo-os/starter-bundle/agents/`. Each role maps to a
2541
+ * specific set of tools, permissions, context sources, and behavioral
2542
+ * hooks.
2543
+ *
2544
+ * @param params - Agent persona parameters.
2545
+ * @returns The complete persona.cant file content.
2546
+ *
2547
+ * @see packages/cleo-os/starter-bundle/agents/cleo-orchestrator.cant
2548
+ * @see packages/cleo-os/starter-bundle/agents/dev-lead.cant
2549
+ * @see packages/cleo-os/starter-bundle/agents/code-worker.cant
2550
+ * @see packages/cleo-os/starter-bundle/agents/docs-worker.cant
2551
+ */
2552
+ function generatePersonaCant(params) {
2553
+ const { name, role, tier, team, domain, parent } = params;
2554
+ switch (role) {
2555
+ case 'orchestrator':
2556
+ return generateOrchestratorPersona(name, tier, team, parent);
2557
+ case 'lead':
2558
+ return generateLeadPersona(name, tier, team, domain, parent);
2559
+ case 'worker':
2560
+ return generateWorkerPersona(name, tier, team, domain, parent);
2561
+ case 'docs-worker':
2562
+ return generateDocsWorkerPersona(name, tier, team, domain, parent);
2563
+ default:
2564
+ return generateWorkerPersona(name, tier, team, domain, parent);
2565
+ }
2566
+ }
2567
+ /**
2568
+ * Generate an orchestrator persona.cant.
2569
+ *
2570
+ * Orchestrators coordinate work but do not execute code. They hold
2571
+ * read-only core tools (Read, Grep, Glob) plus dispatch tools for
2572
+ * routing work to leads and workers.
2573
+ *
2574
+ * @param name - Agent name (kebab-case).
2575
+ * @param tier - Agent tier.
2576
+ * @param team - Optional team name.
2577
+ * @param parent - Optional parent agent.
2578
+ * @returns The persona.cant content string.
2579
+ */
2580
+ function generateOrchestratorPersona(name, tier, team, parent) {
2581
+ const parentLine = parent ? `\n parent: ${parent}` : '';
2582
+ const teamComment = team ? `\n# Team: ${team}` : '';
2583
+ return `---
2584
+ kind: agent
2585
+ version: "1"
2586
+ ---
2587
+
2588
+ # ${name} — orchestrator agent.${teamComment}
2589
+ # Coordinates the team, classifies work, dispatches to leads/workers.
2590
+
2591
+ agent ${name}:
2592
+ role: orchestrator${parentLine}
2593
+ tier: ${tier}
2594
+ description: "Orchestrator agent. Reads task context, classifies work, dispatches to leads, and synthesizes results. Does not execute code — coordinates."
2595
+ consult-when: "Cross-team decisions, scope changes, human-in-the-loop escalation, or when a lead reports a blocking ambiguity"
2596
+
2597
+ context_sources:
2598
+ - source: decisions
2599
+ query: "recent architectural and project decisions"
2600
+ max_entries: 5
2601
+ - source: patterns
2602
+ query: "project conventions and established patterns"
2603
+ max_entries: 3
2604
+ on_overflow: escalate_tier
2605
+
2606
+ mental_model:
2607
+ scope: project
2608
+ max_tokens: 2000
2609
+ on_load:
2610
+ validate: true
2611
+
2612
+ permissions:
2613
+ tasks: read, write
2614
+ session: read, write
2615
+ memory: read, write
2616
+
2617
+ skills:
2618
+ - ct-cleo
2619
+ - ct-task-executor
2620
+
2621
+ tools:
2622
+ core: [Read, Grep, Glob]
2623
+ dispatch: [dispatch_worker, report_to_user]
2624
+
2625
+ on SessionStart:
2626
+ session "Read active tasks and recent decisions to build situational awareness"
2627
+ context: [active-tasks, memory-bridge, recent-decisions]
2628
+
2629
+ on TaskCompleted:
2630
+ if **the completed task unblocks downstream work**:
2631
+ session "Reassess task queue and dispatch next work"
2632
+ `;
2633
+ }
2634
+ /**
2635
+ * Generate a lead persona.cant.
2636
+ *
2637
+ * Leads decide HOW to build and dispatch work to workers. They hold
2638
+ * read-only tools per TEAM-002 / ULTRAPLAN 10.3 — no Edit, Write, or
2639
+ * Bash access.
2640
+ *
2641
+ * @param name - Agent name (kebab-case).
2642
+ * @param tier - Agent tier.
2643
+ * @param team - Optional team name.
2644
+ * @param domain - Optional domain description.
2645
+ * @param parent - Optional parent agent.
2646
+ * @returns The persona.cant content string.
2647
+ */
2648
+ function generateLeadPersona(name, tier, team, domain, parent) {
2649
+ const parentLine = parent ? `\n parent: ${parent}` : '\n parent: cleo-orchestrator';
2650
+ const teamComment = team ? `\n# Team: ${team}` : '';
2651
+ const domainDesc = domain ? ` Specializes in ${domain}.` : '';
2652
+ return `---
2653
+ kind: agent
2654
+ version: "1"
2655
+ ---
2656
+
2657
+ # ${name} — lead agent.${teamComment}
2658
+ # Decomposes tasks, reviews worker output, decides technical approach.
2659
+ # MUST NOT hold Edit/Write/Bash tools (TEAM-002 / ULTRAPLAN 10.3).
2660
+
2661
+ agent ${name}:
2662
+ role: lead${parentLine}
2663
+ tier: ${tier}
2664
+ description: "Development lead.${domainDesc} Decomposes tasks into concrete implementation steps, reviews worker output, and decides technical approach. Does not write code directly."
2665
+ consult-when: "Implementation strategy, code architecture, refactoring direction, task decomposition, or when workers need clarification"
2666
+
2667
+ context_sources:
2668
+ - source: patterns
2669
+ query: "codebase conventions and architecture patterns"
2670
+ max_entries: 5
2671
+ - source: decisions
2672
+ query: "technical decisions affecting implementation"
2673
+ max_entries: 3
2674
+ on_overflow: escalate_tier
2675
+
2676
+ mental_model:
2677
+ scope: project
2678
+ max_tokens: 1000
2679
+ on_load:
2680
+ validate: true
2681
+
2682
+ permissions:
2683
+ files:
2684
+ read: ["**/*"]
2685
+
2686
+ skills:
2687
+ - ct-cleo
2688
+ - ct-dev-workflow
2689
+ - ct-task-executor
2690
+
2691
+ tools:
2692
+ core: [Read, Grep, Glob]
2693
+ dispatch: [dispatch_worker, report_to_orchestrator]
2694
+
2695
+ on SessionStart:
2696
+ session "Review current task assignments and worker availability"
2697
+ context: [active-tasks, memory-bridge]
2698
+
2699
+ on TaskCompleted:
2700
+ if **the completed task introduced new code**:
2701
+ session "Review worker output for quality and completeness before reporting to orchestrator"
2702
+ `;
2703
+ }
2704
+ /**
2705
+ * Generate a worker persona.cant.
2706
+ *
2707
+ * Workers execute code changes within declared file globs. They hold
2708
+ * the full tool set (Read, Edit, Write, Bash, Glob, Grep) and operate
2709
+ * within file permission boundaries derived from the `--domain` flag.
2710
+ *
2711
+ * @param name - Agent name (kebab-case).
2712
+ * @param tier - Agent tier.
2713
+ * @param team - Optional team name.
2714
+ * @param domain - Optional domain description for file permissions.
2715
+ * @param parent - Optional parent agent.
2716
+ * @returns The persona.cant content string.
2717
+ */
2718
+ function generateWorkerPersona(name, tier, team, domain, parent) {
2719
+ const parentLine = parent ? `\n parent: ${parent}` : '\n parent: dev-lead';
2720
+ const teamComment = team ? `\n# Team: ${team}` : '';
2721
+ const domainDesc = domain ? ` Specializes in ${domain}.` : '';
2722
+ const writeGlobs = deriveWriteGlobs(domain);
2723
+ return `---
2724
+ kind: agent
2725
+ version: "1"
2726
+ ---
2727
+
2728
+ # ${name} — worker agent.${teamComment}
2729
+ # Executes code changes within declared file globs.
2730
+
2731
+ agent ${name}:
2732
+ role: worker${parentLine}
2733
+ tier: ${tier}
2734
+ description: "Code worker.${domainDesc} Reads requirements, writes code, runs tests, and validates changes. Operates within declared file permission globs."
2735
+ consult-when: "Writing code, fixing bugs, running tests, formatting, or any file modification task"
2736
+
2737
+ context_sources:
2738
+ - source: patterns
2739
+ query: "coding conventions and testing patterns"
2740
+ max_entries: 5
2741
+ - source: learnings
2742
+ query: "past implementation mistakes and fixes"
2743
+ max_entries: 3
2744
+ on_overflow: escalate_tier
2745
+
2746
+ mental_model:
2747
+ scope: project
2748
+ max_tokens: 1000
2749
+ on_load:
2750
+ validate: true
2751
+
2752
+ permissions:
2753
+ files:
2754
+ write: ${JSON.stringify(writeGlobs)}
2755
+ read: ["**/*"]
2756
+ delete: ${JSON.stringify(writeGlobs)}
2757
+
2758
+ skills:
2759
+ - ct-cleo
2760
+ - ct-dev-workflow
2761
+ - ct-task-executor
2762
+
2763
+ tools:
2764
+ core: [Read, Edit, Write, Bash, Glob, Grep]
2765
+
2766
+ on SessionStart:
2767
+ session "Check assigned task and read relevant source files before starting work"
2768
+ context: [active-tasks, memory-bridge]
2769
+
2770
+ on PostToolUse:
2771
+ if tool.name == "Write" or tool.name == "Edit":
2772
+ session "Verify the change compiles and passes lint before proceeding"
2773
+ `;
2774
+ }
2775
+ /**
2776
+ * Generate a docs-worker persona.cant.
2777
+ *
2778
+ * Documentation workers write and maintain documentation within declared
2779
+ * documentation file globs. They carry documentation-specific skills and
2780
+ * context sources.
2781
+ *
2782
+ * @param name - Agent name (kebab-case).
2783
+ * @param tier - Agent tier.
2784
+ * @param team - Optional team name.
2785
+ * @param domain - Optional domain description.
2786
+ * @param parent - Optional parent agent.
2787
+ * @returns The persona.cant content string.
2788
+ */
2789
+ function generateDocsWorkerPersona(name, tier, team, domain, parent) {
2790
+ const parentLine = parent ? `\n parent: ${parent}` : '\n parent: dev-lead';
2791
+ const teamComment = team ? `\n# Team: ${team}` : '';
2792
+ const domainDesc = domain ? ` Specializes in ${domain} documentation.` : '';
2793
+ return `---
2794
+ kind: agent
2795
+ version: "1"
2796
+ ---
2797
+
2798
+ # ${name} — documentation worker agent.${teamComment}
2799
+ # Writes and maintains documentation within declared globs.
2800
+
2801
+ agent ${name}:
2802
+ role: worker${parentLine}
2803
+ tier: ${tier}
2804
+ description: "Documentation worker.${domainDesc} Writes READMEs, updates guides, adds TSDoc comments, and maintains project documentation. Operates within declared documentation file globs."
2805
+ consult-when: "Writing documentation, updating READMEs, adding TSDoc comments, or improving existing docs"
2806
+
2807
+ context_sources:
2808
+ - source: patterns
2809
+ query: "documentation conventions and style patterns"
2810
+ max_entries: 3
2811
+ - source: decisions
2812
+ query: "architectural decisions needing documentation"
2813
+ max_entries: 3
2814
+ on_overflow: escalate_tier
2815
+
2816
+ mental_model:
2817
+ scope: project
2818
+ max_tokens: 1000
2819
+ on_load:
2820
+ validate: true
2821
+
2822
+ permissions:
2823
+ files:
2824
+ write: ["docs/**", "**/*.md", "**/*.mdx"]
2825
+ read: ["**/*"]
2826
+ delete: ["docs/**"]
2827
+
2828
+ skills:
2829
+ - ct-cleo
2830
+ - ct-documentor
2831
+ - ct-docs-write
2832
+
2833
+ tools:
2834
+ core: [Read, Edit, Write, Bash, Glob, Grep]
2835
+
2836
+ on SessionStart:
2837
+ session "Check assigned documentation task and review existing docs for context"
2838
+ context: [active-tasks, memory-bridge]
2839
+
2840
+ on PostToolUse:
2841
+ if tool.name == "Write" or tool.name == "Edit":
2842
+ session "Verify markdown renders correctly and follows project style conventions"
2843
+ `;
2844
+ }
2845
+ /**
2846
+ * Derive file write globs from a domain description string.
2847
+ *
2848
+ * Maps common domain keywords to appropriate file glob patterns.
2849
+ * Falls back to the default `["src/**", "packages/**"]` when no
2850
+ * domain is specified or no keywords match.
2851
+ *
2852
+ * @param domain - Optional domain description string.
2853
+ * @returns Array of glob pattern strings for file write permissions.
2854
+ */
2855
+ function deriveWriteGlobs(domain) {
2856
+ const defaults = ['src/**', 'packages/**', 'lib/**', 'test/**', 'tests/**'];
2857
+ if (!domain)
2858
+ return defaults;
2859
+ const lower = domain.toLowerCase();
2860
+ // Domain-specific glob mappings
2861
+ if (lower.includes('frontend') || lower.includes('ui') || lower.includes('component')) {
2862
+ return ['src/**', 'packages/**', 'components/**', 'styles/**', 'public/**', 'test/**'];
2863
+ }
2864
+ if (lower.includes('backend') || lower.includes('api') || lower.includes('server')) {
2865
+ return ['src/**', 'packages/**', 'lib/**', 'api/**', 'test/**', 'tests/**'];
2866
+ }
2867
+ if (lower.includes('infra') || lower.includes('deploy') || lower.includes('ci')) {
2868
+ return ['.github/**', 'infra/**', 'deploy/**', 'scripts/**', 'Dockerfile*'];
2869
+ }
2870
+ if (lower.includes('test') || lower.includes('qa') || lower.includes('quality')) {
2871
+ return ['test/**', 'tests/**', 'src/**/*.test.*', 'src/**/*.spec.*', 'packages/**/*.test.*'];
2872
+ }
2873
+ if (lower.includes('rust') || lower.includes('crate')) {
2874
+ return ['crates/**', 'src/**', 'Cargo.toml', 'test/**'];
2875
+ }
2876
+ if (lower.includes('doc')) {
2877
+ return ['docs/**', '**/*.md', '**/*.mdx'];
2878
+ }
2879
+ return defaults;
2880
+ }
2881
+ /**
2882
+ * Generate a `manifest.json` object for the agent package.
2883
+ *
2884
+ * Conforms to the CANTZ-PACKAGE-STANDARD.md Section 2.3 schema.
2885
+ *
2886
+ * @param params - Manifest generation parameters.
2887
+ * @returns A plain object ready for JSON serialization.
2888
+ */
2889
+ function generateManifest(params) {
2890
+ return {
2891
+ name: params.name,
2892
+ version: '1.0.0',
2893
+ description: `${capitalizeFirst(params.role)} agent${params.domain ? ` for ${params.domain}` : ''}`,
2894
+ cant: {
2895
+ minVersion: '1',
2896
+ tier: params.tier,
2897
+ role: params.role === 'docs-worker' ? 'worker' : params.role,
2898
+ },
2899
+ createdAt: new Date().toISOString(),
2900
+ };
2901
+ }
2902
+ /**
2903
+ * Generate a team configuration CANT file fragment.
2904
+ *
2905
+ * Creates a minimal team-config.cant that declares the agent's
2906
+ * membership in a named team.
2907
+ *
2908
+ * @param name - Agent name.
2909
+ * @param role - Agent role.
2910
+ * @param team - Team name.
2911
+ * @returns The team-config.cant content string.
2912
+ */
2913
+ function generateTeamConfig(name, role, team) {
2914
+ return `---
2915
+ kind: team-config
2916
+ version: "1"
2917
+ ---
2918
+
2919
+ # Team membership for ${name}
2920
+
2921
+ team ${team}:
2922
+ member ${name}:
2923
+ role: ${role}
2924
+ status: active
2925
+ `;
2926
+ }
2927
+ /**
2928
+ * Generate a mental model seed markdown file.
2929
+ *
2930
+ * Creates an initial expertise document with placeholder sections
2931
+ * for the agent to populate as it learns about the project domain.
2932
+ *
2933
+ * @param name - Agent name.
2934
+ * @param role - Agent role.
2935
+ * @param domain - Optional domain description.
2936
+ * @returns The mental-model-seed.md content string.
2937
+ */
2938
+ function generateMentalModelSeed(name, role, domain) {
2939
+ const domainSection = domain
2940
+ ? `## Domain\n\n${domain}\n`
2941
+ : `## Domain\n\nTODO: Describe the domain this agent specializes in.\n`;
2942
+ return `# Mental Model Seed: ${name}
2943
+
2944
+ > Auto-generated at ${new Date().toISOString()}
2945
+ > Role: ${role}
2946
+
2947
+ ${domainSection}
2948
+ ## Key Patterns
2949
+
2950
+ TODO: Document recurring patterns this agent should recognize.
2951
+
2952
+ ## Known Pitfalls
2953
+
2954
+ TODO: Document common mistakes or anti-patterns in this domain.
2955
+
2956
+ ## Decision History
2957
+
2958
+ TODO: Track important decisions and their rationale.
2959
+
2960
+ ## Learning Log
2961
+
2962
+ TODO: Record discoveries and insights as the agent operates.
2963
+ `;
2964
+ }
2965
+ /**
2966
+ * Capitalize the first letter of a string.
2967
+ *
2968
+ * @param str - Input string.
2969
+ * @returns String with the first character uppercased.
2970
+ */
2971
+ function capitalizeFirst(str) {
2972
+ if (str.length === 0)
2973
+ return str;
2974
+ return str.charAt(0).toUpperCase() + str.slice(1);
2975
+ }
2976
+ //# sourceMappingURL=agent.js.map