beth-copilot 1.0.17 → 1.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 (265) hide show
  1. package/CHANGELOG.md +41 -28
  2. package/README.md +87 -247
  3. package/bin/cli.js +115 -7
  4. package/dist/__tests__/smoke.test.d.ts +8 -0
  5. package/dist/__tests__/smoke.test.d.ts.map +1 -0
  6. package/dist/__tests__/smoke.test.js +49 -0
  7. package/dist/__tests__/smoke.test.js.map +1 -0
  8. package/dist/cli/commands/beads.e2e.test.d.ts +13 -0
  9. package/dist/cli/commands/beads.e2e.test.d.ts.map +1 -0
  10. package/dist/cli/commands/beads.e2e.test.js +526 -0
  11. package/dist/cli/commands/beads.e2e.test.js.map +1 -0
  12. package/dist/cli/commands/cli-edge-cases.e2e.test.d.ts +32 -0
  13. package/dist/cli/commands/cli-edge-cases.e2e.test.d.ts.map +1 -0
  14. package/dist/cli/commands/cli-edge-cases.e2e.test.js +162 -0
  15. package/dist/cli/commands/cli-edge-cases.e2e.test.js.map +1 -0
  16. package/dist/cli/commands/close.d.ts +89 -0
  17. package/dist/cli/commands/close.d.ts.map +1 -0
  18. package/dist/cli/commands/close.e2e.test.d.ts +27 -0
  19. package/dist/cli/commands/close.e2e.test.d.ts.map +1 -0
  20. package/dist/cli/commands/close.e2e.test.js +252 -0
  21. package/dist/cli/commands/close.e2e.test.js.map +1 -0
  22. package/dist/cli/commands/close.js +309 -0
  23. package/dist/cli/commands/close.js.map +1 -0
  24. package/dist/cli/commands/close.test.d.ts +15 -0
  25. package/dist/cli/commands/close.test.d.ts.map +1 -0
  26. package/dist/cli/commands/close.test.js +634 -0
  27. package/dist/cli/commands/close.test.js.map +1 -0
  28. package/dist/cli/commands/doctor.d.ts +23 -0
  29. package/dist/cli/commands/doctor.d.ts.map +1 -1
  30. package/dist/cli/commands/doctor.js +93 -0
  31. package/dist/cli/commands/doctor.js.map +1 -1
  32. package/dist/cli/commands/doctor.test.js +209 -0
  33. package/dist/cli/commands/doctor.test.js.map +1 -1
  34. package/dist/cli/commands/framework-isolation.test.d.ts +30 -0
  35. package/dist/cli/commands/framework-isolation.test.d.ts.map +1 -0
  36. package/dist/cli/commands/framework-isolation.test.js +119 -0
  37. package/dist/cli/commands/framework-isolation.test.js.map +1 -0
  38. package/dist/cli/commands/init-logic.e2e.test.d.ts +37 -0
  39. package/dist/cli/commands/init-logic.e2e.test.d.ts.map +1 -0
  40. package/dist/cli/commands/init-logic.e2e.test.js +305 -0
  41. package/dist/cli/commands/init-logic.e2e.test.js.map +1 -0
  42. package/dist/cli/commands/land.d.ts +142 -0
  43. package/dist/cli/commands/land.d.ts.map +1 -0
  44. package/dist/cli/commands/land.js +647 -0
  45. package/dist/cli/commands/land.js.map +1 -0
  46. package/dist/cli/commands/land.test.d.ts +20 -0
  47. package/dist/cli/commands/land.test.d.ts.map +1 -0
  48. package/dist/cli/commands/land.test.js +622 -0
  49. package/dist/cli/commands/land.test.js.map +1 -0
  50. package/dist/cli/commands/pipeline.e2e.test.js +1 -1
  51. package/dist/cli/commands/pipeline.e2e.test.js.map +1 -1
  52. package/dist/cli/commands/pre-push-guard.d.ts +84 -0
  53. package/dist/cli/commands/pre-push-guard.d.ts.map +1 -0
  54. package/dist/cli/commands/pre-push-guard.e2e.test.d.ts +24 -0
  55. package/dist/cli/commands/pre-push-guard.e2e.test.d.ts.map +1 -0
  56. package/dist/cli/commands/pre-push-guard.e2e.test.js +171 -0
  57. package/dist/cli/commands/pre-push-guard.e2e.test.js.map +1 -0
  58. package/dist/cli/commands/pre-push-guard.js +257 -0
  59. package/dist/cli/commands/pre-push-guard.js.map +1 -0
  60. package/dist/cli/commands/pre-push-guard.test.d.ts +15 -0
  61. package/dist/cli/commands/pre-push-guard.test.d.ts.map +1 -0
  62. package/dist/cli/commands/pre-push-guard.test.js +397 -0
  63. package/dist/cli/commands/pre-push-guard.test.js.map +1 -0
  64. package/dist/cli/commands/quickstart-expanded.e2e.test.d.ts +23 -0
  65. package/dist/cli/commands/quickstart-expanded.e2e.test.d.ts.map +1 -0
  66. package/dist/cli/commands/quickstart-expanded.e2e.test.js +179 -0
  67. package/dist/cli/commands/quickstart-expanded.e2e.test.js.map +1 -0
  68. package/dist/cli/commands/quickstart.test.js +40 -2
  69. package/dist/cli/commands/quickstart.test.js.map +1 -1
  70. package/dist/core/agents/suite.test.js +4 -2
  71. package/dist/core/agents/suite.test.js.map +1 -1
  72. package/dist/core/agents/tools.test.js +5 -1
  73. package/dist/core/agents/tools.test.js.map +1 -1
  74. package/dist/index.d.ts +3 -10
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +5 -10
  77. package/dist/index.js.map +1 -1
  78. package/package.json +15 -9
  79. package/sbom.json +2011 -819
  80. package/templates/.github/agents/beth.agent.md +222 -45
  81. package/templates/.github/agents/developer.agent.md +37 -67
  82. package/templates/.github/agents/product-manager.agent.md +15 -57
  83. package/templates/.github/agents/researcher.agent.md +20 -60
  84. package/templates/.github/agents/security-reviewer.agent.md +29 -70
  85. package/templates/.github/agents/tester.agent.md +40 -58
  86. package/templates/.github/agents/ux-designer.agent.md +20 -63
  87. package/templates/.github/copilot-instructions.md +217 -204
  88. package/templates/AGENTS.md +108 -20
  89. package/dist/core/context.d.ts +0 -171
  90. package/dist/core/context.d.ts.map +0 -1
  91. package/dist/core/context.js +0 -353
  92. package/dist/core/context.js.map +0 -1
  93. package/dist/core/context.test.d.ts +0 -8
  94. package/dist/core/context.test.d.ts.map +0 -1
  95. package/dist/core/context.test.js +0 -253
  96. package/dist/core/context.test.js.map +0 -1
  97. package/dist/core/handoffs.d.ts +0 -151
  98. package/dist/core/handoffs.d.ts.map +0 -1
  99. package/dist/core/handoffs.js +0 -220
  100. package/dist/core/handoffs.js.map +0 -1
  101. package/dist/core/handoffs.test.d.ts +0 -8
  102. package/dist/core/handoffs.test.d.ts.map +0 -1
  103. package/dist/core/handoffs.test.js +0 -231
  104. package/dist/core/handoffs.test.js.map +0 -1
  105. package/dist/core/orchestrator.d.ts +0 -246
  106. package/dist/core/orchestrator.d.ts.map +0 -1
  107. package/dist/core/orchestrator.js +0 -514
  108. package/dist/core/orchestrator.js.map +0 -1
  109. package/dist/core/orchestrator.test.d.ts +0 -8
  110. package/dist/core/orchestrator.test.d.ts.map +0 -1
  111. package/dist/core/orchestrator.test.js +0 -517
  112. package/dist/core/orchestrator.test.js.map +0 -1
  113. package/dist/core/router.d.ts +0 -102
  114. package/dist/core/router.d.ts.map +0 -1
  115. package/dist/core/router.js +0 -178
  116. package/dist/core/router.js.map +0 -1
  117. package/dist/core/router.test.d.ts +0 -8
  118. package/dist/core/router.test.d.ts.map +0 -1
  119. package/dist/core/router.test.js +0 -215
  120. package/dist/core/router.test.js.map +0 -1
  121. package/dist/init.test.js +0 -288
  122. package/dist/providers/azure.d.ts +0 -147
  123. package/dist/providers/azure.d.ts.map +0 -1
  124. package/dist/providers/azure.js +0 -491
  125. package/dist/providers/azure.js.map +0 -1
  126. package/dist/providers/azure.test.d.ts +0 -11
  127. package/dist/providers/azure.test.d.ts.map +0 -1
  128. package/dist/providers/azure.test.js +0 -330
  129. package/dist/providers/azure.test.js.map +0 -1
  130. package/dist/providers/config.d.ts +0 -87
  131. package/dist/providers/config.d.ts.map +0 -1
  132. package/dist/providers/config.js +0 -193
  133. package/dist/providers/config.js.map +0 -1
  134. package/dist/providers/config.test.d.ts +0 -7
  135. package/dist/providers/config.test.d.ts.map +0 -1
  136. package/dist/providers/config.test.js +0 -370
  137. package/dist/providers/config.test.js.map +0 -1
  138. package/dist/providers/index.d.ts +0 -18
  139. package/dist/providers/index.d.ts.map +0 -1
  140. package/dist/providers/index.js +0 -14
  141. package/dist/providers/index.js.map +0 -1
  142. package/dist/providers/interface.d.ts +0 -191
  143. package/dist/providers/interface.d.ts.map +0 -1
  144. package/dist/providers/interface.js +0 -94
  145. package/dist/providers/interface.js.map +0 -1
  146. package/dist/providers/retry.d.ts +0 -128
  147. package/dist/providers/retry.d.ts.map +0 -1
  148. package/dist/providers/retry.js +0 -205
  149. package/dist/providers/retry.js.map +0 -1
  150. package/dist/providers/retry.test.d.ts +0 -7
  151. package/dist/providers/retry.test.d.ts.map +0 -1
  152. package/dist/providers/retry.test.js +0 -439
  153. package/dist/providers/retry.test.js.map +0 -1
  154. package/dist/providers/streaming.d.ts +0 -157
  155. package/dist/providers/streaming.d.ts.map +0 -1
  156. package/dist/providers/streaming.js +0 -233
  157. package/dist/providers/streaming.js.map +0 -1
  158. package/dist/providers/streaming.test.d.ts +0 -7
  159. package/dist/providers/streaming.test.d.ts.map +0 -1
  160. package/dist/providers/streaming.test.js +0 -372
  161. package/dist/providers/streaming.test.js.map +0 -1
  162. package/dist/providers/types.d.ts +0 -209
  163. package/dist/providers/types.d.ts.map +0 -1
  164. package/dist/providers/types.js +0 -53
  165. package/dist/providers/types.js.map +0 -1
  166. package/dist/providers/types.test.d.ts +0 -7
  167. package/dist/providers/types.test.d.ts.map +0 -1
  168. package/dist/providers/types.test.js +0 -141
  169. package/dist/providers/types.test.js.map +0 -1
  170. package/dist/tools/cli/beads.d.ts +0 -27
  171. package/dist/tools/cli/beads.d.ts.map +0 -1
  172. package/dist/tools/cli/beads.js +0 -172
  173. package/dist/tools/cli/beads.js.map +0 -1
  174. package/dist/tools/cli/beads.test.d.ts +0 -8
  175. package/dist/tools/cli/beads.test.d.ts.map +0 -1
  176. package/dist/tools/cli/beads.test.js +0 -264
  177. package/dist/tools/cli/beads.test.js.map +0 -1
  178. package/dist/tools/cli/editFile.d.ts +0 -17
  179. package/dist/tools/cli/editFile.d.ts.map +0 -1
  180. package/dist/tools/cli/editFile.js +0 -125
  181. package/dist/tools/cli/editFile.js.map +0 -1
  182. package/dist/tools/cli/editFile.test.d.ts +0 -8
  183. package/dist/tools/cli/editFile.test.d.ts.map +0 -1
  184. package/dist/tools/cli/editFile.test.js +0 -177
  185. package/dist/tools/cli/editFile.test.js.map +0 -1
  186. package/dist/tools/cli/readFile.d.ts +0 -25
  187. package/dist/tools/cli/readFile.d.ts.map +0 -1
  188. package/dist/tools/cli/readFile.js +0 -118
  189. package/dist/tools/cli/readFile.js.map +0 -1
  190. package/dist/tools/cli/readFile.test.d.ts +0 -8
  191. package/dist/tools/cli/readFile.test.d.ts.map +0 -1
  192. package/dist/tools/cli/readFile.test.js +0 -194
  193. package/dist/tools/cli/readFile.test.js.map +0 -1
  194. package/dist/tools/cli/search.d.ts +0 -16
  195. package/dist/tools/cli/search.d.ts.map +0 -1
  196. package/dist/tools/cli/search.js +0 -261
  197. package/dist/tools/cli/search.js.map +0 -1
  198. package/dist/tools/cli/search.test.d.ts +0 -8
  199. package/dist/tools/cli/search.test.d.ts.map +0 -1
  200. package/dist/tools/cli/search.test.js +0 -172
  201. package/dist/tools/cli/search.test.js.map +0 -1
  202. package/dist/tools/cli/subagent.d.ts +0 -43
  203. package/dist/tools/cli/subagent.d.ts.map +0 -1
  204. package/dist/tools/cli/subagent.js +0 -99
  205. package/dist/tools/cli/subagent.js.map +0 -1
  206. package/dist/tools/cli/subagent.test.d.ts +0 -8
  207. package/dist/tools/cli/subagent.test.d.ts.map +0 -1
  208. package/dist/tools/cli/subagent.test.js +0 -190
  209. package/dist/tools/cli/subagent.test.js.map +0 -1
  210. package/dist/tools/cli/terminal.d.ts +0 -19
  211. package/dist/tools/cli/terminal.d.ts.map +0 -1
  212. package/dist/tools/cli/terminal.js +0 -164
  213. package/dist/tools/cli/terminal.js.map +0 -1
  214. package/dist/tools/cli/terminal.test.d.ts +0 -8
  215. package/dist/tools/cli/terminal.test.d.ts.map +0 -1
  216. package/dist/tools/cli/terminal.test.js +0 -161
  217. package/dist/tools/cli/terminal.test.js.map +0 -1
  218. package/dist/tools/index.d.ts +0 -25
  219. package/dist/tools/index.d.ts.map +0 -1
  220. package/dist/tools/index.js +0 -41
  221. package/dist/tools/index.js.map +0 -1
  222. package/dist/tools/interface.d.ts +0 -64
  223. package/dist/tools/interface.d.ts.map +0 -1
  224. package/dist/tools/interface.js +0 -37
  225. package/dist/tools/interface.js.map +0 -1
  226. package/dist/tools/interface.test.d.ts +0 -7
  227. package/dist/tools/interface.test.d.ts.map +0 -1
  228. package/dist/tools/interface.test.js +0 -179
  229. package/dist/tools/interface.test.js.map +0 -1
  230. package/dist/tools/mcp/bridge.d.ts +0 -48
  231. package/dist/tools/mcp/bridge.d.ts.map +0 -1
  232. package/dist/tools/mcp/bridge.js +0 -128
  233. package/dist/tools/mcp/bridge.js.map +0 -1
  234. package/dist/tools/mcp/bridge.test.d.ts +0 -8
  235. package/dist/tools/mcp/bridge.test.d.ts.map +0 -1
  236. package/dist/tools/mcp/bridge.test.js +0 -300
  237. package/dist/tools/mcp/bridge.test.js.map +0 -1
  238. package/dist/tools/mcp/client.d.ts +0 -135
  239. package/dist/tools/mcp/client.d.ts.map +0 -1
  240. package/dist/tools/mcp/client.js +0 -263
  241. package/dist/tools/mcp/client.js.map +0 -1
  242. package/dist/tools/mcp/client.test.d.ts +0 -8
  243. package/dist/tools/mcp/client.test.d.ts.map +0 -1
  244. package/dist/tools/mcp/client.test.js +0 -390
  245. package/dist/tools/mcp/client.test.js.map +0 -1
  246. package/dist/tools/registry.d.ts +0 -82
  247. package/dist/tools/registry.d.ts.map +0 -1
  248. package/dist/tools/registry.js +0 -99
  249. package/dist/tools/registry.js.map +0 -1
  250. package/dist/tools/registry.test.d.ts +0 -7
  251. package/dist/tools/registry.test.d.ts.map +0 -1
  252. package/dist/tools/registry.test.js +0 -199
  253. package/dist/tools/registry.test.js.map +0 -1
  254. package/dist/tools/suite.test.d.ts +0 -11
  255. package/dist/tools/suite.test.d.ts.map +0 -1
  256. package/dist/tools/suite.test.js +0 -119
  257. package/dist/tools/suite.test.js.map +0 -1
  258. package/dist/tools/types.d.ts +0 -75
  259. package/dist/tools/types.d.ts.map +0 -1
  260. package/dist/tools/types.js +0 -30
  261. package/dist/tools/types.js.map +0 -1
  262. package/dist/tools/types.test.d.ts +0 -7
  263. package/dist/tools/types.test.d.ts.map +0 -1
  264. package/dist/tools/types.test.js +0 -178
  265. package/dist/tools/types.test.js.map +0 -1
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Pre-Push Guard — Branch discipline enforcement
3
+ *
4
+ * Validates before push:
5
+ * - No direct pushes to main/master (BLOCKS)
6
+ * - Current branch follows epic/<id> convention (WARNING)
7
+ * - Open in-progress beads issues reported (WARNING)
8
+ * - Bypassed with BETH_SKIP_PUSH_GUARD=1 environment variable
9
+ */
10
+ import { execFileSync } from 'child_process';
11
+ const COLORS = {
12
+ reset: '\x1b[0m',
13
+ bright: '\x1b[1m',
14
+ red: '\x1b[31m',
15
+ yellow: '\x1b[33m',
16
+ cyan: '\x1b[36m',
17
+ };
18
+ /** Protected branch names that cannot receive direct pushes. */
19
+ const PROTECTED_BRANCHES = ['main', 'master'];
20
+ /** Epic branch naming convention: epic/<rig>-<hash> */
21
+ const EPIC_BRANCH_PATTERN = /^epic\/[a-z]+-[a-z0-9]+$/;
22
+ /** Release branches are also valid push targets. */
23
+ const RELEASE_BRANCH_PATTERN = /^release\/v?\d+/;
24
+ /**
25
+ * Parse pre-push stdin input into structured refs.
26
+ * Git sends: <local ref> <local SHA> <remote ref> <remote SHA>
27
+ * One line per ref being pushed.
28
+ */
29
+ export function parsePushRefs(stdin) {
30
+ return stdin
31
+ .trim()
32
+ .split('\n')
33
+ .filter((line) => line.trim().length > 0)
34
+ .map((line) => {
35
+ const parts = line.trim().split(/\s+/);
36
+ return {
37
+ localRef: parts[0] || '',
38
+ localSha: parts[1] || '',
39
+ remoteRef: parts[2] || '',
40
+ remoteSha: parts[3] || '',
41
+ };
42
+ });
43
+ }
44
+ /**
45
+ * Extract branch name from a Git ref.
46
+ * refs/heads/main → main
47
+ * refs/heads/epic/beth-abc123 → epic/beth-abc123
48
+ */
49
+ export function extractBranchName(ref) {
50
+ const prefix = 'refs/heads/';
51
+ if (ref.startsWith(prefix)) {
52
+ return ref.slice(prefix.length);
53
+ }
54
+ return ref;
55
+ }
56
+ /**
57
+ * Check if a branch name is protected (main, master).
58
+ */
59
+ export function isProtectedBranch(branch) {
60
+ return PROTECTED_BRANCHES.includes(branch);
61
+ }
62
+ /**
63
+ * Check if the branch follows the epic/<id> convention.
64
+ */
65
+ export function isEpicBranch(branch) {
66
+ return EPIC_BRANCH_PATTERN.test(branch);
67
+ }
68
+ /**
69
+ * Check if the branch is a release branch.
70
+ */
71
+ export function isReleaseBranch(branch) {
72
+ return RELEASE_BRANCH_PATTERN.test(branch);
73
+ }
74
+ /**
75
+ * Check if the branch follows any recognized naming convention.
76
+ */
77
+ export function isRecognizedBranch(branch) {
78
+ return isEpicBranch(branch) || isReleaseBranch(branch) || isProtectedBranch(branch);
79
+ }
80
+ /**
81
+ * Get the current Git branch name.
82
+ * Returns null if not in a git repo or in detached HEAD state.
83
+ */
84
+ export function getCurrentBranch() {
85
+ try {
86
+ const result = execFileSync('git', ['branch', '--show-current'], {
87
+ encoding: 'utf-8',
88
+ timeout: 5000,
89
+ stdio: ['pipe', 'pipe', 'pipe'],
90
+ }).trim();
91
+ return result || null;
92
+ }
93
+ catch {
94
+ return null;
95
+ }
96
+ }
97
+ /**
98
+ * Get beads issues with in_progress status.
99
+ * Returns empty array if bd is unavailable or errors.
100
+ */
101
+ export function getInProgressIssues() {
102
+ try {
103
+ const output = execFileSync('bd', ['list', '--json'], {
104
+ encoding: 'utf-8',
105
+ timeout: 10000,
106
+ stdio: ['pipe', 'pipe', 'pipe'],
107
+ });
108
+ const parsed = JSON.parse(output);
109
+ if (!Array.isArray(parsed))
110
+ return [];
111
+ return parsed
112
+ .filter((item) => typeof item === 'object' &&
113
+ item !== null &&
114
+ 'id' in item &&
115
+ 'title' in item &&
116
+ 'status' in item &&
117
+ item.status === 'in_progress')
118
+ .map((item) => ({ id: item.id, title: item.title }));
119
+ }
120
+ catch {
121
+ return [];
122
+ }
123
+ }
124
+ /**
125
+ * Run all pre-push guard checks.
126
+ *
127
+ * @param currentBranch - Current Git branch name
128
+ * @param refs - Optional parsed push refs from Git stdin (for remote ref validation)
129
+ * @param checkBeads - Whether to check for in-progress beads issues
130
+ * @returns GuardResult with allowed status and diagnostics
131
+ */
132
+ export function runGuard(currentBranch, refs, checkBeads = true) {
133
+ const errors = [];
134
+ const warnings = [];
135
+ // Check 1: No pushing to protected branches via remote refs
136
+ if (refs && refs.length > 0) {
137
+ for (const ref of refs) {
138
+ const targetBranch = extractBranchName(ref.remoteRef);
139
+ if (isProtectedBranch(targetBranch)) {
140
+ errors.push(`Direct push to '${targetBranch}' is blocked. Use a PR from your epic branch.`);
141
+ }
142
+ }
143
+ }
144
+ // Check 1b: Also block if current branch IS a protected branch
145
+ // (catches the common case without needing stdin refs)
146
+ if (currentBranch && isProtectedBranch(currentBranch)) {
147
+ const msg = `Pushing from '${currentBranch}' is blocked. Work on an epic branch.`;
148
+ if (!errors.some((e) => e.includes(currentBranch))) {
149
+ errors.push(msg);
150
+ }
151
+ }
152
+ // Check 2: Current branch should follow epic convention
153
+ if (currentBranch && !isRecognizedBranch(currentBranch)) {
154
+ warnings.push(`Branch '${currentBranch}' doesn't follow the epic/<id> convention. Consider renaming.`);
155
+ }
156
+ // Check 3: Warn about in-progress beads issues (soft check)
157
+ if (checkBeads) {
158
+ try {
159
+ const inProgress = getInProgressIssues();
160
+ if (inProgress.length > 0) {
161
+ warnings.push(`${inProgress.length} issue${inProgress.length === 1 ? '' : 's'} still in_progress:`);
162
+ for (const issue of inProgress) {
163
+ warnings.push(` ◐ ${issue.id}: ${issue.title}`);
164
+ }
165
+ warnings.push('Consider closing completed work before pushing.');
166
+ }
167
+ }
168
+ catch {
169
+ // bd not available — skip silently
170
+ }
171
+ }
172
+ return {
173
+ allowed: errors.length === 0,
174
+ errors,
175
+ warnings,
176
+ };
177
+ }
178
+ /**
179
+ * Main entry point for the pre-push guard command.
180
+ * Reads refs from stdin (if available) and runs all checks.
181
+ */
182
+ export async function prePushGuard(stdinInput) {
183
+ // Check bypass
184
+ if (process.env.BETH_SKIP_PUSH_GUARD === '1') {
185
+ console.error(`${COLORS.yellow}⚠ Pre-push guard bypassed (BETH_SKIP_PUSH_GUARD=1)${COLORS.reset}`);
186
+ return;
187
+ }
188
+ // Read stdin if not provided (Git pre-push pipes refs via stdin)
189
+ let stdin = stdinInput;
190
+ if (stdin === undefined) {
191
+ const fs = await import('fs');
192
+ try {
193
+ stdin = fs.readFileSync(0, 'utf-8');
194
+ }
195
+ catch {
196
+ stdin = '';
197
+ }
198
+ }
199
+ const refs = stdin.trim() ? parsePushRefs(stdin) : undefined;
200
+ const currentBranch = getCurrentBranch();
201
+ const result = runGuard(currentBranch, refs);
202
+ // Print warnings
203
+ for (const warning of result.warnings) {
204
+ console.error(`${COLORS.yellow}⚠ ${warning}${COLORS.reset}`);
205
+ }
206
+ // Print errors and exit non-zero to block push
207
+ if (!result.allowed) {
208
+ console.error('');
209
+ for (const error of result.errors) {
210
+ console.error(`${COLORS.red}✗ ${error}${COLORS.reset}`);
211
+ }
212
+ console.error(`\n${COLORS.yellow}Set BETH_SKIP_PUSH_GUARD=1 to bypass.${COLORS.reset}`);
213
+ process.exit(1);
214
+ }
215
+ }
216
+ /**
217
+ * Generate the shell script content to append to .beads/hooks/pre-push.
218
+ * Pure shell — no Node dependency at hook time for speed.
219
+ */
220
+ export function generateHookScript() {
221
+ return `
222
+ # --- BEGIN BETH GUARD ---
223
+ # Branch discipline enforcement — installed by beth-copilot
224
+ # Bypass: BETH_SKIP_PUSH_GUARD=1 git push
225
+ if [ "\$BETH_SKIP_PUSH_GUARD" = "1" ]; then
226
+ echo "⚠ Pre-push guard bypassed (BETH_SKIP_PUSH_GUARD=1)" >&2
227
+ else
228
+ _beth_branch=\$(git branch --show-current 2>/dev/null)
229
+
230
+ # Block pushes from protected branches
231
+ case "\$_beth_branch" in
232
+ main|master)
233
+ echo "✗ Pushing from '\$_beth_branch' is blocked. Work on an epic branch." >&2
234
+ echo " Set BETH_SKIP_PUSH_GUARD=1 to bypass." >&2
235
+ exit 1
236
+ ;;
237
+ esac
238
+
239
+ # Warn if not on an epic or release branch
240
+ case "\$_beth_branch" in
241
+ epic/*) ;;
242
+ release/*) ;;
243
+ "")
244
+ echo "⚠ Detached HEAD — no branch name. Proceeding anyway." >&2
245
+ ;;
246
+ *)
247
+ echo "⚠ Branch '\$_beth_branch' doesn't follow the epic/<id> convention." >&2
248
+ ;;
249
+ esac
250
+ fi
251
+ # --- END BETH GUARD ---
252
+ `;
253
+ }
254
+ /** Marker used to detect if bethguard is already installed in a hook file. */
255
+ export const BETH_GUARD_BEGIN = '# --- BEGIN BETH GUARD ---';
256
+ export const BETH_GUARD_END = '# --- END BETH GUARD ---';
257
+ //# sourceMappingURL=pre-push-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pre-push-guard.js","sourceRoot":"","sources":["../../../src/cli/commands/pre-push-guard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Pre-Push Guard Tests
3
+ *
4
+ * Tests branch discipline enforcement:
5
+ * - Push ref parsing from Git stdin
6
+ * - Branch name extraction from refs
7
+ * - Protected branch detection
8
+ * - Epic branch convention validation
9
+ * - Release branch recognition
10
+ * - Guard logic: errors vs warnings
11
+ * - Hook script generation
12
+ * - Beads in-progress issue detection
13
+ */
14
+ export {};
15
+ //# sourceMappingURL=pre-push-guard.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pre-push-guard.test.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/pre-push-guard.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}