@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,664 @@
1
+ /**
2
+ * Loam CLI client.
3
+ *
4
+ * Wraps the `loam` command-line tool for structured expertise operations.
5
+ * record(), search(), and query() use the @ag-eco/loam-cli programmatic API
6
+ * via a variable-based dynamic import so tsc cannot statically resolve the
7
+ * module (avoiding type errors in loam's raw .ts source files).
8
+ * Remaining methods (prime, status, diff, learn, prune, doctor, ready, compact)
9
+ * remain as Bun.spawn CLI wrappers.
10
+ */
11
+
12
+ import { AgentError } from "../errors.ts";
13
+ import type {
14
+ LoamCompactResult,
15
+ LoamDiffResult,
16
+ LoamDoctorResult,
17
+ LoamLearnResult,
18
+ LoamPruneResult,
19
+ LoamReadyResult,
20
+ LoamStatus,
21
+ } from "../types.ts";
22
+
23
+ export interface LoamClient {
24
+ /** Generate a priming prompt, optionally scoped to specific domains. */
25
+ prime(
26
+ domains?: string[],
27
+ format?: "markdown" | "xml" | "json",
28
+ options?: {
29
+ files?: string[];
30
+ excludeDomain?: string[];
31
+ sortByScore?: boolean;
32
+ },
33
+ ): Promise<string>;
34
+
35
+ /** Append an outcome entry to an existing record by ID in the given domain. */
36
+ appendOutcome(
37
+ domain: string,
38
+ id: string,
39
+ outcome: {
40
+ status: "success" | "failure" | "partial";
41
+ agent?: string;
42
+ notes?: string;
43
+ duration?: number;
44
+ },
45
+ ): Promise<void>;
46
+
47
+ /** Show domain statistics. */
48
+ status(): Promise<LoamStatus>;
49
+
50
+ /** Record an expertise entry for a domain. */
51
+ record(
52
+ domain: string,
53
+ options: {
54
+ type: string;
55
+ name?: string;
56
+ description?: string;
57
+ title?: string;
58
+ rationale?: string;
59
+ tags?: string[];
60
+ classification?: string;
61
+ stdin?: boolean;
62
+ evidenceBead?: string;
63
+ outcomeStatus?: "success" | "failure" | "partial";
64
+ outcomeDuration?: number;
65
+ outcomeTestResults?: string;
66
+ outcomeAgent?: string;
67
+ },
68
+ ): Promise<void>;
69
+
70
+ /** Query expertise records, optionally scoped to a domain. */
71
+ query(domain?: string): Promise<string>;
72
+
73
+ /** Search records across all domains. */
74
+ search(
75
+ query: string,
76
+ options?: {
77
+ file?: string;
78
+ sortByScore?: boolean;
79
+ classification?: string;
80
+ outcomeStatus?: "success" | "failure";
81
+ },
82
+ ): Promise<string>;
83
+
84
+ /** Show expertise record changes since a git ref. */
85
+ diff(options?: { since?: string }): Promise<LoamDiffResult>;
86
+
87
+ /** Show changed files and suggest domains for recording learnings. */
88
+ learn(options?: { since?: string }): Promise<LoamLearnResult>;
89
+
90
+ /** Remove unused or stale records. */
91
+ prune(options?: { dryRun?: boolean }): Promise<LoamPruneResult>;
92
+
93
+ /** Run health checks on loam repository. */
94
+ doctor(options?: { fix?: boolean }): Promise<LoamDoctorResult>;
95
+
96
+ /** Show recently added or updated expertise records. */
97
+ ready(options?: { limit?: number; domain?: string; since?: string }): Promise<LoamReadyResult>;
98
+
99
+ /** Compact and optimize domain storage. */
100
+ compact(
101
+ domain?: string,
102
+ options?: {
103
+ analyze?: boolean;
104
+ apply?: boolean;
105
+ auto?: boolean;
106
+ dryRun?: boolean;
107
+ minGroup?: number;
108
+ maxRecords?: number;
109
+ yes?: boolean;
110
+ records?: string[];
111
+ },
112
+ ): Promise<LoamCompactResult>;
113
+ }
114
+
115
+ /**
116
+ * Local type matching @ag-eco/loam-cli ExpertiseRecord.
117
+ * Defined locally to avoid tsc following into loam's raw .ts source
118
+ * (which conflicts with our noUncheckedIndexedAccess setting).
119
+ */
120
+ type LoamClassification = "foundational" | "tactical" | "observational";
121
+
122
+ interface LoamEvidence {
123
+ commit?: string;
124
+ date?: string;
125
+ issue?: string;
126
+ file?: string;
127
+ bead?: string;
128
+ }
129
+
130
+ interface LoamOutcome {
131
+ status: "success" | "failure" | "partial";
132
+ duration?: number;
133
+ test_results?: string;
134
+ agent?: string;
135
+ notes?: string;
136
+ recorded_at?: string;
137
+ }
138
+
139
+ type LoamExpertiseRecord =
140
+ | {
141
+ type: "convention";
142
+ content: string;
143
+ classification: LoamClassification;
144
+ recorded_at: string;
145
+ id?: string;
146
+ tags?: string[];
147
+ evidence?: LoamEvidence;
148
+ outcomes?: LoamOutcome[];
149
+ relates_to?: string[];
150
+ supersedes?: string[];
151
+ }
152
+ | {
153
+ type: "pattern";
154
+ name: string;
155
+ description: string;
156
+ files?: string[];
157
+ classification: LoamClassification;
158
+ recorded_at: string;
159
+ id?: string;
160
+ tags?: string[];
161
+ evidence?: LoamEvidence;
162
+ outcomes?: LoamOutcome[];
163
+ relates_to?: string[];
164
+ supersedes?: string[];
165
+ }
166
+ | {
167
+ type: "failure";
168
+ description: string;
169
+ resolution: string;
170
+ classification: LoamClassification;
171
+ recorded_at: string;
172
+ id?: string;
173
+ tags?: string[];
174
+ evidence?: LoamEvidence;
175
+ outcomes?: LoamOutcome[];
176
+ relates_to?: string[];
177
+ supersedes?: string[];
178
+ }
179
+ | {
180
+ type: "decision";
181
+ title: string;
182
+ rationale: string;
183
+ classification: LoamClassification;
184
+ recorded_at: string;
185
+ id?: string;
186
+ tags?: string[];
187
+ evidence?: LoamEvidence;
188
+ outcomes?: LoamOutcome[];
189
+ relates_to?: string[];
190
+ supersedes?: string[];
191
+ }
192
+ | {
193
+ type: "reference";
194
+ name: string;
195
+ description: string;
196
+ files?: string[];
197
+ classification: LoamClassification;
198
+ recorded_at: string;
199
+ id?: string;
200
+ tags?: string[];
201
+ evidence?: LoamEvidence;
202
+ outcomes?: LoamOutcome[];
203
+ relates_to?: string[];
204
+ supersedes?: string[];
205
+ }
206
+ | {
207
+ type: "guide";
208
+ name: string;
209
+ description: string;
210
+ classification: LoamClassification;
211
+ recorded_at: string;
212
+ id?: string;
213
+ tags?: string[];
214
+ evidence?: LoamEvidence;
215
+ outcomes?: LoamOutcome[];
216
+ relates_to?: string[];
217
+ supersedes?: string[];
218
+ };
219
+
220
+ /**
221
+ * Interface for loam programmatic API functions.
222
+ * Uses a dynamic import with a variable specifier so tsc cannot statically
223
+ * resolve the module (avoiding type errors in loam's raw .ts source files).
224
+ */
225
+ interface LoamProgrammaticApi {
226
+ recordExpertise(
227
+ domain: string,
228
+ record: LoamExpertiseRecord,
229
+ options?: { force?: boolean; cwd?: string },
230
+ ): Promise<{ action: "created" | "updated" | "skipped"; record: LoamExpertiseRecord }>;
231
+ searchExpertise(
232
+ query: string,
233
+ options?: {
234
+ domain?: string;
235
+ type?: string;
236
+ tag?: string;
237
+ classification?: string;
238
+ outcomeStatus?: "success" | "failure";
239
+ sortByScore?: boolean;
240
+ file?: string;
241
+ cwd?: string;
242
+ },
243
+ ): Promise<Array<{ domain: string; records: LoamExpertiseRecord[] }>>;
244
+ queryDomain(
245
+ domain: string,
246
+ options?: { type?: string; classification?: string; file?: string; cwd?: string },
247
+ ): Promise<LoamExpertiseRecord[]>;
248
+ appendOutcome(
249
+ domain: string,
250
+ id: string,
251
+ outcome: {
252
+ status: "success" | "failure" | "partial";
253
+ agent?: string;
254
+ notes?: string;
255
+ duration?: number;
256
+ recorded_at?: string;
257
+ },
258
+ options?: { cwd?: string },
259
+ ): Promise<{
260
+ record: LoamExpertiseRecord;
261
+ outcome: { status: string; agent?: string; notes?: string; recorded_at?: string };
262
+ total_outcomes: number;
263
+ }>;
264
+ }
265
+
266
+ let _loamApi: LoamProgrammaticApi | undefined;
267
+
268
+ async function loadLoamApi(): Promise<LoamProgrammaticApi> {
269
+ if (!_loamApi) {
270
+ // loam is now bundled in this package (src/tools/loam) rather than a
271
+ // separate @ag-eco/loam-cli dependency. Lazy dynamic import keeps the
272
+ // programmatic API off the hot path. The module's main export
273
+ // (src/tools/loam/index.ts) exposes recordExpertise/queryDomain/
274
+ // searchExpertise/appendOutcome.
275
+ _loamApi = (await import("../tools/loam/index.ts")) as unknown as LoamProgrammaticApi;
276
+ }
277
+ return _loamApi;
278
+ }
279
+
280
+ /**
281
+ * Run a shell command and capture its output.
282
+ */
283
+ async function runCommand(
284
+ cmd: string[],
285
+ cwd: string,
286
+ ): Promise<{ stdout: string; stderr: string; exitCode: number }> {
287
+ const proc = Bun.spawn(cmd, {
288
+ cwd,
289
+ stdout: "pipe",
290
+ stderr: "pipe",
291
+ });
292
+ const stdout = await new Response(proc.stdout).text();
293
+ const stderr = await new Response(proc.stderr).text();
294
+ const exitCode = await proc.exited;
295
+ return { stdout, stderr, exitCode };
296
+ }
297
+
298
+ /**
299
+ * Build an ExpertiseRecord from record() options.
300
+ *
301
+ * CRITICAL MAPPING: --description maps to record.content for convention records,
302
+ * but to record.description for all other types.
303
+ */
304
+ function buildExpertiseRecord(options: {
305
+ type: string;
306
+ name?: string;
307
+ description?: string;
308
+ title?: string;
309
+ rationale?: string;
310
+ tags?: string[];
311
+ classification?: string;
312
+ evidenceBead?: string;
313
+ outcomeStatus?: "success" | "failure" | "partial";
314
+ outcomeDuration?: number;
315
+ outcomeTestResults?: string;
316
+ outcomeAgent?: string;
317
+ }): LoamExpertiseRecord {
318
+ const base = {
319
+ classification: (options.classification ?? "tactical") as
320
+ | "foundational"
321
+ | "tactical"
322
+ | "observational",
323
+ recorded_at: new Date().toISOString(),
324
+ tags: options.tags,
325
+ evidence: options.evidenceBead ? { bead: options.evidenceBead } : undefined,
326
+ outcomes: options.outcomeStatus
327
+ ? [
328
+ {
329
+ status: options.outcomeStatus,
330
+ duration: options.outcomeDuration,
331
+ test_results: options.outcomeTestResults,
332
+ agent: options.outcomeAgent,
333
+ recorded_at: new Date().toISOString(),
334
+ },
335
+ ]
336
+ : undefined,
337
+ };
338
+
339
+ switch (options.type) {
340
+ case "convention":
341
+ return { ...base, type: "convention", content: options.description ?? "" };
342
+ case "pattern":
343
+ return {
344
+ ...base,
345
+ type: "pattern",
346
+ name: options.name ?? "",
347
+ description: options.description ?? "",
348
+ };
349
+ case "failure":
350
+ return {
351
+ ...base,
352
+ type: "failure",
353
+ description: options.description ?? "",
354
+ resolution: "",
355
+ };
356
+ case "decision":
357
+ return {
358
+ ...base,
359
+ type: "decision",
360
+ title: options.title ?? "",
361
+ rationale: options.rationale ?? "",
362
+ };
363
+ case "reference":
364
+ return {
365
+ ...base,
366
+ type: "reference",
367
+ name: options.name ?? "",
368
+ description: options.description ?? "",
369
+ };
370
+ case "guide":
371
+ return {
372
+ ...base,
373
+ type: "guide",
374
+ name: options.name ?? "",
375
+ description: options.description ?? "",
376
+ };
377
+ default:
378
+ return {
379
+ ...base,
380
+ type: "convention",
381
+ content: options.description ?? "",
382
+ } as LoamExpertiseRecord;
383
+ }
384
+ }
385
+
386
+ /**
387
+ * Format search/query results as a plain string for callers that expect string output.
388
+ * Preserves behavior for parseConflictPatterns regex in resolver.ts.
389
+ */
390
+ function formatSearchResults(
391
+ results: Array<{ domain: string; records: LoamExpertiseRecord[] }>,
392
+ ): string {
393
+ const lines: string[] = [];
394
+ for (const result of results) {
395
+ for (const record of result.records) {
396
+ lines.push(formatRecordText(record));
397
+ }
398
+ }
399
+ return lines.join("\n");
400
+ }
401
+
402
+ function formatRecordText(record: LoamExpertiseRecord): string {
403
+ switch (record.type) {
404
+ case "convention":
405
+ return record.content;
406
+ case "pattern":
407
+ return record.description;
408
+ case "failure":
409
+ return record.description;
410
+ case "decision":
411
+ return `${record.title}: ${record.rationale}`;
412
+ case "reference":
413
+ return record.description;
414
+ case "guide":
415
+ return record.description;
416
+ }
417
+ }
418
+
419
+ /**
420
+ * Create a LoamClient bound to the given working directory.
421
+ *
422
+ * @param cwd - Working directory where loam commands should run
423
+ * @returns A LoamClient instance wrapping the loam CLI
424
+ */
425
+ export function createLoamClient(cwd: string): LoamClient {
426
+ async function runLoam(
427
+ args: string[],
428
+ context: string,
429
+ ): Promise<{ stdout: string; stderr: string }> {
430
+ const { stdout, stderr, exitCode } = await runCommand(["lm", ...args], cwd);
431
+ if (exitCode !== 0) {
432
+ throw new AgentError(`loam ${context} failed (exit ${exitCode}): ${stderr.trim()}`);
433
+ }
434
+ return { stdout, stderr };
435
+ }
436
+
437
+ return {
438
+ async prime(domains, format, options) {
439
+ const args = ["prime"];
440
+ if (domains && domains.length > 0) {
441
+ args.push(...domains);
442
+ }
443
+ if (format) {
444
+ args.push("--format", format);
445
+ }
446
+ if (options?.files && options.files.length > 0) {
447
+ args.push("--files", ...options.files);
448
+ }
449
+ if (options?.excludeDomain && options.excludeDomain.length > 0) {
450
+ args.push("--exclude-domain", ...options.excludeDomain);
451
+ }
452
+ if (options?.sortByScore) {
453
+ args.push("--sort-by-score");
454
+ }
455
+ const { stdout } = await runLoam(args, "prime");
456
+ return stdout;
457
+ },
458
+
459
+ async status() {
460
+ const { stdout } = await runLoam(["status", "--json"], "status");
461
+ const trimmed = stdout.trim();
462
+ if (trimmed === "") {
463
+ return { domains: [] };
464
+ }
465
+ try {
466
+ return JSON.parse(trimmed) as LoamStatus;
467
+ } catch {
468
+ throw new AgentError(
469
+ `Failed to parse JSON output from loam status: ${trimmed.slice(0, 200)}`,
470
+ );
471
+ }
472
+ },
473
+
474
+ async record(domain, options) {
475
+ // stdin mode: no programmatic API equivalent, fall back to CLI
476
+ if (options.stdin) {
477
+ const args = ["record", domain, "--type", options.type];
478
+ if (options.description) args.push("--description", options.description);
479
+ args.push("--stdin");
480
+ await runLoam(args, `record ${domain}`);
481
+ return;
482
+ }
483
+
484
+ const expertiseRecord = buildExpertiseRecord(options);
485
+ const api = await loadLoamApi();
486
+ try {
487
+ await api.recordExpertise(domain, expertiseRecord, { cwd });
488
+ } catch (error) {
489
+ if (error instanceof Error && error.message.includes("not found in config")) {
490
+ // Auto-create domain (matching loam CLI 0.6.1+ behavior)
491
+ await runLoam(["add", domain], `add ${domain}`);
492
+ await api.recordExpertise(domain, expertiseRecord, { cwd });
493
+ } else {
494
+ throw new AgentError(
495
+ `loam record ${domain} failed: ${error instanceof Error ? error.message : String(error)}`,
496
+ );
497
+ }
498
+ }
499
+ },
500
+
501
+ async query(domain) {
502
+ if (!domain) {
503
+ throw new AgentError("loam query failed (exit 1): domain argument required");
504
+ }
505
+ try {
506
+ const api = await loadLoamApi();
507
+ const records = await api.queryDomain(domain, { cwd });
508
+ return formatSearchResults([{ domain, records }]);
509
+ } catch (error) {
510
+ throw new AgentError(
511
+ `loam query failed: ${error instanceof Error ? error.message : String(error)}`,
512
+ );
513
+ }
514
+ },
515
+
516
+ async search(query, options) {
517
+ try {
518
+ const api = await loadLoamApi();
519
+ const results = await api.searchExpertise(query, {
520
+ file: options?.file,
521
+ classification: options?.classification,
522
+ outcomeStatus: options?.outcomeStatus,
523
+ sortByScore: options?.sortByScore,
524
+ cwd,
525
+ });
526
+ return formatSearchResults(results);
527
+ } catch (error) {
528
+ throw new AgentError(
529
+ `loam search failed: ${error instanceof Error ? error.message : String(error)}`,
530
+ );
531
+ }
532
+ },
533
+
534
+ async diff(options) {
535
+ const args = ["diff", "--json"];
536
+ if (options?.since) {
537
+ args.push("--since", options.since);
538
+ }
539
+ const { stdout } = await runLoam(args, "diff");
540
+ const trimmed = stdout.trim();
541
+ try {
542
+ return JSON.parse(trimmed) as LoamDiffResult;
543
+ } catch {
544
+ throw new AgentError(`Failed to parse JSON from loam diff: ${trimmed.slice(0, 200)}`);
545
+ }
546
+ },
547
+
548
+ async learn(options) {
549
+ const args = ["learn", "--json"];
550
+ if (options?.since) {
551
+ args.push("--since", options.since);
552
+ }
553
+ const { stdout } = await runLoam(args, "learn");
554
+ const trimmed = stdout.trim();
555
+ try {
556
+ return JSON.parse(trimmed) as LoamLearnResult;
557
+ } catch {
558
+ throw new AgentError(`Failed to parse JSON from loam learn: ${trimmed.slice(0, 200)}`);
559
+ }
560
+ },
561
+
562
+ async prune(options) {
563
+ const args = ["prune", "--json"];
564
+ if (options?.dryRun) {
565
+ args.push("--dry-run");
566
+ }
567
+ const { stdout } = await runLoam(args, "prune");
568
+ const trimmed = stdout.trim();
569
+ try {
570
+ return JSON.parse(trimmed) as LoamPruneResult;
571
+ } catch {
572
+ throw new AgentError(`Failed to parse JSON from loam prune: ${trimmed.slice(0, 200)}`);
573
+ }
574
+ },
575
+
576
+ async doctor(options) {
577
+ const args = ["doctor", "--json"];
578
+ if (options?.fix) {
579
+ args.push("--fix");
580
+ }
581
+ const { stdout } = await runLoam(args, "doctor");
582
+ const trimmed = stdout.trim();
583
+ try {
584
+ return JSON.parse(trimmed) as LoamDoctorResult;
585
+ } catch {
586
+ throw new AgentError(`Failed to parse JSON from loam doctor: ${trimmed.slice(0, 200)}`);
587
+ }
588
+ },
589
+
590
+ async ready(options) {
591
+ const args = ["ready", "--json"];
592
+ if (options?.limit !== undefined) {
593
+ args.push("--limit", String(options.limit));
594
+ }
595
+ if (options?.domain) {
596
+ args.push("--domain", options.domain);
597
+ }
598
+ if (options?.since) {
599
+ args.push("--since", options.since);
600
+ }
601
+ const { stdout } = await runLoam(args, "ready");
602
+ const trimmed = stdout.trim();
603
+ try {
604
+ return JSON.parse(trimmed) as LoamReadyResult;
605
+ } catch {
606
+ throw new AgentError(`Failed to parse JSON from loam ready: ${trimmed.slice(0, 200)}`);
607
+ }
608
+ },
609
+
610
+ async compact(domain, options) {
611
+ const args = ["compact", "--json"];
612
+ if (domain) {
613
+ args.push(domain);
614
+ }
615
+ if (options?.analyze) {
616
+ args.push("--analyze");
617
+ }
618
+ if (options?.apply) {
619
+ args.push("--apply");
620
+ }
621
+ if (options?.auto) {
622
+ args.push("--auto");
623
+ }
624
+ if (options?.dryRun) {
625
+ args.push("--dry-run");
626
+ }
627
+ if (options?.minGroup !== undefined) {
628
+ args.push("--min-group", String(options.minGroup));
629
+ }
630
+ if (options?.maxRecords !== undefined) {
631
+ args.push("--max-records", String(options.maxRecords));
632
+ }
633
+ if (options?.yes) {
634
+ args.push("--yes");
635
+ }
636
+ if (options?.records && options.records.length > 0) {
637
+ args.push("--records", options.records.join(","));
638
+ }
639
+ const { stdout } = await runLoam(args, domain ? `compact ${domain}` : "compact");
640
+ const trimmed = stdout.trim();
641
+ try {
642
+ return JSON.parse(trimmed) as LoamCompactResult;
643
+ } catch {
644
+ throw new AgentError(`Failed to parse JSON from loam compact: ${trimmed.slice(0, 200)}`);
645
+ }
646
+ },
647
+
648
+ async appendOutcome(domain, id, outcome) {
649
+ const api = await loadLoamApi();
650
+ try {
651
+ await api.appendOutcome(
652
+ domain,
653
+ id,
654
+ { ...outcome, recorded_at: new Date().toISOString() },
655
+ { cwd },
656
+ );
657
+ } catch (error) {
658
+ throw new AgentError(
659
+ `loam appendOutcome ${domain}/${id} failed: ${error instanceof Error ? error.message : String(error)}`,
660
+ );
661
+ }
662
+ },
663
+ };
664
+ }