@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,122 @@
1
+ import { join } from "node:path";
2
+ import type { Command } from "commander";
3
+ import { c, errorOut, humanOut, jsonOut } from "../output.ts";
4
+ import { resolvePrompt } from "../render.ts";
5
+ import { dedupById, readJsonl } from "../store.ts";
6
+ import type { Prompt } from "../types.ts";
7
+ import { ExitError } from "../types.ts";
8
+
9
+ export default async function renderCmd(args: string[], json: boolean): Promise<void> {
10
+ const cwd = process.cwd();
11
+ const promptsPath = join(cwd, ".trellis", "prompts.jsonl");
12
+
13
+ if (args.includes("--help") || args.includes("-h")) {
14
+ humanOut(`Usage: tl render <name>[@version] [options]
15
+
16
+ Options:
17
+ --format md|json Output format (default: md)
18
+ --json Output as JSON`);
19
+ return;
20
+ }
21
+
22
+ const nameArg = args.filter((a) => !a.startsWith("--"))[0];
23
+ if (!nameArg) {
24
+ if (json) {
25
+ jsonOut({ success: false, command: "render", error: "Prompt name required" });
26
+ } else {
27
+ errorOut("Usage: tl render <name>[@version] [--format md|json]");
28
+ }
29
+ throw new ExitError(1);
30
+ }
31
+
32
+ // Parse name@version
33
+ let name = nameArg;
34
+ let version: number | undefined;
35
+ const atIdx = nameArg.lastIndexOf("@");
36
+ if (atIdx !== -1) {
37
+ name = nameArg.slice(0, atIdx);
38
+ version = Number.parseInt(nameArg.slice(atIdx + 1), 10);
39
+ }
40
+
41
+ // Parse format
42
+ let format = "md";
43
+ const fmtIdx = args.indexOf("--format");
44
+ if (fmtIdx !== -1 && args[fmtIdx + 1]) {
45
+ format = args[fmtIdx + 1] ?? "md";
46
+ }
47
+
48
+ const allRecords = await readJsonl<Prompt>(promptsPath);
49
+ const current = dedupById(allRecords);
50
+
51
+ try {
52
+ const result = resolvePrompt(name, current, version);
53
+
54
+ if (json) {
55
+ const envelope: Record<string, unknown> = {
56
+ success: true,
57
+ command: "render",
58
+ name,
59
+ version: result.version,
60
+ sections: result.sections,
61
+ resolvedFrom: result.resolvedFrom,
62
+ frontmatter: result.frontmatter,
63
+ };
64
+ if (result.loam !== undefined) envelope.loam = result.loam;
65
+ jsonOut(envelope);
66
+ } else if (format === "json") {
67
+ const payload: Record<string, unknown> = {
68
+ name,
69
+ version: result.version,
70
+ sections: result.sections,
71
+ resolvedFrom: result.resolvedFrom,
72
+ frontmatter: result.frontmatter,
73
+ };
74
+ if (result.loam !== undefined) payload.loam = result.loam;
75
+ jsonOut(payload);
76
+ } else {
77
+ // Markdown format
78
+ humanOut(c.bold(`# ${name}`) + c.dim(` (v${result.version})`));
79
+ humanOut(c.dim(`Resolved from: ${result.resolvedFrom.join(" → ")}`));
80
+ humanOut("");
81
+
82
+ if (Object.keys(result.frontmatter).length > 0) {
83
+ humanOut("---");
84
+ for (const [key, value] of Object.entries(result.frontmatter)) {
85
+ humanOut(`${key}: ${typeof value === "object" ? JSON.stringify(value) : value}`);
86
+ }
87
+ humanOut("---");
88
+ humanOut("");
89
+ }
90
+
91
+ for (const section of result.sections) {
92
+ humanOut(`## ${section.name}`);
93
+ humanOut("");
94
+ humanOut(section.body);
95
+ humanOut("");
96
+ }
97
+ }
98
+ } catch (err: unknown) {
99
+ const msg = err instanceof Error ? err.message : String(err);
100
+ if (json) {
101
+ jsonOut({ success: false, command: "render", error: msg });
102
+ } else {
103
+ errorOut(`Error: ${msg}`);
104
+ }
105
+ throw new ExitError(1);
106
+ }
107
+ }
108
+
109
+ export function registerRenderCommand(program: Command): void {
110
+ program
111
+ .command("render")
112
+ .description("Render full prompt (resolve inheritance)")
113
+ .argument("<name>", "Prompt name (name[@version])")
114
+ .option("--format <format>", "Output format: md or json (default: md)")
115
+ .action(async (name: string, options: { format?: string }) => {
116
+ const json: boolean = program.opts().json ?? false;
117
+ const args = [name];
118
+ if (options.format) args.push("--format", options.format);
119
+ if (json) args.push("--json");
120
+ await renderCmd(args, json);
121
+ });
122
+ }
@@ -0,0 +1,353 @@
1
+ import { join } from "node:path";
2
+ import type { Command } from "commander";
3
+ import { generateId } from "../id.ts";
4
+ import { c, errorOut, fmt, humanOut, jsonOut } from "../output.ts";
5
+ import { acquireLock, appendJsonl, dedupByIdLast, readJsonl, releaseLock } from "../store.ts";
6
+ import type { Schema, ValidationRule } from "../types.ts";
7
+ import { ExitError } from "../types.ts";
8
+
9
+ export default async function schema(args: string[], json: boolean): Promise<void> {
10
+ if (args.includes("--help") || args.includes("-h")) {
11
+ humanOut(`Usage: tl schema <subcommand> [options]
12
+
13
+ Subcommands:
14
+ create --name <name> --required <sections> [--optional <sections>]
15
+ show <name>
16
+ list
17
+ rule add <schema> --section <name> --pattern <regex> --message <text>
18
+
19
+ Options:
20
+ --json Output as JSON`);
21
+ return;
22
+ }
23
+
24
+ const subcommand = args[0];
25
+
26
+ switch (subcommand) {
27
+ case "create":
28
+ await schemaCreate(args.slice(1), json);
29
+ break;
30
+ case "show":
31
+ await schemaShow(args.slice(1), json);
32
+ break;
33
+ case "list":
34
+ await schemaList(args.slice(1), json);
35
+ break;
36
+ case "rule":
37
+ if (args[1] === "add") {
38
+ await schemaRuleAdd(args.slice(2), json);
39
+ } else {
40
+ errorOut(`Unknown schema rule subcommand: ${args[1]}`);
41
+ throw new ExitError(1);
42
+ }
43
+ break;
44
+ default:
45
+ if (json) {
46
+ jsonOut({ success: false, command: "schema", error: `Unknown subcommand: ${subcommand}` });
47
+ } else {
48
+ errorOut(
49
+ `Unknown schema subcommand: ${subcommand}\nUsage: tl schema create|show|list|rule`,
50
+ );
51
+ }
52
+ throw new ExitError(1);
53
+ }
54
+ }
55
+
56
+ async function schemaCreate(args: string[], json: boolean): Promise<void> {
57
+ const cwd = process.cwd();
58
+ const schemasPath = join(cwd, ".trellis", "schemas.jsonl");
59
+
60
+ let name = "";
61
+ const requiredSections: string[] = [];
62
+ const optionalSections: string[] = [];
63
+
64
+ for (let i = 0; i < args.length; i++) {
65
+ if (args[i] === "--name" && args[i + 1]) {
66
+ name = args[++i] ?? "";
67
+ } else if (args[i] === "--required" && args[i + 1]) {
68
+ const parsed = (args[++i] ?? "")
69
+ .split(",")
70
+ .map((s) => s.trim())
71
+ .filter(Boolean);
72
+ requiredSections.push(...parsed);
73
+ } else if (args[i] === "--optional" && args[i + 1]) {
74
+ const parsed = (args[++i] ?? "")
75
+ .split(",")
76
+ .map((s) => s.trim())
77
+ .filter(Boolean);
78
+ optionalSections.push(...parsed);
79
+ }
80
+ }
81
+
82
+ if (!name) {
83
+ if (json) {
84
+ jsonOut({ success: false, command: "schema create", error: "--name is required" });
85
+ } else {
86
+ errorOut("--name is required");
87
+ }
88
+ throw new ExitError(1);
89
+ }
90
+
91
+ await acquireLock(schemasPath);
92
+ try {
93
+ const allRecords = await readJsonl<Schema>(schemasPath);
94
+ const current = dedupByIdLast(allRecords);
95
+
96
+ if (current.find((s) => s.name === name)) {
97
+ if (json) {
98
+ jsonOut({
99
+ success: false,
100
+ command: "schema create",
101
+ error: `Schema '${name}' already exists`,
102
+ });
103
+ } else {
104
+ errorOut(`Schema '${name}' already exists`);
105
+ }
106
+ throw new ExitError(1);
107
+ }
108
+
109
+ const id = generateId(
110
+ "schema",
111
+ current.map((s) => s.id),
112
+ );
113
+ const now = new Date().toISOString();
114
+
115
+ const schemaRecord: Schema = {
116
+ id,
117
+ name,
118
+ requiredSections,
119
+ optionalSections: optionalSections.length > 0 ? optionalSections : undefined,
120
+ createdAt: now,
121
+ updatedAt: now,
122
+ };
123
+
124
+ await appendJsonl(schemasPath, schemaRecord);
125
+
126
+ if (json) {
127
+ jsonOut({ success: true, command: "schema create", id, name });
128
+ } else {
129
+ humanOut(`${fmt.success("Created schema")} ${c.bold(name)} ${fmt.id(id)}`);
130
+ }
131
+ } finally {
132
+ releaseLock(schemasPath);
133
+ }
134
+ }
135
+
136
+ async function schemaShow(args: string[], json: boolean): Promise<void> {
137
+ const cwd = process.cwd();
138
+ const schemasPath = join(cwd, ".trellis", "schemas.jsonl");
139
+
140
+ const name = args.filter((a) => !a.startsWith("--"))[0];
141
+ if (!name) {
142
+ if (json) {
143
+ jsonOut({ success: false, command: "schema show", error: "Schema name required" });
144
+ } else {
145
+ errorOut("Usage: tl schema show <name>");
146
+ }
147
+ throw new ExitError(1);
148
+ }
149
+
150
+ const allRecords = await readJsonl<Schema>(schemasPath);
151
+ const current = dedupByIdLast(allRecords);
152
+ const schemaRecord = current.find((s) => s.name === name);
153
+
154
+ if (!schemaRecord) {
155
+ if (json) {
156
+ jsonOut({ success: false, command: "schema show", error: `Schema '${name}' not found` });
157
+ } else {
158
+ errorOut(`Schema '${name}' not found`);
159
+ }
160
+ throw new ExitError(1);
161
+ }
162
+
163
+ if (json) {
164
+ jsonOut({ success: true, command: "schema show", schema: schemaRecord });
165
+ } else {
166
+ humanOut(`${c.bold(schemaRecord.name)} (${schemaRecord.id})`);
167
+ humanOut(`Required: ${schemaRecord.requiredSections.join(", ") || c.dim("(none)")}`);
168
+ if (schemaRecord.optionalSections?.length) {
169
+ humanOut(`Optional: ${schemaRecord.optionalSections.join(", ")}`);
170
+ }
171
+ if (schemaRecord.rules?.length) {
172
+ humanOut("\nRules:");
173
+ for (const rule of schemaRecord.rules) {
174
+ humanOut(` ${c.cyan(rule.section)}: /${rule.pattern}/ → "${rule.message}"`);
175
+ }
176
+ }
177
+ }
178
+ }
179
+
180
+ async function schemaList(_args: string[], json: boolean): Promise<void> {
181
+ const cwd = process.cwd();
182
+ const schemasPath = join(cwd, ".trellis", "schemas.jsonl");
183
+
184
+ const allRecords = await readJsonl<Schema>(schemasPath);
185
+ const schemas = dedupByIdLast(allRecords);
186
+
187
+ if (json) {
188
+ jsonOut({ success: true, command: "schema list", schemas, count: schemas.length });
189
+ } else {
190
+ if (schemas.length === 0) {
191
+ humanOut("No schemas found.");
192
+ return;
193
+ }
194
+ for (const s of schemas) {
195
+ const required = s.requiredSections.join(", ") || c.dim("(none)");
196
+ humanOut(`${c.bold(s.name)} required: ${required} ${c.dim(s.id)}`);
197
+ }
198
+ }
199
+ }
200
+
201
+ async function schemaRuleAdd(args: string[], json: boolean): Promise<void> {
202
+ const cwd = process.cwd();
203
+ const schemasPath = join(cwd, ".trellis", "schemas.jsonl");
204
+
205
+ const schemaName = args.filter((a) => !a.startsWith("--"))[0];
206
+ if (!schemaName) {
207
+ if (json) {
208
+ jsonOut({ success: false, command: "schema rule add", error: "Schema name required" });
209
+ } else {
210
+ errorOut(
211
+ "Usage: tl schema rule add <schema-name> --section <name> --pattern <regex> --message <text>",
212
+ );
213
+ }
214
+ throw new ExitError(1);
215
+ }
216
+
217
+ let section = "";
218
+ let pattern = "";
219
+ let message = "";
220
+
221
+ for (let i = 0; i < args.length; i++) {
222
+ if (args[i] === "--section" && args[i + 1]) {
223
+ section = args[++i] ?? "";
224
+ } else if (args[i] === "--pattern" && args[i + 1]) {
225
+ pattern = args[++i] ?? "";
226
+ } else if (args[i] === "--message" && args[i + 1]) {
227
+ message = args[++i] ?? "";
228
+ }
229
+ }
230
+
231
+ if (!section || !pattern || !message) {
232
+ if (json) {
233
+ jsonOut({
234
+ success: false,
235
+ command: "schema rule add",
236
+ error: "--section, --pattern, and --message are required",
237
+ });
238
+ } else {
239
+ errorOut("--section, --pattern, and --message are required");
240
+ }
241
+ throw new ExitError(1);
242
+ }
243
+
244
+ await acquireLock(schemasPath);
245
+ try {
246
+ const allRecords = await readJsonl<Schema>(schemasPath);
247
+ const current = dedupByIdLast(allRecords);
248
+
249
+ const schemaRecord = current.find((s) => s.name === schemaName);
250
+ if (!schemaRecord) {
251
+ if (json) {
252
+ jsonOut({
253
+ success: false,
254
+ command: "schema rule add",
255
+ error: `Schema '${schemaName}' not found`,
256
+ });
257
+ } else {
258
+ errorOut(`Schema '${schemaName}' not found`);
259
+ }
260
+ throw new ExitError(1);
261
+ }
262
+
263
+ const rule: ValidationRule = { section, pattern, message };
264
+ const updated: Schema = {
265
+ ...schemaRecord,
266
+ rules: [...(schemaRecord.rules ?? []), rule],
267
+ updatedAt: new Date().toISOString(),
268
+ };
269
+
270
+ // Append updated schema (dedup on read handles version management for schemas)
271
+ await appendJsonl(schemasPath, updated);
272
+
273
+ if (json) {
274
+ jsonOut({ success: true, command: "schema rule add", schema: schemaName, rule });
275
+ } else {
276
+ humanOut(fmt.success(`Added rule to ${c.bold(schemaName)}: /${pattern}/ on "${section}"`));
277
+ }
278
+ } finally {
279
+ releaseLock(schemasPath);
280
+ }
281
+ }
282
+
283
+ export function registerSchemaCommand(program: Command): void {
284
+ const schemaCmd = program
285
+ .command("schema")
286
+ .description("Schema management (create, show, list, rule add)");
287
+
288
+ schemaCmd
289
+ .command("create")
290
+ .description("Create a validation schema")
291
+ .requiredOption("--name <name>", "Schema name")
292
+ .option(
293
+ "--required <sections>",
294
+ "Required sections (comma-separated, repeatable)",
295
+ (v: string, a: string[]) => a.concat([v]),
296
+ [] as string[],
297
+ )
298
+ .option(
299
+ "--optional <sections>",
300
+ "Optional sections (comma-separated, repeatable)",
301
+ (v: string, a: string[]) => a.concat([v]),
302
+ [] as string[],
303
+ )
304
+ .action(async (opts: Record<string, unknown>) => {
305
+ const json: boolean = program.opts().json ?? false;
306
+ const args: string[] = ["--name", opts.name as string];
307
+ for (const r of opts.required as string[]) args.push("--required", r);
308
+ for (const o of opts.optional as string[]) args.push("--optional", o);
309
+ await schemaCreate(args, json);
310
+ });
311
+
312
+ schemaCmd
313
+ .command("show")
314
+ .description("Show schema details")
315
+ .argument("<name>", "Schema name")
316
+ .action(async (name: string) => {
317
+ const json: boolean = program.opts().json ?? false;
318
+ await schemaShow([name], json);
319
+ });
320
+
321
+ schemaCmd
322
+ .command("list")
323
+ .description("List all schemas")
324
+ .action(async () => {
325
+ const json: boolean = program.opts().json ?? false;
326
+ await schemaList([], json);
327
+ });
328
+
329
+ const ruleCmd = schemaCmd.command("rule").description("Schema rule management");
330
+
331
+ ruleCmd
332
+ .command("add")
333
+ .description("Add a validation rule to a schema")
334
+ .argument("<schema>", "Schema name")
335
+ .requiredOption("--section <name>", "Section to validate")
336
+ .requiredOption("--pattern <regex>", "Regex pattern that must match")
337
+ .requiredOption("--message <text>", "Error message if validation fails")
338
+ .action(async (schemaName: string, opts: Record<string, unknown>) => {
339
+ const json: boolean = program.opts().json ?? false;
340
+ await schemaRuleAdd(
341
+ [
342
+ schemaName,
343
+ "--section",
344
+ opts.section as string,
345
+ "--pattern",
346
+ opts.pattern as string,
347
+ "--message",
348
+ opts.message as string,
349
+ ],
350
+ json,
351
+ );
352
+ });
353
+ }
@@ -0,0 +1,115 @@
1
+ import { join } from "node:path";
2
+ import type { Command } from "commander";
3
+ import { c, errorOut, humanOut, jsonOut } from "../output.ts";
4
+ import { dedupById, getVersions, readJsonl } from "../store.ts";
5
+ import type { Prompt } from "../types.ts";
6
+ import { ExitError } from "../types.ts";
7
+
8
+ export default async function show(args: string[], json: boolean): Promise<void> {
9
+ const cwd = process.cwd();
10
+ const promptsPath = join(cwd, ".trellis", "prompts.jsonl");
11
+
12
+ if (args.includes("--help") || args.includes("-h")) {
13
+ humanOut(`Usage: tl show <name>[@version] [options]
14
+
15
+ Options:
16
+ --json Output as JSON`);
17
+ return;
18
+ }
19
+
20
+ // Parse name@version syntax
21
+ const nameArg = args.filter((a) => !a.startsWith("--"))[0];
22
+ if (!nameArg) {
23
+ if (json) {
24
+ jsonOut({ success: false, command: "show", error: "Prompt name required" });
25
+ } else {
26
+ errorOut("Usage: tl show <name>[@version]");
27
+ }
28
+ throw new ExitError(1);
29
+ }
30
+
31
+ let name = nameArg;
32
+ let version: number | undefined;
33
+
34
+ const atIdx = nameArg.lastIndexOf("@");
35
+ if (atIdx !== -1) {
36
+ name = nameArg.slice(0, atIdx);
37
+ version = Number.parseInt(nameArg.slice(atIdx + 1), 10);
38
+ if (Number.isNaN(version)) {
39
+ errorOut(`Invalid version: ${nameArg.slice(atIdx + 1)}`);
40
+ throw new ExitError(1);
41
+ }
42
+ }
43
+
44
+ const allRecords = await readJsonl<Prompt>(promptsPath);
45
+
46
+ let prompt: Prompt | undefined;
47
+ if (version !== undefined) {
48
+ const _versions = getVersions(allRecords, "");
49
+ // Find by name + version
50
+ prompt = allRecords.find((p) => p.name === name && p.version === version);
51
+ if (!prompt) {
52
+ // Try to find by looking at all records with that name
53
+ const withName = allRecords.filter((p) => p.name === name);
54
+ prompt = withName.find((p) => p.version === version);
55
+ }
56
+ } else {
57
+ const current = dedupById(allRecords);
58
+ prompt = current.find((p) => p.name === name);
59
+ }
60
+
61
+ if (!prompt) {
62
+ const versionStr = version !== undefined ? `@${version}` : "";
63
+ if (json) {
64
+ jsonOut({
65
+ success: false,
66
+ command: "show",
67
+ error: `Prompt '${name}${versionStr}' not found`,
68
+ });
69
+ } else {
70
+ errorOut(`Prompt '${name}${versionStr}' not found`);
71
+ }
72
+ throw new ExitError(1);
73
+ }
74
+
75
+ if (json) {
76
+ jsonOut({ success: true, command: "show", prompt });
77
+ } else {
78
+ humanOut(`${c.bold(prompt.name)} (${prompt.id}) v${prompt.version}`);
79
+ if (prompt.description) humanOut(c.dim(prompt.description));
80
+ humanOut(
81
+ `Status: ${prompt.status} Created: ${prompt.createdAt} Updated: ${prompt.updatedAt}`,
82
+ );
83
+ if (prompt.extends) humanOut(`Extends: ${prompt.extends}`);
84
+ if (prompt.mixins?.length) humanOut(`Mixins: ${prompt.mixins.join(", ")}`);
85
+ if (prompt.tags?.length) humanOut(`Tags: ${prompt.tags.join(", ")}`);
86
+ if (prompt.schema) humanOut(`Schema: ${prompt.schema}`);
87
+ if (prompt.pinned !== undefined) humanOut(`Pinned: v${prompt.pinned}`);
88
+ if (prompt.frontmatter && Object.keys(prompt.frontmatter).length > 0) {
89
+ humanOut("Frontmatter:");
90
+ for (const [key, value] of Object.entries(prompt.frontmatter)) {
91
+ const display = typeof value === "object" ? JSON.stringify(value) : String(value);
92
+ humanOut(` ${key}: ${display}`);
93
+ }
94
+ }
95
+ humanOut("");
96
+
97
+ for (const section of prompt.sections) {
98
+ humanOut(`${c.cyan(`## ${section.name}`)}${section.required ? " (required)" : ""}`);
99
+ humanOut(section.body || c.dim("(empty — removed from render)"));
100
+ humanOut("");
101
+ }
102
+ }
103
+ }
104
+
105
+ export function registerShowCommand(program: Command): void {
106
+ program
107
+ .command("show")
108
+ .description("Show prompt record")
109
+ .argument("<name>", "Prompt name (name[@version])")
110
+ .action(async (name: string) => {
111
+ const json: boolean = program.opts().json ?? false;
112
+ const args = [name, ...(json ? ["--json"] : [])];
113
+ await show(args, json);
114
+ });
115
+ }
@@ -0,0 +1,65 @@
1
+ import { join } from "node:path";
2
+ import type { Command } from "commander";
3
+ import { c, humanOut, jsonOut } from "../output.ts";
4
+ import { dedupById, dedupByIdLast, readJsonl } from "../store.ts";
5
+ import type { Prompt, Schema } from "../types.ts";
6
+
7
+ export default async function stats(_args: string[], json: boolean): Promise<void> {
8
+ const cwd = process.cwd();
9
+
10
+ if (_args.includes("--help") || _args.includes("-h")) {
11
+ humanOut(`Usage: tl stats [options]
12
+
13
+ Options:
14
+ --json Output as JSON`);
15
+ return;
16
+ }
17
+
18
+ const promptsPath = join(cwd, ".trellis", "prompts.jsonl");
19
+ const schemasPath = join(cwd, ".trellis", "schemas.jsonl");
20
+
21
+ const allPromptRecords = await readJsonl<Prompt>(promptsPath);
22
+ const allSchemaRecords = await readJsonl<Schema>(schemasPath);
23
+
24
+ const prompts = dedupById(allPromptRecords);
25
+ const schemas = dedupByIdLast(allSchemaRecords);
26
+
27
+ const active = prompts.filter((p) => p.status === "active").length;
28
+ const draft = prompts.filter((p) => p.status === "draft").length;
29
+ const archived = prompts.filter((p) => p.status === "archived").length;
30
+ const total = prompts.length;
31
+ const totalVersions = allPromptRecords.length;
32
+ const withSchema = prompts.filter((p) => p.schema).length;
33
+ const withParent = prompts.filter((p) => p.extends).length;
34
+
35
+ if (json) {
36
+ jsonOut({
37
+ success: true,
38
+ command: "stats",
39
+ prompts: { total, active, draft, archived, withSchema, withParent, totalVersions },
40
+ schemas: schemas.length,
41
+ });
42
+ } else {
43
+ humanOut(c.bold("Trellis Stats"));
44
+ humanOut("");
45
+ humanOut("Prompts:");
46
+ humanOut(` ${c.green(String(active))} active`);
47
+ humanOut(` ${c.yellow(String(draft))} draft`);
48
+ humanOut(` ${c.dim(String(archived))} archived`);
49
+ humanOut(` ${c.dim(`${totalVersions} total versions in JSONL`)}`);
50
+ humanOut("");
51
+ humanOut(` ${withSchema} with schema | ${withParent} with parent (inheritance)`);
52
+ humanOut(` ${schemas.length} schema(s) defined`);
53
+ }
54
+ }
55
+
56
+ export function registerStatsCommand(program: Command): void {
57
+ program
58
+ .command("stats")
59
+ .description("Show prompt statistics")
60
+ .action(async () => {
61
+ const json: boolean = program.opts().json ?? false;
62
+ const args = json ? ["--json"] : [];
63
+ await stats(args, json);
64
+ });
65
+ }