beth-copilot 1.1.0 → 2.1.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 (228) hide show
  1. package/CHANGELOG.md +51 -1
  2. package/README.md +121 -132
  3. package/assets/beth-questioning.png +0 -0
  4. package/assets/yellowstone-beth.png +0 -0
  5. package/bin/cli.js +359 -445
  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.js +13 -0
  35. package/dist/__tests__/smoke.test.js.map +1 -1
  36. package/dist/__tests__/verify-skills.test.d.ts +9 -0
  37. package/dist/__tests__/verify-skills.test.d.ts.map +1 -0
  38. package/dist/__tests__/verify-skills.test.js +78 -0
  39. package/dist/__tests__/verify-skills.test.js.map +1 -0
  40. package/dist/cli/commands/beads.e2e.test.d.ts +4 -2
  41. package/dist/cli/commands/beads.e2e.test.d.ts.map +1 -1
  42. package/dist/cli/commands/beads.e2e.test.js +97 -38
  43. package/dist/cli/commands/beads.e2e.test.js.map +1 -1
  44. package/dist/cli/commands/cli-edge-cases.e2e.test.js +1 -1
  45. package/dist/cli/commands/cli-edge-cases.e2e.test.js.map +1 -1
  46. package/dist/cli/commands/close.d.ts +11 -46
  47. package/dist/cli/commands/close.d.ts.map +1 -1
  48. package/dist/cli/commands/close.e2e.test.d.ts +4 -20
  49. package/dist/cli/commands/close.e2e.test.d.ts.map +1 -1
  50. package/dist/cli/commands/close.e2e.test.js +23 -204
  51. package/dist/cli/commands/close.e2e.test.js.map +1 -1
  52. package/dist/cli/commands/close.js +26 -240
  53. package/dist/cli/commands/close.js.map +1 -1
  54. package/dist/cli/commands/close.test.d.ts +7 -9
  55. package/dist/cli/commands/close.test.d.ts.map +1 -1
  56. package/dist/cli/commands/close.test.js +44 -424
  57. package/dist/cli/commands/close.test.js.map +1 -1
  58. package/dist/cli/commands/doctor.d.ts +16 -22
  59. package/dist/cli/commands/doctor.d.ts.map +1 -1
  60. package/dist/cli/commands/doctor.e2e.test.js +3 -59
  61. package/dist/cli/commands/doctor.e2e.test.js.map +1 -1
  62. package/dist/cli/commands/doctor.js +87 -103
  63. package/dist/cli/commands/doctor.js.map +1 -1
  64. package/dist/cli/commands/doctor.test.js +120 -229
  65. package/dist/cli/commands/doctor.test.js.map +1 -1
  66. package/dist/cli/commands/framework-isolation.test.d.ts +1 -1
  67. package/dist/cli/commands/framework-isolation.test.js +2 -3
  68. package/dist/cli/commands/framework-isolation.test.js.map +1 -1
  69. package/dist/cli/commands/help.e2e.test.js +1 -5
  70. package/dist/cli/commands/help.e2e.test.js.map +1 -1
  71. package/dist/cli/commands/init-logic.e2e.test.js +114 -2
  72. package/dist/cli/commands/init-logic.e2e.test.js.map +1 -1
  73. package/dist/cli/commands/init.test.js +4 -21
  74. package/dist/cli/commands/init.test.js.map +1 -1
  75. package/dist/cli/commands/land.d.ts +3 -15
  76. package/dist/cli/commands/land.d.ts.map +1 -1
  77. package/dist/cli/commands/land.js +13 -68
  78. package/dist/cli/commands/land.js.map +1 -1
  79. package/dist/cli/commands/land.test.d.ts +0 -1
  80. package/dist/cli/commands/land.test.d.ts.map +1 -1
  81. package/dist/cli/commands/land.test.js +2 -57
  82. package/dist/cli/commands/land.test.js.map +1 -1
  83. package/dist/cli/commands/mcp.e2e.test.js +28 -3
  84. package/dist/cli/commands/mcp.e2e.test.js.map +1 -1
  85. package/dist/cli/commands/pipeline.e2e.test.js +23 -26
  86. package/dist/cli/commands/pipeline.e2e.test.js.map +1 -1
  87. package/dist/cli/commands/pre-push-guard.d.ts +2 -12
  88. package/dist/cli/commands/pre-push-guard.d.ts.map +1 -1
  89. package/dist/cli/commands/pre-push-guard.e2e.test.js +1 -1
  90. package/dist/cli/commands/pre-push-guard.e2e.test.js.map +1 -1
  91. package/dist/cli/commands/pre-push-guard.js +2 -47
  92. package/dist/cli/commands/pre-push-guard.js.map +1 -1
  93. package/dist/cli/commands/pre-push-guard.test.d.ts +0 -1
  94. package/dist/cli/commands/pre-push-guard.test.d.ts.map +1 -1
  95. package/dist/cli/commands/pre-push-guard.test.js +15 -98
  96. package/dist/cli/commands/pre-push-guard.test.js.map +1 -1
  97. package/dist/cli/commands/quickstart-expanded.e2e.test.d.ts +1 -1
  98. package/dist/cli/commands/quickstart-expanded.e2e.test.js +3 -30
  99. package/dist/cli/commands/quickstart-expanded.e2e.test.js.map +1 -1
  100. package/dist/cli/commands/quickstart.d.ts +0 -1
  101. package/dist/cli/commands/quickstart.d.ts.map +1 -1
  102. package/dist/cli/commands/quickstart.js +2 -60
  103. package/dist/cli/commands/quickstart.js.map +1 -1
  104. package/dist/cli/commands/quickstart.test.js +10 -104
  105. package/dist/cli/commands/quickstart.test.js.map +1 -1
  106. package/dist/cli/commands/uninstall.test.d.ts +5 -0
  107. package/dist/cli/commands/uninstall.test.d.ts.map +1 -0
  108. package/dist/cli/commands/uninstall.test.js +223 -0
  109. package/dist/cli/commands/uninstall.test.js.map +1 -0
  110. package/dist/cli/commands/update.d.ts +35 -0
  111. package/dist/cli/commands/update.d.ts.map +1 -0
  112. package/dist/cli/commands/update.e2e.test.d.ts +24 -0
  113. package/dist/cli/commands/update.e2e.test.d.ts.map +1 -0
  114. package/dist/cli/commands/update.e2e.test.js +238 -0
  115. package/dist/cli/commands/update.e2e.test.js.map +1 -0
  116. package/dist/cli/commands/update.js +255 -0
  117. package/dist/cli/commands/update.js.map +1 -0
  118. package/dist/core/agents/frontmatter.test.js +1 -1
  119. package/dist/core/agents/frontmatter.test.js.map +1 -1
  120. package/dist/core/agents/handoffs.test.js +1 -1
  121. package/dist/core/agents/handoffs.test.js.map +1 -1
  122. package/dist/core/agents/loader.d.ts +4 -2
  123. package/dist/core/agents/loader.d.ts.map +1 -1
  124. package/dist/core/agents/loader.js +5 -3
  125. package/dist/core/agents/loader.js.map +1 -1
  126. package/dist/core/agents/loader.test.js +42 -4
  127. package/dist/core/agents/loader.test.js.map +1 -1
  128. package/dist/core/agents/suite.test.js +8 -7
  129. package/dist/core/agents/suite.test.js.map +1 -1
  130. package/dist/core/agents/tools.test.js +10 -8
  131. package/dist/core/agents/tools.test.js.map +1 -1
  132. package/dist/core/agents/types.test.js +1 -1
  133. package/dist/core/agents/types.test.js.map +1 -1
  134. package/dist/core/skills/loader.test.js +1 -1
  135. package/dist/core/skills/loader.test.js.map +1 -1
  136. package/dist/index.d.ts +0 -1
  137. package/dist/index.d.ts.map +1 -1
  138. package/dist/index.js +0 -2
  139. package/dist/index.js.map +1 -1
  140. package/dist/lib/pathValidation.d.ts +0 -5
  141. package/dist/lib/pathValidation.d.ts.map +1 -1
  142. package/dist/lib/pathValidation.js +0 -11
  143. package/dist/lib/pathValidation.js.map +1 -1
  144. package/dist/lib/pathValidation.test.js +2 -14
  145. package/dist/lib/pathValidation.test.js.map +1 -1
  146. package/package.json +3 -6
  147. package/sbom.json +259 -371
  148. package/templates/.github/agents/beth.agent.md +194 -122
  149. package/templates/.github/agents/developer.agent.md +30 -22
  150. package/templates/.github/agents/product-manager.agent.md +15 -6
  151. package/templates/.github/agents/researcher.agent.md +10 -7
  152. package/templates/.github/agents/security-reviewer.agent.md +16 -7
  153. package/templates/.github/agents/tester.agent.md +16 -8
  154. package/templates/.github/agents/ux-designer.agent.md +12 -9
  155. package/templates/.github/copilot-instructions.md +33 -4
  156. package/templates/.github/copilot-mcp-config.json +12 -0
  157. package/templates/.github/dependabot.yml +68 -0
  158. package/templates/.github/hooks/scripts/inject-skills.mjs +139 -0
  159. package/templates/.github/hooks/scripts/verify-skills.mjs +47 -0
  160. package/templates/.github/hooks/skill-enforcement.json +18 -0
  161. package/templates/.github/pull_request_template.md +48 -0
  162. package/templates/.github/skills/framer-components/SKILL.md +0 -0
  163. package/templates/.github/skills/prd/SKILL.md +0 -0
  164. package/templates/.github/skills/security-analysis/SKILL.md +798 -798
  165. package/templates/.github/skills/shadcn-ui/SKILL.md +561 -561
  166. package/templates/.github/skills/vercel-react-best-practices/AGENTS.md +0 -0
  167. package/templates/.github/skills/vercel-react-best-practices/SKILL.md +0 -0
  168. package/templates/.github/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -0
  169. package/templates/.github/skills/vercel-react-best-practices/rules/advanced-use-latest.md +0 -0
  170. package/templates/.github/skills/vercel-react-best-practices/rules/async-api-routes.md +0 -0
  171. package/templates/.github/skills/vercel-react-best-practices/rules/async-defer-await.md +0 -0
  172. package/templates/.github/skills/vercel-react-best-practices/rules/async-dependencies.md +0 -0
  173. package/templates/.github/skills/vercel-react-best-practices/rules/async-parallel.md +0 -0
  174. package/templates/.github/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -0
  175. package/templates/.github/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -0
  176. package/templates/.github/skills/vercel-react-best-practices/rules/bundle-conditional.md +0 -0
  177. package/templates/.github/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -0
  178. package/templates/.github/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -0
  179. package/templates/.github/skills/vercel-react-best-practices/rules/bundle-preload.md +0 -0
  180. package/templates/.github/skills/vercel-react-best-practices/rules/client-event-listeners.md +0 -0
  181. package/templates/.github/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -0
  182. package/templates/.github/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -0
  183. package/templates/.github/skills/vercel-react-best-practices/rules/client-swr-dedup.md +0 -0
  184. package/templates/.github/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -0
  185. package/templates/.github/skills/vercel-react-best-practices/rules/js-cache-function-results.md +0 -0
  186. package/templates/.github/skills/vercel-react-best-practices/rules/js-cache-property-access.md +0 -0
  187. package/templates/.github/skills/vercel-react-best-practices/rules/js-cache-storage.md +0 -0
  188. package/templates/.github/skills/vercel-react-best-practices/rules/js-combine-iterations.md +0 -0
  189. package/templates/.github/skills/vercel-react-best-practices/rules/js-early-exit.md +0 -0
  190. package/templates/.github/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -0
  191. package/templates/.github/skills/vercel-react-best-practices/rules/js-index-maps.md +0 -0
  192. package/templates/.github/skills/vercel-react-best-practices/rules/js-length-check-first.md +0 -0
  193. package/templates/.github/skills/vercel-react-best-practices/rules/js-min-max-loop.md +0 -0
  194. package/templates/.github/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -0
  195. package/templates/.github/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -0
  196. package/templates/.github/skills/vercel-react-best-practices/rules/rendering-activity.md +0 -0
  197. package/templates/.github/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -0
  198. package/templates/.github/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -0
  199. package/templates/.github/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -0
  200. package/templates/.github/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -0
  201. package/templates/.github/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -0
  202. package/templates/.github/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -0
  203. package/templates/.github/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -0
  204. package/templates/.github/skills/vercel-react-best-practices/rules/rerender-dependencies.md +0 -0
  205. package/templates/.github/skills/vercel-react-best-practices/rules/rerender-derived-state.md +0 -0
  206. package/templates/.github/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -0
  207. package/templates/.github/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -0
  208. package/templates/.github/skills/vercel-react-best-practices/rules/rerender-memo.md +0 -0
  209. package/templates/.github/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +0 -0
  210. package/templates/.github/skills/vercel-react-best-practices/rules/rerender-transitions.md +0 -0
  211. package/templates/.github/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -0
  212. package/templates/.github/skills/vercel-react-best-practices/rules/server-auth-actions.md +0 -0
  213. package/templates/.github/skills/vercel-react-best-practices/rules/server-cache-lru.md +0 -0
  214. package/templates/.github/skills/vercel-react-best-practices/rules/server-cache-react.md +0 -0
  215. package/templates/.github/skills/vercel-react-best-practices/rules/server-dedup-props.md +0 -0
  216. package/templates/.github/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -0
  217. package/templates/.github/skills/vercel-react-best-practices/rules/server-serialization.md +0 -0
  218. package/templates/.github/skills/web-design-guidelines/SKILL.md +0 -0
  219. package/templates/.vscode/settings.json +16 -16
  220. package/templates/AGENTS.md +59 -98
  221. package/templates/Backlog.md +80 -80
  222. package/templates/mcp.json.example +8 -0
  223. package/assets/beth-portrait-small.txt +0 -13
  224. package/assets/beth-portrait.txt +0 -60
  225. package/bin/beth-animation.sh +0 -155
  226. package/bin/lib/animation.js +0 -189
  227. package/bin/lib/pathValidation.js +0 -233
  228. package/bin/lib/pathValidation.test.js +0 -280
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Tests for uninstall command.
3
+ */
4
+ import { describe, it, beforeEach, afterEach } from 'vitest';
5
+ import assert from 'node:assert';
6
+ import { execSync } from 'child_process';
7
+ import { existsSync, mkdirSync, writeFileSync, rmSync, readFileSync, readdirSync } from 'fs';
8
+ import { join } from 'path';
9
+ import { tmpdir } from 'os';
10
+ const CLI_PATH = join(process.cwd(), 'bin', 'cli.js');
11
+ /**
12
+ * Run init in a directory to set up a Beth installation.
13
+ */
14
+ function runInit(cwd, flags = []) {
15
+ const command = `node "${CLI_PATH}" init ${flags.join(' ')}`;
16
+ try {
17
+ return execSync(command, {
18
+ cwd,
19
+ encoding: 'utf-8',
20
+ env: { ...process.env, NO_COLOR: '1' },
21
+ stdio: ['pipe', 'pipe', 'pipe'],
22
+ });
23
+ }
24
+ catch (error) {
25
+ const execError = error;
26
+ return execError.stdout || '';
27
+ }
28
+ }
29
+ /**
30
+ * Run the uninstall command.
31
+ */
32
+ function runUninstall(cwd, flags = []) {
33
+ const command = `node "${CLI_PATH}" uninstall ${flags.join(' ')}`;
34
+ try {
35
+ const stdout = execSync(command, {
36
+ cwd,
37
+ encoding: 'utf-8',
38
+ env: { ...process.env, NO_COLOR: '1' },
39
+ stdio: ['pipe', 'pipe', 'pipe'],
40
+ });
41
+ return { stdout, stderr: '', exitCode: 0 };
42
+ }
43
+ catch (error) {
44
+ const execError = error;
45
+ return {
46
+ stdout: execError.stdout || '',
47
+ stderr: execError.stderr || '',
48
+ exitCode: execError.status || 1,
49
+ };
50
+ }
51
+ }
52
+ describe('uninstall command', () => {
53
+ let testDir;
54
+ beforeEach(() => {
55
+ testDir = join(tmpdir(), `beth-uninstall-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
56
+ mkdirSync(testDir, { recursive: true });
57
+ });
58
+ afterEach(() => {
59
+ if (existsSync(testDir)) {
60
+ rmSync(testDir, { recursive: true, force: true });
61
+ }
62
+ });
63
+ describe('removes Beth-installed files', () => {
64
+ it('should remove .github/agents directory', () => {
65
+ runInit(testDir, ['--skip-backlog', '--skip-mcp']);
66
+ assert.strictEqual(existsSync(join(testDir, '.github', 'agents')), true, 'agents dir should exist after init');
67
+ runUninstall(testDir, ['--force']);
68
+ assert.strictEqual(existsSync(join(testDir, '.github', 'agents')), false, 'agents dir should be removed');
69
+ });
70
+ it('should remove .github/skills directory', () => {
71
+ runInit(testDir, ['--skip-backlog', '--skip-mcp']);
72
+ assert.strictEqual(existsSync(join(testDir, '.github', 'skills')), true, 'skills dir should exist after init');
73
+ runUninstall(testDir, ['--force']);
74
+ assert.strictEqual(existsSync(join(testDir, '.github', 'skills')), false, 'skills dir should be removed');
75
+ });
76
+ it('should remove .github/hooks directory', () => {
77
+ runInit(testDir, ['--skip-backlog', '--skip-mcp']);
78
+ assert.strictEqual(existsSync(join(testDir, '.github', 'hooks')), true, 'hooks dir should exist after init');
79
+ runUninstall(testDir, ['--force']);
80
+ assert.strictEqual(existsSync(join(testDir, '.github', 'hooks')), false, 'hooks dir should be removed');
81
+ });
82
+ it('should remove AGENTS.md', () => {
83
+ runInit(testDir, ['--skip-backlog', '--skip-mcp']);
84
+ assert.strictEqual(existsSync(join(testDir, 'AGENTS.md')), true, 'AGENTS.md should exist after init');
85
+ runUninstall(testDir, ['--force']);
86
+ assert.strictEqual(existsSync(join(testDir, 'AGENTS.md')), false, 'AGENTS.md should be removed');
87
+ });
88
+ it('should remove Backlog.md', () => {
89
+ // Create a Backlog.md manually (since --skip-backlog skips backlog init)
90
+ writeFileSync(join(testDir, 'Backlog.md'), '# Backlog');
91
+ runInit(testDir, ['--skip-backlog', '--skip-mcp']);
92
+ // Manually ensure Backlog.md exists for the test
93
+ writeFileSync(join(testDir, 'Backlog.md'), '# Backlog');
94
+ runUninstall(testDir, ['--force']);
95
+ assert.strictEqual(existsSync(join(testDir, 'Backlog.md')), false, 'Backlog.md should be removed');
96
+ });
97
+ it('should remove .github/copilot-instructions.md', () => {
98
+ runInit(testDir, ['--skip-backlog', '--skip-mcp']);
99
+ assert.strictEqual(existsSync(join(testDir, '.github', 'copilot-instructions.md')), true, 'copilot-instructions.md should exist after init');
100
+ runUninstall(testDir, ['--force']);
101
+ assert.strictEqual(existsSync(join(testDir, '.github', 'copilot-instructions.md')), false, 'copilot-instructions.md should be removed');
102
+ });
103
+ it('should remove .vscode/settings.json', () => {
104
+ runInit(testDir, ['--skip-backlog', '--skip-mcp']);
105
+ assert.strictEqual(existsSync(join(testDir, '.vscode', 'settings.json')), true, 'settings.json should exist after init');
106
+ runUninstall(testDir, ['--force']);
107
+ assert.strictEqual(existsSync(join(testDir, '.vscode', 'settings.json')), false, 'settings.json should be removed');
108
+ });
109
+ it('should remove mcp.json.example', () => {
110
+ runInit(testDir);
111
+ assert.strictEqual(existsSync(join(testDir, 'mcp.json.example')), true, 'mcp.json.example should exist after init');
112
+ runUninstall(testDir, ['--force']);
113
+ assert.strictEqual(existsSync(join(testDir, 'mcp.json.example')), false, 'mcp.json.example should be removed');
114
+ });
115
+ });
116
+ describe('removes backlog directory', () => {
117
+ it('should remove backlog/ directory if it exists', () => {
118
+ // Simulate what `backlog init` creates
119
+ const backlogDir = join(testDir, 'backlog');
120
+ mkdirSync(join(backlogDir, 'tasks'), { recursive: true });
121
+ writeFileSync(join(backlogDir, 'config.yml'), 'prefix: TEST');
122
+ // Also need agents dir so uninstall detects an installation
123
+ runInit(testDir, ['--skip-backlog', '--skip-mcp']);
124
+ runUninstall(testDir, ['--force']);
125
+ assert.strictEqual(existsSync(backlogDir), false, 'backlog/ should be removed');
126
+ });
127
+ });
128
+ describe('cleans up empty parent directories', () => {
129
+ it('should remove .github/ if empty after cleanup', () => {
130
+ runInit(testDir, ['--skip-backlog', '--skip-mcp']);
131
+ assert.strictEqual(existsSync(join(testDir, '.github')), true, '.github should exist after init');
132
+ runUninstall(testDir, ['--force']);
133
+ assert.strictEqual(existsSync(join(testDir, '.github')), false, '.github should be removed when empty');
134
+ });
135
+ it('should remove .vscode/ if empty after cleanup', () => {
136
+ runInit(testDir, ['--skip-backlog', '--skip-mcp']);
137
+ assert.strictEqual(existsSync(join(testDir, '.vscode')), true, '.vscode should exist after init');
138
+ runUninstall(testDir, ['--force']);
139
+ assert.strictEqual(existsSync(join(testDir, '.vscode')), false, '.vscode should be removed when empty');
140
+ });
141
+ it('should preserve .github/ if it has non-Beth files', () => {
142
+ runInit(testDir, ['--skip-backlog', '--skip-mcp']);
143
+ // Add a non-Beth file to .github
144
+ mkdirSync(join(testDir, '.github', 'workflows'), { recursive: true });
145
+ writeFileSync(join(testDir, '.github', 'workflows', 'ci.yml'), 'name: CI');
146
+ runUninstall(testDir, ['--force']);
147
+ assert.strictEqual(existsSync(join(testDir, '.github')), true, '.github should be preserved');
148
+ assert.strictEqual(existsSync(join(testDir, '.github', 'workflows', 'ci.yml')), true, 'non-Beth files preserved');
149
+ assert.strictEqual(existsSync(join(testDir, '.github', 'agents')), false, 'Beth dirs still removed');
150
+ });
151
+ it('should preserve .vscode/ if it has non-Beth files', () => {
152
+ runInit(testDir, ['--skip-backlog', '--skip-mcp']);
153
+ // Add a non-Beth file to .vscode
154
+ writeFileSync(join(testDir, '.vscode', 'extensions.json'), '{}');
155
+ runUninstall(testDir, ['--force']);
156
+ assert.strictEqual(existsSync(join(testDir, '.vscode')), true, '.vscode should be preserved');
157
+ assert.strictEqual(existsSync(join(testDir, '.vscode', 'extensions.json')), true, 'non-Beth files preserved');
158
+ assert.strictEqual(existsSync(join(testDir, '.vscode', 'settings.json')), false, 'Beth files still removed');
159
+ });
160
+ });
161
+ describe('pre-push hook cleanup', () => {
162
+ it('should remove Beth guard block from pre-push hook', () => {
163
+ // Create a .git/hooks directory and a pre-push hook with Beth guard
164
+ const hooksDir = join(testDir, '.git', 'hooks');
165
+ mkdirSync(hooksDir, { recursive: true });
166
+ const guardContent = `#!/bin/sh
167
+ # User's custom hook
168
+ echo "custom check"
169
+
170
+ # --- BEGIN BETH GUARD ---
171
+ # Branch discipline enforcement — installed by beth-copilot
172
+ echo "beth guard"
173
+ # --- END BETH GUARD ---
174
+ `;
175
+ writeFileSync(join(hooksDir, 'pre-push'), guardContent);
176
+ // Need agents dir so uninstall detects installation
177
+ runInit(testDir, ['--skip-backlog', '--skip-mcp']);
178
+ runUninstall(testDir, ['--force']);
179
+ const hookPath = join(hooksDir, 'pre-push');
180
+ assert.strictEqual(existsSync(hookPath), true, 'hook should still exist (has user content)');
181
+ const remaining = readFileSync(hookPath, 'utf-8');
182
+ assert.ok(!remaining.includes('BEGIN BETH GUARD'), 'guard block should be removed');
183
+ assert.ok(remaining.includes('custom check'), 'user content should be preserved');
184
+ });
185
+ it('should remove entire pre-push file if only Beth guard remains', () => {
186
+ const hooksDir = join(testDir, '.git', 'hooks');
187
+ mkdirSync(hooksDir, { recursive: true });
188
+ const guardOnlyContent = `#!/bin/sh
189
+ # --- BEGIN BETH GUARD ---
190
+ # Branch discipline enforcement — installed by beth-copilot
191
+ echo "beth guard"
192
+ # --- END BETH GUARD ---
193
+ `;
194
+ writeFileSync(join(hooksDir, 'pre-push'), guardOnlyContent);
195
+ runInit(testDir, ['--skip-backlog', '--skip-mcp']);
196
+ runUninstall(testDir, ['--force']);
197
+ assert.strictEqual(existsSync(join(hooksDir, 'pre-push')), false, 'hook should be removed when Beth-only');
198
+ });
199
+ });
200
+ describe('no installation detected', () => {
201
+ it('should exit gracefully when no Beth installation exists', () => {
202
+ const result = runUninstall(testDir, ['--force']);
203
+ assert.ok(result.stdout.includes('No Beth installation') || result.exitCode === 0, 'Should handle missing installation gracefully');
204
+ });
205
+ });
206
+ describe('full round-trip', () => {
207
+ it('init then uninstall should leave directory clean', () => {
208
+ // Record initial state (empty dir)
209
+ const before = readdirSync(testDir);
210
+ // Install Beth
211
+ runInit(testDir, ['--skip-backlog', '--skip-mcp']);
212
+ // Verify something was installed
213
+ assert.strictEqual(existsSync(join(testDir, '.github', 'agents')), true, 'init should install agents');
214
+ assert.strictEqual(existsSync(join(testDir, 'AGENTS.md')), true, 'init should install AGENTS.md');
215
+ // Uninstall Beth
216
+ runUninstall(testDir, ['--force']);
217
+ // Directory should be back to empty (or have only files that existed before)
218
+ const after = readdirSync(testDir);
219
+ assert.deepStrictEqual(after.sort(), before.sort(), 'directory should be clean after uninstall');
220
+ });
221
+ });
222
+ });
223
+ //# sourceMappingURL=uninstall.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uninstall.test.js","sourceRoot":"","sources":["../../../src/cli/commands/uninstall.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Update Command
3
+ *
4
+ * Updates project files to the latest Beth templates.
5
+ * Compares installed files against the package templates and
6
+ * copies new or updated files into the project.
7
+ *
8
+ * Behavior:
9
+ * - New files (exist in template but not in project) → always installed
10
+ * - Unchanged files (content matches template) → skipped
11
+ * - User-modified files (content differs from template):
12
+ * - Without --force → skipped with warning
13
+ * - With --force → overwritten
14
+ * - --check-only → reports status without modifying anything
15
+ * - --verbose → shows per-file detail
16
+ *
17
+ * Options:
18
+ * --check-only Report update status without modifying files
19
+ * --force Overwrite user-modified files with template versions
20
+ * --verbose Show per-file detail
21
+ */
22
+ export interface UpdateOptions {
23
+ checkOnly?: boolean;
24
+ force?: boolean;
25
+ verbose?: boolean;
26
+ }
27
+ /**
28
+ * Parse update command arguments from raw argv.
29
+ */
30
+ export declare function parseUpdateArgs(rawArgs: string[]): UpdateOptions;
31
+ /**
32
+ * Main update command.
33
+ */
34
+ export declare function update(rawArgs: string[]): Promise<void>;
35
+ //# sourceMappingURL=update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/update.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAgBH,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAYD;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,aAAa,CAQhE;AA+DD;;GAEG;AACH,wBAAsB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqJ7D"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * E2E tests for the update command.
3
+ * Run with: npx vitest run src/cli/commands/update.e2e.test.ts
4
+ *
5
+ * beth-r08.6: Validates `npx beth-copilot update` behavior end-to-end.
6
+ *
7
+ * Test scenarios:
8
+ * 1. Command is recognized (not rejected as unknown)
9
+ * 2. Listed in help output
10
+ * 3. --check-only reports version status without modifying files
11
+ * 4. Reports "already up to date" when templates match
12
+ * 5. Shows update summary with --verbose
13
+ * 6. --force overwrites existing files
14
+ * 7. Does not overwrite user-modified files without --force
15
+ * 8. Handles network errors gracefully (npm registry unreachable)
16
+ * 9. Exits with code 0 on success, non-zero on failure
17
+ * 10. Installs new agent/skill files that did not exist before
18
+ *
19
+ * These tests exercise the real CLI binary in temp directories.
20
+ * They do NOT hit the npm registry — network calls are tested
21
+ * separately or mocked via env vars.
22
+ */
23
+ export {};
24
+ //# sourceMappingURL=update.e2e.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.e2e.test.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/update.e2e.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG"}
@@ -0,0 +1,238 @@
1
+ /**
2
+ * E2E tests for the update command.
3
+ * Run with: npx vitest run src/cli/commands/update.e2e.test.ts
4
+ *
5
+ * beth-r08.6: Validates `npx beth-copilot update` behavior end-to-end.
6
+ *
7
+ * Test scenarios:
8
+ * 1. Command is recognized (not rejected as unknown)
9
+ * 2. Listed in help output
10
+ * 3. --check-only reports version status without modifying files
11
+ * 4. Reports "already up to date" when templates match
12
+ * 5. Shows update summary with --verbose
13
+ * 6. --force overwrites existing files
14
+ * 7. Does not overwrite user-modified files without --force
15
+ * 8. Handles network errors gracefully (npm registry unreachable)
16
+ * 9. Exits with code 0 on success, non-zero on failure
17
+ * 10. Installs new agent/skill files that did not exist before
18
+ *
19
+ * These tests exercise the real CLI binary in temp directories.
20
+ * They do NOT hit the npm registry — network calls are tested
21
+ * separately or mocked via env vars.
22
+ */
23
+ import { describe, it, beforeEach, afterEach } from 'vitest';
24
+ import assert from 'node:assert';
25
+ import { execSync } from 'child_process';
26
+ import { existsSync, mkdirSync, writeFileSync, rmSync, readFileSync, readdirSync, } from 'fs';
27
+ import { join, resolve } from 'path';
28
+ import { tmpdir } from 'os';
29
+ const CLI_PATH = resolve(join(import.meta.dirname, '..', '..', '..', 'bin', 'cli.js'));
30
+ /**
31
+ * Run a CLI command and capture output.
32
+ */
33
+ function runCli(args, options = {}) {
34
+ try {
35
+ const stdout = execSync(`node "${CLI_PATH}" ${args}`, {
36
+ cwd: options.cwd,
37
+ encoding: 'utf-8',
38
+ env: { ...process.env, NO_COLOR: '1', ...options.env },
39
+ stdio: ['pipe', 'pipe', 'pipe'],
40
+ timeout: 30000,
41
+ });
42
+ return { stdout, stderr: '', code: 0 };
43
+ }
44
+ catch (error) {
45
+ const e = error;
46
+ return { stdout: e.stdout || '', stderr: e.stderr || '', code: e.status || 1 };
47
+ }
48
+ }
49
+ /**
50
+ * Initialize a temp directory with a minimal beth installation
51
+ * (simulates a project that previously ran `init`).
52
+ */
53
+ function setupInstalledProject(dir) {
54
+ // Create .github/agents with a sample agent
55
+ const agentsDir = join(dir, '.github', 'agents');
56
+ mkdirSync(agentsDir, { recursive: true });
57
+ writeFileSync(join(agentsDir, 'beth.agent.md'), `---
58
+ name: Beth
59
+ description: Orchestrator
60
+ model: Claude Opus 4.6
61
+ tools:
62
+ - runSubagent
63
+ ---
64
+
65
+ # Beth
66
+ `);
67
+ // Create .github/skills with a sample skill
68
+ const skillDir = join(dir, '.github', 'skills', 'prd');
69
+ mkdirSync(skillDir, { recursive: true });
70
+ writeFileSync(join(skillDir, 'SKILL.md'), '# PRD Skill\n');
71
+ // Create AGENTS.md
72
+ writeFileSync(join(dir, 'AGENTS.md'), '# Agent Instructions\n');
73
+ // Create package.json (needed for version detection)
74
+ writeFileSync(join(dir, 'package.json'), JSON.stringify({ name: 'test-project', version: '1.0.0' }, null, 2));
75
+ }
76
+ // ─────────────────────────────────────────────────────────
77
+ // Test suites
78
+ // ─────────────────────────────────────────────────────────
79
+ describe('update command E2E', () => {
80
+ let testDir;
81
+ beforeEach(() => {
82
+ testDir = join(tmpdir(), `beth-update-e2e-${Date.now()}-${Math.random().toString(36).slice(2)}`);
83
+ mkdirSync(testDir, { recursive: true });
84
+ });
85
+ afterEach(() => {
86
+ if (existsSync(testDir)) {
87
+ rmSync(testDir, { recursive: true, force: true });
88
+ }
89
+ });
90
+ // ── 1. Command recognition ──────────────────────────────
91
+ describe('command recognition', () => {
92
+ it('should accept "update" as a valid command (not rejected as unknown)', () => {
93
+ // When update is implemented, this should NOT return the
94
+ // "Unknown command" error that unrecognized commands get.
95
+ const result = runCli('update --check-only', { cwd: testDir });
96
+ // The command should either succeed or fail for a reason
97
+ // OTHER than "unknown command" or "unknown flag". Without this
98
+ // dual check, the test passes vacuously when the CLI rejects
99
+ // --check-only as an unknown flag before it ever dispatches.
100
+ const combined = result.stdout + result.stderr;
101
+ const isRejected = /unknown (command|flag)/i.test(combined);
102
+ assert.strictEqual(isRejected, false, '"update --check-only" should be recognized — not rejected as unknown command or unknown flag');
103
+ });
104
+ });
105
+ // ── 2. Help integration ─────────────────────────────────
106
+ describe('help integration', () => {
107
+ it('should list the update command in help output', () => {
108
+ const result = runCli('help');
109
+ assert.ok(result.stdout.includes('update'), 'Help output should mention the update command');
110
+ });
111
+ });
112
+ // ── 3. --check-only flag ────────────────────────────────
113
+ describe('--check-only flag', () => {
114
+ it('should report version status without modifying any files', () => {
115
+ setupInstalledProject(testDir);
116
+ // Snapshot file state before
117
+ const agentBefore = readFileSync(join(testDir, '.github', 'agents', 'beth.agent.md'), 'utf-8');
118
+ const result = runCli('update --check-only', { cwd: testDir });
119
+ // File should be unchanged
120
+ const agentAfter = readFileSync(join(testDir, '.github', 'agents', 'beth.agent.md'), 'utf-8');
121
+ assert.strictEqual(agentBefore, agentAfter, '--check-only should not modify any files');
122
+ // Should output version information
123
+ assert.ok(result.stdout.includes('version') ||
124
+ result.stdout.includes('up to date') ||
125
+ result.stdout.includes('available'), '--check-only should report version status');
126
+ });
127
+ it('should exit with code 0 when check succeeds', () => {
128
+ setupInstalledProject(testDir);
129
+ const result = runCli('update --check-only', { cwd: testDir });
130
+ assert.strictEqual(result.code, 0, '--check-only should exit 0 on success');
131
+ });
132
+ });
133
+ // ── 4. Already up to date ───────────────────────────────
134
+ describe('already up to date', () => {
135
+ it('should report when no update is available', () => {
136
+ setupInstalledProject(testDir);
137
+ // Run update (templates should match since they came from the same version)
138
+ const result = runCli('update', { cwd: testDir });
139
+ // Should indicate that things are current or that update completed
140
+ const indicatesStatus = result.stdout.includes('up to date') ||
141
+ result.stdout.includes('already') ||
142
+ result.stdout.includes('Updated') ||
143
+ result.stdout.includes('installed');
144
+ assert.ok(indicatesStatus, 'Should report update status');
145
+ });
146
+ });
147
+ // ── 5. --verbose flag ──────────────────────────────────
148
+ describe('--verbose flag', () => {
149
+ it('should show additional detail with --verbose', () => {
150
+ setupInstalledProject(testDir);
151
+ const normal = runCli('update --check-only', { cwd: testDir });
152
+ const verbose = runCli('update --check-only --verbose', { cwd: testDir });
153
+ // Verbose output should be equal or longer than normal output
154
+ assert.ok(verbose.stdout.length >= normal.stdout.length, '--verbose should produce equal or more output than default');
155
+ });
156
+ });
157
+ // ── 6. --force flag ────────────────────────────────────
158
+ describe('--force flag', () => {
159
+ it('should overwrite existing files when --force is used', () => {
160
+ setupInstalledProject(testDir);
161
+ // Modify a file to simulate user customization
162
+ const agentPath = join(testDir, '.github', 'agents', 'beth.agent.md');
163
+ writeFileSync(agentPath, 'USER CUSTOMIZED CONTENT');
164
+ runCli('update --force', { cwd: testDir });
165
+ // With --force, the file should be overwritten with the template version
166
+ const afterContent = readFileSync(agentPath, 'utf-8');
167
+ assert.notStrictEqual(afterContent, 'USER CUSTOMIZED CONTENT', '--force should overwrite user-modified files with template versions');
168
+ });
169
+ });
170
+ // ── 7. Preserve user modifications ──────────────────────
171
+ describe('preserve user modifications', () => {
172
+ it('should not overwrite user-modified files without --force', () => {
173
+ setupInstalledProject(testDir);
174
+ // Modify a file to simulate user customization
175
+ const agentPath = join(testDir, '.github', 'agents', 'beth.agent.md');
176
+ writeFileSync(agentPath, 'USER CUSTOMIZED CONTENT');
177
+ const result = runCli('update', { cwd: testDir });
178
+ // Without --force, the user's customization should be preserved
179
+ const afterContent = readFileSync(agentPath, 'utf-8');
180
+ assert.strictEqual(afterContent, 'USER CUSTOMIZED CONTENT', 'Should preserve user-modified files without --force');
181
+ // Should warn the user that files were skipped
182
+ const mentionsSkipped = result.stdout.includes('skip') ||
183
+ result.stdout.includes('Skip') ||
184
+ result.stdout.includes('modified') ||
185
+ result.stdout.includes('preserved');
186
+ assert.ok(mentionsSkipped, 'Should mention that user-modified files were skipped');
187
+ });
188
+ });
189
+ // ── 8. Network error handling ───────────────────────────
190
+ describe('network error handling', () => {
191
+ it('should handle npm registry being unreachable gracefully', () => {
192
+ setupInstalledProject(testDir);
193
+ // Use a bogus registry URL to simulate network failure
194
+ const result = runCli('update --check-only', {
195
+ cwd: testDir,
196
+ env: { npm_config_registry: 'http://localhost:1' },
197
+ });
198
+ // Should not crash — either succeeds with cached data or
199
+ // reports the error cleanly
200
+ const crashed = result.stderr.includes('Unhandled') ||
201
+ result.stderr.includes('FATAL');
202
+ assert.strictEqual(crashed, false, 'Should handle network errors without crashing');
203
+ });
204
+ });
205
+ // ── 9. Exit codes ──────────────────────────────────────
206
+ describe('exit codes', () => {
207
+ it('should exit with code 0 on successful update', () => {
208
+ setupInstalledProject(testDir);
209
+ const result = runCli('update', { cwd: testDir });
210
+ assert.strictEqual(result.code, 0, 'Successful update should exit with code 0');
211
+ });
212
+ });
213
+ // ── 10. New files added by update ───────────────────────
214
+ describe('new template files', () => {
215
+ it('should install new agent files that did not exist before', () => {
216
+ setupInstalledProject(testDir);
217
+ // Setup creates only beth.agent.md — update should add more
218
+ const agentsDir = join(testDir, '.github', 'agents');
219
+ const beforeCount = readdirSync(agentsDir).filter(f => f.endsWith('.agent.md')).length;
220
+ runCli('update', { cwd: testDir });
221
+ const afterCount = readdirSync(agentsDir).filter(f => f.endsWith('.agent.md')).length;
222
+ assert.ok(afterCount > beforeCount, `Update should install new agent files. Before: ${beforeCount}, after: ${afterCount}`);
223
+ });
224
+ it('should install new skill directories that did not exist before', () => {
225
+ setupInstalledProject(testDir);
226
+ // Setup creates only prd/ — update should add more
227
+ const skillsDir = join(testDir, '.github', 'skills');
228
+ const beforeCount = readdirSync(skillsDir, { withFileTypes: true })
229
+ .filter(d => d.isDirectory()).length;
230
+ runCli('update', { cwd: testDir });
231
+ assert.ok(existsSync(skillsDir), 'Skills directory should exist after update');
232
+ const afterCount = readdirSync(skillsDir, { withFileTypes: true })
233
+ .filter(d => d.isDirectory()).length;
234
+ assert.ok(afterCount > beforeCount, `Update should install new skill dirs. Before: ${beforeCount}, after: ${afterCount}`);
235
+ });
236
+ });
237
+ });
238
+ //# sourceMappingURL=update.e2e.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.e2e.test.js","sourceRoot":"","sources":["../../../src/cli/commands/update.e2e.test.ts"],"names":[],"mappings":"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"}