@ag-eco/agentplate-cli 0.13.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 (455) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +462 -0
  3. package/agents/ap-co-creation.md +90 -0
  4. package/agents/builder.md +144 -0
  5. package/agents/coordinator.md +377 -0
  6. package/agents/lead.md +435 -0
  7. package/agents/merger.md +164 -0
  8. package/agents/monitor.md +214 -0
  9. package/agents/orchestrator.md +239 -0
  10. package/agents/reviewer.md +140 -0
  11. package/agents/scout.md +125 -0
  12. package/agents/supervisor.md +427 -0
  13. package/package.json +66 -0
  14. package/src/agents/capabilities.test.ts +85 -0
  15. package/src/agents/capabilities.ts +125 -0
  16. package/src/agents/checkpoint.test.ts +88 -0
  17. package/src/agents/checkpoint.ts +101 -0
  18. package/src/agents/copilot-hooks-deployer.test.ts +162 -0
  19. package/src/agents/copilot-hooks-deployer.ts +93 -0
  20. package/src/agents/guard-rules.test.ts +372 -0
  21. package/src/agents/guard-rules.ts +97 -0
  22. package/src/agents/headless-mail-injector.test.ts +709 -0
  23. package/src/agents/headless-mail-injector.ts +377 -0
  24. package/src/agents/headless-prompt.test.ts +102 -0
  25. package/src/agents/headless-prompt.ts +68 -0
  26. package/src/agents/hooks-deployer.test.ts +3119 -0
  27. package/src/agents/hooks-deployer.ts +804 -0
  28. package/src/agents/identity.test.ts +604 -0
  29. package/src/agents/identity.ts +384 -0
  30. package/src/agents/lifecycle.test.ts +196 -0
  31. package/src/agents/lifecycle.ts +183 -0
  32. package/src/agents/mail-poll-detect.test.ts +153 -0
  33. package/src/agents/mail-poll-detect.ts +73 -0
  34. package/src/agents/manifest.test.ts +1026 -0
  35. package/src/agents/manifest.ts +376 -0
  36. package/src/agents/overlay.test.ts +1058 -0
  37. package/src/agents/overlay.ts +490 -0
  38. package/src/agents/scope-detect.test.ts +190 -0
  39. package/src/agents/scope-detect.ts +146 -0
  40. package/src/agents/turn-lock.test.ts +181 -0
  41. package/src/agents/turn-lock.ts +235 -0
  42. package/src/agents/turn-runner-dispatch.test.ts +182 -0
  43. package/src/agents/turn-runner-dispatch.ts +105 -0
  44. package/src/agents/turn-runner.test.ts +2312 -0
  45. package/src/agents/turn-runner.ts +1383 -0
  46. package/src/beads/client.test.ts +217 -0
  47. package/src/beads/client.ts +230 -0
  48. package/src/beads/molecules.test.ts +338 -0
  49. package/src/beads/molecules.ts +198 -0
  50. package/src/commands/agents.test.ts +328 -0
  51. package/src/commands/agents.ts +299 -0
  52. package/src/commands/clean.test.ts +797 -0
  53. package/src/commands/clean.ts +791 -0
  54. package/src/commands/completions.test.ts +348 -0
  55. package/src/commands/completions.ts +981 -0
  56. package/src/commands/coordinator.test.ts +2975 -0
  57. package/src/commands/coordinator.ts +1841 -0
  58. package/src/commands/costs.test.ts +1183 -0
  59. package/src/commands/costs.ts +599 -0
  60. package/src/commands/dashboard.test.ts +954 -0
  61. package/src/commands/dashboard.ts +1212 -0
  62. package/src/commands/discover.test.ts +288 -0
  63. package/src/commands/discover.ts +202 -0
  64. package/src/commands/doctor.test.ts +303 -0
  65. package/src/commands/doctor.ts +311 -0
  66. package/src/commands/ecosystem.test.ts +226 -0
  67. package/src/commands/ecosystem.ts +248 -0
  68. package/src/commands/errors.test.ts +654 -0
  69. package/src/commands/errors.ts +197 -0
  70. package/src/commands/feed.test.ts +709 -0
  71. package/src/commands/feed.ts +260 -0
  72. package/src/commands/group.test.ts +475 -0
  73. package/src/commands/group.ts +546 -0
  74. package/src/commands/hooks.test.ts +458 -0
  75. package/src/commands/hooks.ts +263 -0
  76. package/src/commands/init.test.ts +1011 -0
  77. package/src/commands/init.ts +967 -0
  78. package/src/commands/inspect.test.ts +1239 -0
  79. package/src/commands/inspect.ts +648 -0
  80. package/src/commands/log.test.ts +1913 -0
  81. package/src/commands/log.ts +958 -0
  82. package/src/commands/logs.test.ts +801 -0
  83. package/src/commands/logs.ts +483 -0
  84. package/src/commands/mail.test.ts +1501 -0
  85. package/src/commands/mail.ts +848 -0
  86. package/src/commands/merge.test.ts +864 -0
  87. package/src/commands/merge.ts +381 -0
  88. package/src/commands/metrics.test.ts +458 -0
  89. package/src/commands/metrics.ts +129 -0
  90. package/src/commands/monitor.test.ts +191 -0
  91. package/src/commands/monitor.ts +409 -0
  92. package/src/commands/nudge.test.ts +579 -0
  93. package/src/commands/nudge.ts +646 -0
  94. package/src/commands/orchestrator.ts +42 -0
  95. package/src/commands/prime.test.ts +612 -0
  96. package/src/commands/prime.ts +359 -0
  97. package/src/commands/replay.test.ts +757 -0
  98. package/src/commands/replay.ts +231 -0
  99. package/src/commands/run.test.ts +469 -0
  100. package/src/commands/run.ts +353 -0
  101. package/src/commands/serve/agent-actions.test.ts +210 -0
  102. package/src/commands/serve/agent-actions.ts +192 -0
  103. package/src/commands/serve/build.test.ts +202 -0
  104. package/src/commands/serve/build.ts +206 -0
  105. package/src/commands/serve/coordinator-actions.test.ts +339 -0
  106. package/src/commands/serve/coordinator-actions.ts +410 -0
  107. package/src/commands/serve/dev.test.ts +168 -0
  108. package/src/commands/serve/dev.ts +117 -0
  109. package/src/commands/serve/mail-actions.test.ts +312 -0
  110. package/src/commands/serve/mail-actions.ts +167 -0
  111. package/src/commands/serve/rest.test.ts +1680 -0
  112. package/src/commands/serve/rest.ts +1130 -0
  113. package/src/commands/serve/static.ts +51 -0
  114. package/src/commands/serve/ws.test.ts +361 -0
  115. package/src/commands/serve/ws.ts +332 -0
  116. package/src/commands/serve.test.ts +459 -0
  117. package/src/commands/serve.ts +654 -0
  118. package/src/commands/sling.test.ts +1583 -0
  119. package/src/commands/sling.ts +1351 -0
  120. package/src/commands/spec.test.ts +179 -0
  121. package/src/commands/spec.ts +105 -0
  122. package/src/commands/status.test.ts +614 -0
  123. package/src/commands/status.ts +403 -0
  124. package/src/commands/stop.test.ts +964 -0
  125. package/src/commands/stop.ts +319 -0
  126. package/src/commands/supervisor.test.ts +185 -0
  127. package/src/commands/supervisor.ts +537 -0
  128. package/src/commands/trace.test.ts +762 -0
  129. package/src/commands/trace.ts +205 -0
  130. package/src/commands/update.test.ts +466 -0
  131. package/src/commands/update.ts +263 -0
  132. package/src/commands/upgrade.test.ts +48 -0
  133. package/src/commands/upgrade.ts +240 -0
  134. package/src/commands/watch.test.ts +257 -0
  135. package/src/commands/watch.ts +308 -0
  136. package/src/commands/worktree.test.ts +1297 -0
  137. package/src/commands/worktree.ts +451 -0
  138. package/src/config.test.ts +1535 -0
  139. package/src/config.ts +1064 -0
  140. package/src/doctor/agents.test.ts +523 -0
  141. package/src/doctor/agents.ts +399 -0
  142. package/src/doctor/config-check.test.ts +191 -0
  143. package/src/doctor/config-check.ts +183 -0
  144. package/src/doctor/consistency.test.ts +807 -0
  145. package/src/doctor/consistency.ts +347 -0
  146. package/src/doctor/databases.test.ts +350 -0
  147. package/src/doctor/databases.ts +243 -0
  148. package/src/doctor/dependencies.test.ts +296 -0
  149. package/src/doctor/dependencies.ts +272 -0
  150. package/src/doctor/ecosystem.test.ts +308 -0
  151. package/src/doctor/ecosystem.ts +156 -0
  152. package/src/doctor/logs.test.ts +253 -0
  153. package/src/doctor/logs.ts +295 -0
  154. package/src/doctor/merge-queue.test.ts +315 -0
  155. package/src/doctor/merge-queue.ts +167 -0
  156. package/src/doctor/providers.test.ts +409 -0
  157. package/src/doctor/providers.ts +250 -0
  158. package/src/doctor/serve.test.ts +95 -0
  159. package/src/doctor/serve.ts +86 -0
  160. package/src/doctor/structure.test.ts +423 -0
  161. package/src/doctor/structure.ts +285 -0
  162. package/src/doctor/types.ts +43 -0
  163. package/src/doctor/version.test.ts +241 -0
  164. package/src/doctor/version.ts +132 -0
  165. package/src/doctor/watchdog.test.ts +167 -0
  166. package/src/doctor/watchdog.ts +214 -0
  167. package/src/e2e/init-sling-lifecycle.test.ts +283 -0
  168. package/src/errors.test.ts +350 -0
  169. package/src/errors.ts +217 -0
  170. package/src/events/store.test.ts +660 -0
  171. package/src/events/store.ts +369 -0
  172. package/src/events/tailer.test.ts +719 -0
  173. package/src/events/tailer.ts +332 -0
  174. package/src/events/tool-filter.test.ts +330 -0
  175. package/src/events/tool-filter.ts +126 -0
  176. package/src/index.ts +533 -0
  177. package/src/insights/analyzer.test.ts +466 -0
  178. package/src/insights/analyzer.ts +203 -0
  179. package/src/insights/quality-gates.test.ts +141 -0
  180. package/src/insights/quality-gates.ts +156 -0
  181. package/src/json.test.ts +72 -0
  182. package/src/json.ts +53 -0
  183. package/src/loam/client.test.ts +752 -0
  184. package/src/loam/client.ts +664 -0
  185. package/src/logging/color.test.ts +252 -0
  186. package/src/logging/color.ts +105 -0
  187. package/src/logging/format.test.ts +110 -0
  188. package/src/logging/format.ts +255 -0
  189. package/src/logging/logger.test.ts +814 -0
  190. package/src/logging/logger.ts +266 -0
  191. package/src/logging/reporter.test.ts +259 -0
  192. package/src/logging/reporter.ts +110 -0
  193. package/src/logging/sanitizer.test.ts +190 -0
  194. package/src/logging/sanitizer.ts +57 -0
  195. package/src/logging/theme.ts +140 -0
  196. package/src/mail/broadcast.test.ts +204 -0
  197. package/src/mail/broadcast.ts +92 -0
  198. package/src/mail/client.test.ts +774 -0
  199. package/src/mail/client.ts +236 -0
  200. package/src/mail/store.test.ts +898 -0
  201. package/src/mail/store.ts +425 -0
  202. package/src/merge/lock.test.ts +149 -0
  203. package/src/merge/lock.ts +140 -0
  204. package/src/merge/predict.test.ts +387 -0
  205. package/src/merge/predict.ts +249 -0
  206. package/src/merge/queue.test.ts +426 -0
  207. package/src/merge/queue.ts +246 -0
  208. package/src/merge/resolver.test.ts +1993 -0
  209. package/src/merge/resolver.ts +926 -0
  210. package/src/metrics/pricing.test.ts +258 -0
  211. package/src/metrics/pricing.ts +135 -0
  212. package/src/metrics/store.test.ts +978 -0
  213. package/src/metrics/store.ts +501 -0
  214. package/src/metrics/summary.test.ts +398 -0
  215. package/src/metrics/summary.ts +178 -0
  216. package/src/metrics/transcript.test.ts +483 -0
  217. package/src/metrics/transcript.ts +114 -0
  218. package/src/runtimes/__fixtures__/claude-stream-fixture.ts +22 -0
  219. package/src/runtimes/aider.test.ts +124 -0
  220. package/src/runtimes/aider.ts +147 -0
  221. package/src/runtimes/amp.test.ts +164 -0
  222. package/src/runtimes/amp.ts +154 -0
  223. package/src/runtimes/claude.test.ts +1474 -0
  224. package/src/runtimes/claude.ts +579 -0
  225. package/src/runtimes/codex.test.ts +805 -0
  226. package/src/runtimes/codex.ts +273 -0
  227. package/src/runtimes/connections.test.ts +214 -0
  228. package/src/runtimes/connections.ts +103 -0
  229. package/src/runtimes/copilot.test.ts +707 -0
  230. package/src/runtimes/copilot.ts +316 -0
  231. package/src/runtimes/cursor.test.ts +497 -0
  232. package/src/runtimes/cursor.ts +205 -0
  233. package/src/runtimes/gemini.test.ts +537 -0
  234. package/src/runtimes/gemini.ts +243 -0
  235. package/src/runtimes/goose.test.ts +133 -0
  236. package/src/runtimes/goose.ts +157 -0
  237. package/src/runtimes/headless-connection.test.ts +264 -0
  238. package/src/runtimes/headless-connection.ts +158 -0
  239. package/src/runtimes/opencode.test.ts +325 -0
  240. package/src/runtimes/opencode.ts +188 -0
  241. package/src/runtimes/pi-guards.test.ts +486 -0
  242. package/src/runtimes/pi-guards.ts +367 -0
  243. package/src/runtimes/pi.test.ts +789 -0
  244. package/src/runtimes/pi.ts +305 -0
  245. package/src/runtimes/registry.test.ts +196 -0
  246. package/src/runtimes/registry.ts +99 -0
  247. package/src/runtimes/sapling.test.ts +1267 -0
  248. package/src/runtimes/sapling.ts +710 -0
  249. package/src/runtimes/types.ts +266 -0
  250. package/src/schema-consistency.test.ts +246 -0
  251. package/src/sessions/compat.test.ts +281 -0
  252. package/src/sessions/compat.ts +105 -0
  253. package/src/sessions/store.test.ts +1748 -0
  254. package/src/sessions/store.ts +858 -0
  255. package/src/test-helpers.test.ts +124 -0
  256. package/src/test-helpers.ts +145 -0
  257. package/src/test-setup.test.ts +31 -0
  258. package/src/test-setup.ts +28 -0
  259. package/src/tools/loam/api.ts +368 -0
  260. package/src/tools/loam/cli.ts +278 -0
  261. package/src/tools/loam/commands/add.ts +52 -0
  262. package/src/tools/loam/commands/archive.ts +214 -0
  263. package/src/tools/loam/commands/audit.ts +276 -0
  264. package/src/tools/loam/commands/compact.ts +1062 -0
  265. package/src/tools/loam/commands/completions.ts +79 -0
  266. package/src/tools/loam/commands/config.ts +381 -0
  267. package/src/tools/loam/commands/delete-domain.ts +121 -0
  268. package/src/tools/loam/commands/delete.ts +316 -0
  269. package/src/tools/loam/commands/diff.ts +200 -0
  270. package/src/tools/loam/commands/doctor.ts +1113 -0
  271. package/src/tools/loam/commands/edit.ts +226 -0
  272. package/src/tools/loam/commands/init.ts +31 -0
  273. package/src/tools/loam/commands/learn.ts +179 -0
  274. package/src/tools/loam/commands/move.ts +323 -0
  275. package/src/tools/loam/commands/onboard.ts +374 -0
  276. package/src/tools/loam/commands/outcome.ts +185 -0
  277. package/src/tools/loam/commands/prime.ts +688 -0
  278. package/src/tools/loam/commands/prune.ts +614 -0
  279. package/src/tools/loam/commands/query.ts +218 -0
  280. package/src/tools/loam/commands/rank.ts +180 -0
  281. package/src/tools/loam/commands/ready.ts +189 -0
  282. package/src/tools/loam/commands/record.ts +1210 -0
  283. package/src/tools/loam/commands/restore.ts +166 -0
  284. package/src/tools/loam/commands/search.ts +327 -0
  285. package/src/tools/loam/commands/setup.ts +887 -0
  286. package/src/tools/loam/commands/status.ts +103 -0
  287. package/src/tools/loam/commands/sync.ts +298 -0
  288. package/src/tools/loam/commands/update.ts +19 -0
  289. package/src/tools/loam/commands/upgrade.ts +93 -0
  290. package/src/tools/loam/commands/validate.ts +190 -0
  291. package/src/tools/loam/index.ts +62 -0
  292. package/src/tools/loam/log.ts +127 -0
  293. package/src/tools/loam/registry/builtins.ts +409 -0
  294. package/src/tools/loam/registry/custom.ts +431 -0
  295. package/src/tools/loam/registry/init.ts +55 -0
  296. package/src/tools/loam/registry/template.ts +40 -0
  297. package/src/tools/loam/registry/type-registry.ts +113 -0
  298. package/src/tools/loam/schemas/config-schema.ts +489 -0
  299. package/src/tools/loam/schemas/config.ts +245 -0
  300. package/src/tools/loam/schemas/index.ts +18 -0
  301. package/src/tools/loam/schemas/record-schema.ts +191 -0
  302. package/src/tools/loam/schemas/record.ts +115 -0
  303. package/src/tools/loam/utils/active-work.ts +205 -0
  304. package/src/tools/loam/utils/anchor-validity.ts +80 -0
  305. package/src/tools/loam/utils/archive.ts +146 -0
  306. package/src/tools/loam/utils/audit.ts +667 -0
  307. package/src/tools/loam/utils/bm25.ts +238 -0
  308. package/src/tools/loam/utils/budget.ts +142 -0
  309. package/src/tools/loam/utils/config.ts +344 -0
  310. package/src/tools/loam/utils/dir-anchors.ts +62 -0
  311. package/src/tools/loam/utils/domain-rules.ts +114 -0
  312. package/src/tools/loam/utils/expertise.ts +393 -0
  313. package/src/tools/loam/utils/format-helpers.ts +96 -0
  314. package/src/tools/loam/utils/format.ts +1234 -0
  315. package/src/tools/loam/utils/git-context.ts +50 -0
  316. package/src/tools/loam/utils/git.ts +183 -0
  317. package/src/tools/loam/utils/hooks.ts +299 -0
  318. package/src/tools/loam/utils/index.ts +52 -0
  319. package/src/tools/loam/utils/json-output.ts +13 -0
  320. package/src/tools/loam/utils/lock.ts +76 -0
  321. package/src/tools/loam/utils/markers.ts +48 -0
  322. package/src/tools/loam/utils/numeric-flags.ts +20 -0
  323. package/src/tools/loam/utils/palette.ts +44 -0
  324. package/src/tools/loam/utils/prime-ranking.ts +135 -0
  325. package/src/tools/loam/utils/recipe-discovery.ts +195 -0
  326. package/src/tools/loam/utils/runtime-flags.ts +28 -0
  327. package/src/tools/loam/utils/scoring.ts +94 -0
  328. package/src/tools/loam/utils/version.ts +116 -0
  329. package/src/tools/sprout/commands/block.ts +64 -0
  330. package/src/tools/sprout/commands/blocked.ts +86 -0
  331. package/src/tools/sprout/commands/close.ts +129 -0
  332. package/src/tools/sprout/commands/completions.ts +198 -0
  333. package/src/tools/sprout/commands/config.ts +238 -0
  334. package/src/tools/sprout/commands/create.ts +164 -0
  335. package/src/tools/sprout/commands/dep.ts +148 -0
  336. package/src/tools/sprout/commands/doctor.ts +979 -0
  337. package/src/tools/sprout/commands/init.ts +83 -0
  338. package/src/tools/sprout/commands/label.ts +178 -0
  339. package/src/tools/sprout/commands/list.ts +210 -0
  340. package/src/tools/sprout/commands/migrate.ts +133 -0
  341. package/src/tools/sprout/commands/onboard.ts +207 -0
  342. package/src/tools/sprout/commands/plan-show.ts +278 -0
  343. package/src/tools/sprout/commands/plan.ts +2526 -0
  344. package/src/tools/sprout/commands/prime.ts +399 -0
  345. package/src/tools/sprout/commands/ready.ts +245 -0
  346. package/src/tools/sprout/commands/search.ts +221 -0
  347. package/src/tools/sprout/commands/show.ts +277 -0
  348. package/src/tools/sprout/commands/stats.ts +146 -0
  349. package/src/tools/sprout/commands/sync.ts +134 -0
  350. package/src/tools/sprout/commands/tpl.ts +364 -0
  351. package/src/tools/sprout/commands/unblock.ts +115 -0
  352. package/src/tools/sprout/commands/update.ts +257 -0
  353. package/src/tools/sprout/commands/upgrade.ts +91 -0
  354. package/src/tools/sprout/config-schema.ts +152 -0
  355. package/src/tools/sprout/config.ts +355 -0
  356. package/src/tools/sprout/filter.ts +107 -0
  357. package/src/tools/sprout/format.ts +43 -0
  358. package/src/tools/sprout/id.ts +22 -0
  359. package/src/tools/sprout/index.ts +204 -0
  360. package/src/tools/sprout/log.ts +76 -0
  361. package/src/tools/sprout/markers.ts +22 -0
  362. package/src/tools/sprout/output.ts +121 -0
  363. package/src/tools/sprout/plan-backref.ts +93 -0
  364. package/src/tools/sprout/plan-context.ts +81 -0
  365. package/src/tools/sprout/plan-domain.ts +139 -0
  366. package/src/tools/sprout/plan-lifecycle.ts +65 -0
  367. package/src/tools/sprout/plan-loam.ts +207 -0
  368. package/src/tools/sprout/plan-schema.ts +209 -0
  369. package/src/tools/sprout/sort.ts +31 -0
  370. package/src/tools/sprout/store.ts +172 -0
  371. package/src/tools/sprout/types.ts +118 -0
  372. package/src/tools/sprout/validation.ts +119 -0
  373. package/src/tools/sprout/version.ts +1 -0
  374. package/src/tools/sprout/yaml.ts +387 -0
  375. package/src/tools/trellis/commands/archive.ts +87 -0
  376. package/src/tools/trellis/commands/completions.ts +610 -0
  377. package/src/tools/trellis/commands/config.ts +382 -0
  378. package/src/tools/trellis/commands/create.ts +252 -0
  379. package/src/tools/trellis/commands/diff.ts +150 -0
  380. package/src/tools/trellis/commands/doctor.ts +771 -0
  381. package/src/tools/trellis/commands/emit.ts +365 -0
  382. package/src/tools/trellis/commands/history.ts +83 -0
  383. package/src/tools/trellis/commands/import.ts +198 -0
  384. package/src/tools/trellis/commands/init.ts +81 -0
  385. package/src/tools/trellis/commands/list.ts +103 -0
  386. package/src/tools/trellis/commands/onboard.ts +156 -0
  387. package/src/tools/trellis/commands/pin.ts +172 -0
  388. package/src/tools/trellis/commands/prime.ts +193 -0
  389. package/src/tools/trellis/commands/render.ts +122 -0
  390. package/src/tools/trellis/commands/schema.ts +353 -0
  391. package/src/tools/trellis/commands/show.ts +115 -0
  392. package/src/tools/trellis/commands/stats.ts +65 -0
  393. package/src/tools/trellis/commands/sync.ts +112 -0
  394. package/src/tools/trellis/commands/tree.ts +123 -0
  395. package/src/tools/trellis/commands/update.ts +330 -0
  396. package/src/tools/trellis/commands/upgrade.ts +95 -0
  397. package/src/tools/trellis/commands/validate.ts +166 -0
  398. package/src/tools/trellis/config-schema.ts +81 -0
  399. package/src/tools/trellis/config.ts +108 -0
  400. package/src/tools/trellis/frontmatter.ts +348 -0
  401. package/src/tools/trellis/id.ts +24 -0
  402. package/src/tools/trellis/index.ts +209 -0
  403. package/src/tools/trellis/markers.ts +28 -0
  404. package/src/tools/trellis/output.ts +84 -0
  405. package/src/tools/trellis/render.ts +212 -0
  406. package/src/tools/trellis/store.ts +144 -0
  407. package/src/tools/trellis/types.ts +82 -0
  408. package/src/tools/trellis/validate.ts +199 -0
  409. package/src/tools/trellis/yaml.ts +309 -0
  410. package/src/tracker/beads.test.ts +454 -0
  411. package/src/tracker/beads.ts +56 -0
  412. package/src/tracker/factory.test.ts +90 -0
  413. package/src/tracker/factory.ts +65 -0
  414. package/src/tracker/sprout.test.ts +461 -0
  415. package/src/tracker/sprout.ts +182 -0
  416. package/src/tracker/types.ts +52 -0
  417. package/src/trellis/client.test.ts +107 -0
  418. package/src/trellis/client.ts +179 -0
  419. package/src/types.ts +970 -0
  420. package/src/utils/bin.test.ts +10 -0
  421. package/src/utils/bin.ts +37 -0
  422. package/src/utils/browser.test.ts +49 -0
  423. package/src/utils/browser.ts +48 -0
  424. package/src/utils/fs.test.ts +119 -0
  425. package/src/utils/fs.ts +62 -0
  426. package/src/utils/pid.test.ts +152 -0
  427. package/src/utils/pid.ts +130 -0
  428. package/src/utils/process-scan.test.ts +53 -0
  429. package/src/utils/process-scan.ts +76 -0
  430. package/src/utils/time.test.ts +43 -0
  431. package/src/utils/time.ts +37 -0
  432. package/src/utils/version.test.ts +33 -0
  433. package/src/utils/version.ts +70 -0
  434. package/src/version.ts +5 -0
  435. package/src/watchdog/daemon.test.ts +3721 -0
  436. package/src/watchdog/daemon.ts +1257 -0
  437. package/src/watchdog/health.test.ts +830 -0
  438. package/src/watchdog/health.ts +434 -0
  439. package/src/watchdog/triage.test.ts +205 -0
  440. package/src/watchdog/triage.ts +205 -0
  441. package/src/worktree/manager.test.ts +720 -0
  442. package/src/worktree/manager.ts +405 -0
  443. package/src/worktree/process.test.ts +172 -0
  444. package/src/worktree/process.ts +131 -0
  445. package/src/worktree/tmux.test.ts +1616 -0
  446. package/src/worktree/tmux.ts +721 -0
  447. package/templates/CLAUDE.md.tmpl +100 -0
  448. package/templates/copilot-hooks.json.tmpl +13 -0
  449. package/templates/hooks.json.tmpl +109 -0
  450. package/templates/overlay.md.tmpl +88 -0
  451. package/ui/dist/apple-touch-icon-bdy6teep.png +0 -0
  452. package/ui/dist/chunk-8s31f05k.css +1 -0
  453. package/ui/dist/chunk-vm5rz679.js +300 -0
  454. package/ui/dist/favicon-nzb39vza.svg +4 -0
  455. package/ui/dist/index.html +17 -0
@@ -0,0 +1,399 @@
1
+ import { readdir, stat } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import type { AgentManifest } from "../types.ts";
4
+ import type { DoctorCheck, DoctorCheckFn } from "./types.ts";
5
+
6
+ const VALID_NAME_REGEX = /^[a-zA-Z0-9_-]+$/;
7
+
8
+ /**
9
+ * Check if a path exists.
10
+ */
11
+ async function pathExists(path: string): Promise<boolean> {
12
+ try {
13
+ await stat(path);
14
+ return true;
15
+ } catch {
16
+ return false;
17
+ }
18
+ }
19
+
20
+ /**
21
+ * Parse and validate agent-manifest.json structure.
22
+ */
23
+ async function loadAndValidateManifest(
24
+ agentplateDir: string,
25
+ ): Promise<{ manifest: AgentManifest | null; errors: string[] }> {
26
+ const manifestPath = join(agentplateDir, "agent-manifest.json");
27
+ const errors: string[] = [];
28
+
29
+ try {
30
+ const content = await Bun.file(manifestPath).text();
31
+ const raw = JSON.parse(content) as {
32
+ version?: unknown;
33
+ agents?: unknown;
34
+ capabilityIndex?: unknown;
35
+ };
36
+
37
+ // Validate top-level fields
38
+ if (typeof raw.version !== "string" || raw.version.length === 0) {
39
+ errors.push('Missing or empty "version" field');
40
+ }
41
+
42
+ if (typeof raw.agents !== "object" || raw.agents === null) {
43
+ errors.push('"agents" must be an object');
44
+ return { manifest: null, errors };
45
+ }
46
+
47
+ if (typeof raw.capabilityIndex !== "object" || raw.capabilityIndex === null) {
48
+ errors.push('"capabilityIndex" must be an object');
49
+ }
50
+
51
+ const agents = raw.agents as Record<string, unknown>;
52
+
53
+ // Validate each agent definition
54
+ for (const [name, def] of Object.entries(agents)) {
55
+ if (typeof def !== "object" || def === null) {
56
+ errors.push(`Agent "${name}": definition must be an object`);
57
+ continue;
58
+ }
59
+
60
+ const agentDef = def as Record<string, unknown>;
61
+
62
+ if (typeof agentDef.file !== "string" || agentDef.file.length === 0) {
63
+ errors.push(`Agent "${name}": "file" must be a non-empty string`);
64
+ }
65
+
66
+ if (typeof agentDef.model !== "string" || agentDef.model.length === 0) {
67
+ errors.push(`Agent "${name}": "model" must be a non-empty string`);
68
+ }
69
+
70
+ if (!Array.isArray(agentDef.tools)) {
71
+ errors.push(`Agent "${name}": "tools" must be an array`);
72
+ }
73
+
74
+ if (!Array.isArray(agentDef.capabilities)) {
75
+ errors.push(`Agent "${name}": "capabilities" must be an array`);
76
+ } else if (agentDef.capabilities.length === 0) {
77
+ errors.push(`Agent "${name}": must have at least one capability`);
78
+ }
79
+
80
+ if (typeof agentDef.canSpawn !== "boolean") {
81
+ errors.push(`Agent "${name}": "canSpawn" must be a boolean`);
82
+ }
83
+
84
+ if (!Array.isArray(agentDef.constraints)) {
85
+ errors.push(`Agent "${name}": "constraints" must be an array`);
86
+ }
87
+ }
88
+
89
+ // Return manifest only if structure is valid
90
+ if (errors.length > 0) {
91
+ return { manifest: null, errors };
92
+ }
93
+
94
+ return { manifest: raw as AgentManifest, errors: [] };
95
+ } catch (error) {
96
+ if (error instanceof SyntaxError) {
97
+ errors.push("Invalid JSON syntax");
98
+ } else {
99
+ errors.push(error instanceof Error ? error.message : "Failed to read manifest");
100
+ }
101
+ return { manifest: null, errors };
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Validate capability index bidirectional consistency.
107
+ */
108
+ function validateCapabilityIndex(manifest: AgentManifest): string[] {
109
+ const errors: string[] = [];
110
+
111
+ // Build expected index from agent definitions
112
+ const expectedIndex: Record<string, string[]> = {};
113
+ for (const [name, def] of Object.entries(manifest.agents)) {
114
+ for (const cap of def.capabilities) {
115
+ const existing = expectedIndex[cap];
116
+ if (existing) {
117
+ existing.push(name);
118
+ } else {
119
+ expectedIndex[cap] = [name];
120
+ }
121
+ }
122
+ }
123
+
124
+ // Check that declared index matches expected
125
+ for (const [cap, agentNames] of Object.entries(manifest.capabilityIndex)) {
126
+ const expected = expectedIndex[cap];
127
+ if (!expected) {
128
+ errors.push(`Capability "${cap}" in index but no agents declare it`);
129
+ continue;
130
+ }
131
+
132
+ const missing = expected.filter((name) => !agentNames.includes(name));
133
+ const extra = agentNames.filter((name) => !expected.includes(name));
134
+
135
+ if (missing.length > 0) {
136
+ errors.push(`Capability "${cap}": missing agents in index: ${missing.join(", ")}`);
137
+ }
138
+
139
+ if (extra.length > 0) {
140
+ errors.push(`Capability "${cap}": extra agents in index: ${extra.join(", ")}`);
141
+ }
142
+ }
143
+
144
+ // Check for missing capabilities in index
145
+ for (const [cap, agentNames] of Object.entries(expectedIndex)) {
146
+ if (!manifest.capabilityIndex[cap]) {
147
+ errors.push(
148
+ `Capability "${cap}" declared by ${agentNames.join(", ")} but missing from index`,
149
+ );
150
+ }
151
+ }
152
+
153
+ // Check for capabilities with zero providers
154
+ for (const [cap, agentNames] of Object.entries(expectedIndex)) {
155
+ if (agentNames.length === 0) {
156
+ errors.push(`Capability "${cap}" has zero providers`);
157
+ }
158
+ }
159
+
160
+ return errors;
161
+ }
162
+
163
+ /**
164
+ * Parse a simple YAML identity file.
165
+ */
166
+ function parseIdentityYaml(text: string): {
167
+ name?: string;
168
+ capability?: string;
169
+ created?: string;
170
+ sessionsCompleted?: number;
171
+ } {
172
+ const lines = text.split("\n");
173
+ const identity: {
174
+ name?: string;
175
+ capability?: string;
176
+ created?: string;
177
+ sessionsCompleted?: number;
178
+ } = {};
179
+
180
+ for (const line of lines) {
181
+ const trimmed = line.trim();
182
+ if (!trimmed || trimmed.startsWith("#")) continue;
183
+
184
+ const colonIndex = trimmed.indexOf(":");
185
+ if (colonIndex === -1) continue;
186
+
187
+ const key = trimmed.slice(0, colonIndex).trim();
188
+ let value = trimmed.slice(colonIndex + 1).trim();
189
+
190
+ // Remove quotes if present
191
+ if (
192
+ (value.startsWith('"') && value.endsWith('"')) ||
193
+ (value.startsWith("'") && value.endsWith("'"))
194
+ ) {
195
+ value = value.slice(1, -1);
196
+ }
197
+
198
+ if (key === "name") {
199
+ identity.name = value;
200
+ } else if (key === "capability") {
201
+ identity.capability = value;
202
+ } else if (key === "created") {
203
+ identity.created = value;
204
+ } else if (key === "sessionsCompleted") {
205
+ identity.sessionsCompleted = Number.parseInt(value, 10);
206
+ }
207
+ }
208
+
209
+ return identity;
210
+ }
211
+
212
+ /**
213
+ * Agent state checks.
214
+ * Validates agent definitions, tmux sessions, and agent identity files.
215
+ */
216
+ export const checkAgents: DoctorCheckFn = async (
217
+ _config,
218
+ agentplateDir,
219
+ ): Promise<DoctorCheck[]> => {
220
+ const checks: DoctorCheck[] = [];
221
+
222
+ // Check 1: Parse agent-manifest.json
223
+ const { manifest, errors: parseErrors } = await loadAndValidateManifest(agentplateDir);
224
+
225
+ if (parseErrors.length > 0) {
226
+ checks.push({
227
+ name: "Manifest parsing",
228
+ category: "agents",
229
+ status: "fail",
230
+ message: `Found ${parseErrors.length} error(s)`,
231
+ details: parseErrors,
232
+ fixable: false,
233
+ });
234
+ return checks; // Can't proceed without valid manifest
235
+ }
236
+
237
+ checks.push({
238
+ name: "Manifest parsing",
239
+ category: "agents",
240
+ status: "pass",
241
+ message: "JSON parses successfully",
242
+ fixable: false,
243
+ });
244
+
245
+ if (!manifest) {
246
+ return checks;
247
+ }
248
+
249
+ // Check 2: Validate referenced .md files exist
250
+ const agentDefsDir = join(agentplateDir, "agent-defs");
251
+ const missingFiles: string[] = [];
252
+
253
+ for (const [name, def] of Object.entries(manifest.agents)) {
254
+ const filePath = join(agentDefsDir, def.file);
255
+ const exists = await pathExists(filePath);
256
+ if (!exists) {
257
+ missingFiles.push(`${name}: ${def.file}`);
258
+ }
259
+ }
260
+
261
+ checks.push({
262
+ name: "Agent definition files",
263
+ category: "agents",
264
+ status: missingFiles.length === 0 ? "pass" : "fail",
265
+ message:
266
+ missingFiles.length === 0 ? "All .md files found" : `Missing ${missingFiles.length} file(s)`,
267
+ details: missingFiles.length > 0 ? missingFiles : undefined,
268
+ fixable: missingFiles.length > 0,
269
+ });
270
+
271
+ // Check 3: Capability index consistency
272
+ const indexErrors = validateCapabilityIndex(manifest);
273
+
274
+ checks.push({
275
+ name: "Capability index",
276
+ category: "agents",
277
+ status: indexErrors.length === 0 ? "pass" : "warn",
278
+ message:
279
+ indexErrors.length === 0 ? "Index is consistent" : `Found ${indexErrors.length} issue(s)`,
280
+ details: indexErrors.length > 0 ? indexErrors : undefined,
281
+ fixable: indexErrors.length > 0,
282
+ });
283
+
284
+ // Check 4: Validate identity files
285
+ const agentsDir = join(agentplateDir, "agents");
286
+ const agentsDirExists = await pathExists(agentsDir);
287
+
288
+ if (!agentsDirExists) {
289
+ checks.push({
290
+ name: "Agent identities",
291
+ category: "agents",
292
+ status: "pass",
293
+ message: "No agent identities yet (agents/ directory missing)",
294
+ fixable: false,
295
+ });
296
+ return checks;
297
+ }
298
+
299
+ try {
300
+ const identityErrors: string[] = [];
301
+ const staleIdentities: string[] = [];
302
+ const agentDirs = await readdir(agentsDir, { withFileTypes: true });
303
+ let identityFileCount = 0;
304
+
305
+ for (const dir of agentDirs) {
306
+ if (!dir.isDirectory()) continue;
307
+
308
+ const agentName = dir.name;
309
+ const identityPath = join(agentsDir, agentName, "identity.yaml");
310
+ const identityExists = await pathExists(identityPath);
311
+
312
+ if (!identityExists) {
313
+ continue; // Skip if no identity file
314
+ }
315
+
316
+ identityFileCount++;
317
+
318
+ // Parse and validate identity
319
+ try {
320
+ const content = await Bun.file(identityPath).text();
321
+ const identity = parseIdentityYaml(content);
322
+
323
+ if (!identity.name) {
324
+ identityErrors.push(`${agentName}: missing "name" field`);
325
+ }
326
+
327
+ if (!identity.capability) {
328
+ identityErrors.push(`${agentName}: missing "capability" field`);
329
+ }
330
+
331
+ if (!identity.created) {
332
+ identityErrors.push(`${agentName}: missing "created" field`);
333
+ } else {
334
+ // Validate ISO timestamp format
335
+ const timestamp = new Date(identity.created);
336
+ if (Number.isNaN(timestamp.getTime())) {
337
+ identityErrors.push(`${agentName}: invalid "created" timestamp`);
338
+ }
339
+ }
340
+
341
+ if (typeof identity.sessionsCompleted !== "number" || identity.sessionsCompleted < 0) {
342
+ identityErrors.push(`${agentName}: "sessionsCompleted" must be a non-negative integer`);
343
+ }
344
+
345
+ // Identity directories are keyed by runtime agent names (for example
346
+ // lead-foo-1234), not by manifest role names. Validate the recorded
347
+ // role/capability against the manifest instead of the directory name.
348
+ if (identity.capability && !manifest.agents[identity.capability]) {
349
+ staleIdentities.push(`${agentName} (capability: ${identity.capability})`);
350
+ }
351
+
352
+ // Validate name is valid identifier
353
+ if (identity.name && !VALID_NAME_REGEX.test(identity.name)) {
354
+ identityErrors.push(
355
+ `${agentName}: name "${identity.name}" contains invalid characters (use alphanumeric, dash, underscore only)`,
356
+ );
357
+ }
358
+ } catch (error) {
359
+ identityErrors.push(
360
+ `${agentName}: ${error instanceof Error ? error.message : "failed to parse YAML"}`,
361
+ );
362
+ }
363
+ }
364
+
365
+ if (identityErrors.length > 0) {
366
+ checks.push({
367
+ name: "Identity validation",
368
+ category: "agents",
369
+ status: "warn",
370
+ message: `Found ${identityErrors.length} issue(s)`,
371
+ details: identityErrors,
372
+ fixable: false,
373
+ });
374
+ } else if (identityFileCount > 0) {
375
+ checks.push({
376
+ name: "Identity validation",
377
+ category: "agents",
378
+ status: "pass",
379
+ message: "All identity files are valid",
380
+ fixable: false,
381
+ });
382
+ }
383
+
384
+ if (staleIdentities.length > 0) {
385
+ checks.push({
386
+ name: "Stale identities",
387
+ category: "agents",
388
+ status: "warn",
389
+ message: `Found ${staleIdentities.length} stale identity file(s)`,
390
+ details: staleIdentities.map((name) => `${name} (role not present in manifest)`),
391
+ fixable: true,
392
+ });
393
+ }
394
+ } catch {
395
+ // Ignore errors reading agents directory
396
+ }
397
+
398
+ return checks;
399
+ };
@@ -0,0 +1,191 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import type { AgentplateConfig } from "../types.ts";
6
+ import { checkConfig } from "./config-check.ts";
7
+
8
+ // Helper to create a temp agentplate dir with config.yaml
9
+ function createTempAgentplateDir(configYaml: string): string {
10
+ const tempDir = mkdtempSync(join(tmpdir(), "agentplate-test-"));
11
+ const agentplateDir = join(tempDir, ".agentplate");
12
+ mkdirSync(agentplateDir, { recursive: true });
13
+ writeFileSync(join(agentplateDir, "config.yaml"), configYaml);
14
+ return agentplateDir;
15
+ }
16
+
17
+ // Valid minimal config
18
+ const validConfigYaml = `
19
+ projectName: test-project
20
+ project:
21
+ root: ${tmpdir()}
22
+ canonicalBranch: main
23
+ maxConcurrent: 5
24
+ maxDepth: 2
25
+ watchdog:
26
+ tier0Enabled: false
27
+ tier1Enabled: false
28
+ tier2Enabled: false
29
+ tier3Enabled: false
30
+ `;
31
+
32
+ const mockConfig: AgentplateConfig = {
33
+ project: {
34
+ name: "test-project",
35
+ root: tmpdir(),
36
+ canonicalBranch: "main",
37
+ },
38
+ agents: {
39
+ manifestPath: `${tmpdir()}/.agentplate/agent-manifest.json`,
40
+ baseDir: `${tmpdir()}/.agentplate/agents`,
41
+ maxConcurrent: 5,
42
+ staggerDelayMs: 1000,
43
+ maxDepth: 2,
44
+ maxSessionsPerRun: 0,
45
+ maxAgentsPerLead: 5,
46
+ },
47
+ worktrees: {
48
+ baseDir: `${tmpdir()}/.agentplate/worktrees`,
49
+ },
50
+ taskTracker: {
51
+ backend: "auto",
52
+ enabled: false,
53
+ },
54
+ loam: {
55
+ enabled: false,
56
+ domains: [],
57
+ primeFormat: "markdown",
58
+ },
59
+ merge: {
60
+ aiResolveEnabled: false,
61
+ reimagineEnabled: false,
62
+ },
63
+ providers: {
64
+ anthropic: { type: "native" },
65
+ },
66
+ watchdog: {
67
+ tier0Enabled: false,
68
+ tier0IntervalMs: 30000,
69
+ tier1Enabled: false,
70
+ tier2Enabled: false,
71
+ staleThresholdMs: 300000,
72
+ zombieThresholdMs: 600000,
73
+ nudgeIntervalMs: 60000,
74
+ },
75
+ models: {},
76
+ logging: {
77
+ verbose: false,
78
+ redactSecrets: true,
79
+ },
80
+ };
81
+
82
+ describe("checkConfig", () => {
83
+ test("returns checks with category config", async () => {
84
+ const agentplateDir = createTempAgentplateDir(validConfigYaml);
85
+ const checks = await checkConfig(mockConfig, agentplateDir);
86
+
87
+ expect(checks).toBeArray();
88
+ expect(checks.length).toBeGreaterThan(0);
89
+
90
+ for (const check of checks) {
91
+ expect(check.category).toBe("config");
92
+ }
93
+ });
94
+
95
+ test("includes all four config checks", async () => {
96
+ const agentplateDir = createTempAgentplateDir(validConfigYaml);
97
+ const checks = await checkConfig(mockConfig, agentplateDir);
98
+
99
+ const checkNames = checks.map((c) => c.name);
100
+ expect(checkNames).toContain("config-parseable");
101
+ expect(checkNames).toContain("config-valid");
102
+ expect(checkNames).toContain("project-root-exists");
103
+ expect(checkNames).toContain("canonical-branch-exists");
104
+ });
105
+
106
+ test("config-parseable passes with valid config", async () => {
107
+ const agentplateDir = createTempAgentplateDir(validConfigYaml);
108
+ const checks = await checkConfig(mockConfig, agentplateDir);
109
+
110
+ const parseableCheck = checks.find((c) => c.name === "config-parseable");
111
+ expect(parseableCheck).toBeDefined();
112
+ expect(parseableCheck?.status).toBe("pass");
113
+ });
114
+
115
+ test("config-valid passes with valid config", async () => {
116
+ const agentplateDir = createTempAgentplateDir(validConfigYaml);
117
+ const checks = await checkConfig(mockConfig, agentplateDir);
118
+
119
+ const validCheck = checks.find((c) => c.name === "config-valid");
120
+ expect(validCheck).toBeDefined();
121
+ expect(validCheck?.status).toBe("pass");
122
+ });
123
+
124
+ test("project-root-exists passes when directory exists", async () => {
125
+ const agentplateDir = createTempAgentplateDir(validConfigYaml);
126
+ const checks = await checkConfig(mockConfig, agentplateDir);
127
+
128
+ const rootCheck = checks.find((c) => c.name === "project-root-exists");
129
+ expect(rootCheck).toBeDefined();
130
+ expect(rootCheck?.status).toBe("pass");
131
+ expect(rootCheck?.details).toBeDefined();
132
+ });
133
+
134
+ test("project-root-exists fails when directory does not exist", async () => {
135
+ const agentplateDir = createTempAgentplateDir(validConfigYaml);
136
+ const configWithBadRoot = {
137
+ ...mockConfig,
138
+ project: {
139
+ ...mockConfig.project,
140
+ root: "/nonexistent/path/that/does/not/exist",
141
+ },
142
+ };
143
+ const checks = await checkConfig(configWithBadRoot, agentplateDir);
144
+
145
+ const rootCheck = checks.find((c) => c.name === "project-root-exists");
146
+ expect(rootCheck).toBeDefined();
147
+ expect(rootCheck?.status).toBe("fail");
148
+ expect(rootCheck?.fixable).toBe(true);
149
+ });
150
+
151
+ test("canonical-branch-exists warns when branch does not exist", async () => {
152
+ const agentplateDir = createTempAgentplateDir(validConfigYaml);
153
+ const configWithBadBranch = {
154
+ ...mockConfig,
155
+ project: {
156
+ ...mockConfig.project,
157
+ canonicalBranch: "nonexistent-branch-xyz",
158
+ },
159
+ };
160
+ const checks = await checkConfig(configWithBadBranch, agentplateDir);
161
+
162
+ const branchCheck = checks.find((c) => c.name === "canonical-branch-exists");
163
+ expect(branchCheck).toBeDefined();
164
+ expect(branchCheck?.status).toBe("warn");
165
+ expect(branchCheck?.message).toContain("nonexistent-branch-xyz");
166
+ });
167
+
168
+ test("all checks have required DoctorCheck fields", async () => {
169
+ const agentplateDir = createTempAgentplateDir(validConfigYaml);
170
+ const checks = await checkConfig(mockConfig, agentplateDir);
171
+
172
+ for (const check of checks) {
173
+ expect(check).toHaveProperty("name");
174
+ expect(check).toHaveProperty("category");
175
+ expect(check).toHaveProperty("status");
176
+ expect(check).toHaveProperty("message");
177
+
178
+ expect(typeof check.name).toBe("string");
179
+ expect(typeof check.message).toBe("string");
180
+ expect(["pass", "warn", "fail"]).toContain(check.status);
181
+
182
+ if (check.details !== undefined) {
183
+ expect(check.details).toBeArray();
184
+ }
185
+
186
+ if (check.fixable !== undefined) {
187
+ expect(typeof check.fixable).toBe("boolean");
188
+ }
189
+ }
190
+ });
191
+ });