beth-copilot 1.0.18 → 2.0.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 (429) hide show
  1. package/CHANGELOG.md +79 -28
  2. package/README.md +127 -298
  3. package/assets/beth-questioning.png +0 -0
  4. package/assets/yellowstone-beth.png +0 -0
  5. package/bin/cli.js +124 -715
  6. package/dist/__tests__/inject-skills.test.d.ts +9 -0
  7. package/dist/__tests__/inject-skills.test.d.ts.map +1 -0
  8. package/dist/__tests__/inject-skills.test.js +143 -0
  9. package/dist/__tests__/inject-skills.test.js.map +1 -0
  10. package/dist/__tests__/skills/disambiguation.test.d.ts +10 -0
  11. package/dist/__tests__/skills/disambiguation.test.d.ts.map +1 -0
  12. package/dist/__tests__/skills/disambiguation.test.js +192 -0
  13. package/dist/__tests__/skills/disambiguation.test.js.map +1 -0
  14. package/dist/__tests__/skills/hook-injection.test.d.ts +11 -0
  15. package/dist/__tests__/skills/hook-injection.test.d.ts.map +1 -0
  16. package/dist/__tests__/skills/hook-injection.test.js +173 -0
  17. package/dist/__tests__/skills/hook-injection.test.js.map +1 -0
  18. package/dist/__tests__/skills/mapping-completeness.test.d.ts +17 -0
  19. package/dist/__tests__/skills/mapping-completeness.test.d.ts.map +1 -0
  20. package/dist/__tests__/skills/mapping-completeness.test.js +281 -0
  21. package/dist/__tests__/skills/mapping-completeness.test.js.map +1 -0
  22. package/dist/__tests__/skills/pipeline-integration.test.d.ts +18 -0
  23. package/dist/__tests__/skills/pipeline-integration.test.d.ts.map +1 -0
  24. package/dist/__tests__/skills/pipeline-integration.test.js +234 -0
  25. package/dist/__tests__/skills/pipeline-integration.test.js.map +1 -0
  26. package/dist/__tests__/skills/skill-routing.test.d.ts +15 -0
  27. package/dist/__tests__/skills/skill-routing.test.d.ts.map +1 -0
  28. package/dist/__tests__/skills/skill-routing.test.js +723 -0
  29. package/dist/__tests__/skills/skill-routing.test.js.map +1 -0
  30. package/dist/__tests__/skills/trigger-coverage.test.d.ts +24 -0
  31. package/dist/__tests__/skills/trigger-coverage.test.d.ts.map +1 -0
  32. package/dist/__tests__/skills/trigger-coverage.test.js +746 -0
  33. package/dist/__tests__/skills/trigger-coverage.test.js.map +1 -0
  34. package/dist/__tests__/smoke.test.d.ts +8 -0
  35. package/dist/__tests__/smoke.test.d.ts.map +1 -0
  36. package/dist/__tests__/smoke.test.js +62 -0
  37. package/dist/__tests__/smoke.test.js.map +1 -0
  38. package/dist/__tests__/verify-skills.test.d.ts +9 -0
  39. package/dist/__tests__/verify-skills.test.d.ts.map +1 -0
  40. package/dist/__tests__/verify-skills.test.js +78 -0
  41. package/dist/__tests__/verify-skills.test.js.map +1 -0
  42. package/dist/cli/commands/beads.e2e.test.d.ts +15 -0
  43. package/dist/cli/commands/beads.e2e.test.d.ts.map +1 -0
  44. package/dist/cli/commands/beads.e2e.test.js +585 -0
  45. package/dist/cli/commands/beads.e2e.test.js.map +1 -0
  46. package/dist/cli/commands/cli-edge-cases.e2e.test.d.ts +32 -0
  47. package/dist/cli/commands/cli-edge-cases.e2e.test.d.ts.map +1 -0
  48. package/dist/cli/commands/cli-edge-cases.e2e.test.js +162 -0
  49. package/dist/cli/commands/cli-edge-cases.e2e.test.js.map +1 -0
  50. package/dist/cli/commands/close.d.ts +54 -0
  51. package/dist/cli/commands/close.d.ts.map +1 -0
  52. package/dist/cli/commands/close.e2e.test.d.ts +11 -0
  53. package/dist/cli/commands/close.e2e.test.d.ts.map +1 -0
  54. package/dist/cli/commands/close.e2e.test.js +71 -0
  55. package/dist/cli/commands/close.e2e.test.js.map +1 -0
  56. package/dist/cli/commands/close.js +95 -0
  57. package/dist/cli/commands/close.js.map +1 -0
  58. package/dist/cli/commands/close.test.d.ts +13 -0
  59. package/dist/cli/commands/close.test.d.ts.map +1 -0
  60. package/dist/cli/commands/close.test.js +254 -0
  61. package/dist/cli/commands/close.test.js.map +1 -0
  62. package/dist/cli/commands/doctor.d.ts +7 -1
  63. package/dist/cli/commands/doctor.d.ts.map +1 -1
  64. package/dist/cli/commands/doctor.e2e.test.js +3 -59
  65. package/dist/cli/commands/doctor.e2e.test.js.map +1 -1
  66. package/dist/cli/commands/doctor.js +38 -18
  67. package/dist/cli/commands/doctor.js.map +1 -1
  68. package/dist/cli/commands/doctor.test.js +32 -25
  69. package/dist/cli/commands/doctor.test.js.map +1 -1
  70. package/dist/cli/commands/framework-isolation.test.d.ts +30 -0
  71. package/dist/cli/commands/framework-isolation.test.d.ts.map +1 -0
  72. package/dist/cli/commands/framework-isolation.test.js +118 -0
  73. package/dist/cli/commands/framework-isolation.test.js.map +1 -0
  74. package/dist/cli/commands/help.e2e.test.js +5 -9
  75. package/dist/cli/commands/help.e2e.test.js.map +1 -1
  76. package/dist/cli/commands/init-logic.e2e.test.d.ts +37 -0
  77. package/dist/cli/commands/init-logic.e2e.test.d.ts.map +1 -0
  78. package/dist/cli/commands/init-logic.e2e.test.js +315 -0
  79. package/dist/cli/commands/init-logic.e2e.test.js.map +1 -0
  80. package/dist/cli/commands/init.test.js +4 -21
  81. package/dist/cli/commands/init.test.js.map +1 -1
  82. package/dist/cli/commands/land.d.ts +130 -0
  83. package/dist/cli/commands/land.d.ts.map +1 -0
  84. package/dist/cli/commands/land.js +592 -0
  85. package/dist/cli/commands/land.js.map +1 -0
  86. package/dist/cli/commands/land.test.d.ts +19 -0
  87. package/dist/cli/commands/land.test.d.ts.map +1 -0
  88. package/dist/cli/commands/land.test.js +567 -0
  89. package/dist/cli/commands/land.test.js.map +1 -0
  90. package/dist/cli/commands/mcp.e2e.test.js +24 -31
  91. package/dist/cli/commands/mcp.e2e.test.js.map +1 -1
  92. package/dist/cli/commands/pipeline.e2e.test.js +28 -31
  93. package/dist/cli/commands/pipeline.e2e.test.js.map +1 -1
  94. package/dist/cli/commands/pre-push-guard.d.ts +74 -0
  95. package/dist/cli/commands/pre-push-guard.d.ts.map +1 -0
  96. package/dist/cli/commands/pre-push-guard.e2e.test.d.ts +24 -0
  97. package/dist/cli/commands/pre-push-guard.e2e.test.d.ts.map +1 -0
  98. package/dist/cli/commands/pre-push-guard.e2e.test.js +171 -0
  99. package/dist/cli/commands/pre-push-guard.e2e.test.js.map +1 -0
  100. package/dist/cli/commands/pre-push-guard.js +212 -0
  101. package/dist/cli/commands/pre-push-guard.js.map +1 -0
  102. package/dist/cli/commands/pre-push-guard.test.d.ts +14 -0
  103. package/dist/cli/commands/pre-push-guard.test.d.ts.map +1 -0
  104. package/dist/cli/commands/pre-push-guard.test.js +314 -0
  105. package/dist/cli/commands/pre-push-guard.test.js.map +1 -0
  106. package/dist/cli/commands/quickstart-expanded.e2e.test.d.ts +23 -0
  107. package/dist/cli/commands/quickstart-expanded.e2e.test.d.ts.map +1 -0
  108. package/dist/cli/commands/quickstart-expanded.e2e.test.js +152 -0
  109. package/dist/cli/commands/quickstart-expanded.e2e.test.js.map +1 -0
  110. package/dist/cli/commands/quickstart.d.ts +0 -1
  111. package/dist/cli/commands/quickstart.d.ts.map +1 -1
  112. package/dist/cli/commands/quickstart.js +9 -83
  113. package/dist/cli/commands/quickstart.js.map +1 -1
  114. package/dist/cli/commands/quickstart.test.js +8 -129
  115. package/dist/cli/commands/quickstart.test.js.map +1 -1
  116. package/dist/cli/commands/update.d.ts +35 -0
  117. package/dist/cli/commands/update.d.ts.map +1 -0
  118. package/dist/cli/commands/update.e2e.test.d.ts +24 -0
  119. package/dist/cli/commands/update.e2e.test.d.ts.map +1 -0
  120. package/dist/cli/commands/update.e2e.test.js +240 -0
  121. package/dist/cli/commands/update.e2e.test.js.map +1 -0
  122. package/dist/cli/commands/update.js +255 -0
  123. package/dist/cli/commands/update.js.map +1 -0
  124. package/dist/core/agents/frontmatter.test.js +1 -1
  125. package/dist/core/agents/frontmatter.test.js.map +1 -1
  126. package/dist/core/agents/handoffs.test.js +1 -1
  127. package/dist/core/agents/handoffs.test.js.map +1 -1
  128. package/dist/core/agents/loader.d.ts +4 -2
  129. package/dist/core/agents/loader.d.ts.map +1 -1
  130. package/dist/core/agents/loader.js +5 -3
  131. package/dist/core/agents/loader.js.map +1 -1
  132. package/dist/core/agents/loader.test.js +42 -4
  133. package/dist/core/agents/loader.test.js.map +1 -1
  134. package/dist/core/agents/suite.test.js +12 -9
  135. package/dist/core/agents/suite.test.js.map +1 -1
  136. package/dist/core/agents/tools.test.js +15 -9
  137. package/dist/core/agents/tools.test.js.map +1 -1
  138. package/dist/core/agents/types.test.js +1 -1
  139. package/dist/core/agents/types.test.js.map +1 -1
  140. package/dist/core/skills/loader.test.js +1 -1
  141. package/dist/core/skills/loader.test.js.map +1 -1
  142. package/dist/index.d.ts +3 -11
  143. package/dist/index.d.ts.map +1 -1
  144. package/dist/index.js +5 -12
  145. package/dist/index.js.map +1 -1
  146. package/dist/lib/pathValidation.d.ts +0 -5
  147. package/dist/lib/pathValidation.d.ts.map +1 -1
  148. package/dist/lib/pathValidation.js +0 -11
  149. package/dist/lib/pathValidation.js.map +1 -1
  150. package/dist/lib/pathValidation.test.js +2 -14
  151. package/dist/lib/pathValidation.test.js.map +1 -1
  152. package/package.json +13 -10
  153. package/sbom.json +1927 -847
  154. package/templates/.github/agents/beth.agent.md +331 -105
  155. package/templates/.github/agents/developer.agent.md +73 -102
  156. package/templates/.github/agents/product-manager.agent.md +24 -68
  157. package/templates/.github/agents/researcher.agent.md +21 -69
  158. package/templates/.github/agents/security-reviewer.agent.md +39 -82
  159. package/templates/.github/agents/tester.agent.md +44 -65
  160. package/templates/.github/agents/ux-designer.agent.md +25 -76
  161. package/templates/.github/copilot-instructions.md +246 -225
  162. package/templates/.github/copilot-mcp-config.json +12 -0
  163. package/templates/.github/dependabot.yml +68 -0
  164. package/templates/.github/hooks/scripts/inject-skills.mjs +139 -0
  165. package/templates/.github/hooks/scripts/verify-skills.mjs +47 -0
  166. package/templates/.github/hooks/skill-enforcement.json +18 -0
  167. package/templates/.github/pull_request_template.md +48 -0
  168. package/templates/.github/skills/framer-components/SKILL.md +0 -0
  169. package/templates/.github/skills/prd/SKILL.md +0 -0
  170. package/templates/.github/skills/security-analysis/SKILL.md +798 -798
  171. package/templates/.github/skills/shadcn-ui/SKILL.md +561 -561
  172. package/templates/.github/skills/vercel-react-best-practices/AGENTS.md +0 -0
  173. package/templates/.github/skills/vercel-react-best-practices/SKILL.md +0 -0
  174. package/templates/.github/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -0
  175. package/templates/.github/skills/vercel-react-best-practices/rules/advanced-use-latest.md +0 -0
  176. package/templates/.github/skills/vercel-react-best-practices/rules/async-api-routes.md +0 -0
  177. package/templates/.github/skills/vercel-react-best-practices/rules/async-defer-await.md +0 -0
  178. package/templates/.github/skills/vercel-react-best-practices/rules/async-dependencies.md +0 -0
  179. package/templates/.github/skills/vercel-react-best-practices/rules/async-parallel.md +0 -0
  180. package/templates/.github/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -0
  181. package/templates/.github/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -0
  182. package/templates/.github/skills/vercel-react-best-practices/rules/bundle-conditional.md +0 -0
  183. package/templates/.github/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -0
  184. package/templates/.github/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -0
  185. package/templates/.github/skills/vercel-react-best-practices/rules/bundle-preload.md +0 -0
  186. package/templates/.github/skills/vercel-react-best-practices/rules/client-event-listeners.md +0 -0
  187. package/templates/.github/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -0
  188. package/templates/.github/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -0
  189. package/templates/.github/skills/vercel-react-best-practices/rules/client-swr-dedup.md +0 -0
  190. package/templates/.github/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -0
  191. package/templates/.github/skills/vercel-react-best-practices/rules/js-cache-function-results.md +0 -0
  192. package/templates/.github/skills/vercel-react-best-practices/rules/js-cache-property-access.md +0 -0
  193. package/templates/.github/skills/vercel-react-best-practices/rules/js-cache-storage.md +0 -0
  194. package/templates/.github/skills/vercel-react-best-practices/rules/js-combine-iterations.md +0 -0
  195. package/templates/.github/skills/vercel-react-best-practices/rules/js-early-exit.md +0 -0
  196. package/templates/.github/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -0
  197. package/templates/.github/skills/vercel-react-best-practices/rules/js-index-maps.md +0 -0
  198. package/templates/.github/skills/vercel-react-best-practices/rules/js-length-check-first.md +0 -0
  199. package/templates/.github/skills/vercel-react-best-practices/rules/js-min-max-loop.md +0 -0
  200. package/templates/.github/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -0
  201. package/templates/.github/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -0
  202. package/templates/.github/skills/vercel-react-best-practices/rules/rendering-activity.md +0 -0
  203. package/templates/.github/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -0
  204. package/templates/.github/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -0
  205. package/templates/.github/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -0
  206. package/templates/.github/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -0
  207. package/templates/.github/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -0
  208. package/templates/.github/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -0
  209. package/templates/.github/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -0
  210. package/templates/.github/skills/vercel-react-best-practices/rules/rerender-dependencies.md +0 -0
  211. package/templates/.github/skills/vercel-react-best-practices/rules/rerender-derived-state.md +0 -0
  212. package/templates/.github/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -0
  213. package/templates/.github/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -0
  214. package/templates/.github/skills/vercel-react-best-practices/rules/rerender-memo.md +0 -0
  215. package/templates/.github/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +0 -0
  216. package/templates/.github/skills/vercel-react-best-practices/rules/rerender-transitions.md +0 -0
  217. package/templates/.github/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -0
  218. package/templates/.github/skills/vercel-react-best-practices/rules/server-auth-actions.md +0 -0
  219. package/templates/.github/skills/vercel-react-best-practices/rules/server-cache-lru.md +0 -0
  220. package/templates/.github/skills/vercel-react-best-practices/rules/server-cache-react.md +0 -0
  221. package/templates/.github/skills/vercel-react-best-practices/rules/server-dedup-props.md +0 -0
  222. package/templates/.github/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -0
  223. package/templates/.github/skills/vercel-react-best-practices/rules/server-serialization.md +0 -0
  224. package/templates/.github/skills/web-design-guidelines/SKILL.md +0 -0
  225. package/templates/.vscode/settings.json +16 -16
  226. package/templates/AGENTS.md +103 -54
  227. package/templates/Backlog.md +80 -80
  228. package/templates/mcp.json.example +0 -3
  229. package/assets/beth-portrait-small.txt +0 -13
  230. package/assets/beth-portrait.txt +0 -60
  231. package/bin/beth-animation.sh +0 -155
  232. package/bin/lib/animation.js +0 -189
  233. package/bin/lib/pathValidation.js +0 -233
  234. package/bin/lib/pathValidation.test.js +0 -280
  235. package/dist/cli/commands/client-config.d.ts +0 -31
  236. package/dist/cli/commands/client-config.d.ts.map +0 -1
  237. package/dist/cli/commands/client-config.e2e.test.d.ts +0 -15
  238. package/dist/cli/commands/client-config.e2e.test.d.ts.map +0 -1
  239. package/dist/cli/commands/client-config.e2e.test.js +0 -556
  240. package/dist/cli/commands/client-config.e2e.test.js.map +0 -1
  241. package/dist/cli/commands/client-config.js +0 -73
  242. package/dist/cli/commands/client-config.js.map +0 -1
  243. package/dist/cli/commands/client-config.test.d.ts +0 -6
  244. package/dist/cli/commands/client-config.test.d.ts.map +0 -1
  245. package/dist/cli/commands/client-config.test.js +0 -133
  246. package/dist/cli/commands/client-config.test.js.map +0 -1
  247. package/dist/cli/commands/init-quickstart.e2e.test.d.ts +0 -11
  248. package/dist/cli/commands/init-quickstart.e2e.test.d.ts.map +0 -1
  249. package/dist/cli/commands/init-quickstart.e2e.test.js +0 -221
  250. package/dist/cli/commands/init-quickstart.e2e.test.js.map +0 -1
  251. package/dist/core/context.d.ts +0 -171
  252. package/dist/core/context.d.ts.map +0 -1
  253. package/dist/core/context.js +0 -353
  254. package/dist/core/context.js.map +0 -1
  255. package/dist/core/context.test.d.ts +0 -8
  256. package/dist/core/context.test.d.ts.map +0 -1
  257. package/dist/core/context.test.js +0 -253
  258. package/dist/core/context.test.js.map +0 -1
  259. package/dist/core/handoffs.d.ts +0 -151
  260. package/dist/core/handoffs.d.ts.map +0 -1
  261. package/dist/core/handoffs.js +0 -220
  262. package/dist/core/handoffs.js.map +0 -1
  263. package/dist/core/handoffs.test.d.ts +0 -8
  264. package/dist/core/handoffs.test.d.ts.map +0 -1
  265. package/dist/core/handoffs.test.js +0 -231
  266. package/dist/core/handoffs.test.js.map +0 -1
  267. package/dist/core/orchestrator.d.ts +0 -246
  268. package/dist/core/orchestrator.d.ts.map +0 -1
  269. package/dist/core/orchestrator.js +0 -514
  270. package/dist/core/orchestrator.js.map +0 -1
  271. package/dist/core/orchestrator.test.d.ts +0 -8
  272. package/dist/core/orchestrator.test.d.ts.map +0 -1
  273. package/dist/core/orchestrator.test.js +0 -517
  274. package/dist/core/orchestrator.test.js.map +0 -1
  275. package/dist/core/router.d.ts +0 -102
  276. package/dist/core/router.d.ts.map +0 -1
  277. package/dist/core/router.js +0 -178
  278. package/dist/core/router.js.map +0 -1
  279. package/dist/core/router.test.d.ts +0 -8
  280. package/dist/core/router.test.d.ts.map +0 -1
  281. package/dist/core/router.test.js +0 -215
  282. package/dist/core/router.test.js.map +0 -1
  283. package/dist/init.test.js +0 -288
  284. package/dist/providers/azure.d.ts +0 -147
  285. package/dist/providers/azure.d.ts.map +0 -1
  286. package/dist/providers/azure.js +0 -491
  287. package/dist/providers/azure.js.map +0 -1
  288. package/dist/providers/azure.test.d.ts +0 -11
  289. package/dist/providers/azure.test.d.ts.map +0 -1
  290. package/dist/providers/azure.test.js +0 -330
  291. package/dist/providers/azure.test.js.map +0 -1
  292. package/dist/providers/config.d.ts +0 -87
  293. package/dist/providers/config.d.ts.map +0 -1
  294. package/dist/providers/config.js +0 -193
  295. package/dist/providers/config.js.map +0 -1
  296. package/dist/providers/config.test.d.ts +0 -7
  297. package/dist/providers/config.test.d.ts.map +0 -1
  298. package/dist/providers/config.test.js +0 -370
  299. package/dist/providers/config.test.js.map +0 -1
  300. package/dist/providers/index.d.ts +0 -18
  301. package/dist/providers/index.d.ts.map +0 -1
  302. package/dist/providers/index.js +0 -14
  303. package/dist/providers/index.js.map +0 -1
  304. package/dist/providers/interface.d.ts +0 -191
  305. package/dist/providers/interface.d.ts.map +0 -1
  306. package/dist/providers/interface.js +0 -94
  307. package/dist/providers/interface.js.map +0 -1
  308. package/dist/providers/retry.d.ts +0 -128
  309. package/dist/providers/retry.d.ts.map +0 -1
  310. package/dist/providers/retry.js +0 -205
  311. package/dist/providers/retry.js.map +0 -1
  312. package/dist/providers/retry.test.d.ts +0 -7
  313. package/dist/providers/retry.test.d.ts.map +0 -1
  314. package/dist/providers/retry.test.js +0 -439
  315. package/dist/providers/retry.test.js.map +0 -1
  316. package/dist/providers/streaming.d.ts +0 -157
  317. package/dist/providers/streaming.d.ts.map +0 -1
  318. package/dist/providers/streaming.js +0 -233
  319. package/dist/providers/streaming.js.map +0 -1
  320. package/dist/providers/streaming.test.d.ts +0 -7
  321. package/dist/providers/streaming.test.d.ts.map +0 -1
  322. package/dist/providers/streaming.test.js +0 -372
  323. package/dist/providers/streaming.test.js.map +0 -1
  324. package/dist/providers/types.d.ts +0 -209
  325. package/dist/providers/types.d.ts.map +0 -1
  326. package/dist/providers/types.js +0 -53
  327. package/dist/providers/types.js.map +0 -1
  328. package/dist/providers/types.test.d.ts +0 -7
  329. package/dist/providers/types.test.d.ts.map +0 -1
  330. package/dist/providers/types.test.js +0 -141
  331. package/dist/providers/types.test.js.map +0 -1
  332. package/dist/tools/cli/beads.d.ts +0 -27
  333. package/dist/tools/cli/beads.d.ts.map +0 -1
  334. package/dist/tools/cli/beads.js +0 -172
  335. package/dist/tools/cli/beads.js.map +0 -1
  336. package/dist/tools/cli/beads.test.d.ts +0 -8
  337. package/dist/tools/cli/beads.test.d.ts.map +0 -1
  338. package/dist/tools/cli/beads.test.js +0 -264
  339. package/dist/tools/cli/beads.test.js.map +0 -1
  340. package/dist/tools/cli/editFile.d.ts +0 -17
  341. package/dist/tools/cli/editFile.d.ts.map +0 -1
  342. package/dist/tools/cli/editFile.js +0 -125
  343. package/dist/tools/cli/editFile.js.map +0 -1
  344. package/dist/tools/cli/editFile.test.d.ts +0 -8
  345. package/dist/tools/cli/editFile.test.d.ts.map +0 -1
  346. package/dist/tools/cli/editFile.test.js +0 -177
  347. package/dist/tools/cli/editFile.test.js.map +0 -1
  348. package/dist/tools/cli/readFile.d.ts +0 -25
  349. package/dist/tools/cli/readFile.d.ts.map +0 -1
  350. package/dist/tools/cli/readFile.js +0 -118
  351. package/dist/tools/cli/readFile.js.map +0 -1
  352. package/dist/tools/cli/readFile.test.d.ts +0 -8
  353. package/dist/tools/cli/readFile.test.d.ts.map +0 -1
  354. package/dist/tools/cli/readFile.test.js +0 -194
  355. package/dist/tools/cli/readFile.test.js.map +0 -1
  356. package/dist/tools/cli/search.d.ts +0 -16
  357. package/dist/tools/cli/search.d.ts.map +0 -1
  358. package/dist/tools/cli/search.js +0 -261
  359. package/dist/tools/cli/search.js.map +0 -1
  360. package/dist/tools/cli/search.test.d.ts +0 -8
  361. package/dist/tools/cli/search.test.d.ts.map +0 -1
  362. package/dist/tools/cli/search.test.js +0 -172
  363. package/dist/tools/cli/search.test.js.map +0 -1
  364. package/dist/tools/cli/subagent.d.ts +0 -43
  365. package/dist/tools/cli/subagent.d.ts.map +0 -1
  366. package/dist/tools/cli/subagent.js +0 -99
  367. package/dist/tools/cli/subagent.js.map +0 -1
  368. package/dist/tools/cli/subagent.test.d.ts +0 -8
  369. package/dist/tools/cli/subagent.test.d.ts.map +0 -1
  370. package/dist/tools/cli/subagent.test.js +0 -190
  371. package/dist/tools/cli/subagent.test.js.map +0 -1
  372. package/dist/tools/cli/terminal.d.ts +0 -19
  373. package/dist/tools/cli/terminal.d.ts.map +0 -1
  374. package/dist/tools/cli/terminal.js +0 -164
  375. package/dist/tools/cli/terminal.js.map +0 -1
  376. package/dist/tools/cli/terminal.test.d.ts +0 -8
  377. package/dist/tools/cli/terminal.test.d.ts.map +0 -1
  378. package/dist/tools/cli/terminal.test.js +0 -161
  379. package/dist/tools/cli/terminal.test.js.map +0 -1
  380. package/dist/tools/index.d.ts +0 -25
  381. package/dist/tools/index.d.ts.map +0 -1
  382. package/dist/tools/index.js +0 -41
  383. package/dist/tools/index.js.map +0 -1
  384. package/dist/tools/interface.d.ts +0 -64
  385. package/dist/tools/interface.d.ts.map +0 -1
  386. package/dist/tools/interface.js +0 -37
  387. package/dist/tools/interface.js.map +0 -1
  388. package/dist/tools/interface.test.d.ts +0 -7
  389. package/dist/tools/interface.test.d.ts.map +0 -1
  390. package/dist/tools/interface.test.js +0 -179
  391. package/dist/tools/interface.test.js.map +0 -1
  392. package/dist/tools/mcp/bridge.d.ts +0 -48
  393. package/dist/tools/mcp/bridge.d.ts.map +0 -1
  394. package/dist/tools/mcp/bridge.js +0 -128
  395. package/dist/tools/mcp/bridge.js.map +0 -1
  396. package/dist/tools/mcp/bridge.test.d.ts +0 -8
  397. package/dist/tools/mcp/bridge.test.d.ts.map +0 -1
  398. package/dist/tools/mcp/bridge.test.js +0 -300
  399. package/dist/tools/mcp/bridge.test.js.map +0 -1
  400. package/dist/tools/mcp/client.d.ts +0 -135
  401. package/dist/tools/mcp/client.d.ts.map +0 -1
  402. package/dist/tools/mcp/client.js +0 -263
  403. package/dist/tools/mcp/client.js.map +0 -1
  404. package/dist/tools/mcp/client.test.d.ts +0 -8
  405. package/dist/tools/mcp/client.test.d.ts.map +0 -1
  406. package/dist/tools/mcp/client.test.js +0 -390
  407. package/dist/tools/mcp/client.test.js.map +0 -1
  408. package/dist/tools/registry.d.ts +0 -82
  409. package/dist/tools/registry.d.ts.map +0 -1
  410. package/dist/tools/registry.js +0 -99
  411. package/dist/tools/registry.js.map +0 -1
  412. package/dist/tools/registry.test.d.ts +0 -7
  413. package/dist/tools/registry.test.d.ts.map +0 -1
  414. package/dist/tools/registry.test.js +0 -199
  415. package/dist/tools/registry.test.js.map +0 -1
  416. package/dist/tools/suite.test.d.ts +0 -11
  417. package/dist/tools/suite.test.d.ts.map +0 -1
  418. package/dist/tools/suite.test.js +0 -119
  419. package/dist/tools/suite.test.js.map +0 -1
  420. package/dist/tools/types.d.ts +0 -75
  421. package/dist/tools/types.d.ts.map +0 -1
  422. package/dist/tools/types.js +0 -30
  423. package/dist/tools/types.js.map +0 -1
  424. package/dist/tools/types.test.d.ts +0 -7
  425. package/dist/tools/types.test.d.ts.map +0 -1
  426. package/dist/tools/types.test.js +0 -178
  427. package/dist/tools/types.test.js.map +0 -1
  428. package/templates/.vscode/mcp.json +0 -20
  429. package/templates/CLAUDE.md +0 -129
package/bin/cli.js CHANGED
@@ -2,10 +2,9 @@
2
2
 
3
3
  import { fileURLToPath } from 'url';
4
4
  import { dirname, join, relative } from 'path';
5
- import { existsSync, mkdirSync, readdirSync, statSync, copyFileSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
5
+ import { existsSync, mkdirSync, readdirSync, statSync, copyFileSync, readFileSync, writeFileSync, unlinkSync, chmodSync } from 'fs';
6
6
  import { createRequire } from 'module';
7
7
  import { execSync, spawn } from 'child_process';
8
- import { validateBeadsPath, validateBinaryPath } from './lib/pathValidation.js';
9
8
 
10
9
  const require = createRequire(import.meta.url);
11
10
  const __filename = fileURLToPath(import.meta.url);
@@ -518,59 +517,6 @@ async function checkForUpdates() {
518
517
  }
519
518
  }
520
519
 
521
- function getBeadsPath() {
522
- // Check if bd is available in PATH
523
- try {
524
- logDebug('Checking if bd is in PATH...');
525
- execSync('bd --version', { stdio: 'ignore' });
526
- logDebug('Found bd in PATH');
527
- return 'bd';
528
- } catch {
529
- logDebug('bd not in PATH, checking common locations...');
530
- // Check common installation paths based on platform
531
- const homeDir = process.env.HOME || process.env.USERPROFILE || '';
532
- const isWindows = process.platform === 'win32';
533
-
534
- const commonPaths = isWindows ? [
535
- // Windows: npm global, Go bin, local apps
536
- join(process.env.APPDATA || '', 'npm', 'bd.cmd'),
537
- join(homeDir, 'AppData', 'Roaming', 'npm', 'bd.cmd'),
538
- join(homeDir, 'AppData', 'Local', 'Microsoft', 'WindowsApps', 'bd.exe'),
539
- join(homeDir, 'go', 'bin', 'bd.exe'),
540
- join(process.env.GOPATH || join(homeDir, 'go'), 'bin', 'bd.exe'),
541
- ] : [
542
- // Unix: homebrew, npm global, go bin, local bin
543
- '/opt/homebrew/bin/bd',
544
- '/usr/local/bin/bd',
545
- join(homeDir, '.local', 'bin', 'bd'),
546
- join(homeDir, 'bin', 'bd'),
547
- join(homeDir, '.npm-global', 'bin', 'bd'),
548
- join(homeDir, 'go', 'bin', 'bd'),
549
- join(process.env.GOPATH || join(homeDir, 'go'), 'bin', 'bd'),
550
- ];
551
-
552
- for (const bdPath of commonPaths) {
553
- logDebug(`Checking: ${bdPath}`);
554
- if (existsSync(bdPath)) {
555
- logDebug(`Found at: ${bdPath}`);
556
- return bdPath;
557
- }
558
- }
559
-
560
- logDebug('bd not found in any common location');
561
- return null;
562
- }
563
- }
564
-
565
- function isBeadsInstalled() {
566
- return getBeadsPath() !== null;
567
- }
568
-
569
- function isBeadsInitialized(cwd) {
570
- // Check if .beads directory exists in the project
571
- return existsSync(join(cwd, '.beads'));
572
- }
573
-
574
520
  async function promptYesNo(question) {
575
521
  const readline = await import('readline');
576
522
  const rl = readline.createInterface({
@@ -601,178 +547,46 @@ async function promptForInput(question) {
601
547
  });
602
548
  }
603
549
 
604
- /**
605
- * Installs the beads CLI globally via npm.
606
- *
607
- * SECURITY NOTE - shell:true usage:
608
- * - Required for cross-platform npm execution (npm.cmd on Windows, npm on Unix)
609
- * - Arguments are HARDCODED - no user input is passed to the shell
610
- * - Command injection risk: NONE (no dynamic/user-supplied values)
611
- *
612
- * Alternative considered: Using platform-specific binary names (npm.cmd vs npm)
613
- * would eliminate shell:true but adds complexity and edge cases for non-standard installs.
614
- *
615
- * @returns {Promise<boolean>} True if installation succeeded and was verified
616
- */
617
- async function installBeads() {
618
- const isWindows = process.platform === 'win32';
619
- const isMac = process.platform === 'darwin';
620
-
621
- log('\nInstalling beads CLI via npm...', COLORS.cyan);
622
- logInfo('npm install -g @beads/bd');
623
-
624
- // SECURITY: shell:true is required for cross-platform npm execution.
625
- // All arguments are hardcoded constants - no user input reaches the shell.
626
- return new Promise((resolve) => {
627
- const child = spawn('npm', ['install', '-g', '@beads/bd'], {
628
- stdio: 'inherit',
629
- shell: true
630
- });
631
-
632
- child.on('close', (code) => {
633
- if (code === 0) {
634
- // CRITICAL: Verify installation actually worked before claiming success
635
- // npm can exit 0 even when the package isn't properly installed
636
- const verifiedPath = getBeadsPath();
637
- if (verifiedPath) {
638
- logSuccess('beads CLI installed and verified!');
639
- resolve(true);
640
- } else {
641
- logWarning('npm reported success but beads CLI not found in PATH.');
642
- logInfo('This can happen if npm global bin is not in your PATH.');
643
- if (globalThis.VERBOSE) {
644
- showPathDiagnostics();
645
- } else {
646
- logInfo('Run with --verbose for PATH diagnostics.');
647
- }
648
- console.log('');
649
- showBeadsAlternatives(isWindows, isMac);
650
- resolve(false);
651
- }
652
- } else {
653
- logError('npm install failed.');
654
- console.log('');
655
- showBeadsAlternatives(isWindows, isMac);
656
- resolve(false);
657
- }
658
- });
659
-
660
- child.on('error', () => {
661
- logError('Failed to run npm.');
662
- logInfo('Make sure npm is installed and in your PATH.');
663
- resolve(false);
664
- });
665
- });
666
- }
667
-
668
- function showBeadsAlternatives(isWindows, isMac) {
669
- logInfo('Alternative installation methods:');
670
- if (isWindows) {
671
- logInfo(' PowerShell: irm https://raw.githubusercontent.com/steveyegge/beads/main/install.ps1 | iex');
672
- logInfo(' Go: go install github.com/steveyegge/beads/cmd/bd@latest');
673
- } else {
674
- if (isMac) {
675
- logInfo(' Homebrew: brew install beads');
676
- }
677
- logInfo(' Script: curl -fsSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash');
678
- logInfo(' Go: go install github.com/steveyegge/beads/cmd/bd@latest');
679
- }
680
- logInfo('');
681
- logInfo('Learn more: https://github.com/steveyegge/beads');
682
- }
550
+ const BETH_GUARD_BEGIN = '# --- BEGIN BETH GUARD ---';
551
+ const BETH_GUARD_END = '# --- END BETH GUARD ---';
683
552
 
684
553
  /**
685
- * Initializes beads in the current project directory.
686
- *
687
- * SECURITY NOTE - shell:true usage:
688
- * - bdPath is validated via getBeadsPath() which only returns paths that:
689
- * 1. Pass execSync('bd --version') verification, OR
690
- * 2. Exist on disk (verified via existsSync) from a HARDCODED list of paths
691
- * - Arguments are HARDCODED ('init') - no user input is passed to the shell
692
- * - Command injection risk: LOW (bdPath is validated, no user input in args)
693
- *
694
- * The shell:true is used for PATH resolution consistency, though it could be
695
- * eliminated since we have an absolute path. Kept for consistency with other
696
- * spawn calls and to handle edge cases in shell script wrappers.
697
- *
698
- * @param {string} cwd - Current working directory (validated by caller)
699
- * @returns {Promise<boolean>} True if initialization succeeded
554
+ * Generate the shell script to append to the pre-push hook.
555
+ * Pure shell — no Node dependency at hook time for speed.
700
556
  */
701
- async function initializeBeads(cwd) {
702
- log('\nInitializing beads in project...', COLORS.cyan);
703
-
704
- const bdPath = getBeadsPath();
705
- if (!bdPath) {
706
- logWarning('Failed to initialize beads. Run manually: bd init');
707
- return false;
708
- }
709
-
710
- // SECURITY: bdPath is validated by getBeadsPath() (existsSync check).
711
- // Only 'init' argument is passed - no user input reaches the shell.
712
- return new Promise((resolve) => {
713
- const child = spawn(bdPath, ['init'], {
714
- stdio: 'inherit',
715
- shell: true,
716
- cwd
717
- });
718
-
719
- child.on('close', (code) => {
720
- if (code === 0) {
721
- logSuccess('beads initialized successfully!');
722
- resolve(true);
723
- } else {
724
- logWarning('Failed to initialize beads. Run manually: bd init');
725
- resolve(false);
726
- }
727
- });
728
-
729
- child.on('error', () => {
730
- logWarning('Failed to initialize beads. Run manually: bd init');
731
- resolve(false);
732
- });
733
- });
734
- }
735
-
736
- /**
737
- * Runs `bd doctor` to verify beads configuration health.
738
- *
739
- * SECURITY NOTE - shell:true usage:
740
- * - bdPath is validated via getBeadsPath() (same as initializeBeads)
741
- * - Arguments are HARDCODED ('doctor') - no user input is passed to the shell
742
- * - Command injection risk: LOW (bdPath is validated, no user input in args)
743
- *
744
- * @returns {Promise<boolean>} True if bd doctor passed
745
- */
746
- async function runBeadsDoctor() {
747
- log('\nRunning beads doctor to verify configuration...', COLORS.cyan);
748
-
749
- const bdPath = getBeadsPath();
750
- if (!bdPath) {
751
- logWarning('Cannot run beads doctor: bd not found.');
752
- return false;
753
- }
754
-
755
- return new Promise((resolve) => {
756
- const child = spawn(bdPath, ['doctor'], {
757
- stdio: 'inherit',
758
- shell: true,
759
- });
760
-
761
- child.on('close', (code) => {
762
- if (code === 0) {
763
- logSuccess('beads doctor passed!');
764
- resolve(true);
765
- } else {
766
- logWarning('beads doctor reported issues. Run "bd doctor" manually to investigate.');
767
- resolve(false);
768
- }
769
- });
770
-
771
- child.on('error', () => {
772
- logWarning('Failed to run beads doctor. Run "bd doctor" manually.');
773
- resolve(false);
774
- });
775
- });
557
+ function generateGuardScript() {
558
+ return `
559
+ ${BETH_GUARD_BEGIN}
560
+ # Branch discipline enforcement — installed by beth-copilot
561
+ # Bypass: BETH_SKIP_PUSH_GUARD=1 git push
562
+ if [ "\$BETH_SKIP_PUSH_GUARD" = "1" ]; then
563
+ echo "⚠ Pre-push guard bypassed (BETH_SKIP_PUSH_GUARD=1)" >&2
564
+ else
565
+ _beth_branch=\$(git branch --show-current 2>/dev/null)
566
+
567
+ # Block pushes from protected branches
568
+ case "\$_beth_branch" in
569
+ main|master)
570
+ echo "✗ Pushing from '\$_beth_branch' is blocked. Work on an epic branch." >&2
571
+ echo " Set BETH_SKIP_PUSH_GUARD=1 to bypass." >&2
572
+ exit 1
573
+ ;;
574
+ esac
575
+
576
+ # Warn if not on an epic or release branch
577
+ case "\$_beth_branch" in
578
+ epic/*) ;;
579
+ release/*) ;;
580
+ "")
581
+ echo "⚠ Detached HEAD — no branch name. Proceeding anyway." >&2
582
+ ;;
583
+ *)
584
+ echo "⚠ Branch '\$_beth_branch' doesn't follow the epic/<id> convention." >&2
585
+ ;;
586
+ esac
587
+ fi
588
+ ${BETH_GUARD_END}
589
+ `;
776
590
  }
777
591
 
778
592
  function showHelp() {
@@ -782,65 +596,43 @@ function showHelp() {
782
596
  ${COLORS.bright}Usage:${COLORS.reset}
783
597
  npx beth-copilot init [options] Initialize Beth in current directory
784
598
  npx beth-copilot doctor Check system health and dependencies
785
- npx beth-copilot quickstart Run init + doctor + beads setup
599
+ npx beth-copilot land [opts] Automated session completion (test, commit, push)
600
+ npx beth-copilot pre-push-guard Run branch discipline checks (used by git hook)
601
+ npx beth-copilot update [options] Update project files to latest templates
602
+ npx beth-copilot quickstart Run init + doctor
786
603
  npx beth-copilot help Show this help message
787
604
 
788
605
  ${COLORS.bright}Options:${COLORS.reset}
789
606
  --force Overwrite existing files
790
607
  --skip-backlog Don't create Backlog.md
791
- --skip-mcp Don't install MCP server configs
792
- --skip-beads Skip beads check (not recommended)
608
+ --skip-mcp Don't create mcp.json.example
793
609
  --verbose Show detailed diagnostics on errors
794
- --client <type> Skip interactive prompt. Values:
795
- vscode, copilot-cli, claude-code, all
610
+ --check-only Check for updates without modifying files
796
611
 
797
612
  ${COLORS.bright}Examples:${COLORS.reset}
798
- npx beth-copilot init Set up Beth (interactive client selection)
799
- npx beth-copilot init --client vscode VS Code + Copilot only
800
- npx beth-copilot init --client claude-code Claude Code only
801
- npx beth-copilot init --client all All clients
613
+ npx beth-copilot init Set up Beth in current project
802
614
  npx beth-copilot init --force Overwrite existing Beth files
803
615
  npx beth-copilot doctor Verify installation health
804
616
 
805
617
  ${COLORS.bright}What gets installed:${COLORS.reset}
806
- ${COLORS.dim}Shared (all clients):${COLORS.reset}
807
- .github/skills/ Domain knowledge modules
808
- AGENTS.md Workflow documentation
809
- Backlog.md Task tracking file
810
-
811
- ${COLORS.dim}VS Code + GitHub Copilot:${COLORS.reset}
812
- .github/agents/ 7 specialized AI agents
813
- .github/copilot-instructions.md Copilot configuration
814
- .vscode/settings.json Recommended VS Code settings
815
- .vscode/mcp.json MCP servers (beads, shadcn, playwright, deepwiki)
816
-
817
- ${COLORS.dim}GitHub Copilot CLI:${COLORS.reset}
818
- .github/copilot-instructions.md Copilot configuration
819
-
820
- ${COLORS.dim}Claude Code:${COLORS.reset}
821
- CLAUDE.md Claude Code instructions
822
-
823
- ${COLORS.bright}Supported clients:${COLORS.reset}
824
- VS Code with GitHub Copilot Full agent orchestration with MCP
825
- GitHub Copilot CLI Terminal-based with bd CLI
826
- Claude Code CLAUDE.md + bd setup claude hooks
618
+ .github/agents/ 7 specialized AI agents
619
+ .github/skills/ 8 domain knowledge modules
620
+ .github/copilot-instructions.md Copilot configuration
621
+ .vscode/settings.json Recommended VS Code settings
622
+ AGENTS.md Workflow documentation
623
+ Backlog.md Task tracking file
624
+ mcp.json.example Optional MCP server config
625
+
626
+ ${COLORS.bright}After installation:${COLORS.reset}
627
+ 1. Open project in VS Code
628
+ 2. Open Copilot Chat (Ctrl+Alt+I / Cmd+Alt+I)
629
+ 3. Type @Beth to start working
827
630
 
828
631
  ${COLORS.bright}Documentation:${COLORS.reset}
829
632
  https://github.com/stephschofield/beth
830
633
  `);
831
634
  }
832
635
 
833
- /**
834
- * Persist client selection to .github/.beth-client.json
835
- * So quickstart and other commands know which client was configured.
836
- */
837
- function persistClientConfig(cwd, clients) {
838
- const configDir = join(cwd, '.github');
839
- const configPath = join(configDir, '.beth-client.json');
840
- mkdirSync(configDir, { recursive: true });
841
- writeFileSync(configPath, JSON.stringify(clients, null, 2) + '\n');
842
- }
843
-
844
636
  function copyDirRecursive(src, dest, options = {}) {
845
637
  const { force = false, copiedFiles = [] } = options;
846
638
 
@@ -889,149 +681,8 @@ function copyDirRecursive(src, dest, options = {}) {
889
681
  return copiedFiles;
890
682
  }
891
683
 
892
- /**
893
- * Prompt the user to select their AI coding client(s).
894
- * Returns an object with boolean flags for each client.
895
- */
896
- async function promptForClient() {
897
- console.log('');
898
- log('Which AI coding tool are you using?', COLORS.bright);
899
- console.log('');
900
- console.log(` ${COLORS.cyan}[1]${COLORS.reset} VS Code with GitHub Copilot`);
901
- console.log(` ${COLORS.cyan}[2]${COLORS.reset} GitHub Copilot CLI (terminal)`);
902
- console.log(` ${COLORS.cyan}[3]${COLORS.reset} Claude Code`);
903
- console.log(` ${COLORS.cyan}[a]${COLORS.reset} All of the above`);
904
- console.log('');
905
-
906
- const answer = await promptForInput('Enter selection (1/2/3/a, or comma-separated e.g. 1,3):');
907
-
908
- if (!answer || answer.toLowerCase() === 'a') {
909
- return { vscode: true, copilotCli: true, claudeCode: true };
910
- }
911
-
912
- const selections = answer.split(',').map(s => s.trim());
913
- return {
914
- vscode: selections.includes('1'),
915
- copilotCli: selections.includes('2'),
916
- claudeCode: selections.includes('3'),
917
- };
918
- }
919
-
920
- /**
921
- * Parse --client flag value into client selection object.
922
- */
923
- function parseClientFlag(clientArg) {
924
- if (!clientArg || clientArg === 'all') {
925
- return { vscode: true, copilotCli: true, claudeCode: true };
926
- }
927
- return {
928
- vscode: clientArg === 'vscode',
929
- copilotCli: clientArg === 'copilot-cli',
930
- claudeCode: clientArg === 'claude-code',
931
- };
932
- }
933
-
934
- /**
935
- * Install beads-mcp (MCP server) for VS Code integration.
936
- *
937
- * SECURITY NOTE - shell:true usage:
938
- * - Required for cross-platform uv/pip execution
939
- * - Arguments are HARDCODED - no user input is passed to the shell
940
- * - Command injection risk: NONE (no dynamic/user-supplied values)
941
- */
942
- async function installBeadsMcp() {
943
- log('\nInstalling beads-mcp (MCP server for VS Code)...', COLORS.cyan);
944
-
945
- // Try uv first, then pip
946
- const installers = [
947
- { cmd: 'uv', args: ['tool', 'install', 'beads-mcp'], label: 'uv tool install beads-mcp' },
948
- { cmd: 'pip', args: ['install', 'beads-mcp'], label: 'pip install beads-mcp' },
949
- ];
950
-
951
- for (const installer of installers) {
952
- try {
953
- execSync(`${installer.cmd} --version`, { stdio: 'ignore' });
954
- } catch {
955
- logDebug(`${installer.cmd} not found, trying next installer...`);
956
- continue;
957
- }
958
-
959
- logInfo(installer.label);
960
-
961
- // SECURITY: All arguments are hardcoded constants.
962
- return new Promise((resolve) => {
963
- const child = spawn(installer.cmd, installer.args, {
964
- stdio: 'inherit',
965
- shell: true,
966
- });
967
-
968
- child.on('close', (code) => {
969
- if (code === 0) {
970
- logSuccess('beads-mcp installed!');
971
- resolve(true);
972
- } else {
973
- logWarning(`${installer.label} failed.`);
974
- resolve(false);
975
- }
976
- });
977
-
978
- child.on('error', () => {
979
- logWarning(`Failed to run ${installer.cmd}.`);
980
- resolve(false);
981
- });
982
- });
983
- }
984
-
985
- logWarning('Neither uv nor pip found. Install beads-mcp manually:');
986
- logInfo(' uv tool install beads-mcp');
987
- logInfo(' OR: pip install beads-mcp');
988
- return false;
989
- }
990
-
991
- /**
992
- * Run `bd setup claude` to configure Claude Code integration.
993
- *
994
- * SECURITY NOTE - shell:true usage:
995
- * - bdPath is validated via getBeadsPath()
996
- * - Arguments are HARDCODED ('setup', 'claude')
997
- * - Command injection risk: LOW (bdPath validated, no user input in args)
998
- */
999
- async function runBdSetupClaude() {
1000
- log('\nConfiguring beads for Claude Code...', COLORS.cyan);
1001
-
1002
- const bdPath = getBeadsPath();
1003
- if (!bdPath) {
1004
- logWarning('Cannot run bd setup claude: bd not found.');
1005
- logInfo('Run manually after installing beads: bd setup claude');
1006
- return false;
1007
- }
1008
-
1009
- // SECURITY: bdPath is validated, only hardcoded args.
1010
- return new Promise((resolve) => {
1011
- const child = spawn(bdPath, ['setup', 'claude'], {
1012
- stdio: 'inherit',
1013
- shell: true,
1014
- });
1015
-
1016
- child.on('close', (code) => {
1017
- if (code === 0) {
1018
- logSuccess('Claude Code integration configured!');
1019
- resolve(true);
1020
- } else {
1021
- logWarning('bd setup claude failed. Run manually: bd setup claude');
1022
- resolve(false);
1023
- }
1024
- });
1025
-
1026
- child.on('error', () => {
1027
- logWarning('Failed to run bd setup claude. Run manually: bd setup claude');
1028
- resolve(false);
1029
- });
1030
- });
1031
- }
1032
-
1033
684
  async function init(options = {}) {
1034
- const { force = false, skipBacklog = false, skipMcp = false, skipBeads = false, client: clientArg } = options;
685
+ const { force = false, skipBacklog = false, skipMcp = false } = options;
1035
686
  const cwd = process.cwd();
1036
687
 
1037
688
  // Check for updates
@@ -1054,27 +705,6 @@ ${COLORS.yellow}╔════════════════════
1054
705
 
1055
706
  log(`${COLORS.yellow}Tip: Run with --verbose for detailed diagnostics if you hit issues.${COLORS.reset}`);
1056
707
 
1057
- // Determine which client(s) to configure
1058
- let clients;
1059
- if (clientArg) {
1060
- clients = parseClientFlag(clientArg);
1061
- } else {
1062
- clients = await promptForClient();
1063
- }
1064
-
1065
- // Validate at least one client selected
1066
- if (!clients.vscode && !clients.copilotCli && !clients.claudeCode) {
1067
- logWarning('No client selected. Defaulting to VS Code with GitHub Copilot.');
1068
- clients.vscode = true;
1069
- }
1070
-
1071
- const selectedNames = [];
1072
- if (clients.vscode) selectedNames.push('VS Code + Copilot');
1073
- if (clients.copilotCli) selectedNames.push('Copilot CLI');
1074
- if (clients.claudeCode) selectedNames.push('Claude Code');
1075
- log(`\nConfiguring for: ${COLORS.cyan}${selectedNames.join(', ')}${COLORS.reset}`);
1076
-
1077
-
1078
708
  // Check if templates exist
1079
709
  if (!existsSync(TEMPLATES_DIR)) {
1080
710
  logError('Templates directory not found. Package may be corrupted.');
@@ -1083,15 +713,13 @@ ${COLORS.yellow}╔════════════════════
1083
713
 
1084
714
  const copiedFiles = [];
1085
715
 
1086
- // === SHARED FILES (all clients) ===
1087
-
1088
- // Copy .github/skills/ (domain knowledge - useful for all clients)
1089
- const skillsSrc = join(TEMPLATES_DIR, '.github', 'skills');
1090
- const skillsDest = join(cwd, '.github', 'skills');
716
+ // Copy .github directory (agents, skills, copilot-instructions.md)
717
+ const githubSrc = join(TEMPLATES_DIR, '.github');
718
+ const githubDest = join(cwd, '.github');
1091
719
 
1092
- if (existsSync(skillsSrc)) {
1093
- log('\nInstalling skills (domain knowledge)...');
1094
- copyDirRecursive(skillsSrc, skillsDest, { force, copiedFiles });
720
+ if (existsSync(githubSrc)) {
721
+ log('\nInstalling agents and skills...');
722
+ copyDirRecursive(githubSrc, githubDest, { force, copiedFiles });
1095
723
  }
1096
724
 
1097
725
  // Copy AGENTS.md
@@ -1122,38 +750,33 @@ ${COLORS.yellow}╔════════════════════
1122
750
  }
1123
751
  }
1124
752
 
1125
- // === VS CODE + COPILOT FILES ===
1126
- if (clients.vscode) {
1127
- log('\nInstalling VS Code + Copilot configuration...');
1128
-
1129
- // .github/agents/ (agent definitions with frontmatter)
1130
- const agentsSrc = join(TEMPLATES_DIR, '.github', 'agents');
1131
- const agentsDest = join(cwd, '.github', 'agents');
1132
- if (existsSync(agentsSrc)) {
1133
- copyDirRecursive(agentsSrc, agentsDest, { force, copiedFiles });
1134
- }
753
+ // Copy mcp.json.example (unless skipped)
754
+ if (!skipMcp) {
755
+ const mcpSrc = join(TEMPLATES_DIR, 'mcp.json.example');
756
+ const mcpDest = join(cwd, 'mcp.json.example');
1135
757
 
1136
- // .github/copilot-instructions.md
1137
- const copilotInstructionsSrc = join(TEMPLATES_DIR, '.github', 'copilot-instructions.md');
1138
- const copilotInstructionsDest = join(cwd, '.github', 'copilot-instructions.md');
1139
- if (existsSync(copilotInstructionsSrc)) {
1140
- if (existsSync(copilotInstructionsDest) && !force) {
1141
- logWarning('Skipped (exists): .github/copilot-instructions.md');
758
+ if (existsSync(mcpSrc)) {
759
+ if (existsSync(mcpDest) && !force) {
760
+ logWarning('Skipped (exists): mcp.json.example');
1142
761
  } else {
1143
- mkdirSync(join(cwd, '.github'), { recursive: true });
1144
- copyFileSync(copilotInstructionsSrc, copilotInstructionsDest);
1145
- copiedFiles.push('.github/copilot-instructions.md');
762
+ copyFileSync(mcpSrc, mcpDest);
763
+ copiedFiles.push('mcp.json.example');
1146
764
  }
1147
765
  }
1148
-
1149
- // .vscode/settings.json
1150
- const vscodeDest = join(cwd, '.vscode');
766
+ }
767
+
768
+ // Copy .vscode/settings.json (recommended settings for agent mode)
769
+ const vscodeSrc = join(TEMPLATES_DIR, '.vscode');
770
+ const vscodeDest = join(cwd, '.vscode');
771
+
772
+ if (existsSync(vscodeSrc)) {
1151
773
  if (!existsSync(vscodeDest)) {
1152
774
  mkdirSync(vscodeDest, { recursive: true });
1153
775
  }
1154
776
 
1155
- const settingsSrc = join(TEMPLATES_DIR, '.vscode', 'settings.json');
777
+ const settingsSrc = join(vscodeSrc, 'settings.json');
1156
778
  const settingsDest = join(vscodeDest, 'settings.json');
779
+
1157
780
  if (existsSync(settingsSrc)) {
1158
781
  if (existsSync(settingsDest) && !force) {
1159
782
  logWarning('Skipped (exists): .vscode/settings.json');
@@ -1162,61 +785,8 @@ ${COLORS.yellow}╔════════════════════
1162
785
  copiedFiles.push('.vscode/settings.json');
1163
786
  }
1164
787
  }
1165
-
1166
- // .vscode/mcp.json (beads + shadcn + playwright + deepwiki)
1167
- if (!skipMcp) {
1168
- const mcpJsonSrc = join(TEMPLATES_DIR, '.vscode', 'mcp.json');
1169
- const mcpJsonDest = join(vscodeDest, 'mcp.json');
1170
- if (existsSync(mcpJsonSrc)) {
1171
- if (existsSync(mcpJsonDest) && !force) {
1172
- logWarning('Skipped (exists): .vscode/mcp.json');
1173
- } else {
1174
- copyFileSync(mcpJsonSrc, mcpJsonDest);
1175
- copiedFiles.push('.vscode/mcp.json');
1176
- }
1177
- }
1178
- }
1179
788
  }
1180
789
 
1181
- // === COPILOT CLI FILES ===
1182
- if (clients.copilotCli && !clients.vscode) {
1183
- // Only install copilot-instructions.md if VS Code didn't already do it
1184
- log('\nInstalling Copilot CLI configuration...');
1185
-
1186
- const copilotInstructionsSrc = join(TEMPLATES_DIR, '.github', 'copilot-instructions.md');
1187
- const copilotInstructionsDest = join(cwd, '.github', 'copilot-instructions.md');
1188
- if (existsSync(copilotInstructionsSrc)) {
1189
- if (existsSync(copilotInstructionsDest) && !force) {
1190
- logWarning('Skipped (exists): .github/copilot-instructions.md');
1191
- } else {
1192
- mkdirSync(join(cwd, '.github'), { recursive: true });
1193
- copyFileSync(copilotInstructionsSrc, copilotInstructionsDest);
1194
- copiedFiles.push('.github/copilot-instructions.md');
1195
- }
1196
- }
1197
- }
1198
-
1199
- // === CLAUDE CODE FILES ===
1200
- if (clients.claudeCode) {
1201
- log('\nInstalling Claude Code configuration...');
1202
-
1203
- // CLAUDE.md
1204
- const claudeMdSrc = join(TEMPLATES_DIR, 'CLAUDE.md');
1205
- const claudeMdDest = join(cwd, 'CLAUDE.md');
1206
- if (existsSync(claudeMdSrc)) {
1207
- if (existsSync(claudeMdDest) && !force) {
1208
- logWarning('Skipped (exists): CLAUDE.md');
1209
- } else {
1210
- copyFileSync(claudeMdSrc, claudeMdDest);
1211
- copiedFiles.push('CLAUDE.md');
1212
- }
1213
- }
1214
- }
1215
-
1216
- // Persist client selection for quickstart and other commands
1217
- persistClientConfig(cwd, clients);
1218
- copiedFiles.push('.github/.beth-client.json');
1219
-
1220
790
  // Summary
1221
791
  console.log('');
1222
792
  if (copiedFiles.length > 0) {
@@ -1226,190 +796,20 @@ ${COLORS.yellow}╔════════════════════
1226
796
  logWarning('No files were copied. Use --force to overwrite existing files.');
1227
797
  }
1228
798
 
1229
- // Check for beads CLI (REQUIRED for Beth)
1230
- if (!skipBeads) {
1231
- console.log('');
1232
- log('Checking beads (required for task tracking)...', COLORS.cyan);
1233
-
1234
- let bdPath = getBeadsPath();
1235
-
1236
- // Loop until beads is installed
1237
- while (!bdPath) {
1238
- logWarning('beads CLI is not installed.');
1239
- logInfo('Beth requires beads for task tracking. Agents use it to coordinate work.');
1240
- logInfo('Learn more: https://github.com/steveyegge/beads');
1241
- console.log('');
1242
-
1243
- const shouldInstallBeads = await promptYesNo('Install beads CLI now? (required)');
1244
- if (shouldInstallBeads) {
1245
- const installed = await installBeads();
1246
- if (installed) {
1247
- // Re-check for beads after installation
1248
- bdPath = getBeadsPath();
1249
- if (!bdPath) {
1250
- console.log('');
1251
- logWarning('beads installed but not found in common paths.');
1252
- logInfo('The installer may have placed it in a custom location.');
1253
- console.log('');
1254
- logInfo('Please try one of these options:');
1255
- logInfo(' 1. Open a NEW terminal and run: npx beth-copilot init');
1256
- logInfo(' 2. Add ~/.local/bin to your PATH and retry');
1257
- logInfo(' 3. Run: source ~/.bashrc (or ~/.zshrc) then retry');
1258
- console.log('');
1259
-
1260
- const retryCheck = await promptYesNo('Retry detection? (select No to enter path manually)');
1261
- if (retryCheck) {
1262
- bdPath = getBeadsPath();
1263
- continue;
1264
- }
1265
-
1266
- // Allow manual path entry
1267
- const customPath = await promptForInput('Enter full path to bd binary (or press Enter to retry installation):');
1268
- if (customPath) {
1269
- const validation = validateBeadsPath(customPath);
1270
- if (validation.valid) {
1271
- bdPath = validation.normalizedPath;
1272
- logSuccess(`Found beads at: ${bdPath}`);
1273
- } else {
1274
- logError(`Invalid path: ${validation.error}`);
1275
- }
1276
- }
1277
- }
1278
- } else {
1279
- console.log('');
1280
- logError('Installation script failed.');
1281
- logInfo('You can try installing manually:');
1282
- logInfo(' curl -fsSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash');
1283
- console.log('');
1284
- }
1285
- } else {
1286
- console.log('');
1287
- logError('beads is REQUIRED for Beth to function.');
1288
- logInfo('Beth agents use beads to track tasks, dependencies, and coordinate work.');
1289
- logInfo('Without beads, the multi-agent workflow will not work correctly.');
1290
- console.log('');
1291
-
1292
- const tryAgain = await promptYesNo('Would you like to try installing beads?');
1293
- if (!tryAgain) {
1294
- logError('Cannot continue without beads. Exiting.');
1295
- logInfo('Install beads manually and run "npx beth-copilot init" again:');
1296
- logInfo(' npm install -g @beads/bd');
1297
- process.exit(1);
1298
- }
1299
- }
1300
- }
1301
-
1302
- // Show path info if not in standard PATH
1303
- if (bdPath && bdPath !== 'bd') {
1304
- logSuccess(`beads CLI found at: ${bdPath}`);
1305
- const isWindows = process.platform === 'win32';
1306
- if (isWindows) {
1307
- logInfo('Tip: Ensure npm global bin is in your PATH to use "bd" directly.');
1308
- } else {
1309
- logInfo('Tip: Add ~/.local/bin or npm global bin to your PATH to use "bd" directly.');
1310
- }
1311
- } else {
1312
- logSuccess('beads CLI is installed');
1313
- }
1314
-
1315
- // Initialize beads in the project if not already done
1316
- if (!isBeadsInitialized(cwd)) {
1317
- logInfo('beads not initialized in this project.');
1318
- let initialized = false;
1319
-
1320
- while (!initialized) {
1321
- const shouldInitBeads = await promptYesNo('Initialize beads now? (required)');
1322
- if (shouldInitBeads) {
1323
- initialized = await initializeBeads(cwd);
1324
- if (!initialized) {
1325
- logWarning('Initialization failed. Let\'s try again.');
1326
- }
1327
- } else {
1328
- logError('beads must be initialized for Beth to work correctly.');
1329
- logInfo('The .beads directory stores task tracking data used by all agents.');
1330
- console.log('');
1331
- }
1332
- }
1333
- } else {
1334
- logSuccess('beads is initialized in this project');
1335
- }
1336
- } else {
1337
- logWarning('Skipped beads check (--skip-beads). Beth may not function correctly.');
1338
- }
1339
-
1340
- // Run bd doctor to verify beads configuration
1341
- if (!skipBeads && getBeadsPath() && isBeadsInitialized(cwd)) {
1342
- await runBeadsDoctor();
1343
- }
1344
-
1345
- // === CLIENT-SPECIFIC BEADS INTEGRATION ===
1346
- if (!skipBeads && getBeadsPath() && isBeadsInitialized(cwd)) {
1347
- // VS Code: install beads-mcp (MCP server)
1348
- if (clients.vscode) {
1349
- const shouldInstallMcp = await promptYesNo('Install beads-mcp for VS Code MCP integration?');
1350
- if (shouldInstallMcp) {
1351
- await installBeadsMcp();
1352
- } else {
1353
- logInfo('Skipped beads-mcp. Install later with: uv tool install beads-mcp');
1354
- }
1355
- }
1356
-
1357
- // Claude Code: run bd setup claude
1358
- if (clients.claudeCode) {
1359
- const shouldSetupClaude = await promptYesNo('Configure beads for Claude Code? (bd setup claude)');
1360
- if (shouldSetupClaude) {
1361
- await runBdSetupClaude();
1362
- } else {
1363
- logInfo('Skipped Claude Code setup. Run later: bd setup claude');
1364
- }
1365
- }
1366
- }
1367
-
1368
799
  // Final verification
1369
800
  console.log('');
1370
801
  log('Verifying installation...', COLORS.cyan);
1371
-
1372
- const finalBeadsOk = skipBeads || getBeadsPath();
1373
- const finalBeadsInit = skipBeads || isBeadsInitialized(cwd);
1374
-
1375
- if (finalBeadsOk && finalBeadsInit) {
1376
- logSuccess('All dependencies installed and configured!');
1377
- } else {
1378
- if (!finalBeadsOk) logError('beads CLI not found');
1379
- if (!finalBeadsInit) logError('beads not initialized in project');
1380
- logError('Setup incomplete. Please resolve issues above and run init again.');
1381
- process.exit(1);
1382
- }
802
+ logSuccess('All files installed and configured!');
1383
803
 
1384
- // Next steps (client-specific)
1385
- console.log('');
1386
- log('Next steps:', COLORS.bright);
1387
-
1388
- if (clients.vscode) {
1389
- console.log(`
1390
- ${COLORS.bright}VS Code + Copilot:${COLORS.reset}
804
+ // Next steps
805
+ console.log(`
806
+ ${COLORS.bright}Next steps:${COLORS.reset}
1391
807
  1. Open this project in VS Code
1392
808
  2. Open Copilot Chat (${COLORS.cyan}Ctrl+Alt+I${COLORS.reset} / ${COLORS.cyan}Cmd+Alt+I${COLORS.reset})
1393
- 3. Type ${COLORS.cyan}@Beth${COLORS.reset} to start she's your orchestrator`);
1394
- }
1395
-
1396
- if (clients.copilotCli) {
1397
- console.log(`
1398
- ${COLORS.bright}Copilot CLI:${COLORS.reset}
1399
- 1. Run ${COLORS.cyan}copilot${COLORS.reset} in your project directory
1400
- 2. Beth's instructions are in ${COLORS.cyan}.github/copilot-instructions.md${COLORS.reset}
1401
- 3. Use ${COLORS.cyan}bd ready${COLORS.reset} to find work, ${COLORS.cyan}bd create${COLORS.reset} to track tasks`);
1402
- }
1403
-
1404
- if (clients.claudeCode) {
1405
- console.log(`
1406
- ${COLORS.bright}Claude Code:${COLORS.reset}
1407
- 1. Run ${COLORS.cyan}claude${COLORS.reset} in your project directory
1408
- 2. Beth's instructions are in ${COLORS.cyan}CLAUDE.md${COLORS.reset}
1409
- 3. Use ${COLORS.cyan}bd ready${COLORS.reset} to find work, ${COLORS.cyan}bd prime${COLORS.reset} for session context`);
1410
- }
809
+ 3. Type ${COLORS.cyan}@Beth${COLORS.reset} to start - she's your orchestrator
810
+
811
+ ${COLORS.bright}Pro tip:${COLORS.reset} Start every session with ${COLORS.cyan}@Beth${COLORS.reset} and let her route work to the right specialists.
1411
812
 
1412
- console.log(`
1413
813
  ${COLORS.bright}Documentation:${COLORS.reset}
1414
814
  https://github.com/stephschofield/beth
1415
815
 
@@ -1418,13 +818,16 @@ ${COLORS.cyan}"They broke my wings and forgot I had claws."${COLORS.reset}
1418
818
  }
1419
819
 
1420
820
  // Input validation constants
1421
- const ALLOWED_COMMANDS = ['init', 'help', '--help', '-h', 'doctor', 'quickstart'];
1422
- const ALLOWED_FLAGS = ['--force', '--skip-backlog', '--skip-mcp', '--skip-beads', '--verbose', '--client'];
1423
- const ALLOWED_CLIENTS = ['vscode', 'copilot-cli', 'claude-code', 'all'];
821
+ const ALLOWED_COMMANDS = ['init', 'help', '--help', '-h', 'doctor', 'quickstart', 'pre-push-guard', 'update', 'land'];
822
+ const ALLOWED_FLAGS = ['--force', '--skip-backlog', '--skip-mcp', '--verbose', '--reason', '-r', '-f', '--skip-tests', '--message', '-m', '--dry-run', '--check-only'];
1424
823
  const MAX_ARG_LENGTH = 50;
1425
824
 
1426
825
  // Validate and sanitize input
1427
826
  function validateArgs(args) {
827
+ // The 'land' and 'update' commands handle their own arg validation
828
+ const command = args[0]?.toLowerCase();
829
+ if (command === 'land' || command === 'update') return;
830
+
1428
831
  for (const arg of args) {
1429
832
  // Prevent excessively long arguments (log injection, DoS)
1430
833
  if (arg.length > MAX_ARG_LENGTH) {
@@ -1445,40 +848,25 @@ validateArgs(args);
1445
848
 
1446
849
  const command = args[0]?.toLowerCase();
1447
850
 
1448
- // Parse --client flag value (e.g. --client vscode)
1449
- let clientArg = null;
1450
- const clientFlagIndex = args.indexOf('--client');
1451
- if (clientFlagIndex !== -1 && clientFlagIndex + 1 < args.length) {
1452
- clientArg = args[clientFlagIndex + 1].toLowerCase();
1453
- if (!ALLOWED_CLIENTS.includes(clientArg)) {
1454
- logError(`Invalid client: ${clientArg.slice(0, MAX_ARG_LENGTH)}`);
1455
- console.log(`Valid clients: ${ALLOWED_CLIENTS.join(', ')}`);
1456
- process.exit(1);
1457
- }
1458
- }
1459
-
1460
851
  const options = {
1461
852
  force: args.includes('--force'),
1462
853
  skipBacklog: args.includes('--skip-backlog'),
1463
854
  skipMcp: args.includes('--skip-mcp'),
1464
- skipBeads: args.includes('--skip-beads'),
1465
855
  verbose: args.includes('--verbose'),
1466
- client: clientArg,
1467
856
  };
1468
857
 
1469
858
  // Set global verbose flag for logDebug
1470
859
  globalThis.VERBOSE = options.verbose;
1471
860
 
1472
861
  // Validate unknown flags (exclude --help which is handled as a command)
1473
- // Also exclude the value after --client since it's not a flag
1474
- const clientValueIndex = clientFlagIndex !== -1 ? clientFlagIndex + 1 : -1;
1475
- const unknownFlags = args.filter((arg, i) =>
1476
- arg.startsWith('--') && !ALLOWED_FLAGS.includes(arg) && arg !== '--help' && i !== clientValueIndex
1477
- );
1478
- if (unknownFlags.length > 0) {
1479
- logError(`Unknown flag: ${unknownFlags[0].slice(0, MAX_ARG_LENGTH)}`);
1480
- console.log('Run "npx beth-copilot help" for usage information.');
1481
- process.exit(1);
862
+ // Skip for 'land' and 'update' commands which handle their own arg parsing
863
+ if (command !== 'land' && command !== 'update') {
864
+ const unknownFlags = args.filter(arg => arg.startsWith('--') && !ALLOWED_FLAGS.includes(arg) && arg !== '--help');
865
+ if (unknownFlags.length > 0) {
866
+ logError(`Unknown flag: ${unknownFlags[0].slice(0, MAX_ARG_LENGTH)}`);
867
+ console.log('Run "npx beth-copilot help" for usage information.');
868
+ process.exit(1);
869
+ }
1482
870
  }
1483
871
 
1484
872
  switch (command) {
@@ -1505,6 +893,27 @@ switch (command) {
1505
893
  await quickstart(options);
1506
894
  }
1507
895
  break;
896
+ case 'land':
897
+ {
898
+ const { land } = await loadTsCommand('land');
899
+ // Pass raw args after 'land' — the command handles its own parsing
900
+ const landArgs = process.argv.slice(3);
901
+ await land(landArgs);
902
+ }
903
+ break;
904
+ case 'update':
905
+ {
906
+ const { update } = await loadTsCommand('update');
907
+ const updateArgs = process.argv.slice(3);
908
+ await update(updateArgs);
909
+ }
910
+ break;
911
+ case 'pre-push-guard':
912
+ {
913
+ const { prePushGuard } = await loadTsCommand('pre-push-guard');
914
+ await prePushGuard();
915
+ }
916
+ break;
1508
917
  case 'help':
1509
918
  case '--help':
1510
919
  case '-h':