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.
- package/CHANGELOG.md +51 -1
- package/README.md +121 -132
- package/assets/beth-questioning.png +0 -0
- package/assets/yellowstone-beth.png +0 -0
- package/bin/cli.js +359 -445
- package/dist/__tests__/inject-skills.test.d.ts +9 -0
- package/dist/__tests__/inject-skills.test.d.ts.map +1 -0
- package/dist/__tests__/inject-skills.test.js +143 -0
- package/dist/__tests__/inject-skills.test.js.map +1 -0
- package/dist/__tests__/skills/disambiguation.test.d.ts +10 -0
- package/dist/__tests__/skills/disambiguation.test.d.ts.map +1 -0
- package/dist/__tests__/skills/disambiguation.test.js +192 -0
- package/dist/__tests__/skills/disambiguation.test.js.map +1 -0
- package/dist/__tests__/skills/hook-injection.test.d.ts +11 -0
- package/dist/__tests__/skills/hook-injection.test.d.ts.map +1 -0
- package/dist/__tests__/skills/hook-injection.test.js +173 -0
- package/dist/__tests__/skills/hook-injection.test.js.map +1 -0
- package/dist/__tests__/skills/mapping-completeness.test.d.ts +17 -0
- package/dist/__tests__/skills/mapping-completeness.test.d.ts.map +1 -0
- package/dist/__tests__/skills/mapping-completeness.test.js +281 -0
- package/dist/__tests__/skills/mapping-completeness.test.js.map +1 -0
- package/dist/__tests__/skills/pipeline-integration.test.d.ts +18 -0
- package/dist/__tests__/skills/pipeline-integration.test.d.ts.map +1 -0
- package/dist/__tests__/skills/pipeline-integration.test.js +234 -0
- package/dist/__tests__/skills/pipeline-integration.test.js.map +1 -0
- package/dist/__tests__/skills/skill-routing.test.d.ts +15 -0
- package/dist/__tests__/skills/skill-routing.test.d.ts.map +1 -0
- package/dist/__tests__/skills/skill-routing.test.js +723 -0
- package/dist/__tests__/skills/skill-routing.test.js.map +1 -0
- package/dist/__tests__/skills/trigger-coverage.test.d.ts +24 -0
- package/dist/__tests__/skills/trigger-coverage.test.d.ts.map +1 -0
- package/dist/__tests__/skills/trigger-coverage.test.js +746 -0
- package/dist/__tests__/skills/trigger-coverage.test.js.map +1 -0
- package/dist/__tests__/smoke.test.js +13 -0
- package/dist/__tests__/smoke.test.js.map +1 -1
- package/dist/__tests__/verify-skills.test.d.ts +9 -0
- package/dist/__tests__/verify-skills.test.d.ts.map +1 -0
- package/dist/__tests__/verify-skills.test.js +78 -0
- package/dist/__tests__/verify-skills.test.js.map +1 -0
- package/dist/cli/commands/beads.e2e.test.d.ts +4 -2
- package/dist/cli/commands/beads.e2e.test.d.ts.map +1 -1
- package/dist/cli/commands/beads.e2e.test.js +97 -38
- package/dist/cli/commands/beads.e2e.test.js.map +1 -1
- package/dist/cli/commands/cli-edge-cases.e2e.test.js +1 -1
- package/dist/cli/commands/cli-edge-cases.e2e.test.js.map +1 -1
- package/dist/cli/commands/close.d.ts +11 -46
- package/dist/cli/commands/close.d.ts.map +1 -1
- package/dist/cli/commands/close.e2e.test.d.ts +4 -20
- package/dist/cli/commands/close.e2e.test.d.ts.map +1 -1
- package/dist/cli/commands/close.e2e.test.js +23 -204
- package/dist/cli/commands/close.e2e.test.js.map +1 -1
- package/dist/cli/commands/close.js +26 -240
- package/dist/cli/commands/close.js.map +1 -1
- package/dist/cli/commands/close.test.d.ts +7 -9
- package/dist/cli/commands/close.test.d.ts.map +1 -1
- package/dist/cli/commands/close.test.js +44 -424
- package/dist/cli/commands/close.test.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts +16 -22
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.e2e.test.js +3 -59
- package/dist/cli/commands/doctor.e2e.test.js.map +1 -1
- package/dist/cli/commands/doctor.js +87 -103
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/doctor.test.js +120 -229
- package/dist/cli/commands/doctor.test.js.map +1 -1
- package/dist/cli/commands/framework-isolation.test.d.ts +1 -1
- package/dist/cli/commands/framework-isolation.test.js +2 -3
- package/dist/cli/commands/framework-isolation.test.js.map +1 -1
- package/dist/cli/commands/help.e2e.test.js +1 -5
- package/dist/cli/commands/help.e2e.test.js.map +1 -1
- package/dist/cli/commands/init-logic.e2e.test.js +114 -2
- package/dist/cli/commands/init-logic.e2e.test.js.map +1 -1
- package/dist/cli/commands/init.test.js +4 -21
- package/dist/cli/commands/init.test.js.map +1 -1
- package/dist/cli/commands/land.d.ts +3 -15
- package/dist/cli/commands/land.d.ts.map +1 -1
- package/dist/cli/commands/land.js +13 -68
- package/dist/cli/commands/land.js.map +1 -1
- package/dist/cli/commands/land.test.d.ts +0 -1
- package/dist/cli/commands/land.test.d.ts.map +1 -1
- package/dist/cli/commands/land.test.js +2 -57
- package/dist/cli/commands/land.test.js.map +1 -1
- package/dist/cli/commands/mcp.e2e.test.js +28 -3
- package/dist/cli/commands/mcp.e2e.test.js.map +1 -1
- package/dist/cli/commands/pipeline.e2e.test.js +23 -26
- package/dist/cli/commands/pipeline.e2e.test.js.map +1 -1
- package/dist/cli/commands/pre-push-guard.d.ts +2 -12
- package/dist/cli/commands/pre-push-guard.d.ts.map +1 -1
- package/dist/cli/commands/pre-push-guard.e2e.test.js +1 -1
- package/dist/cli/commands/pre-push-guard.e2e.test.js.map +1 -1
- package/dist/cli/commands/pre-push-guard.js +2 -47
- package/dist/cli/commands/pre-push-guard.js.map +1 -1
- package/dist/cli/commands/pre-push-guard.test.d.ts +0 -1
- package/dist/cli/commands/pre-push-guard.test.d.ts.map +1 -1
- package/dist/cli/commands/pre-push-guard.test.js +15 -98
- package/dist/cli/commands/pre-push-guard.test.js.map +1 -1
- package/dist/cli/commands/quickstart-expanded.e2e.test.d.ts +1 -1
- package/dist/cli/commands/quickstart-expanded.e2e.test.js +3 -30
- package/dist/cli/commands/quickstart-expanded.e2e.test.js.map +1 -1
- package/dist/cli/commands/quickstart.d.ts +0 -1
- package/dist/cli/commands/quickstart.d.ts.map +1 -1
- package/dist/cli/commands/quickstart.js +2 -60
- package/dist/cli/commands/quickstart.js.map +1 -1
- package/dist/cli/commands/quickstart.test.js +10 -104
- package/dist/cli/commands/quickstart.test.js.map +1 -1
- package/dist/cli/commands/uninstall.test.d.ts +5 -0
- package/dist/cli/commands/uninstall.test.d.ts.map +1 -0
- package/dist/cli/commands/uninstall.test.js +223 -0
- package/dist/cli/commands/uninstall.test.js.map +1 -0
- package/dist/cli/commands/update.d.ts +35 -0
- package/dist/cli/commands/update.d.ts.map +1 -0
- package/dist/cli/commands/update.e2e.test.d.ts +24 -0
- package/dist/cli/commands/update.e2e.test.d.ts.map +1 -0
- package/dist/cli/commands/update.e2e.test.js +238 -0
- package/dist/cli/commands/update.e2e.test.js.map +1 -0
- package/dist/cli/commands/update.js +255 -0
- package/dist/cli/commands/update.js.map +1 -0
- package/dist/core/agents/frontmatter.test.js +1 -1
- package/dist/core/agents/frontmatter.test.js.map +1 -1
- package/dist/core/agents/handoffs.test.js +1 -1
- package/dist/core/agents/handoffs.test.js.map +1 -1
- package/dist/core/agents/loader.d.ts +4 -2
- package/dist/core/agents/loader.d.ts.map +1 -1
- package/dist/core/agents/loader.js +5 -3
- package/dist/core/agents/loader.js.map +1 -1
- package/dist/core/agents/loader.test.js +42 -4
- package/dist/core/agents/loader.test.js.map +1 -1
- package/dist/core/agents/suite.test.js +8 -7
- package/dist/core/agents/suite.test.js.map +1 -1
- package/dist/core/agents/tools.test.js +10 -8
- package/dist/core/agents/tools.test.js.map +1 -1
- package/dist/core/agents/types.test.js +1 -1
- package/dist/core/agents/types.test.js.map +1 -1
- package/dist/core/skills/loader.test.js +1 -1
- package/dist/core/skills/loader.test.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/pathValidation.d.ts +0 -5
- package/dist/lib/pathValidation.d.ts.map +1 -1
- package/dist/lib/pathValidation.js +0 -11
- package/dist/lib/pathValidation.js.map +1 -1
- package/dist/lib/pathValidation.test.js +2 -14
- package/dist/lib/pathValidation.test.js.map +1 -1
- package/package.json +3 -6
- package/sbom.json +259 -371
- package/templates/.github/agents/beth.agent.md +194 -122
- package/templates/.github/agents/developer.agent.md +30 -22
- package/templates/.github/agents/product-manager.agent.md +15 -6
- package/templates/.github/agents/researcher.agent.md +10 -7
- package/templates/.github/agents/security-reviewer.agent.md +16 -7
- package/templates/.github/agents/tester.agent.md +16 -8
- package/templates/.github/agents/ux-designer.agent.md +12 -9
- package/templates/.github/copilot-instructions.md +33 -4
- package/templates/.github/copilot-mcp-config.json +12 -0
- package/templates/.github/dependabot.yml +68 -0
- package/templates/.github/hooks/scripts/inject-skills.mjs +139 -0
- package/templates/.github/hooks/scripts/verify-skills.mjs +47 -0
- package/templates/.github/hooks/skill-enforcement.json +18 -0
- package/templates/.github/pull_request_template.md +48 -0
- package/templates/.github/skills/framer-components/SKILL.md +0 -0
- package/templates/.github/skills/prd/SKILL.md +0 -0
- package/templates/.github/skills/security-analysis/SKILL.md +798 -798
- package/templates/.github/skills/shadcn-ui/SKILL.md +561 -561
- package/templates/.github/skills/vercel-react-best-practices/AGENTS.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/SKILL.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/advanced-use-latest.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/async-api-routes.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/async-defer-await.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/async-dependencies.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/async-parallel.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/bundle-conditional.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/bundle-preload.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/client-event-listeners.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/client-swr-dedup.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-cache-function-results.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-cache-property-access.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-cache-storage.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-combine-iterations.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-early-exit.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-index-maps.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-length-check-first.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-min-max-loop.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rendering-activity.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rerender-dependencies.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rerender-derived-state.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rerender-memo.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/rerender-transitions.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/server-auth-actions.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/server-cache-lru.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/server-cache-react.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/server-dedup-props.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +0 -0
- package/templates/.github/skills/vercel-react-best-practices/rules/server-serialization.md +0 -0
- package/templates/.github/skills/web-design-guidelines/SKILL.md +0 -0
- package/templates/.vscode/settings.json +16 -16
- package/templates/AGENTS.md +59 -98
- package/templates/Backlog.md +80 -80
- package/templates/mcp.json.example +8 -0
- package/assets/beth-portrait-small.txt +0 -13
- package/assets/beth-portrait.txt +0 -60
- package/bin/beth-animation.sh +0 -155
- package/bin/lib/animation.js +0 -189
- package/bin/lib/pathValidation.js +0 -233
- package/bin/lib/pathValidation.test.js +0 -280
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Tests the intended user journey: run init, then doctor to verify,
|
|
6
6
|
* confirming the two commands compose correctly.
|
|
7
7
|
*/
|
|
8
|
-
import { describe, it, beforeEach, afterEach } from '
|
|
8
|
+
import { describe, it, beforeEach, afterEach } from 'vitest';
|
|
9
9
|
import assert from 'node:assert';
|
|
10
10
|
import { execSync } from 'child_process';
|
|
11
11
|
import { existsSync, mkdirSync, rmSync, readdirSync, readFileSync, writeFileSync } from 'fs';
|
|
@@ -48,7 +48,7 @@ describe('init → doctor pipeline E2E', () => {
|
|
|
48
48
|
describe('init creates what doctor checks', () => {
|
|
49
49
|
it('should pass agent check after init', () => {
|
|
50
50
|
// Step 1: Run init
|
|
51
|
-
const initResult = runCli(testDir, 'init', [
|
|
51
|
+
const initResult = runCli(testDir, 'init', []);
|
|
52
52
|
assert.strictEqual(initResult.code, 0, `Init should succeed. Output: ${initResult.stdout}`);
|
|
53
53
|
// Step 2: Run doctor
|
|
54
54
|
const doctorResult = runCli(testDir, 'doctor');
|
|
@@ -57,33 +57,34 @@ describe('init → doctor pipeline E2E', () => {
|
|
|
57
57
|
assert.ok(doctorResult.stdout.includes(`${EXPECTED_AGENT_COUNT} agents`), `Doctor should find ${EXPECTED_AGENT_COUNT} agents`);
|
|
58
58
|
});
|
|
59
59
|
it('should pass skills check after init', () => {
|
|
60
|
-
const initResult = runCli(testDir, 'init', [
|
|
60
|
+
const initResult = runCli(testDir, 'init', []);
|
|
61
61
|
assert.strictEqual(initResult.code, 0, 'Init should succeed');
|
|
62
62
|
const doctorResult = runCli(testDir, 'doctor');
|
|
63
63
|
assert.ok(doctorResult.stdout.includes('skills configured') || doctorResult.stdout.includes('Skills'), 'Doctor should find skills after init');
|
|
64
64
|
assert.ok(doctorResult.stdout.includes(`${EXPECTED_SKILL_COUNT} skills`), `Doctor should find ${EXPECTED_SKILL_COUNT} skills`);
|
|
65
65
|
});
|
|
66
|
-
it('should
|
|
67
|
-
runCli(testDir, 'init', [
|
|
66
|
+
it('should not produce legacy system warnings', () => {
|
|
67
|
+
runCli(testDir, 'init', []);
|
|
68
68
|
const doctorResult = runCli(testDir, 'doctor');
|
|
69
|
-
//
|
|
70
|
-
|
|
69
|
+
// Doctor output should only reference current systems (backlog, agents, skills)
|
|
70
|
+
const output = doctorResult.stdout.toLowerCase();
|
|
71
|
+
assert.ok(!output.includes('dolt') && !output.includes('bead'), 'Doctor should not produce legacy system warnings');
|
|
71
72
|
});
|
|
72
73
|
it('Node.js check should always pass', () => {
|
|
73
|
-
runCli(testDir, 'init', [
|
|
74
|
+
runCli(testDir, 'init', []);
|
|
74
75
|
const doctorResult = runCli(testDir, 'doctor');
|
|
75
76
|
assert.ok(doctorResult.stdout.includes('Node.js') && doctorResult.stdout.includes('✓'), 'Node.js check should pass');
|
|
76
77
|
});
|
|
77
78
|
});
|
|
78
79
|
describe('doctor detects init --skip-* gaps', () => {
|
|
79
80
|
it('should still pass agent/skills checks with --skip-mcp', () => {
|
|
80
|
-
runCli(testDir, 'init', ['--skip-
|
|
81
|
+
runCli(testDir, 'init', ['--skip-mcp']);
|
|
81
82
|
const doctorResult = runCli(testDir, 'doctor');
|
|
82
83
|
// Agents and skills should still be checked and pass
|
|
83
84
|
assert.ok(doctorResult.stdout.includes(`${EXPECTED_AGENT_COUNT} agents`), 'Agent check should pass even with --skip-mcp');
|
|
84
85
|
});
|
|
85
86
|
it('should still pass agent/skills checks with --skip-backlog', () => {
|
|
86
|
-
runCli(testDir, 'init', ['--skip-
|
|
87
|
+
runCli(testDir, 'init', ['--skip-backlog']);
|
|
87
88
|
const doctorResult = runCli(testDir, 'doctor');
|
|
88
89
|
assert.ok(doctorResult.stdout.includes(`${EXPECTED_AGENT_COUNT} agents`), 'Agent check should pass even with --skip-backlog');
|
|
89
90
|
});
|
|
@@ -91,7 +92,7 @@ describe('init → doctor pipeline E2E', () => {
|
|
|
91
92
|
describe('init --force then doctor', () => {
|
|
92
93
|
it('should pass doctor after init --force over existing files', () => {
|
|
93
94
|
// First init
|
|
94
|
-
runCli(testDir, 'init', [
|
|
95
|
+
runCli(testDir, 'init', []);
|
|
95
96
|
// Corrupt an agent file
|
|
96
97
|
const bethAgent = join(testDir, '.github', 'agents', 'beth.agent.md');
|
|
97
98
|
writeFileSync(bethAgent, 'corrupted content');
|
|
@@ -99,7 +100,7 @@ describe('init → doctor pipeline E2E', () => {
|
|
|
99
100
|
const doctorBefore = runCli(testDir, 'doctor');
|
|
100
101
|
assert.ok(doctorBefore.stdout.includes('⚠') || doctorBefore.stdout.includes('issues'), 'Doctor should detect corrupted agent');
|
|
101
102
|
// Re-init with --force
|
|
102
|
-
runCli(testDir, 'init', ['--
|
|
103
|
+
runCli(testDir, 'init', ['--force']);
|
|
103
104
|
// Doctor should now be healthy again
|
|
104
105
|
const doctorAfter = runCli(testDir, 'doctor');
|
|
105
106
|
assert.ok(doctorAfter.stdout.includes(`${EXPECTED_AGENT_COUNT} agents configured`), 'Doctor should pass after init --force repairs the corrupted file');
|
|
@@ -107,7 +108,7 @@ describe('init → doctor pipeline E2E', () => {
|
|
|
107
108
|
});
|
|
108
109
|
describe('full installed structure validation', () => {
|
|
109
110
|
it('should have complete directory structure after init', () => {
|
|
110
|
-
runCli(testDir, 'init', [
|
|
111
|
+
runCli(testDir, 'init', []);
|
|
111
112
|
// Verify the full expected structure
|
|
112
113
|
assert.ok(existsSync(join(testDir, '.github', 'agents')), '.github/agents should exist');
|
|
113
114
|
assert.ok(existsSync(join(testDir, '.github', 'skills')), '.github/skills should exist');
|
|
@@ -118,7 +119,7 @@ describe('init → doctor pipeline E2E', () => {
|
|
|
118
119
|
assert.ok(existsSync(join(testDir, 'mcp.json.example')), 'mcp.json.example should exist');
|
|
119
120
|
});
|
|
120
121
|
it('all installed agent files should have valid frontmatter', () => {
|
|
121
|
-
runCli(testDir, 'init', [
|
|
122
|
+
runCli(testDir, 'init', []);
|
|
122
123
|
const agentsDir = join(testDir, '.github', 'agents');
|
|
123
124
|
const agentFiles = readdirSync(agentsDir).filter(f => f.endsWith('.agent.md'));
|
|
124
125
|
assert.strictEqual(agentFiles.length, EXPECTED_AGENT_COUNT, `Should have ${EXPECTED_AGENT_COUNT} agent files`);
|
|
@@ -131,7 +132,7 @@ describe('init → doctor pipeline E2E', () => {
|
|
|
131
132
|
}
|
|
132
133
|
});
|
|
133
134
|
it('all installed skill directories should have SKILL.md', () => {
|
|
134
|
-
runCli(testDir, 'init', [
|
|
135
|
+
runCli(testDir, 'init', []);
|
|
135
136
|
const skillsDir = join(testDir, '.github', 'skills');
|
|
136
137
|
const skillDirs = readdirSync(skillsDir, { withFileTypes: true })
|
|
137
138
|
.filter(d => d.isDirectory())
|
|
@@ -148,7 +149,7 @@ describe('init → doctor pipeline E2E', () => {
|
|
|
148
149
|
assert.strictEqual(missingSkillMd.length, 0, `Skill directories missing SKILL.md or AGENTS.md: ${missingSkillMd.join(', ')}`);
|
|
149
150
|
});
|
|
150
151
|
it('installed mcp.json.example should be valid JSON', () => {
|
|
151
|
-
runCli(testDir, 'init', [
|
|
152
|
+
runCli(testDir, 'init', []);
|
|
152
153
|
const mcpPath = join(testDir, 'mcp.json.example');
|
|
153
154
|
const content = readFileSync(mcpPath, 'utf-8');
|
|
154
155
|
assert.doesNotThrow(() => {
|
|
@@ -156,7 +157,7 @@ describe('init → doctor pipeline E2E', () => {
|
|
|
156
157
|
}, 'mcp.json.example should be valid JSON');
|
|
157
158
|
});
|
|
158
159
|
it('installed .vscode/settings.json should be valid JSONC', () => {
|
|
159
|
-
runCli(testDir, 'init', [
|
|
160
|
+
runCli(testDir, 'init', []);
|
|
160
161
|
const settingsPath = join(testDir, '.vscode', 'settings.json');
|
|
161
162
|
const content = readFileSync(settingsPath, 'utf-8');
|
|
162
163
|
// VS Code settings use JSONC (JSON with comments) — strip comments before parsing
|
|
@@ -166,7 +167,7 @@ describe('init → doctor pipeline E2E', () => {
|
|
|
166
167
|
}, '.vscode/settings.json should be valid JSONC');
|
|
167
168
|
});
|
|
168
169
|
it('installed .vscode/settings.json should enable subagent delegation', () => {
|
|
169
|
-
runCli(testDir, 'init', [
|
|
170
|
+
runCli(testDir, 'init', []);
|
|
170
171
|
const settingsPath = join(testDir, '.vscode', 'settings.json');
|
|
171
172
|
const content = readFileSync(settingsPath, 'utf-8');
|
|
172
173
|
const stripped = content.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
|
|
@@ -176,16 +177,12 @@ describe('init → doctor pipeline E2E', () => {
|
|
|
176
177
|
});
|
|
177
178
|
describe('doctor output after complete init', () => {
|
|
178
179
|
it('doctor summary should show no failures after full init', () => {
|
|
179
|
-
runCli(testDir, 'init', [
|
|
180
|
-
// Simulate beads init so doctor has no failures
|
|
181
|
-
mkdirSync(join(testDir, '.beads'), { recursive: true });
|
|
180
|
+
runCli(testDir, 'init', []);
|
|
182
181
|
const doctorResult = runCli(testDir, 'doctor');
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
// beads CLI might not be installed, which would be a failure
|
|
186
|
-
// but agents, skills, Node.js, and beads init should all pass
|
|
182
|
+
// Core checks: Node.js, backlog.md CLI, Agents, Skills
|
|
183
|
+
// Backlog Init may warn (backlog/ not initialized in temp dir)
|
|
187
184
|
const passCount = (doctorResult.stdout.match(/✓/g) || []).length;
|
|
188
|
-
assert.ok(passCount >=
|
|
185
|
+
assert.ok(passCount >= 3, `Should have at least 3 passing checks (Node.js, Agents, Skills). Got ${passCount} passes. Output:\n${doctorResult.stdout}`);
|
|
189
186
|
});
|
|
190
187
|
});
|
|
191
188
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.e2e.test.js","sourceRoot":"","sources":["../../../src/cli/commands/pipeline.e2e.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"pipeline.e2e.test.js","sourceRoot":"","sources":["../../../src/cli/commands/pipeline.e2e.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* Validates before push:
|
|
5
5
|
* - No direct pushes to main/master (BLOCKS)
|
|
6
6
|
* - Current branch follows epic/<id> convention (WARNING)
|
|
7
|
-
* - Open in-progress beads issues reported (WARNING)
|
|
8
7
|
* - Bypassed with BETH_SKIP_PUSH_GUARD=1 environment variable
|
|
9
8
|
*/
|
|
10
9
|
export interface PushRef {
|
|
@@ -51,30 +50,21 @@ export declare function isRecognizedBranch(branch: string): boolean;
|
|
|
51
50
|
* Returns null if not in a git repo or in detached HEAD state.
|
|
52
51
|
*/
|
|
53
52
|
export declare function getCurrentBranch(): string | null;
|
|
54
|
-
/**
|
|
55
|
-
* Get beads issues with in_progress status.
|
|
56
|
-
* Returns empty array if bd is unavailable or errors.
|
|
57
|
-
*/
|
|
58
|
-
export declare function getInProgressIssues(): Array<{
|
|
59
|
-
id: string;
|
|
60
|
-
title: string;
|
|
61
|
-
}>;
|
|
62
53
|
/**
|
|
63
54
|
* Run all pre-push guard checks.
|
|
64
55
|
*
|
|
65
56
|
* @param currentBranch - Current Git branch name
|
|
66
57
|
* @param refs - Optional parsed push refs from Git stdin (for remote ref validation)
|
|
67
|
-
* @param checkBeads - Whether to check for in-progress beads issues
|
|
68
58
|
* @returns GuardResult with allowed status and diagnostics
|
|
69
59
|
*/
|
|
70
|
-
export declare function runGuard(currentBranch: string | null, refs?: PushRef[]
|
|
60
|
+
export declare function runGuard(currentBranch: string | null, refs?: PushRef[]): GuardResult;
|
|
71
61
|
/**
|
|
72
62
|
* Main entry point for the pre-push guard command.
|
|
73
63
|
* Reads refs from stdin (if available) and runs all checks.
|
|
74
64
|
*/
|
|
75
65
|
export declare function prePushGuard(stdinInput?: string): Promise<void>;
|
|
76
66
|
/**
|
|
77
|
-
* Generate the shell script content
|
|
67
|
+
* Generate the shell script content for the pre-push hook.
|
|
78
68
|
* Pure shell — no Node dependency at hook time for speed.
|
|
79
69
|
*/
|
|
80
70
|
export declare function generateHookScript(): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pre-push-guard.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/pre-push-guard.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pre-push-guard.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/pre-push-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAqBH,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,CActD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMrD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAWhD;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CACtB,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,IAAI,CAAC,EAAE,OAAO,EAAE,GACf,WAAW,CAqCb;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwCrE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAiC3C;AAED,8EAA8E;AAC9E,eAAO,MAAM,gBAAgB,+BAA+B,CAAC;AAC7D,eAAO,MAAM,cAAc,6BAA6B,CAAC"}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*
|
|
21
21
|
* Expected outcomes documented inline per test case.
|
|
22
22
|
*/
|
|
23
|
-
import { describe, it, beforeEach, afterEach } from '
|
|
23
|
+
import { describe, it, beforeEach, afterEach } from 'vitest';
|
|
24
24
|
import assert from 'node:assert';
|
|
25
25
|
import { execSync, spawnSync } from 'child_process';
|
|
26
26
|
import { resolve, join } from 'path';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pre-push-guard.e2e.test.js","sourceRoot":"","sources":["../../../src/cli/commands/pre-push-guard.e2e.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"pre-push-guard.e2e.test.js","sourceRoot":"","sources":["../../../src/cli/commands/pre-push-guard.e2e.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* Validates before push:
|
|
5
5
|
* - No direct pushes to main/master (BLOCKS)
|
|
6
6
|
* - Current branch follows epic/<id> convention (WARNING)
|
|
7
|
-
* - Open in-progress beads issues reported (WARNING)
|
|
8
7
|
* - Bypassed with BETH_SKIP_PUSH_GUARD=1 environment variable
|
|
9
8
|
*/
|
|
10
9
|
import { execFileSync } from 'child_process';
|
|
@@ -94,42 +93,14 @@ export function getCurrentBranch() {
|
|
|
94
93
|
return null;
|
|
95
94
|
}
|
|
96
95
|
}
|
|
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
96
|
/**
|
|
125
97
|
* Run all pre-push guard checks.
|
|
126
98
|
*
|
|
127
99
|
* @param currentBranch - Current Git branch name
|
|
128
100
|
* @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
101
|
* @returns GuardResult with allowed status and diagnostics
|
|
131
102
|
*/
|
|
132
|
-
export function runGuard(currentBranch, refs
|
|
103
|
+
export function runGuard(currentBranch, refs) {
|
|
133
104
|
const errors = [];
|
|
134
105
|
const warnings = [];
|
|
135
106
|
// Check 1: No pushing to protected branches via remote refs
|
|
@@ -153,22 +124,6 @@ export function runGuard(currentBranch, refs, checkBeads = true) {
|
|
|
153
124
|
if (currentBranch && !isRecognizedBranch(currentBranch)) {
|
|
154
125
|
warnings.push(`Branch '${currentBranch}' doesn't follow the epic/<id> convention. Consider renaming.`);
|
|
155
126
|
}
|
|
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
127
|
return {
|
|
173
128
|
allowed: errors.length === 0,
|
|
174
129
|
errors,
|
|
@@ -214,7 +169,7 @@ export async function prePushGuard(stdinInput) {
|
|
|
214
169
|
}
|
|
215
170
|
}
|
|
216
171
|
/**
|
|
217
|
-
* Generate the shell script content
|
|
172
|
+
* Generate the shell script content for the pre-push hook.
|
|
218
173
|
* Pure shell — no Node dependency at hook time for speed.
|
|
219
174
|
*/
|
|
220
175
|
export function generateHookScript() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pre-push-guard.js","sourceRoot":"","sources":["../../../src/cli/commands/pre-push-guard.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pre-push-guard.js","sourceRoot":"","sources":["../../../src/cli/commands/pre-push-guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pre-push-guard.test.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/pre-push-guard.test.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pre-push-guard.test.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/pre-push-guard.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
|
|
@@ -9,18 +9,10 @@
|
|
|
9
9
|
* - Release branch recognition
|
|
10
10
|
* - Guard logic: errors vs warnings
|
|
11
11
|
* - Hook script generation
|
|
12
|
-
* - Beads in-progress issue detection
|
|
13
12
|
*/
|
|
14
|
-
import { describe, it, expect,
|
|
15
|
-
import
|
|
16
|
-
// Mock child_process before importing the module under test
|
|
17
|
-
vi.mock('child_process', () => ({
|
|
18
|
-
execFileSync: vi.fn(),
|
|
19
|
-
}));
|
|
20
|
-
import { parsePushRefs, extractBranchName, isProtectedBranch, isEpicBranch, isReleaseBranch, isRecognizedBranch, runGuard, getInProgressIssues, generateHookScript, BETH_GUARD_BEGIN, BETH_GUARD_END, } from './pre-push-guard.js';
|
|
21
|
-
const mockedExecFileSync = vi.mocked(child_process.execFileSync);
|
|
13
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
14
|
+
import { parsePushRefs, extractBranchName, isProtectedBranch, isEpicBranch, isReleaseBranch, isRecognizedBranch, runGuard, generateHookScript, BETH_GUARD_BEGIN, BETH_GUARD_END, } from './pre-push-guard.js';
|
|
22
15
|
beforeEach(() => {
|
|
23
|
-
vi.clearAllMocks();
|
|
24
16
|
});
|
|
25
17
|
// ─── parsePushRefs ─────────────────────────────────────────────────────────────
|
|
26
18
|
describe('parsePushRefs', () => {
|
|
@@ -162,63 +154,18 @@ describe('isRecognizedBranch', () => {
|
|
|
162
154
|
expect(isRecognizedBranch('')).toBe(false);
|
|
163
155
|
});
|
|
164
156
|
});
|
|
165
|
-
// ─── getInProgressIssues ───────────────────────────────────────────────────────
|
|
166
|
-
describe('getInProgressIssues', () => {
|
|
167
|
-
it('returns in-progress issues from bd list', () => {
|
|
168
|
-
mockedExecFileSync.mockReturnValueOnce(JSON.stringify([
|
|
169
|
-
{ id: 'beth-abc', title: 'Task A', status: 'in_progress' },
|
|
170
|
-
{ id: 'beth-def', title: 'Task B', status: 'open' },
|
|
171
|
-
{ id: 'beth-ghi', title: 'Task C', status: 'in_progress' },
|
|
172
|
-
]));
|
|
173
|
-
const result = getInProgressIssues();
|
|
174
|
-
expect(result).toHaveLength(2);
|
|
175
|
-
expect(result[0]).toEqual({ id: 'beth-abc', title: 'Task A' });
|
|
176
|
-
expect(result[1]).toEqual({ id: 'beth-ghi', title: 'Task C' });
|
|
177
|
-
});
|
|
178
|
-
it('returns empty array when no in-progress issues', () => {
|
|
179
|
-
mockedExecFileSync.mockReturnValueOnce(JSON.stringify([
|
|
180
|
-
{ id: 'beth-abc', title: 'Task A', status: 'open' },
|
|
181
|
-
{ id: 'beth-def', title: 'Task B', status: 'closed' },
|
|
182
|
-
]));
|
|
183
|
-
expect(getInProgressIssues()).toHaveLength(0);
|
|
184
|
-
});
|
|
185
|
-
it('returns empty array when bd is unavailable', () => {
|
|
186
|
-
mockedExecFileSync.mockImplementationOnce(() => {
|
|
187
|
-
throw new Error('bd not found');
|
|
188
|
-
});
|
|
189
|
-
expect(getInProgressIssues()).toHaveLength(0);
|
|
190
|
-
});
|
|
191
|
-
it('returns empty array on invalid JSON', () => {
|
|
192
|
-
mockedExecFileSync.mockReturnValueOnce('not json');
|
|
193
|
-
expect(getInProgressIssues()).toHaveLength(0);
|
|
194
|
-
});
|
|
195
|
-
it('returns empty array when bd returns non-array', () => {
|
|
196
|
-
mockedExecFileSync.mockReturnValueOnce(JSON.stringify({ error: 'nope' }));
|
|
197
|
-
expect(getInProgressIssues()).toHaveLength(0);
|
|
198
|
-
});
|
|
199
|
-
it('filters out items missing required fields', () => {
|
|
200
|
-
mockedExecFileSync.mockReturnValueOnce(JSON.stringify([
|
|
201
|
-
{ id: 'beth-abc', status: 'in_progress' }, // missing title
|
|
202
|
-
{ title: 'Task B', status: 'in_progress' }, // missing id
|
|
203
|
-
{ id: 'beth-ccc', title: 'Task C', status: 'in_progress' }, // valid
|
|
204
|
-
]));
|
|
205
|
-
const result = getInProgressIssues();
|
|
206
|
-
expect(result).toHaveLength(1);
|
|
207
|
-
expect(result[0].id).toBe('beth-ccc');
|
|
208
|
-
});
|
|
209
|
-
});
|
|
210
157
|
// ─── runGuard ──────────────────────────────────────────────────────────────────
|
|
211
158
|
describe('runGuard', () => {
|
|
212
159
|
describe('protected branch blocking', () => {
|
|
213
160
|
it('blocks push when current branch is main', () => {
|
|
214
|
-
const result = runGuard('main'
|
|
161
|
+
const result = runGuard('main');
|
|
215
162
|
expect(result.allowed).toBe(false);
|
|
216
163
|
expect(result.errors).toHaveLength(1);
|
|
217
164
|
expect(result.errors[0]).toContain('main');
|
|
218
165
|
expect(result.errors[0]).toContain('blocked');
|
|
219
166
|
});
|
|
220
167
|
it('blocks push when current branch is master', () => {
|
|
221
|
-
const result = runGuard('master'
|
|
168
|
+
const result = runGuard('master');
|
|
222
169
|
expect(result.allowed).toBe(false);
|
|
223
170
|
expect(result.errors[0]).toContain('master');
|
|
224
171
|
});
|
|
@@ -231,7 +178,7 @@ describe('runGuard', () => {
|
|
|
231
178
|
remoteSha: '000',
|
|
232
179
|
},
|
|
233
180
|
];
|
|
234
|
-
const result = runGuard('feature/x', refs
|
|
181
|
+
const result = runGuard('feature/x', refs);
|
|
235
182
|
expect(result.allowed).toBe(false);
|
|
236
183
|
expect(result.errors[0]).toContain("'main'");
|
|
237
184
|
});
|
|
@@ -244,7 +191,7 @@ describe('runGuard', () => {
|
|
|
244
191
|
remoteSha: '000',
|
|
245
192
|
},
|
|
246
193
|
];
|
|
247
|
-
const result = runGuard('feature/x', refs
|
|
194
|
+
const result = runGuard('feature/x', refs);
|
|
248
195
|
expect(result.allowed).toBe(false);
|
|
249
196
|
});
|
|
250
197
|
it('deduplicates error when both current branch and ref target main', () => {
|
|
@@ -256,7 +203,7 @@ describe('runGuard', () => {
|
|
|
256
203
|
remoteSha: '000',
|
|
257
204
|
},
|
|
258
205
|
];
|
|
259
|
-
const result = runGuard('main', refs
|
|
206
|
+
const result = runGuard('main', refs);
|
|
260
207
|
expect(result.allowed).toBe(false);
|
|
261
208
|
// Should have error about remote ref + error about pushing from main
|
|
262
209
|
// The current-branch check deduplicates if the branch name is already in errors
|
|
@@ -265,64 +212,34 @@ describe('runGuard', () => {
|
|
|
265
212
|
});
|
|
266
213
|
describe('branch convention warnings', () => {
|
|
267
214
|
it('does not warn on epic branches', () => {
|
|
268
|
-
const result = runGuard('epic/beth-abc'
|
|
215
|
+
const result = runGuard('epic/beth-abc');
|
|
269
216
|
expect(result.allowed).toBe(true);
|
|
270
217
|
expect(result.warnings).toHaveLength(0);
|
|
271
218
|
});
|
|
272
219
|
it('does not warn on release branches', () => {
|
|
273
|
-
const result = runGuard('release/v1.0.0'
|
|
220
|
+
const result = runGuard('release/v1.0.0');
|
|
274
221
|
expect(result.allowed).toBe(true);
|
|
275
222
|
expect(result.warnings).toHaveLength(0);
|
|
276
223
|
});
|
|
277
224
|
it('warns on unrecognized branch names', () => {
|
|
278
|
-
const result = runGuard('feature/random'
|
|
225
|
+
const result = runGuard('feature/random');
|
|
279
226
|
expect(result.allowed).toBe(true);
|
|
280
227
|
expect(result.warnings).toHaveLength(1);
|
|
281
228
|
expect(result.warnings[0]).toContain('feature/random');
|
|
282
229
|
expect(result.warnings[0]).toContain('epic/<id>');
|
|
283
230
|
});
|
|
284
231
|
it('warns on branches like dev or staging', () => {
|
|
285
|
-
const result = runGuard('dev'
|
|
232
|
+
const result = runGuard('dev');
|
|
286
233
|
expect(result.allowed).toBe(true);
|
|
287
234
|
expect(result.warnings[0]).toContain('dev');
|
|
288
235
|
});
|
|
289
236
|
it('handles null currentBranch (detached HEAD)', () => {
|
|
290
|
-
const result = runGuard(null
|
|
237
|
+
const result = runGuard(null);
|
|
291
238
|
expect(result.allowed).toBe(true);
|
|
292
239
|
expect(result.warnings).toHaveLength(0);
|
|
293
240
|
expect(result.errors).toHaveLength(0);
|
|
294
241
|
});
|
|
295
242
|
});
|
|
296
|
-
describe('beads in-progress check', () => {
|
|
297
|
-
it('warns when there are in-progress issues', () => {
|
|
298
|
-
mockedExecFileSync.mockReturnValueOnce(JSON.stringify([
|
|
299
|
-
{ id: 'beth-abc', title: 'Unfinished work', status: 'in_progress' },
|
|
300
|
-
]));
|
|
301
|
-
const result = runGuard('epic/beth-abc', undefined, true);
|
|
302
|
-
expect(result.allowed).toBe(true); // warning only, not blocking
|
|
303
|
-
expect(result.warnings.length).toBeGreaterThan(0);
|
|
304
|
-
expect(result.warnings.some((w) => w.includes('in_progress'))).toBe(true);
|
|
305
|
-
});
|
|
306
|
-
it('no warning when no in-progress issues', () => {
|
|
307
|
-
mockedExecFileSync.mockReturnValueOnce(JSON.stringify([
|
|
308
|
-
{ id: 'beth-abc', title: 'Done', status: 'closed' },
|
|
309
|
-
]));
|
|
310
|
-
const result = runGuard('epic/beth-abc', undefined, true);
|
|
311
|
-
expect(result.warnings).toHaveLength(0);
|
|
312
|
-
});
|
|
313
|
-
it('skips beads check when checkBeads is false', () => {
|
|
314
|
-
const result = runGuard('epic/beth-abc', undefined, false);
|
|
315
|
-
expect(result.warnings).toHaveLength(0);
|
|
316
|
-
expect(mockedExecFileSync).not.toHaveBeenCalled();
|
|
317
|
-
});
|
|
318
|
-
it('does not block on beads errors', () => {
|
|
319
|
-
mockedExecFileSync.mockImplementationOnce(() => {
|
|
320
|
-
throw new Error('bd timeout');
|
|
321
|
-
});
|
|
322
|
-
const result = runGuard('epic/beth-abc', undefined, true);
|
|
323
|
-
expect(result.allowed).toBe(true);
|
|
324
|
-
});
|
|
325
|
-
});
|
|
326
243
|
describe('happy path', () => {
|
|
327
244
|
it('allows push from epic branch to epic remote', () => {
|
|
328
245
|
const refs = [
|
|
@@ -333,7 +250,7 @@ describe('runGuard', () => {
|
|
|
333
250
|
remoteSha: '000',
|
|
334
251
|
},
|
|
335
252
|
];
|
|
336
|
-
const result = runGuard('epic/beth-abc', refs
|
|
253
|
+
const result = runGuard('epic/beth-abc', refs);
|
|
337
254
|
expect(result.allowed).toBe(true);
|
|
338
255
|
expect(result.errors).toHaveLength(0);
|
|
339
256
|
expect(result.warnings).toHaveLength(0);
|
|
@@ -347,11 +264,11 @@ describe('runGuard', () => {
|
|
|
347
264
|
remoteSha: '000',
|
|
348
265
|
},
|
|
349
266
|
];
|
|
350
|
-
const result = runGuard('release/v1.0.15', refs
|
|
267
|
+
const result = runGuard('release/v1.0.15', refs);
|
|
351
268
|
expect(result.allowed).toBe(true);
|
|
352
269
|
});
|
|
353
270
|
it('allows push with no refs (branch deletion)', () => {
|
|
354
|
-
const result = runGuard('epic/beth-abc', []
|
|
271
|
+
const result = runGuard('epic/beth-abc', []);
|
|
355
272
|
expect(result.allowed).toBe(true);
|
|
356
273
|
});
|
|
357
274
|
});
|