beth-copilot 1.0.14 → 1.0.16

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 (236) hide show
  1. package/CHANGELOG.md +195 -177
  2. package/README.md +528 -185
  3. package/bin/cli.js +47 -0
  4. package/dist/cli/commands/doctor.e2e.test.d.ts +8 -0
  5. package/dist/cli/commands/doctor.e2e.test.d.ts.map +1 -0
  6. package/dist/cli/commands/doctor.e2e.test.js +428 -0
  7. package/dist/cli/commands/doctor.e2e.test.js.map +1 -0
  8. package/dist/cli/commands/doctor.test.js +1 -1
  9. package/dist/cli/commands/help.e2e.test.d.ts +9 -0
  10. package/dist/cli/commands/help.e2e.test.d.ts.map +1 -0
  11. package/dist/cli/commands/help.e2e.test.js +150 -0
  12. package/dist/cli/commands/help.e2e.test.js.map +1 -0
  13. package/dist/cli/commands/init.test.d.ts +6 -0
  14. package/dist/cli/commands/init.test.d.ts.map +1 -0
  15. package/dist/cli/commands/init.test.js +289 -0
  16. package/dist/cli/commands/init.test.js.map +1 -0
  17. package/dist/cli/commands/mcp.e2e.test.d.ts +9 -0
  18. package/dist/cli/commands/mcp.e2e.test.d.ts.map +1 -0
  19. package/dist/cli/commands/mcp.e2e.test.js +139 -0
  20. package/dist/cli/commands/mcp.e2e.test.js.map +1 -0
  21. package/dist/cli/commands/pipeline.e2e.test.d.ts +9 -0
  22. package/dist/cli/commands/pipeline.e2e.test.d.ts.map +1 -0
  23. package/dist/cli/commands/pipeline.e2e.test.js +192 -0
  24. package/dist/cli/commands/pipeline.e2e.test.js.map +1 -0
  25. package/dist/cli/commands/quickstart.test.d.ts +6 -0
  26. package/dist/cli/commands/quickstart.test.d.ts.map +1 -0
  27. package/dist/cli/commands/quickstart.test.js +232 -0
  28. package/dist/cli/commands/quickstart.test.js.map +1 -0
  29. package/dist/core/agents/frontmatter.test.d.ts +8 -0
  30. package/dist/core/agents/frontmatter.test.d.ts.map +1 -0
  31. package/dist/core/agents/frontmatter.test.js +589 -0
  32. package/dist/core/agents/frontmatter.test.js.map +1 -0
  33. package/dist/core/agents/handoffs.test.d.ts +8 -0
  34. package/dist/core/agents/handoffs.test.d.ts.map +1 -0
  35. package/dist/core/agents/handoffs.test.js +320 -0
  36. package/dist/core/agents/handoffs.test.js.map +1 -0
  37. package/dist/core/agents/loader.test.js +1 -1
  38. package/dist/core/agents/suite.test.d.ts +8 -0
  39. package/dist/core/agents/suite.test.d.ts.map +1 -0
  40. package/dist/core/agents/suite.test.js +207 -0
  41. package/dist/core/agents/suite.test.js.map +1 -0
  42. package/dist/core/agents/tools.test.d.ts +8 -0
  43. package/dist/core/agents/tools.test.d.ts.map +1 -0
  44. package/dist/core/agents/tools.test.js +332 -0
  45. package/dist/core/agents/tools.test.js.map +1 -0
  46. package/dist/core/context.d.ts +171 -0
  47. package/dist/core/context.d.ts.map +1 -0
  48. package/dist/core/context.js +353 -0
  49. package/dist/core/context.js.map +1 -0
  50. package/dist/core/context.test.d.ts +8 -0
  51. package/dist/core/context.test.d.ts.map +1 -0
  52. package/dist/core/context.test.js +253 -0
  53. package/dist/core/context.test.js.map +1 -0
  54. package/dist/core/handoffs.d.ts +151 -0
  55. package/dist/core/handoffs.d.ts.map +1 -0
  56. package/dist/core/handoffs.js +220 -0
  57. package/dist/core/handoffs.js.map +1 -0
  58. package/dist/core/handoffs.test.d.ts +8 -0
  59. package/dist/core/handoffs.test.d.ts.map +1 -0
  60. package/dist/core/handoffs.test.js +231 -0
  61. package/dist/core/handoffs.test.js.map +1 -0
  62. package/dist/core/orchestrator.d.ts +246 -0
  63. package/dist/core/orchestrator.d.ts.map +1 -0
  64. package/dist/core/orchestrator.js +514 -0
  65. package/dist/core/orchestrator.js.map +1 -0
  66. package/dist/core/orchestrator.test.d.ts +8 -0
  67. package/dist/core/orchestrator.test.d.ts.map +1 -0
  68. package/dist/core/orchestrator.test.js +517 -0
  69. package/dist/core/orchestrator.test.js.map +1 -0
  70. package/dist/core/router.d.ts +102 -0
  71. package/dist/core/router.d.ts.map +1 -0
  72. package/dist/core/router.js +178 -0
  73. package/dist/core/router.js.map +1 -0
  74. package/dist/core/router.test.d.ts +8 -0
  75. package/dist/core/router.test.d.ts.map +1 -0
  76. package/dist/core/router.test.js +215 -0
  77. package/dist/core/router.test.js.map +1 -0
  78. package/dist/index.d.ts +9 -0
  79. package/dist/index.d.ts.map +1 -1
  80. package/dist/index.js +7 -0
  81. package/dist/index.js.map +1 -1
  82. package/dist/init.test.js +288 -0
  83. package/dist/providers/azure.d.ts +147 -0
  84. package/dist/providers/azure.d.ts.map +1 -0
  85. package/dist/providers/azure.js +491 -0
  86. package/dist/providers/azure.js.map +1 -0
  87. package/dist/providers/azure.test.d.ts +11 -0
  88. package/dist/providers/azure.test.d.ts.map +1 -0
  89. package/dist/providers/azure.test.js +330 -0
  90. package/dist/providers/azure.test.js.map +1 -0
  91. package/dist/providers/config.d.ts +87 -0
  92. package/dist/providers/config.d.ts.map +1 -0
  93. package/dist/providers/config.js +193 -0
  94. package/dist/providers/config.js.map +1 -0
  95. package/dist/providers/config.test.d.ts +7 -0
  96. package/dist/providers/config.test.d.ts.map +1 -0
  97. package/dist/providers/config.test.js +370 -0
  98. package/dist/providers/config.test.js.map +1 -0
  99. package/dist/providers/index.d.ts +18 -0
  100. package/dist/providers/index.d.ts.map +1 -0
  101. package/dist/providers/index.js +14 -0
  102. package/dist/providers/index.js.map +1 -0
  103. package/dist/providers/interface.d.ts +191 -0
  104. package/dist/providers/interface.d.ts.map +1 -0
  105. package/dist/providers/interface.js +94 -0
  106. package/dist/providers/interface.js.map +1 -0
  107. package/dist/providers/retry.d.ts +128 -0
  108. package/dist/providers/retry.d.ts.map +1 -0
  109. package/dist/providers/retry.js +205 -0
  110. package/dist/providers/retry.js.map +1 -0
  111. package/dist/providers/retry.test.d.ts +7 -0
  112. package/dist/providers/retry.test.d.ts.map +1 -0
  113. package/dist/providers/retry.test.js +439 -0
  114. package/dist/providers/retry.test.js.map +1 -0
  115. package/dist/providers/streaming.d.ts +157 -0
  116. package/dist/providers/streaming.d.ts.map +1 -0
  117. package/dist/providers/streaming.js +233 -0
  118. package/dist/providers/streaming.js.map +1 -0
  119. package/dist/providers/streaming.test.d.ts +7 -0
  120. package/dist/providers/streaming.test.d.ts.map +1 -0
  121. package/dist/providers/streaming.test.js +372 -0
  122. package/dist/providers/streaming.test.js.map +1 -0
  123. package/dist/providers/types.d.ts +209 -0
  124. package/dist/providers/types.d.ts.map +1 -0
  125. package/dist/providers/types.js +53 -0
  126. package/dist/providers/types.js.map +1 -0
  127. package/dist/providers/types.test.d.ts +7 -0
  128. package/dist/providers/types.test.d.ts.map +1 -0
  129. package/dist/providers/types.test.js +141 -0
  130. package/dist/providers/types.test.js.map +1 -0
  131. package/dist/tools/cli/beads.d.ts +27 -0
  132. package/dist/tools/cli/beads.d.ts.map +1 -0
  133. package/dist/tools/cli/beads.js +172 -0
  134. package/dist/tools/cli/beads.js.map +1 -0
  135. package/dist/tools/cli/beads.test.d.ts +8 -0
  136. package/dist/tools/cli/beads.test.d.ts.map +1 -0
  137. package/dist/tools/cli/beads.test.js +264 -0
  138. package/dist/tools/cli/beads.test.js.map +1 -0
  139. package/dist/tools/cli/editFile.d.ts +17 -0
  140. package/dist/tools/cli/editFile.d.ts.map +1 -0
  141. package/dist/tools/cli/editFile.js +125 -0
  142. package/dist/tools/cli/editFile.js.map +1 -0
  143. package/dist/tools/cli/editFile.test.d.ts +8 -0
  144. package/dist/tools/cli/editFile.test.d.ts.map +1 -0
  145. package/dist/tools/cli/editFile.test.js +177 -0
  146. package/dist/tools/cli/editFile.test.js.map +1 -0
  147. package/dist/tools/cli/readFile.d.ts +25 -0
  148. package/dist/tools/cli/readFile.d.ts.map +1 -0
  149. package/dist/tools/cli/readFile.js +118 -0
  150. package/dist/tools/cli/readFile.js.map +1 -0
  151. package/dist/tools/cli/readFile.test.d.ts +8 -0
  152. package/dist/tools/cli/readFile.test.d.ts.map +1 -0
  153. package/dist/tools/cli/readFile.test.js +194 -0
  154. package/dist/tools/cli/readFile.test.js.map +1 -0
  155. package/dist/tools/cli/search.d.ts +16 -0
  156. package/dist/tools/cli/search.d.ts.map +1 -0
  157. package/dist/tools/cli/search.js +261 -0
  158. package/dist/tools/cli/search.js.map +1 -0
  159. package/dist/tools/cli/search.test.d.ts +8 -0
  160. package/dist/tools/cli/search.test.d.ts.map +1 -0
  161. package/dist/tools/cli/search.test.js +172 -0
  162. package/dist/tools/cli/search.test.js.map +1 -0
  163. package/dist/tools/cli/subagent.d.ts +43 -0
  164. package/dist/tools/cli/subagent.d.ts.map +1 -0
  165. package/dist/tools/cli/subagent.js +99 -0
  166. package/dist/tools/cli/subagent.js.map +1 -0
  167. package/dist/tools/cli/subagent.test.d.ts +8 -0
  168. package/dist/tools/cli/subagent.test.d.ts.map +1 -0
  169. package/dist/tools/cli/subagent.test.js +190 -0
  170. package/dist/tools/cli/subagent.test.js.map +1 -0
  171. package/dist/tools/cli/terminal.d.ts +19 -0
  172. package/dist/tools/cli/terminal.d.ts.map +1 -0
  173. package/dist/tools/cli/terminal.js +164 -0
  174. package/dist/tools/cli/terminal.js.map +1 -0
  175. package/dist/tools/cli/terminal.test.d.ts +8 -0
  176. package/dist/tools/cli/terminal.test.d.ts.map +1 -0
  177. package/dist/tools/cli/terminal.test.js +161 -0
  178. package/dist/tools/cli/terminal.test.js.map +1 -0
  179. package/dist/tools/index.d.ts +25 -0
  180. package/dist/tools/index.d.ts.map +1 -0
  181. package/dist/tools/index.js +41 -0
  182. package/dist/tools/index.js.map +1 -0
  183. package/dist/tools/interface.d.ts +64 -0
  184. package/dist/tools/interface.d.ts.map +1 -0
  185. package/dist/tools/interface.js +37 -0
  186. package/dist/tools/interface.js.map +1 -0
  187. package/dist/tools/interface.test.d.ts +7 -0
  188. package/dist/tools/interface.test.d.ts.map +1 -0
  189. package/dist/tools/interface.test.js +179 -0
  190. package/dist/tools/interface.test.js.map +1 -0
  191. package/dist/tools/mcp/bridge.d.ts +48 -0
  192. package/dist/tools/mcp/bridge.d.ts.map +1 -0
  193. package/dist/tools/mcp/bridge.js +128 -0
  194. package/dist/tools/mcp/bridge.js.map +1 -0
  195. package/dist/tools/mcp/bridge.test.d.ts +8 -0
  196. package/dist/tools/mcp/bridge.test.d.ts.map +1 -0
  197. package/dist/tools/mcp/bridge.test.js +300 -0
  198. package/dist/tools/mcp/bridge.test.js.map +1 -0
  199. package/dist/tools/mcp/client.d.ts +135 -0
  200. package/dist/tools/mcp/client.d.ts.map +1 -0
  201. package/dist/tools/mcp/client.js +263 -0
  202. package/dist/tools/mcp/client.js.map +1 -0
  203. package/dist/tools/mcp/client.test.d.ts +8 -0
  204. package/dist/tools/mcp/client.test.d.ts.map +1 -0
  205. package/dist/tools/mcp/client.test.js +390 -0
  206. package/dist/tools/mcp/client.test.js.map +1 -0
  207. package/dist/tools/registry.d.ts +82 -0
  208. package/dist/tools/registry.d.ts.map +1 -0
  209. package/dist/tools/registry.js +99 -0
  210. package/dist/tools/registry.js.map +1 -0
  211. package/dist/tools/registry.test.d.ts +7 -0
  212. package/dist/tools/registry.test.d.ts.map +1 -0
  213. package/dist/tools/registry.test.js +199 -0
  214. package/dist/tools/registry.test.js.map +1 -0
  215. package/dist/tools/suite.test.d.ts +11 -0
  216. package/dist/tools/suite.test.d.ts.map +1 -0
  217. package/dist/tools/suite.test.js +119 -0
  218. package/dist/tools/suite.test.js.map +1 -0
  219. package/dist/tools/types.d.ts +75 -0
  220. package/dist/tools/types.d.ts.map +1 -0
  221. package/dist/tools/types.js +30 -0
  222. package/dist/tools/types.js.map +1 -0
  223. package/dist/tools/types.test.d.ts +7 -0
  224. package/dist/tools/types.test.d.ts.map +1 -0
  225. package/dist/tools/types.test.js +178 -0
  226. package/dist/tools/types.test.js.map +1 -0
  227. package/package.json +60 -56
  228. package/sbom.json +3302 -8
  229. package/templates/.github/agents/beth.agent.md +329 -329
  230. package/templates/.github/agents/developer.agent.md +572 -572
  231. package/templates/.github/agents/product-manager.agent.md +272 -272
  232. package/templates/.github/agents/researcher.agent.md +338 -338
  233. package/templates/.github/agents/security-reviewer.agent.md +465 -465
  234. package/templates/.github/agents/tester.agent.md +496 -496
  235. package/templates/.github/agents/ux-designer.agent.md +393 -393
  236. package/templates/mcp.json.example +4 -0
@@ -0,0 +1,150 @@
1
+ /**
2
+ * E2E tests for the help command.
3
+ * Run with: node --test dist/cli/commands/help.e2e.test.js
4
+ *
5
+ * Validates that `npx beth-copilot help` shows all available commands,
6
+ * options, and what gets installed.
7
+ */
8
+ import { describe, it } from 'node:test';
9
+ import assert from 'node:assert';
10
+ import { execSync } from 'child_process';
11
+ import { join, resolve } from 'path';
12
+ const CLI_PATH = resolve(join(import.meta.dirname, '..', '..', '..', 'bin', 'cli.js'));
13
+ /**
14
+ * Run a CLI command and capture output.
15
+ */
16
+ function runCli(args) {
17
+ try {
18
+ const stdout = execSync(`node "${CLI_PATH}" ${args}`, {
19
+ encoding: 'utf-8',
20
+ env: { ...process.env, NO_COLOR: '1' },
21
+ stdio: ['pipe', 'pipe', 'pipe'],
22
+ });
23
+ return { stdout, stderr: '', code: 0 };
24
+ }
25
+ catch (error) {
26
+ const e = error;
27
+ return { stdout: e.stdout || '', stderr: e.stderr || '', code: e.status || 1 };
28
+ }
29
+ }
30
+ describe('help command E2E', () => {
31
+ describe('invocation methods', () => {
32
+ it('should show help with "help" command', () => {
33
+ const result = runCli('help');
34
+ assert.strictEqual(result.code, 0, 'help should exit with code 0');
35
+ assert.ok(result.stdout.includes('Beth'), 'Should mention Beth');
36
+ });
37
+ it('should show help with "--help" flag', () => {
38
+ const result = runCli('--help');
39
+ assert.strictEqual(result.code, 0, '--help should exit with code 0');
40
+ assert.ok(result.stdout.includes('Beth'), 'Should mention Beth');
41
+ });
42
+ it('should show help with "-h" flag', () => {
43
+ const result = runCli('-h');
44
+ assert.strictEqual(result.code, 0, '-h should exit with code 0');
45
+ assert.ok(result.stdout.includes('Beth'), 'Should mention Beth');
46
+ });
47
+ it('should show help when run with no command', () => {
48
+ const result = runCli('');
49
+ assert.strictEqual(result.code, 0, 'No command should show help and exit 0');
50
+ assert.ok(result.stdout.includes('Beth'), 'Should mention Beth');
51
+ });
52
+ });
53
+ describe('all CLI commands listed', () => {
54
+ it('should list the init command', () => {
55
+ const result = runCli('help');
56
+ assert.ok(result.stdout.includes('init'), 'Help should list the init command');
57
+ });
58
+ it('should list the doctor command', () => {
59
+ const result = runCli('help');
60
+ assert.ok(result.stdout.includes('doctor'), 'Help should list the doctor command');
61
+ });
62
+ it('should list the quickstart command', () => {
63
+ const result = runCli('help');
64
+ assert.ok(result.stdout.includes('quickstart'), 'Help should list the quickstart command');
65
+ });
66
+ it('should list the help command', () => {
67
+ const result = runCli('help');
68
+ assert.ok(result.stdout.includes('help'), 'Help should list the help command');
69
+ });
70
+ });
71
+ describe('CLI options listed', () => {
72
+ it('should list --force option', () => {
73
+ const result = runCli('help');
74
+ assert.ok(result.stdout.includes('--force'), 'Help should list --force option');
75
+ });
76
+ it('should list --skip-backlog option', () => {
77
+ const result = runCli('help');
78
+ assert.ok(result.stdout.includes('--skip-backlog'), 'Help should list --skip-backlog option');
79
+ });
80
+ it('should list --skip-mcp option', () => {
81
+ const result = runCli('help');
82
+ assert.ok(result.stdout.includes('--skip-mcp'), 'Help should list --skip-mcp option');
83
+ });
84
+ it('should list --skip-beads option', () => {
85
+ const result = runCli('help');
86
+ assert.ok(result.stdout.includes('--skip-beads'), 'Help should list --skip-beads option');
87
+ });
88
+ it('should list --verbose option', () => {
89
+ const result = runCli('help');
90
+ assert.ok(result.stdout.includes('--verbose'), 'Help should list --verbose option');
91
+ });
92
+ });
93
+ describe('installation contents documented', () => {
94
+ it('should mention agents directory', () => {
95
+ const result = runCli('help');
96
+ assert.ok(result.stdout.includes('.github/agents') || result.stdout.includes('agents'), 'Help should document that agents get installed');
97
+ });
98
+ it('should mention skills directory', () => {
99
+ const result = runCli('help');
100
+ assert.ok(result.stdout.includes('.github/skills') || result.stdout.includes('skills'), 'Help should document that skills get installed');
101
+ });
102
+ it('should mention MCP config', () => {
103
+ const result = runCli('help');
104
+ assert.ok(result.stdout.includes('mcp.json') || result.stdout.includes('MCP'), 'Help should document MCP server config');
105
+ });
106
+ it('should mention AGENTS.md', () => {
107
+ const result = runCli('help');
108
+ assert.ok(result.stdout.includes('AGENTS.md'), 'Help should document AGENTS.md');
109
+ });
110
+ it('should mention copilot-instructions.md', () => {
111
+ const result = runCli('help');
112
+ assert.ok(result.stdout.includes('copilot-instructions'), 'Help should document copilot-instructions.md');
113
+ });
114
+ it('should mention VS Code settings', () => {
115
+ const result = runCli('help');
116
+ assert.ok(result.stdout.includes('settings.json') || result.stdout.includes('.vscode'), 'Help should document VS Code settings');
117
+ });
118
+ });
119
+ describe('post-install guidance', () => {
120
+ it('should mention VS Code as the target editor', () => {
121
+ const result = runCli('help');
122
+ assert.ok(result.stdout.includes('VS Code'), 'Help should mention VS Code');
123
+ });
124
+ it('should mention Copilot Chat', () => {
125
+ const result = runCli('help');
126
+ assert.ok(result.stdout.includes('Copilot Chat'), 'Help should mention Copilot Chat');
127
+ });
128
+ it('should mention @Beth as the entry point', () => {
129
+ const result = runCli('help');
130
+ assert.ok(result.stdout.includes('@Beth'), 'Help should mention @Beth as the entry point to the agent system');
131
+ });
132
+ });
133
+ describe('unknown command handling', () => {
134
+ it('should show error for unknown command', () => {
135
+ const result = runCli('foobar');
136
+ assert.strictEqual(result.code, 1, 'Unknown command should exit with code 1');
137
+ assert.ok(result.stdout.includes('Unknown command') || result.stderr.includes('Unknown command'), 'Should indicate unknown command');
138
+ });
139
+ it('should suggest help for unknown command', () => {
140
+ const result = runCli('foobar');
141
+ assert.ok(result.stdout.includes('help') || result.stderr.includes('help'), 'Should suggest running help');
142
+ });
143
+ it('should reject unknown flags', () => {
144
+ const result = runCli('init --nonexistent');
145
+ assert.strictEqual(result.code, 1, 'Unknown flag should exit with code 1');
146
+ assert.ok(result.stdout.includes('Unknown flag') || result.stderr.includes('Unknown flag'), 'Should indicate unknown flag');
147
+ });
148
+ });
149
+ });
150
+ //# sourceMappingURL=help.e2e.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.e2e.test.js","sourceRoot":"","sources":["../../../src/cli/commands/help.e2e.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAErC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;AAEvF;;GAEG;AACH,SAAS,MAAM,CAAC,IAAY;IAC1B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,QAAQ,KAAK,IAAI,EAAE,EAAE;YACpD,QAAQ,EAAE,OAAO;YACjB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE;YACtC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;QACH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IACzC,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,CAAC,GAAG,KAA8D,CAAC;QACzE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;IACjF,CAAC;AACH,CAAC;AAED,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,8BAA8B,CAAC,CAAC;YACnE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,qBAAqB,CAAC,CAAC;QACnE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC7C,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;YAChC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,gCAAgC,CAAC,CAAC;YACrE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,qBAAqB,CAAC,CAAC;QACnE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;YAC5B,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,4BAA4B,CAAC,CAAC;YACjE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,qBAAqB,CAAC,CAAC;QACnE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;YAC1B,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,wCAAwC,CAAC,CAAC;YAC7E,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,qBAAqB,CAAC,CAAC;QACnE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACvC,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;YACtC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAC9B,mCAAmC,CACpC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;YACxC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAChC,qCAAqC,CACtC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;YAC5C,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,EACpC,yCAAyC,CAC1C,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;YACtC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAC9B,mCAAmC,CACpC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;QAClC,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;YACpC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,EACjC,iCAAiC,CAClC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;YAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EACxC,wCAAwC,CACzC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;YACvC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,EACpC,oCAAoC,CACrC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,EACtC,sCAAsC,CACvC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;YACtC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,EACnC,mCAAmC,CACpC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAChD,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAC5E,gDAAgD,CACjD,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAC5E,gDAAgD,CACjD,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;YACnC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EACnE,wCAAwC,CACzC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;YAClC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,EACnC,gCAAgC,CACjC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;YAChD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAC9C,8CAA8C,CAC/C,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,EAC5E,uCAAuC,CACxC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACrC,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;YACrD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,EACjC,6BAA6B,CAC9B,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;YACrC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,EACtC,kCAAkC,CACnC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;YACjD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9B,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAC/B,kEAAkE,CACnE,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;QACxC,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;YAC/C,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;YAChC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,yCAAyC,CAAC,CAAC;YAC9E,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EACtF,iCAAiC,CAClC,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;YACjD,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;YAChC,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAChE,6BAA6B,CAC9B,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;YACrC,MAAM,MAAM,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAC;YAC5C,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,sCAAsC,CAAC,CAAC;YAC3E,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,EAChF,8BAA8B,CAC/B,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * E2E tests for init command.
3
+ * Run with: node --test dist/cli/commands/init.test.js
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=init.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.test.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,289 @@
1
+ /**
2
+ * E2E tests for init command.
3
+ * Run with: node --test dist/cli/commands/init.test.js
4
+ */
5
+ import { describe, it, beforeEach, afterEach } from 'node:test';
6
+ import assert from 'node:assert';
7
+ import { execSync } from 'child_process';
8
+ import { existsSync, mkdirSync, writeFileSync, rmSync, readFileSync, readdirSync } from 'fs';
9
+ import { join } from 'path';
10
+ import { tmpdir } from 'os';
11
+ // Expected files and directories from templates
12
+ const EXPECTED_AGENTS = [
13
+ 'beth.agent.md',
14
+ 'developer.agent.md',
15
+ 'product-manager.agent.md',
16
+ 'researcher.agent.md',
17
+ 'security-reviewer.agent.md',
18
+ 'tester.agent.md',
19
+ 'ux-designer.agent.md',
20
+ ];
21
+ const EXPECTED_SKILLS = [
22
+ 'framer-components',
23
+ 'prd',
24
+ 'security-analysis',
25
+ 'shadcn-ui',
26
+ 'vercel-react-best-practices',
27
+ 'web-design-guidelines',
28
+ ];
29
+ // Path to CLI binary
30
+ const CLI_PATH = join(process.cwd(), 'bin', 'cli.js');
31
+ /**
32
+ * Run the init command in a specified directory.
33
+ * Uses --skip-beads to avoid interactive prompts during testing.
34
+ */
35
+ function runInit(cwd, flags = []) {
36
+ // Always include --skip-beads to avoid interactive prompts
37
+ const allFlags = ['--skip-beads', ...flags];
38
+ const command = `node "${CLI_PATH}" init ${allFlags.join(' ')}`;
39
+ try {
40
+ const stdout = execSync(command, {
41
+ cwd,
42
+ encoding: 'utf-8',
43
+ env: { ...process.env, NO_COLOR: '1' }, // Disable colors and animations
44
+ stdio: ['pipe', 'pipe', 'pipe'],
45
+ });
46
+ return { stdout, stderr: '', exitCode: 0 };
47
+ }
48
+ catch (error) {
49
+ const execError = error;
50
+ return {
51
+ stdout: execError.stdout || '',
52
+ stderr: execError.stderr || '',
53
+ exitCode: execError.status || 1,
54
+ };
55
+ }
56
+ }
57
+ describe('init command E2E', () => {
58
+ let testDir;
59
+ beforeEach(() => {
60
+ // Create a temp directory for each test
61
+ testDir = join(tmpdir(), `beth-init-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
62
+ mkdirSync(testDir, { recursive: true });
63
+ });
64
+ afterEach(() => {
65
+ // Clean up temp directory
66
+ if (existsSync(testDir)) {
67
+ rmSync(testDir, { recursive: true, force: true });
68
+ }
69
+ });
70
+ describe('directory structure creation', () => {
71
+ it('should create .github/agents directory with all 7 agent files', () => {
72
+ runInit(testDir);
73
+ const agentsDir = join(testDir, '.github', 'agents');
74
+ assert.strictEqual(existsSync(agentsDir), true, '.github/agents directory should exist');
75
+ const files = readdirSync(agentsDir).filter(f => f.endsWith('.agent.md')).sort();
76
+ assert.deepStrictEqual(files, EXPECTED_AGENTS, 'All 7 agent files should be created');
77
+ });
78
+ it('should create .github/skills directory with all skill directories', () => {
79
+ runInit(testDir);
80
+ const skillsDir = join(testDir, '.github', 'skills');
81
+ assert.strictEqual(existsSync(skillsDir), true, '.github/skills directory should exist');
82
+ const dirs = readdirSync(skillsDir).filter(f => {
83
+ return existsSync(join(skillsDir, f, 'SKILL.md')) ||
84
+ existsSync(join(skillsDir, f, 'AGENTS.md'));
85
+ }).sort();
86
+ assert.deepStrictEqual(dirs, EXPECTED_SKILLS, 'All skill directories should be created');
87
+ });
88
+ it('should create AGENTS.md in project root', () => {
89
+ runInit(testDir);
90
+ const agentsMd = join(testDir, 'AGENTS.md');
91
+ assert.strictEqual(existsSync(agentsMd), true, 'AGENTS.md should exist');
92
+ const content = readFileSync(agentsMd, 'utf-8');
93
+ assert.ok(content.includes('beads'), 'AGENTS.md should mention beads');
94
+ });
95
+ it('should create Backlog.md in project root', () => {
96
+ runInit(testDir);
97
+ const backlogMd = join(testDir, 'Backlog.md');
98
+ assert.strictEqual(existsSync(backlogMd), true, 'Backlog.md should exist');
99
+ });
100
+ it('should create mcp.json.example in project root', () => {
101
+ runInit(testDir);
102
+ const mcpJson = join(testDir, 'mcp.json.example');
103
+ assert.strictEqual(existsSync(mcpJson), true, 'mcp.json.example should exist');
104
+ });
105
+ it('should create .vscode/settings.json', () => {
106
+ runInit(testDir);
107
+ const settingsJson = join(testDir, '.vscode', 'settings.json');
108
+ assert.strictEqual(existsSync(settingsJson), true, '.vscode/settings.json should exist');
109
+ });
110
+ it('should create copilot-instructions.md in .github', () => {
111
+ runInit(testDir);
112
+ const copilotInstructions = join(testDir, '.github', 'copilot-instructions.md');
113
+ assert.strictEqual(existsSync(copilotInstructions), true, '.github/copilot-instructions.md should exist');
114
+ });
115
+ });
116
+ describe('--force flag', () => {
117
+ it('should overwrite existing files when --force is used', () => {
118
+ // Create existing AGENTS.md with different content
119
+ const agentsMd = join(testDir, 'AGENTS.md');
120
+ writeFileSync(agentsMd, 'ORIGINAL CONTENT');
121
+ // Run init without --force
122
+ runInit(testDir);
123
+ let content = readFileSync(agentsMd, 'utf-8');
124
+ assert.strictEqual(content, 'ORIGINAL CONTENT', 'Should not overwrite without --force');
125
+ // Run init with --force
126
+ runInit(testDir, ['--force']);
127
+ content = readFileSync(agentsMd, 'utf-8');
128
+ assert.notStrictEqual(content, 'ORIGINAL CONTENT', 'Should overwrite with --force');
129
+ assert.ok(content.includes('beads'), 'Content should be from template');
130
+ });
131
+ it('should overwrite existing agent files with --force', () => {
132
+ // Create existing .github/agents directory with modified file
133
+ const agentsDir = join(testDir, '.github', 'agents');
134
+ mkdirSync(agentsDir, { recursive: true });
135
+ const bethAgent = join(agentsDir, 'beth.agent.md');
136
+ writeFileSync(bethAgent, 'MODIFIED BETH');
137
+ // Run init without --force
138
+ runInit(testDir);
139
+ let content = readFileSync(bethAgent, 'utf-8');
140
+ assert.strictEqual(content, 'MODIFIED BETH', 'Should not overwrite without --force');
141
+ // Run init with --force
142
+ runInit(testDir, ['--force']);
143
+ content = readFileSync(bethAgent, 'utf-8');
144
+ assert.notStrictEqual(content, 'MODIFIED BETH', 'Should overwrite with --force');
145
+ });
146
+ });
147
+ describe('--skip-backlog flag', () => {
148
+ it('should not create Backlog.md when --skip-backlog is used', () => {
149
+ runInit(testDir, ['--skip-backlog']);
150
+ const backlogMd = join(testDir, 'Backlog.md');
151
+ assert.strictEqual(existsSync(backlogMd), false, 'Backlog.md should not exist');
152
+ });
153
+ it('should still create other files when --skip-backlog is used', () => {
154
+ runInit(testDir, ['--skip-backlog']);
155
+ assert.strictEqual(existsSync(join(testDir, 'AGENTS.md')), true, 'AGENTS.md should exist');
156
+ assert.strictEqual(existsSync(join(testDir, 'mcp.json.example')), true, 'mcp.json.example should exist');
157
+ assert.strictEqual(existsSync(join(testDir, '.github', 'agents')), true, '.github/agents should exist');
158
+ });
159
+ });
160
+ describe('--skip-mcp flag', () => {
161
+ it('should not create mcp.json.example when --skip-mcp is used', () => {
162
+ runInit(testDir, ['--skip-mcp']);
163
+ const mcpJson = join(testDir, 'mcp.json.example');
164
+ assert.strictEqual(existsSync(mcpJson), false, 'mcp.json.example should not exist');
165
+ });
166
+ it('should still create other files when --skip-mcp is used', () => {
167
+ runInit(testDir, ['--skip-mcp']);
168
+ assert.strictEqual(existsSync(join(testDir, 'AGENTS.md')), true, 'AGENTS.md should exist');
169
+ assert.strictEqual(existsSync(join(testDir, 'Backlog.md')), true, 'Backlog.md should exist');
170
+ assert.strictEqual(existsSync(join(testDir, '.github', 'agents')), true, '.github/agents should exist');
171
+ });
172
+ });
173
+ describe('--skip-beads flag', () => {
174
+ it('should complete without beads check when --skip-beads is used', () => {
175
+ const result = runInit(testDir);
176
+ // Should complete successfully (exit 0)
177
+ assert.strictEqual(result.exitCode, 0, 'Should exit with code 0');
178
+ // Should have created files
179
+ assert.strictEqual(existsSync(join(testDir, '.github', 'agents')), true, 'Should create agents');
180
+ });
181
+ it('should show warning about skipping beads', () => {
182
+ const result = runInit(testDir);
183
+ // Output should mention skipping beads
184
+ assert.ok(result.stdout.includes('Skipped beads check') || result.stdout.includes('skip-beads'), 'Should warn about skipping beads');
185
+ });
186
+ });
187
+ describe('existing files handling', () => {
188
+ it('should warn about existing files without --force', () => {
189
+ // Create existing file
190
+ writeFileSync(join(testDir, 'AGENTS.md'), 'EXISTING');
191
+ const result = runInit(testDir);
192
+ assert.ok(result.stdout.includes('Skipped') || result.stdout.includes('exists'), 'Should mention that file was skipped');
193
+ });
194
+ it('should not overwrite existing files without --force', () => {
195
+ const agentsMd = join(testDir, 'AGENTS.md');
196
+ writeFileSync(agentsMd, 'ORIGINAL');
197
+ runInit(testDir);
198
+ const content = readFileSync(agentsMd, 'utf-8');
199
+ assert.strictEqual(content, 'ORIGINAL', 'Should preserve original content');
200
+ });
201
+ it('should count files correctly when some are skipped', () => {
202
+ // Create some existing files
203
+ writeFileSync(join(testDir, 'AGENTS.md'), 'EXISTING');
204
+ writeFileSync(join(testDir, 'Backlog.md'), 'EXISTING');
205
+ const result = runInit(testDir);
206
+ // Should have installed some files but not all
207
+ assert.ok(result.stdout.includes('Installed'), 'Should report installed files');
208
+ });
209
+ });
210
+ describe('empty directory behavior', () => {
211
+ it('should work correctly in an empty directory', () => {
212
+ const result = runInit(testDir);
213
+ assert.strictEqual(result.exitCode, 0, 'Should exit with code 0');
214
+ assert.strictEqual(existsSync(join(testDir, '.github', 'agents')), true, '.github/agents should exist');
215
+ assert.strictEqual(existsSync(join(testDir, '.github', 'skills')), true, '.github/skills should exist');
216
+ assert.strictEqual(existsSync(join(testDir, 'AGENTS.md')), true, 'AGENTS.md should exist');
217
+ });
218
+ it('should install all expected files in empty directory', () => {
219
+ runInit(testDir);
220
+ // Check all expected files exist
221
+ const agentsDir = join(testDir, '.github', 'agents');
222
+ const agentFiles = readdirSync(agentsDir).filter(f => f.endsWith('.agent.md'));
223
+ assert.strictEqual(agentFiles.length, 7, 'Should create 7 agent files');
224
+ const skillsDir = join(testDir, '.github', 'skills');
225
+ const skillDirs = readdirSync(skillsDir);
226
+ assert.strictEqual(skillDirs.length, 6, 'Should create 6 skill directories');
227
+ });
228
+ });
229
+ describe('existing .github folder behavior', () => {
230
+ it('should work in directory with existing .github folder', () => {
231
+ // Create existing .github folder with some content
232
+ const existingGithub = join(testDir, '.github', 'workflows');
233
+ mkdirSync(existingGithub, { recursive: true });
234
+ writeFileSync(join(existingGithub, 'ci.yml'), 'name: CI');
235
+ const result = runInit(testDir);
236
+ assert.strictEqual(result.exitCode, 0, 'Should exit with code 0');
237
+ // Should preserve existing content
238
+ assert.strictEqual(existsSync(join(existingGithub, 'ci.yml')), true, 'Should preserve existing .github/workflows/ci.yml');
239
+ // Should add new content
240
+ assert.strictEqual(existsSync(join(testDir, '.github', 'agents')), true, 'Should create .github/agents');
241
+ });
242
+ it('should merge with existing .github/agents folder', () => {
243
+ // Create existing agents folder with custom agent
244
+ const agentsDir = join(testDir, '.github', 'agents');
245
+ mkdirSync(agentsDir, { recursive: true });
246
+ writeFileSync(join(agentsDir, 'custom.agent.md'), 'CUSTOM AGENT');
247
+ runInit(testDir);
248
+ // Should preserve custom agent
249
+ assert.strictEqual(existsSync(join(agentsDir, 'custom.agent.md')), true, 'Should preserve custom.agent.md');
250
+ // Custom agent content should be unchanged
251
+ const customContent = readFileSync(join(agentsDir, 'custom.agent.md'), 'utf-8');
252
+ assert.strictEqual(customContent, 'CUSTOM AGENT', 'Custom agent content preserved');
253
+ // Should have added Beth agents (they don't exist yet)
254
+ assert.strictEqual(existsSync(join(agentsDir, 'beth.agent.md')), true, 'Should create beth.agent.md');
255
+ });
256
+ });
257
+ describe('multiple flag combinations', () => {
258
+ it('should handle --skip-backlog and --skip-mcp together', () => {
259
+ runInit(testDir, ['--skip-backlog', '--skip-mcp']);
260
+ assert.strictEqual(existsSync(join(testDir, 'Backlog.md')), false, 'Backlog.md should not exist');
261
+ assert.strictEqual(existsSync(join(testDir, 'mcp.json.example')), false, 'mcp.json.example should not exist');
262
+ assert.strictEqual(existsSync(join(testDir, 'AGENTS.md')), true, 'AGENTS.md should exist');
263
+ assert.strictEqual(existsSync(join(testDir, '.github', 'agents')), true, '.github/agents should exist');
264
+ });
265
+ it('should handle --force with skip flags', () => {
266
+ // Create existing file
267
+ writeFileSync(join(testDir, 'AGENTS.md'), 'ORIGINAL');
268
+ runInit(testDir, ['--force', '--skip-backlog', '--skip-mcp']);
269
+ // Force should overwrite
270
+ const content = readFileSync(join(testDir, 'AGENTS.md'), 'utf-8');
271
+ assert.notStrictEqual(content, 'ORIGINAL', 'Should overwrite with --force');
272
+ // Skip flags should still work
273
+ assert.strictEqual(existsSync(join(testDir, 'Backlog.md')), false, 'Backlog.md should not exist');
274
+ assert.strictEqual(existsSync(join(testDir, 'mcp.json.example')), false, 'mcp.json.example should not exist');
275
+ });
276
+ });
277
+ describe('output messages', () => {
278
+ it('should report number of installed files', () => {
279
+ const result = runInit(testDir);
280
+ assert.ok(result.stdout.includes('Installed'), 'Should mention installed files');
281
+ assert.ok(/Installed \d+ files/.test(result.stdout), 'Should report file count');
282
+ });
283
+ it('should show next steps after installation', () => {
284
+ const result = runInit(testDir);
285
+ assert.ok(result.stdout.includes('Next steps') || result.stdout.includes('VS Code'), 'Should show next steps');
286
+ });
287
+ });
288
+ });
289
+ //# sourceMappingURL=init.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.test.js","sourceRoot":"","sources":["../../../src/cli/commands/init.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * E2E tests for MCP configuration validation.
3
+ * Run with: node --test dist/cli/commands/mcp.e2e.test.js
4
+ *
5
+ * Validates that mcp.json.example is valid JSON, has expected structure,
6
+ * and that init correctly copies it to target projects.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=mcp.e2e.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.e2e.test.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/mcp.e2e.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * E2E tests for MCP configuration validation.
3
+ * Run with: node --test dist/cli/commands/mcp.e2e.test.js
4
+ *
5
+ * Validates that mcp.json.example is valid JSON, has expected structure,
6
+ * and that init correctly copies it to target projects.
7
+ */
8
+ import { describe, it, beforeEach, afterEach } from 'node:test';
9
+ import assert from 'node:assert';
10
+ import { execSync } from 'child_process';
11
+ import { existsSync, mkdirSync, rmSync, readFileSync, writeFileSync } from 'fs';
12
+ import { join, resolve } from 'path';
13
+ import { tmpdir } from 'os';
14
+ // Paths
15
+ const PROJECT_ROOT = resolve(join(import.meta.dirname, '..', '..', '..'));
16
+ const CLI_PATH = join(PROJECT_ROOT, 'bin', 'cli.js');
17
+ const TEMPLATE_MCP = join(PROJECT_ROOT, 'templates', 'mcp.json.example');
18
+ /**
19
+ * Run init command in a directory (with --skip-beads to avoid interactive prompts).
20
+ */
21
+ function runInit(cwd, flags = []) {
22
+ const allFlags = ['--skip-beads', ...flags];
23
+ const command = `node "${CLI_PATH}" init ${allFlags.join(' ')}`;
24
+ try {
25
+ const stdout = execSync(command, {
26
+ cwd,
27
+ encoding: 'utf-8',
28
+ env: { ...process.env, NO_COLOR: '1' },
29
+ stdio: ['pipe', 'pipe', 'pipe'],
30
+ });
31
+ return { stdout, stderr: '', exitCode: 0 };
32
+ }
33
+ catch (error) {
34
+ const execError = error;
35
+ return {
36
+ stdout: execError.stdout || '',
37
+ stderr: execError.stderr || '',
38
+ exitCode: execError.status || 1,
39
+ };
40
+ }
41
+ }
42
+ describe('MCP configuration validation', () => {
43
+ describe('template mcp.json.example', () => {
44
+ it('should exist in templates directory', () => {
45
+ assert.ok(existsSync(TEMPLATE_MCP), `mcp.json.example should exist at ${TEMPLATE_MCP}`);
46
+ });
47
+ it('should be valid JSON', () => {
48
+ const content = readFileSync(TEMPLATE_MCP, 'utf-8');
49
+ let parsed;
50
+ assert.doesNotThrow(() => {
51
+ parsed = JSON.parse(content);
52
+ }, 'mcp.json.example must be valid JSON');
53
+ assert.ok(parsed !== null && typeof parsed === 'object', 'Parsed JSON should be an object');
54
+ });
55
+ it('should have servers object at top level', () => {
56
+ const config = JSON.parse(readFileSync(TEMPLATE_MCP, 'utf-8'));
57
+ assert.ok(config.servers && typeof config.servers === 'object', 'mcp.json.example must have a "servers" object');
58
+ });
59
+ it('should have $schema field for VS Code validation', () => {
60
+ const config = JSON.parse(readFileSync(TEMPLATE_MCP, 'utf-8'));
61
+ assert.ok(config.$schema && typeof config.$schema === 'string', 'mcp.json.example should have $schema for VS Code MCP validation');
62
+ assert.ok(config.$schema.includes('vscode') || config.$schema.includes('mcp'), '$schema should reference VS Code or MCP schema');
63
+ });
64
+ it('should define at least one MCP server', () => {
65
+ const config = JSON.parse(readFileSync(TEMPLATE_MCP, 'utf-8'));
66
+ const serverNames = Object.keys(config.servers);
67
+ assert.ok(serverNames.length >= 1, `Should have at least 1 MCP server configured, found ${serverNames.length}`);
68
+ });
69
+ it('each server should have command+args or type+url', () => {
70
+ const config = JSON.parse(readFileSync(TEMPLATE_MCP, 'utf-8'));
71
+ for (const [name, server] of Object.entries(config.servers)) {
72
+ const s = server;
73
+ const hasCommandArgs = typeof s.command === 'string' && Array.isArray(s.args);
74
+ const hasTypeUrl = typeof s.type === 'string' && typeof s.url === 'string';
75
+ assert.ok(hasCommandArgs || hasTypeUrl, `Server "${name}" must have either (command + args) or (type + url). Got: ${JSON.stringify(s)}`);
76
+ }
77
+ });
78
+ it('should include shadcn server for component browsing', () => {
79
+ const config = JSON.parse(readFileSync(TEMPLATE_MCP, 'utf-8'));
80
+ assert.ok(config.servers.shadcn, 'Should include shadcn MCP server (used by developer agent for component browsing)');
81
+ });
82
+ });
83
+ describe('MCP file installation via init', () => {
84
+ let testDir;
85
+ beforeEach(() => {
86
+ testDir = join(tmpdir(), `beth-mcp-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
87
+ mkdirSync(testDir, { recursive: true });
88
+ });
89
+ afterEach(() => {
90
+ if (existsSync(testDir)) {
91
+ rmSync(testDir, { recursive: true, force: true });
92
+ }
93
+ });
94
+ it('should copy mcp.json.example to target project', () => {
95
+ runInit(testDir);
96
+ const mcpDest = join(testDir, 'mcp.json.example');
97
+ assert.ok(existsSync(mcpDest), 'mcp.json.example should be copied to project');
98
+ });
99
+ it('copied mcp.json.example should be valid JSON', () => {
100
+ runInit(testDir);
101
+ const mcpDest = join(testDir, 'mcp.json.example');
102
+ const content = readFileSync(mcpDest, 'utf-8');
103
+ assert.doesNotThrow(() => {
104
+ JSON.parse(content);
105
+ }, 'Copied mcp.json.example must be valid JSON');
106
+ });
107
+ it('copied file should match template content exactly', () => {
108
+ runInit(testDir);
109
+ const templateContent = readFileSync(TEMPLATE_MCP, 'utf-8');
110
+ const copiedContent = readFileSync(join(testDir, 'mcp.json.example'), 'utf-8');
111
+ assert.strictEqual(copiedContent, templateContent, 'Copied file should match template exactly');
112
+ });
113
+ it('should NOT copy mcp.json.example when --skip-mcp is used', () => {
114
+ runInit(testDir, ['--skip-mcp']);
115
+ const mcpDest = join(testDir, 'mcp.json.example');
116
+ assert.ok(!existsSync(mcpDest), 'mcp.json.example should NOT exist with --skip-mcp');
117
+ });
118
+ it('should preserve existing mcp.json.example without --force', () => {
119
+ const mcpDest = join(testDir, 'mcp.json.example');
120
+ const original = '{"custom": true}';
121
+ writeFileSync(mcpDest, original);
122
+ runInit(testDir);
123
+ const content = readFileSync(mcpDest, 'utf-8');
124
+ assert.strictEqual(content, original, 'Should not overwrite existing mcp.json.example without --force');
125
+ });
126
+ it('should overwrite mcp.json.example with --force', () => {
127
+ const mcpDest = join(testDir, 'mcp.json.example');
128
+ const original = '{"custom": true}';
129
+ writeFileSync(mcpDest, original);
130
+ runInit(testDir, ['--force']);
131
+ const content = readFileSync(mcpDest, 'utf-8');
132
+ assert.notStrictEqual(content, original, 'Should overwrite with --force');
133
+ // Verify it's valid JSON from the template
134
+ const parsed = JSON.parse(content);
135
+ assert.ok(parsed.servers, 'Overwritten file should have servers from template');
136
+ });
137
+ });
138
+ });
139
+ //# sourceMappingURL=mcp.e2e.test.js.map