beth-copilot 1.0.18 → 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.
- package/CHANGELOG.md +41 -28
- package/README.md +87 -247
- package/bin/cli.js +158 -358
- package/dist/__tests__/smoke.test.d.ts +8 -0
- package/dist/__tests__/smoke.test.d.ts.map +1 -0
- package/dist/__tests__/smoke.test.js +49 -0
- package/dist/__tests__/smoke.test.js.map +1 -0
- package/dist/cli/commands/beads.e2e.test.d.ts +13 -0
- package/dist/cli/commands/beads.e2e.test.d.ts.map +1 -0
- package/dist/cli/commands/beads.e2e.test.js +526 -0
- package/dist/cli/commands/beads.e2e.test.js.map +1 -0
- package/dist/cli/commands/cli-edge-cases.e2e.test.d.ts +32 -0
- package/dist/cli/commands/cli-edge-cases.e2e.test.d.ts.map +1 -0
- package/dist/cli/commands/cli-edge-cases.e2e.test.js +162 -0
- package/dist/cli/commands/cli-edge-cases.e2e.test.js.map +1 -0
- package/dist/cli/commands/close.d.ts +89 -0
- package/dist/cli/commands/close.d.ts.map +1 -0
- package/dist/cli/commands/close.e2e.test.d.ts +27 -0
- package/dist/cli/commands/close.e2e.test.d.ts.map +1 -0
- package/dist/cli/commands/close.e2e.test.js +252 -0
- package/dist/cli/commands/close.e2e.test.js.map +1 -0
- package/dist/cli/commands/close.js +309 -0
- package/dist/cli/commands/close.js.map +1 -0
- package/dist/cli/commands/close.test.d.ts +15 -0
- package/dist/cli/commands/close.test.d.ts.map +1 -0
- package/dist/cli/commands/close.test.js +634 -0
- package/dist/cli/commands/close.test.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +23 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.js +93 -0
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/doctor.test.js +209 -0
- package/dist/cli/commands/doctor.test.js.map +1 -1
- package/dist/cli/commands/framework-isolation.test.d.ts +30 -0
- package/dist/cli/commands/framework-isolation.test.d.ts.map +1 -0
- package/dist/cli/commands/framework-isolation.test.js +119 -0
- package/dist/cli/commands/framework-isolation.test.js.map +1 -0
- package/dist/cli/commands/help.e2e.test.js +4 -4
- package/dist/cli/commands/help.e2e.test.js.map +1 -1
- package/dist/cli/commands/init-logic.e2e.test.d.ts +37 -0
- package/dist/cli/commands/init-logic.e2e.test.d.ts.map +1 -0
- package/dist/cli/commands/init-logic.e2e.test.js +305 -0
- package/dist/cli/commands/init-logic.e2e.test.js.map +1 -0
- package/dist/cli/commands/land.d.ts +142 -0
- package/dist/cli/commands/land.d.ts.map +1 -0
- package/dist/cli/commands/land.js +647 -0
- package/dist/cli/commands/land.js.map +1 -0
- package/dist/cli/commands/land.test.d.ts +20 -0
- package/dist/cli/commands/land.test.d.ts.map +1 -0
- package/dist/cli/commands/land.test.js +622 -0
- package/dist/cli/commands/land.test.js.map +1 -0
- package/dist/cli/commands/mcp.e2e.test.js +22 -29
- package/dist/cli/commands/mcp.e2e.test.js.map +1 -1
- package/dist/cli/commands/pipeline.e2e.test.js +20 -20
- package/dist/cli/commands/pipeline.e2e.test.js.map +1 -1
- package/dist/cli/commands/pre-push-guard.d.ts +84 -0
- package/dist/cli/commands/pre-push-guard.d.ts.map +1 -0
- package/dist/cli/commands/pre-push-guard.e2e.test.d.ts +24 -0
- package/dist/cli/commands/pre-push-guard.e2e.test.d.ts.map +1 -0
- package/dist/cli/commands/pre-push-guard.e2e.test.js +171 -0
- package/dist/cli/commands/pre-push-guard.e2e.test.js.map +1 -0
- package/dist/cli/commands/pre-push-guard.js +257 -0
- package/dist/cli/commands/pre-push-guard.js.map +1 -0
- package/dist/cli/commands/pre-push-guard.test.d.ts +15 -0
- package/dist/cli/commands/pre-push-guard.test.d.ts.map +1 -0
- package/dist/cli/commands/pre-push-guard.test.js +397 -0
- package/dist/cli/commands/pre-push-guard.test.js.map +1 -0
- package/dist/cli/commands/quickstart-expanded.e2e.test.d.ts +23 -0
- package/dist/cli/commands/quickstart-expanded.e2e.test.d.ts.map +1 -0
- package/dist/cli/commands/quickstart-expanded.e2e.test.js +179 -0
- package/dist/cli/commands/quickstart-expanded.e2e.test.js.map +1 -0
- package/dist/cli/commands/quickstart.d.ts.map +1 -1
- package/dist/cli/commands/quickstart.js +7 -23
- package/dist/cli/commands/quickstart.js.map +1 -1
- package/dist/cli/commands/quickstart.test.js +40 -67
- package/dist/cli/commands/quickstart.test.js.map +1 -1
- package/dist/core/agents/suite.test.js +4 -2
- package/dist/core/agents/suite.test.js.map +1 -1
- package/dist/core/agents/tools.test.js +5 -1
- package/dist/core/agents/tools.test.js.map +1 -1
- package/dist/index.d.ts +3 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -10
- package/dist/index.js.map +1 -1
- package/package.json +15 -9
- package/sbom.json +2011 -819
- package/templates/.github/agents/beth.agent.md +220 -66
- package/templates/.github/agents/developer.agent.md +53 -90
- package/templates/.github/agents/product-manager.agent.md +15 -68
- package/templates/.github/agents/researcher.agent.md +20 -71
- package/templates/.github/agents/security-reviewer.agent.md +29 -81
- package/templates/.github/agents/tester.agent.md +40 -69
- package/templates/.github/agents/ux-designer.agent.md +20 -74
- package/templates/.github/copilot-instructions.md +217 -225
- package/templates/AGENTS.md +108 -20
- package/templates/mcp.json.example +0 -3
- package/dist/cli/commands/client-config.d.ts +0 -31
- package/dist/cli/commands/client-config.d.ts.map +0 -1
- package/dist/cli/commands/client-config.e2e.test.d.ts +0 -15
- package/dist/cli/commands/client-config.e2e.test.d.ts.map +0 -1
- package/dist/cli/commands/client-config.e2e.test.js +0 -556
- package/dist/cli/commands/client-config.e2e.test.js.map +0 -1
- package/dist/cli/commands/client-config.js +0 -73
- package/dist/cli/commands/client-config.js.map +0 -1
- package/dist/cli/commands/client-config.test.d.ts +0 -6
- package/dist/cli/commands/client-config.test.d.ts.map +0 -1
- package/dist/cli/commands/client-config.test.js +0 -133
- package/dist/cli/commands/client-config.test.js.map +0 -1
- package/dist/cli/commands/init-quickstart.e2e.test.d.ts +0 -11
- package/dist/cli/commands/init-quickstart.e2e.test.d.ts.map +0 -1
- package/dist/cli/commands/init-quickstart.e2e.test.js +0 -221
- package/dist/cli/commands/init-quickstart.e2e.test.js.map +0 -1
- package/dist/core/context.d.ts +0 -171
- package/dist/core/context.d.ts.map +0 -1
- package/dist/core/context.js +0 -353
- package/dist/core/context.js.map +0 -1
- package/dist/core/context.test.d.ts +0 -8
- package/dist/core/context.test.d.ts.map +0 -1
- package/dist/core/context.test.js +0 -253
- package/dist/core/context.test.js.map +0 -1
- package/dist/core/handoffs.d.ts +0 -151
- package/dist/core/handoffs.d.ts.map +0 -1
- package/dist/core/handoffs.js +0 -220
- package/dist/core/handoffs.js.map +0 -1
- package/dist/core/handoffs.test.d.ts +0 -8
- package/dist/core/handoffs.test.d.ts.map +0 -1
- package/dist/core/handoffs.test.js +0 -231
- package/dist/core/handoffs.test.js.map +0 -1
- package/dist/core/orchestrator.d.ts +0 -246
- package/dist/core/orchestrator.d.ts.map +0 -1
- package/dist/core/orchestrator.js +0 -514
- package/dist/core/orchestrator.js.map +0 -1
- package/dist/core/orchestrator.test.d.ts +0 -8
- package/dist/core/orchestrator.test.d.ts.map +0 -1
- package/dist/core/orchestrator.test.js +0 -517
- package/dist/core/orchestrator.test.js.map +0 -1
- package/dist/core/router.d.ts +0 -102
- package/dist/core/router.d.ts.map +0 -1
- package/dist/core/router.js +0 -178
- package/dist/core/router.js.map +0 -1
- package/dist/core/router.test.d.ts +0 -8
- package/dist/core/router.test.d.ts.map +0 -1
- package/dist/core/router.test.js +0 -215
- package/dist/core/router.test.js.map +0 -1
- package/dist/init.test.js +0 -288
- package/dist/providers/azure.d.ts +0 -147
- package/dist/providers/azure.d.ts.map +0 -1
- package/dist/providers/azure.js +0 -491
- package/dist/providers/azure.js.map +0 -1
- package/dist/providers/azure.test.d.ts +0 -11
- package/dist/providers/azure.test.d.ts.map +0 -1
- package/dist/providers/azure.test.js +0 -330
- package/dist/providers/azure.test.js.map +0 -1
- package/dist/providers/config.d.ts +0 -87
- package/dist/providers/config.d.ts.map +0 -1
- package/dist/providers/config.js +0 -193
- package/dist/providers/config.js.map +0 -1
- package/dist/providers/config.test.d.ts +0 -7
- package/dist/providers/config.test.d.ts.map +0 -1
- package/dist/providers/config.test.js +0 -370
- package/dist/providers/config.test.js.map +0 -1
- package/dist/providers/index.d.ts +0 -18
- package/dist/providers/index.d.ts.map +0 -1
- package/dist/providers/index.js +0 -14
- package/dist/providers/index.js.map +0 -1
- package/dist/providers/interface.d.ts +0 -191
- package/dist/providers/interface.d.ts.map +0 -1
- package/dist/providers/interface.js +0 -94
- package/dist/providers/interface.js.map +0 -1
- package/dist/providers/retry.d.ts +0 -128
- package/dist/providers/retry.d.ts.map +0 -1
- package/dist/providers/retry.js +0 -205
- package/dist/providers/retry.js.map +0 -1
- package/dist/providers/retry.test.d.ts +0 -7
- package/dist/providers/retry.test.d.ts.map +0 -1
- package/dist/providers/retry.test.js +0 -439
- package/dist/providers/retry.test.js.map +0 -1
- package/dist/providers/streaming.d.ts +0 -157
- package/dist/providers/streaming.d.ts.map +0 -1
- package/dist/providers/streaming.js +0 -233
- package/dist/providers/streaming.js.map +0 -1
- package/dist/providers/streaming.test.d.ts +0 -7
- package/dist/providers/streaming.test.d.ts.map +0 -1
- package/dist/providers/streaming.test.js +0 -372
- package/dist/providers/streaming.test.js.map +0 -1
- package/dist/providers/types.d.ts +0 -209
- package/dist/providers/types.d.ts.map +0 -1
- package/dist/providers/types.js +0 -53
- package/dist/providers/types.js.map +0 -1
- package/dist/providers/types.test.d.ts +0 -7
- package/dist/providers/types.test.d.ts.map +0 -1
- package/dist/providers/types.test.js +0 -141
- package/dist/providers/types.test.js.map +0 -1
- package/dist/tools/cli/beads.d.ts +0 -27
- package/dist/tools/cli/beads.d.ts.map +0 -1
- package/dist/tools/cli/beads.js +0 -172
- package/dist/tools/cli/beads.js.map +0 -1
- package/dist/tools/cli/beads.test.d.ts +0 -8
- package/dist/tools/cli/beads.test.d.ts.map +0 -1
- package/dist/tools/cli/beads.test.js +0 -264
- package/dist/tools/cli/beads.test.js.map +0 -1
- package/dist/tools/cli/editFile.d.ts +0 -17
- package/dist/tools/cli/editFile.d.ts.map +0 -1
- package/dist/tools/cli/editFile.js +0 -125
- package/dist/tools/cli/editFile.js.map +0 -1
- package/dist/tools/cli/editFile.test.d.ts +0 -8
- package/dist/tools/cli/editFile.test.d.ts.map +0 -1
- package/dist/tools/cli/editFile.test.js +0 -177
- package/dist/tools/cli/editFile.test.js.map +0 -1
- package/dist/tools/cli/readFile.d.ts +0 -25
- package/dist/tools/cli/readFile.d.ts.map +0 -1
- package/dist/tools/cli/readFile.js +0 -118
- package/dist/tools/cli/readFile.js.map +0 -1
- package/dist/tools/cli/readFile.test.d.ts +0 -8
- package/dist/tools/cli/readFile.test.d.ts.map +0 -1
- package/dist/tools/cli/readFile.test.js +0 -194
- package/dist/tools/cli/readFile.test.js.map +0 -1
- package/dist/tools/cli/search.d.ts +0 -16
- package/dist/tools/cli/search.d.ts.map +0 -1
- package/dist/tools/cli/search.js +0 -261
- package/dist/tools/cli/search.js.map +0 -1
- package/dist/tools/cli/search.test.d.ts +0 -8
- package/dist/tools/cli/search.test.d.ts.map +0 -1
- package/dist/tools/cli/search.test.js +0 -172
- package/dist/tools/cli/search.test.js.map +0 -1
- package/dist/tools/cli/subagent.d.ts +0 -43
- package/dist/tools/cli/subagent.d.ts.map +0 -1
- package/dist/tools/cli/subagent.js +0 -99
- package/dist/tools/cli/subagent.js.map +0 -1
- package/dist/tools/cli/subagent.test.d.ts +0 -8
- package/dist/tools/cli/subagent.test.d.ts.map +0 -1
- package/dist/tools/cli/subagent.test.js +0 -190
- package/dist/tools/cli/subagent.test.js.map +0 -1
- package/dist/tools/cli/terminal.d.ts +0 -19
- package/dist/tools/cli/terminal.d.ts.map +0 -1
- package/dist/tools/cli/terminal.js +0 -164
- package/dist/tools/cli/terminal.js.map +0 -1
- package/dist/tools/cli/terminal.test.d.ts +0 -8
- package/dist/tools/cli/terminal.test.d.ts.map +0 -1
- package/dist/tools/cli/terminal.test.js +0 -161
- package/dist/tools/cli/terminal.test.js.map +0 -1
- package/dist/tools/index.d.ts +0 -25
- package/dist/tools/index.d.ts.map +0 -1
- package/dist/tools/index.js +0 -41
- package/dist/tools/index.js.map +0 -1
- package/dist/tools/interface.d.ts +0 -64
- package/dist/tools/interface.d.ts.map +0 -1
- package/dist/tools/interface.js +0 -37
- package/dist/tools/interface.js.map +0 -1
- package/dist/tools/interface.test.d.ts +0 -7
- package/dist/tools/interface.test.d.ts.map +0 -1
- package/dist/tools/interface.test.js +0 -179
- package/dist/tools/interface.test.js.map +0 -1
- package/dist/tools/mcp/bridge.d.ts +0 -48
- package/dist/tools/mcp/bridge.d.ts.map +0 -1
- package/dist/tools/mcp/bridge.js +0 -128
- package/dist/tools/mcp/bridge.js.map +0 -1
- package/dist/tools/mcp/bridge.test.d.ts +0 -8
- package/dist/tools/mcp/bridge.test.d.ts.map +0 -1
- package/dist/tools/mcp/bridge.test.js +0 -300
- package/dist/tools/mcp/bridge.test.js.map +0 -1
- package/dist/tools/mcp/client.d.ts +0 -135
- package/dist/tools/mcp/client.d.ts.map +0 -1
- package/dist/tools/mcp/client.js +0 -263
- package/dist/tools/mcp/client.js.map +0 -1
- package/dist/tools/mcp/client.test.d.ts +0 -8
- package/dist/tools/mcp/client.test.d.ts.map +0 -1
- package/dist/tools/mcp/client.test.js +0 -390
- package/dist/tools/mcp/client.test.js.map +0 -1
- package/dist/tools/registry.d.ts +0 -82
- package/dist/tools/registry.d.ts.map +0 -1
- package/dist/tools/registry.js +0 -99
- package/dist/tools/registry.js.map +0 -1
- package/dist/tools/registry.test.d.ts +0 -7
- package/dist/tools/registry.test.d.ts.map +0 -1
- package/dist/tools/registry.test.js +0 -199
- package/dist/tools/registry.test.js.map +0 -1
- package/dist/tools/suite.test.d.ts +0 -11
- package/dist/tools/suite.test.d.ts.map +0 -1
- package/dist/tools/suite.test.js +0 -119
- package/dist/tools/suite.test.js.map +0 -1
- package/dist/tools/types.d.ts +0 -75
- package/dist/tools/types.d.ts.map +0 -1
- package/dist/tools/types.js +0 -30
- package/dist/tools/types.js.map +0 -1
- package/dist/tools/types.test.d.ts +0 -7
- package/dist/tools/types.test.d.ts.map +0 -1
- package/dist/tools/types.test.js +0 -178
- package/dist/tools/types.test.js.map +0 -1
- package/templates/.vscode/mcp.json +0 -20
- package/templates/CLAUDE.md +0 -129
package/bin/cli.js
CHANGED
|
@@ -775,6 +775,77 @@ async function runBeadsDoctor() {
|
|
|
775
775
|
});
|
|
776
776
|
}
|
|
777
777
|
|
|
778
|
+
const BETH_GUARD_BEGIN = '# --- BEGIN BETH GUARD ---';
|
|
779
|
+
const BETH_GUARD_END = '# --- END BETH GUARD ---';
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* Generate the shell script to append to the pre-push hook.
|
|
783
|
+
* Pure shell — no Node dependency at hook time for speed.
|
|
784
|
+
*/
|
|
785
|
+
function generateGuardScript() {
|
|
786
|
+
return `
|
|
787
|
+
${BETH_GUARD_BEGIN}
|
|
788
|
+
# Branch discipline enforcement — installed by beth-copilot
|
|
789
|
+
# Bypass: BETH_SKIP_PUSH_GUARD=1 git push
|
|
790
|
+
if [ "\$BETH_SKIP_PUSH_GUARD" = "1" ]; then
|
|
791
|
+
echo "⚠ Pre-push guard bypassed (BETH_SKIP_PUSH_GUARD=1)" >&2
|
|
792
|
+
else
|
|
793
|
+
_beth_branch=\$(git branch --show-current 2>/dev/null)
|
|
794
|
+
|
|
795
|
+
# Block pushes from protected branches
|
|
796
|
+
case "\$_beth_branch" in
|
|
797
|
+
main|master)
|
|
798
|
+
echo "✗ Pushing from '\$_beth_branch' is blocked. Work on an epic branch." >&2
|
|
799
|
+
echo " Set BETH_SKIP_PUSH_GUARD=1 to bypass." >&2
|
|
800
|
+
exit 1
|
|
801
|
+
;;
|
|
802
|
+
esac
|
|
803
|
+
|
|
804
|
+
# Warn if not on an epic or release branch
|
|
805
|
+
case "\$_beth_branch" in
|
|
806
|
+
epic/*) ;;
|
|
807
|
+
release/*) ;;
|
|
808
|
+
"")
|
|
809
|
+
echo "⚠ Detached HEAD — no branch name. Proceeding anyway." >&2
|
|
810
|
+
;;
|
|
811
|
+
*)
|
|
812
|
+
echo "⚠ Branch '\$_beth_branch' doesn't follow the epic/<id> convention." >&2
|
|
813
|
+
;;
|
|
814
|
+
esac
|
|
815
|
+
fi
|
|
816
|
+
${BETH_GUARD_END}
|
|
817
|
+
`;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* Install the pre-push guard into .beads/hooks/pre-push.
|
|
822
|
+
* Appends the guard section after the beads integration section.
|
|
823
|
+
* Idempotent — skips if guard is already installed.
|
|
824
|
+
*
|
|
825
|
+
* @param {string} cwd - Project root directory
|
|
826
|
+
*/
|
|
827
|
+
function installPrePushGuard(cwd) {
|
|
828
|
+
const hookPath = join(cwd, '.beads', 'hooks', 'pre-push');
|
|
829
|
+
|
|
830
|
+
if (!existsSync(hookPath)) {
|
|
831
|
+
logWarning('Pre-push hook not found (.beads/hooks/pre-push). Skipping guard installation.');
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
const content = readFileSync(hookPath, 'utf-8');
|
|
836
|
+
|
|
837
|
+
// Already installed?
|
|
838
|
+
if (content.includes(BETH_GUARD_BEGIN)) {
|
|
839
|
+
logSuccess('Pre-push branch guard already installed');
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
// Append guard after existing content
|
|
844
|
+
const guardScript = generateGuardScript();
|
|
845
|
+
writeFileSync(hookPath, content.trimEnd() + '\n' + guardScript, 'utf-8');
|
|
846
|
+
logSuccess('Installed pre-push branch guard (blocks direct pushes to main)');
|
|
847
|
+
}
|
|
848
|
+
|
|
778
849
|
function showHelp() {
|
|
779
850
|
showBethBannerStatic({ showQuickHelp: false });
|
|
780
851
|
console.log(`${COLORS.bright}Beth${COLORS.reset} - AI Orchestrator for GitHub Copilot
|
|
@@ -782,65 +853,43 @@ function showHelp() {
|
|
|
782
853
|
${COLORS.bright}Usage:${COLORS.reset}
|
|
783
854
|
npx beth-copilot init [options] Initialize Beth in current directory
|
|
784
855
|
npx beth-copilot doctor Check system health and dependencies
|
|
856
|
+
npx beth-copilot close <id> [opts] Close issue with dependency enforcement
|
|
857
|
+
npx beth-copilot land [opts] Automated session completion (test, commit, push)
|
|
858
|
+
npx beth-copilot pre-push-guard Run branch discipline checks (used by git hook)
|
|
785
859
|
npx beth-copilot quickstart Run init + doctor + beads setup
|
|
786
860
|
npx beth-copilot help Show this help message
|
|
787
861
|
|
|
788
862
|
${COLORS.bright}Options:${COLORS.reset}
|
|
789
863
|
--force Overwrite existing files
|
|
790
864
|
--skip-backlog Don't create Backlog.md
|
|
791
|
-
--skip-mcp Don't
|
|
865
|
+
--skip-mcp Don't create mcp.json.example
|
|
792
866
|
--skip-beads Skip beads check (not recommended)
|
|
793
867
|
--verbose Show detailed diagnostics on errors
|
|
794
|
-
--client <type> Skip interactive prompt. Values:
|
|
795
|
-
vscode, copilot-cli, claude-code, all
|
|
796
868
|
|
|
797
869
|
${COLORS.bright}Examples:${COLORS.reset}
|
|
798
|
-
npx beth-copilot init Set up Beth
|
|
799
|
-
npx beth-copilot init --client vscode VS Code + Copilot only
|
|
800
|
-
npx beth-copilot init --client claude-code Claude Code only
|
|
801
|
-
npx beth-copilot init --client all All clients
|
|
870
|
+
npx beth-copilot init Set up Beth in current project
|
|
802
871
|
npx beth-copilot init --force Overwrite existing Beth files
|
|
803
872
|
npx beth-copilot doctor Verify installation health
|
|
804
873
|
|
|
805
874
|
${COLORS.bright}What gets installed:${COLORS.reset}
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
.github/copilot-instructions.md Copilot configuration
|
|
819
|
-
|
|
820
|
-
${COLORS.dim}Claude Code:${COLORS.reset}
|
|
821
|
-
CLAUDE.md Claude Code instructions
|
|
822
|
-
|
|
823
|
-
${COLORS.bright}Supported clients:${COLORS.reset}
|
|
824
|
-
VS Code with GitHub Copilot Full agent orchestration with MCP
|
|
825
|
-
GitHub Copilot CLI Terminal-based with bd CLI
|
|
826
|
-
Claude Code CLAUDE.md + bd setup claude hooks
|
|
875
|
+
.github/agents/ 7 specialized AI agents
|
|
876
|
+
.github/skills/ 8 domain knowledge modules
|
|
877
|
+
.github/copilot-instructions.md Copilot configuration
|
|
878
|
+
.vscode/settings.json Recommended VS Code settings
|
|
879
|
+
AGENTS.md Workflow documentation
|
|
880
|
+
Backlog.md Task tracking file
|
|
881
|
+
mcp.json.example Optional MCP server config
|
|
882
|
+
|
|
883
|
+
${COLORS.bright}After installation:${COLORS.reset}
|
|
884
|
+
1. Open project in VS Code
|
|
885
|
+
2. Open Copilot Chat (Ctrl+Alt+I / Cmd+Alt+I)
|
|
886
|
+
3. Type @Beth to start working
|
|
827
887
|
|
|
828
888
|
${COLORS.bright}Documentation:${COLORS.reset}
|
|
829
889
|
https://github.com/stephschofield/beth
|
|
830
890
|
`);
|
|
831
891
|
}
|
|
832
892
|
|
|
833
|
-
/**
|
|
834
|
-
* Persist client selection to .github/.beth-client.json
|
|
835
|
-
* So quickstart and other commands know which client was configured.
|
|
836
|
-
*/
|
|
837
|
-
function persistClientConfig(cwd, clients) {
|
|
838
|
-
const configDir = join(cwd, '.github');
|
|
839
|
-
const configPath = join(configDir, '.beth-client.json');
|
|
840
|
-
mkdirSync(configDir, { recursive: true });
|
|
841
|
-
writeFileSync(configPath, JSON.stringify(clients, null, 2) + '\n');
|
|
842
|
-
}
|
|
843
|
-
|
|
844
893
|
function copyDirRecursive(src, dest, options = {}) {
|
|
845
894
|
const { force = false, copiedFiles = [] } = options;
|
|
846
895
|
|
|
@@ -889,149 +938,8 @@ function copyDirRecursive(src, dest, options = {}) {
|
|
|
889
938
|
return copiedFiles;
|
|
890
939
|
}
|
|
891
940
|
|
|
892
|
-
/**
|
|
893
|
-
* Prompt the user to select their AI coding client(s).
|
|
894
|
-
* Returns an object with boolean flags for each client.
|
|
895
|
-
*/
|
|
896
|
-
async function promptForClient() {
|
|
897
|
-
console.log('');
|
|
898
|
-
log('Which AI coding tool are you using?', COLORS.bright);
|
|
899
|
-
console.log('');
|
|
900
|
-
console.log(` ${COLORS.cyan}[1]${COLORS.reset} VS Code with GitHub Copilot`);
|
|
901
|
-
console.log(` ${COLORS.cyan}[2]${COLORS.reset} GitHub Copilot CLI (terminal)`);
|
|
902
|
-
console.log(` ${COLORS.cyan}[3]${COLORS.reset} Claude Code`);
|
|
903
|
-
console.log(` ${COLORS.cyan}[a]${COLORS.reset} All of the above`);
|
|
904
|
-
console.log('');
|
|
905
|
-
|
|
906
|
-
const answer = await promptForInput('Enter selection (1/2/3/a, or comma-separated e.g. 1,3):');
|
|
907
|
-
|
|
908
|
-
if (!answer || answer.toLowerCase() === 'a') {
|
|
909
|
-
return { vscode: true, copilotCli: true, claudeCode: true };
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
const selections = answer.split(',').map(s => s.trim());
|
|
913
|
-
return {
|
|
914
|
-
vscode: selections.includes('1'),
|
|
915
|
-
copilotCli: selections.includes('2'),
|
|
916
|
-
claudeCode: selections.includes('3'),
|
|
917
|
-
};
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
/**
|
|
921
|
-
* Parse --client flag value into client selection object.
|
|
922
|
-
*/
|
|
923
|
-
function parseClientFlag(clientArg) {
|
|
924
|
-
if (!clientArg || clientArg === 'all') {
|
|
925
|
-
return { vscode: true, copilotCli: true, claudeCode: true };
|
|
926
|
-
}
|
|
927
|
-
return {
|
|
928
|
-
vscode: clientArg === 'vscode',
|
|
929
|
-
copilotCli: clientArg === 'copilot-cli',
|
|
930
|
-
claudeCode: clientArg === 'claude-code',
|
|
931
|
-
};
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
/**
|
|
935
|
-
* Install beads-mcp (MCP server) for VS Code integration.
|
|
936
|
-
*
|
|
937
|
-
* SECURITY NOTE - shell:true usage:
|
|
938
|
-
* - Required for cross-platform uv/pip execution
|
|
939
|
-
* - Arguments are HARDCODED - no user input is passed to the shell
|
|
940
|
-
* - Command injection risk: NONE (no dynamic/user-supplied values)
|
|
941
|
-
*/
|
|
942
|
-
async function installBeadsMcp() {
|
|
943
|
-
log('\nInstalling beads-mcp (MCP server for VS Code)...', COLORS.cyan);
|
|
944
|
-
|
|
945
|
-
// Try uv first, then pip
|
|
946
|
-
const installers = [
|
|
947
|
-
{ cmd: 'uv', args: ['tool', 'install', 'beads-mcp'], label: 'uv tool install beads-mcp' },
|
|
948
|
-
{ cmd: 'pip', args: ['install', 'beads-mcp'], label: 'pip install beads-mcp' },
|
|
949
|
-
];
|
|
950
|
-
|
|
951
|
-
for (const installer of installers) {
|
|
952
|
-
try {
|
|
953
|
-
execSync(`${installer.cmd} --version`, { stdio: 'ignore' });
|
|
954
|
-
} catch {
|
|
955
|
-
logDebug(`${installer.cmd} not found, trying next installer...`);
|
|
956
|
-
continue;
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
logInfo(installer.label);
|
|
960
|
-
|
|
961
|
-
// SECURITY: All arguments are hardcoded constants.
|
|
962
|
-
return new Promise((resolve) => {
|
|
963
|
-
const child = spawn(installer.cmd, installer.args, {
|
|
964
|
-
stdio: 'inherit',
|
|
965
|
-
shell: true,
|
|
966
|
-
});
|
|
967
|
-
|
|
968
|
-
child.on('close', (code) => {
|
|
969
|
-
if (code === 0) {
|
|
970
|
-
logSuccess('beads-mcp installed!');
|
|
971
|
-
resolve(true);
|
|
972
|
-
} else {
|
|
973
|
-
logWarning(`${installer.label} failed.`);
|
|
974
|
-
resolve(false);
|
|
975
|
-
}
|
|
976
|
-
});
|
|
977
|
-
|
|
978
|
-
child.on('error', () => {
|
|
979
|
-
logWarning(`Failed to run ${installer.cmd}.`);
|
|
980
|
-
resolve(false);
|
|
981
|
-
});
|
|
982
|
-
});
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
logWarning('Neither uv nor pip found. Install beads-mcp manually:');
|
|
986
|
-
logInfo(' uv tool install beads-mcp');
|
|
987
|
-
logInfo(' OR: pip install beads-mcp');
|
|
988
|
-
return false;
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
/**
|
|
992
|
-
* Run `bd setup claude` to configure Claude Code integration.
|
|
993
|
-
*
|
|
994
|
-
* SECURITY NOTE - shell:true usage:
|
|
995
|
-
* - bdPath is validated via getBeadsPath()
|
|
996
|
-
* - Arguments are HARDCODED ('setup', 'claude')
|
|
997
|
-
* - Command injection risk: LOW (bdPath validated, no user input in args)
|
|
998
|
-
*/
|
|
999
|
-
async function runBdSetupClaude() {
|
|
1000
|
-
log('\nConfiguring beads for Claude Code...', COLORS.cyan);
|
|
1001
|
-
|
|
1002
|
-
const bdPath = getBeadsPath();
|
|
1003
|
-
if (!bdPath) {
|
|
1004
|
-
logWarning('Cannot run bd setup claude: bd not found.');
|
|
1005
|
-
logInfo('Run manually after installing beads: bd setup claude');
|
|
1006
|
-
return false;
|
|
1007
|
-
}
|
|
1008
|
-
|
|
1009
|
-
// SECURITY: bdPath is validated, only hardcoded args.
|
|
1010
|
-
return new Promise((resolve) => {
|
|
1011
|
-
const child = spawn(bdPath, ['setup', 'claude'], {
|
|
1012
|
-
stdio: 'inherit',
|
|
1013
|
-
shell: true,
|
|
1014
|
-
});
|
|
1015
|
-
|
|
1016
|
-
child.on('close', (code) => {
|
|
1017
|
-
if (code === 0) {
|
|
1018
|
-
logSuccess('Claude Code integration configured!');
|
|
1019
|
-
resolve(true);
|
|
1020
|
-
} else {
|
|
1021
|
-
logWarning('bd setup claude failed. Run manually: bd setup claude');
|
|
1022
|
-
resolve(false);
|
|
1023
|
-
}
|
|
1024
|
-
});
|
|
1025
|
-
|
|
1026
|
-
child.on('error', () => {
|
|
1027
|
-
logWarning('Failed to run bd setup claude. Run manually: bd setup claude');
|
|
1028
|
-
resolve(false);
|
|
1029
|
-
});
|
|
1030
|
-
});
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
941
|
async function init(options = {}) {
|
|
1034
|
-
const { force = false, skipBacklog = false, skipMcp = false, skipBeads = false
|
|
942
|
+
const { force = false, skipBacklog = false, skipMcp = false, skipBeads = false } = options;
|
|
1035
943
|
const cwd = process.cwd();
|
|
1036
944
|
|
|
1037
945
|
// Check for updates
|
|
@@ -1054,27 +962,6 @@ ${COLORS.yellow}╔════════════════════
|
|
|
1054
962
|
|
|
1055
963
|
log(`${COLORS.yellow}Tip: Run with --verbose for detailed diagnostics if you hit issues.${COLORS.reset}`);
|
|
1056
964
|
|
|
1057
|
-
// Determine which client(s) to configure
|
|
1058
|
-
let clients;
|
|
1059
|
-
if (clientArg) {
|
|
1060
|
-
clients = parseClientFlag(clientArg);
|
|
1061
|
-
} else {
|
|
1062
|
-
clients = await promptForClient();
|
|
1063
|
-
}
|
|
1064
|
-
|
|
1065
|
-
// Validate at least one client selected
|
|
1066
|
-
if (!clients.vscode && !clients.copilotCli && !clients.claudeCode) {
|
|
1067
|
-
logWarning('No client selected. Defaulting to VS Code with GitHub Copilot.');
|
|
1068
|
-
clients.vscode = true;
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
const selectedNames = [];
|
|
1072
|
-
if (clients.vscode) selectedNames.push('VS Code + Copilot');
|
|
1073
|
-
if (clients.copilotCli) selectedNames.push('Copilot CLI');
|
|
1074
|
-
if (clients.claudeCode) selectedNames.push('Claude Code');
|
|
1075
|
-
log(`\nConfiguring for: ${COLORS.cyan}${selectedNames.join(', ')}${COLORS.reset}`);
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
965
|
// Check if templates exist
|
|
1079
966
|
if (!existsSync(TEMPLATES_DIR)) {
|
|
1080
967
|
logError('Templates directory not found. Package may be corrupted.');
|
|
@@ -1083,15 +970,13 @@ ${COLORS.yellow}╔════════════════════
|
|
|
1083
970
|
|
|
1084
971
|
const copiedFiles = [];
|
|
1085
972
|
|
|
1086
|
-
//
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
const skillsSrc = join(TEMPLATES_DIR, '.github', 'skills');
|
|
1090
|
-
const skillsDest = join(cwd, '.github', 'skills');
|
|
973
|
+
// Copy .github directory (agents, skills, copilot-instructions.md)
|
|
974
|
+
const githubSrc = join(TEMPLATES_DIR, '.github');
|
|
975
|
+
const githubDest = join(cwd, '.github');
|
|
1091
976
|
|
|
1092
|
-
if (existsSync(
|
|
1093
|
-
log('\nInstalling
|
|
1094
|
-
copyDirRecursive(
|
|
977
|
+
if (existsSync(githubSrc)) {
|
|
978
|
+
log('\nInstalling agents and skills...');
|
|
979
|
+
copyDirRecursive(githubSrc, githubDest, { force, copiedFiles });
|
|
1095
980
|
}
|
|
1096
981
|
|
|
1097
982
|
// Copy AGENTS.md
|
|
@@ -1122,38 +1007,33 @@ ${COLORS.yellow}╔════════════════════
|
|
|
1122
1007
|
}
|
|
1123
1008
|
}
|
|
1124
1009
|
|
|
1125
|
-
//
|
|
1126
|
-
if (
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
// .github/agents/ (agent definitions with frontmatter)
|
|
1130
|
-
const agentsSrc = join(TEMPLATES_DIR, '.github', 'agents');
|
|
1131
|
-
const agentsDest = join(cwd, '.github', 'agents');
|
|
1132
|
-
if (existsSync(agentsSrc)) {
|
|
1133
|
-
copyDirRecursive(agentsSrc, agentsDest, { force, copiedFiles });
|
|
1134
|
-
}
|
|
1010
|
+
// Copy mcp.json.example (unless skipped)
|
|
1011
|
+
if (!skipMcp) {
|
|
1012
|
+
const mcpSrc = join(TEMPLATES_DIR, 'mcp.json.example');
|
|
1013
|
+
const mcpDest = join(cwd, 'mcp.json.example');
|
|
1135
1014
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
if (existsSync(copilotInstructionsSrc)) {
|
|
1140
|
-
if (existsSync(copilotInstructionsDest) && !force) {
|
|
1141
|
-
logWarning('Skipped (exists): .github/copilot-instructions.md');
|
|
1015
|
+
if (existsSync(mcpSrc)) {
|
|
1016
|
+
if (existsSync(mcpDest) && !force) {
|
|
1017
|
+
logWarning('Skipped (exists): mcp.json.example');
|
|
1142
1018
|
} else {
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
copiedFiles.push('.github/copilot-instructions.md');
|
|
1019
|
+
copyFileSync(mcpSrc, mcpDest);
|
|
1020
|
+
copiedFiles.push('mcp.json.example');
|
|
1146
1021
|
}
|
|
1147
1022
|
}
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
// Copy .vscode/settings.json (recommended settings for agent mode)
|
|
1026
|
+
const vscodeSrc = join(TEMPLATES_DIR, '.vscode');
|
|
1027
|
+
const vscodeDest = join(cwd, '.vscode');
|
|
1028
|
+
|
|
1029
|
+
if (existsSync(vscodeSrc)) {
|
|
1151
1030
|
if (!existsSync(vscodeDest)) {
|
|
1152
1031
|
mkdirSync(vscodeDest, { recursive: true });
|
|
1153
1032
|
}
|
|
1154
1033
|
|
|
1155
|
-
const settingsSrc = join(
|
|
1034
|
+
const settingsSrc = join(vscodeSrc, 'settings.json');
|
|
1156
1035
|
const settingsDest = join(vscodeDest, 'settings.json');
|
|
1036
|
+
|
|
1157
1037
|
if (existsSync(settingsSrc)) {
|
|
1158
1038
|
if (existsSync(settingsDest) && !force) {
|
|
1159
1039
|
logWarning('Skipped (exists): .vscode/settings.json');
|
|
@@ -1162,61 +1042,8 @@ ${COLORS.yellow}╔════════════════════
|
|
|
1162
1042
|
copiedFiles.push('.vscode/settings.json');
|
|
1163
1043
|
}
|
|
1164
1044
|
}
|
|
1165
|
-
|
|
1166
|
-
// .vscode/mcp.json (beads + shadcn + playwright + deepwiki)
|
|
1167
|
-
if (!skipMcp) {
|
|
1168
|
-
const mcpJsonSrc = join(TEMPLATES_DIR, '.vscode', 'mcp.json');
|
|
1169
|
-
const mcpJsonDest = join(vscodeDest, 'mcp.json');
|
|
1170
|
-
if (existsSync(mcpJsonSrc)) {
|
|
1171
|
-
if (existsSync(mcpJsonDest) && !force) {
|
|
1172
|
-
logWarning('Skipped (exists): .vscode/mcp.json');
|
|
1173
|
-
} else {
|
|
1174
|
-
copyFileSync(mcpJsonSrc, mcpJsonDest);
|
|
1175
|
-
copiedFiles.push('.vscode/mcp.json');
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
// === COPILOT CLI FILES ===
|
|
1182
|
-
if (clients.copilotCli && !clients.vscode) {
|
|
1183
|
-
// Only install copilot-instructions.md if VS Code didn't already do it
|
|
1184
|
-
log('\nInstalling Copilot CLI configuration...');
|
|
1185
|
-
|
|
1186
|
-
const copilotInstructionsSrc = join(TEMPLATES_DIR, '.github', 'copilot-instructions.md');
|
|
1187
|
-
const copilotInstructionsDest = join(cwd, '.github', 'copilot-instructions.md');
|
|
1188
|
-
if (existsSync(copilotInstructionsSrc)) {
|
|
1189
|
-
if (existsSync(copilotInstructionsDest) && !force) {
|
|
1190
|
-
logWarning('Skipped (exists): .github/copilot-instructions.md');
|
|
1191
|
-
} else {
|
|
1192
|
-
mkdirSync(join(cwd, '.github'), { recursive: true });
|
|
1193
|
-
copyFileSync(copilotInstructionsSrc, copilotInstructionsDest);
|
|
1194
|
-
copiedFiles.push('.github/copilot-instructions.md');
|
|
1195
|
-
}
|
|
1196
|
-
}
|
|
1197
|
-
}
|
|
1198
|
-
|
|
1199
|
-
// === CLAUDE CODE FILES ===
|
|
1200
|
-
if (clients.claudeCode) {
|
|
1201
|
-
log('\nInstalling Claude Code configuration...');
|
|
1202
|
-
|
|
1203
|
-
// CLAUDE.md
|
|
1204
|
-
const claudeMdSrc = join(TEMPLATES_DIR, 'CLAUDE.md');
|
|
1205
|
-
const claudeMdDest = join(cwd, 'CLAUDE.md');
|
|
1206
|
-
if (existsSync(claudeMdSrc)) {
|
|
1207
|
-
if (existsSync(claudeMdDest) && !force) {
|
|
1208
|
-
logWarning('Skipped (exists): CLAUDE.md');
|
|
1209
|
-
} else {
|
|
1210
|
-
copyFileSync(claudeMdSrc, claudeMdDest);
|
|
1211
|
-
copiedFiles.push('CLAUDE.md');
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
1045
|
}
|
|
1215
1046
|
|
|
1216
|
-
// Persist client selection for quickstart and other commands
|
|
1217
|
-
persistClientConfig(cwd, clients);
|
|
1218
|
-
copiedFiles.push('.github/.beth-client.json');
|
|
1219
|
-
|
|
1220
1047
|
// Summary
|
|
1221
1048
|
console.log('');
|
|
1222
1049
|
if (copiedFiles.length > 0) {
|
|
@@ -1342,27 +1169,9 @@ ${COLORS.yellow}╔════════════════════
|
|
|
1342
1169
|
await runBeadsDoctor();
|
|
1343
1170
|
}
|
|
1344
1171
|
|
|
1345
|
-
//
|
|
1346
|
-
if (!skipBeads &&
|
|
1347
|
-
|
|
1348
|
-
if (clients.vscode) {
|
|
1349
|
-
const shouldInstallMcp = await promptYesNo('Install beads-mcp for VS Code MCP integration?');
|
|
1350
|
-
if (shouldInstallMcp) {
|
|
1351
|
-
await installBeadsMcp();
|
|
1352
|
-
} else {
|
|
1353
|
-
logInfo('Skipped beads-mcp. Install later with: uv tool install beads-mcp');
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1356
|
-
|
|
1357
|
-
// Claude Code: run bd setup claude
|
|
1358
|
-
if (clients.claudeCode) {
|
|
1359
|
-
const shouldSetupClaude = await promptYesNo('Configure beads for Claude Code? (bd setup claude)');
|
|
1360
|
-
if (shouldSetupClaude) {
|
|
1361
|
-
await runBdSetupClaude();
|
|
1362
|
-
} else {
|
|
1363
|
-
logInfo('Skipped Claude Code setup. Run later: bd setup claude');
|
|
1364
|
-
}
|
|
1365
|
-
}
|
|
1172
|
+
// Install pre-push guard hook
|
|
1173
|
+
if (!skipBeads && isBeadsInitialized(cwd)) {
|
|
1174
|
+
installPrePushGuard(cwd);
|
|
1366
1175
|
}
|
|
1367
1176
|
|
|
1368
1177
|
// Final verification
|
|
@@ -1381,35 +1190,15 @@ ${COLORS.yellow}╔════════════════════
|
|
|
1381
1190
|
process.exit(1);
|
|
1382
1191
|
}
|
|
1383
1192
|
|
|
1384
|
-
// Next steps
|
|
1385
|
-
console.log(
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
if (clients.vscode) {
|
|
1389
|
-
console.log(`
|
|
1390
|
-
${COLORS.bright}VS Code + Copilot:${COLORS.reset}
|
|
1193
|
+
// Next steps
|
|
1194
|
+
console.log(`
|
|
1195
|
+
${COLORS.bright}Next steps:${COLORS.reset}
|
|
1391
1196
|
1. Open this project in VS Code
|
|
1392
1197
|
2. Open Copilot Chat (${COLORS.cyan}Ctrl+Alt+I${COLORS.reset} / ${COLORS.cyan}Cmd+Alt+I${COLORS.reset})
|
|
1393
|
-
3. Type ${COLORS.cyan}@Beth${COLORS.reset} to start
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
if (clients.copilotCli) {
|
|
1397
|
-
console.log(`
|
|
1398
|
-
${COLORS.bright}Copilot CLI:${COLORS.reset}
|
|
1399
|
-
1. Run ${COLORS.cyan}copilot${COLORS.reset} in your project directory
|
|
1400
|
-
2. Beth's instructions are in ${COLORS.cyan}.github/copilot-instructions.md${COLORS.reset}
|
|
1401
|
-
3. Use ${COLORS.cyan}bd ready${COLORS.reset} to find work, ${COLORS.cyan}bd create${COLORS.reset} to track tasks`);
|
|
1402
|
-
}
|
|
1403
|
-
|
|
1404
|
-
if (clients.claudeCode) {
|
|
1405
|
-
console.log(`
|
|
1406
|
-
${COLORS.bright}Claude Code:${COLORS.reset}
|
|
1407
|
-
1. Run ${COLORS.cyan}claude${COLORS.reset} in your project directory
|
|
1408
|
-
2. Beth's instructions are in ${COLORS.cyan}CLAUDE.md${COLORS.reset}
|
|
1409
|
-
3. Use ${COLORS.cyan}bd ready${COLORS.reset} to find work, ${COLORS.cyan}bd prime${COLORS.reset} for session context`);
|
|
1410
|
-
}
|
|
1198
|
+
3. Type ${COLORS.cyan}@Beth${COLORS.reset} to start - she's your orchestrator
|
|
1199
|
+
|
|
1200
|
+
${COLORS.bright}Pro tip:${COLORS.reset} Start every session with ${COLORS.cyan}@Beth${COLORS.reset} and let her route work to the right specialists.
|
|
1411
1201
|
|
|
1412
|
-
console.log(`
|
|
1413
1202
|
${COLORS.bright}Documentation:${COLORS.reset}
|
|
1414
1203
|
https://github.com/stephschofield/beth
|
|
1415
1204
|
|
|
@@ -1418,13 +1207,16 @@ ${COLORS.cyan}"They broke my wings and forgot I had claws."${COLORS.reset}
|
|
|
1418
1207
|
}
|
|
1419
1208
|
|
|
1420
1209
|
// Input validation constants
|
|
1421
|
-
const ALLOWED_COMMANDS = ['init', 'help', '--help', '-h', 'doctor', 'quickstart'];
|
|
1422
|
-
const ALLOWED_FLAGS = ['--force', '--skip-backlog', '--skip-mcp', '--skip-beads', '--verbose', '--
|
|
1423
|
-
const ALLOWED_CLIENTS = ['vscode', 'copilot-cli', 'claude-code', 'all'];
|
|
1210
|
+
const ALLOWED_COMMANDS = ['init', 'help', '--help', '-h', 'doctor', 'quickstart', 'close', 'pre-push-guard'];
|
|
1211
|
+
const ALLOWED_FLAGS = ['--force', '--skip-backlog', '--skip-mcp', '--skip-beads', '--verbose', '--reason', '-r', '-f', '--skip-tests', '--skip-backup', '--message', '-m', '--dry-run'];
|
|
1424
1212
|
const MAX_ARG_LENGTH = 50;
|
|
1425
1213
|
|
|
1426
1214
|
// Validate and sanitize input
|
|
1427
1215
|
function validateArgs(args) {
|
|
1216
|
+
// The 'close' and 'land' commands handle their own arg validation
|
|
1217
|
+
const command = args[0]?.toLowerCase();
|
|
1218
|
+
if (command === 'close' || command === 'land') return;
|
|
1219
|
+
|
|
1428
1220
|
for (const arg of args) {
|
|
1429
1221
|
// Prevent excessively long arguments (log injection, DoS)
|
|
1430
1222
|
if (arg.length > MAX_ARG_LENGTH) {
|
|
@@ -1445,40 +1237,26 @@ validateArgs(args);
|
|
|
1445
1237
|
|
|
1446
1238
|
const command = args[0]?.toLowerCase();
|
|
1447
1239
|
|
|
1448
|
-
// Parse --client flag value (e.g. --client vscode)
|
|
1449
|
-
let clientArg = null;
|
|
1450
|
-
const clientFlagIndex = args.indexOf('--client');
|
|
1451
|
-
if (clientFlagIndex !== -1 && clientFlagIndex + 1 < args.length) {
|
|
1452
|
-
clientArg = args[clientFlagIndex + 1].toLowerCase();
|
|
1453
|
-
if (!ALLOWED_CLIENTS.includes(clientArg)) {
|
|
1454
|
-
logError(`Invalid client: ${clientArg.slice(0, MAX_ARG_LENGTH)}`);
|
|
1455
|
-
console.log(`Valid clients: ${ALLOWED_CLIENTS.join(', ')}`);
|
|
1456
|
-
process.exit(1);
|
|
1457
|
-
}
|
|
1458
|
-
}
|
|
1459
|
-
|
|
1460
1240
|
const options = {
|
|
1461
1241
|
force: args.includes('--force'),
|
|
1462
1242
|
skipBacklog: args.includes('--skip-backlog'),
|
|
1463
1243
|
skipMcp: args.includes('--skip-mcp'),
|
|
1464
1244
|
skipBeads: args.includes('--skip-beads'),
|
|
1465
1245
|
verbose: args.includes('--verbose'),
|
|
1466
|
-
client: clientArg,
|
|
1467
1246
|
};
|
|
1468
1247
|
|
|
1469
1248
|
// Set global verbose flag for logDebug
|
|
1470
1249
|
globalThis.VERBOSE = options.verbose;
|
|
1471
1250
|
|
|
1472
1251
|
// Validate unknown flags (exclude --help which is handled as a command)
|
|
1473
|
-
//
|
|
1474
|
-
|
|
1475
|
-
const unknownFlags = args.filter(
|
|
1476
|
-
|
|
1477
|
-
);
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
process.exit(1);
|
|
1252
|
+
// Skip for 'close' and 'land' commands which handle their own arg parsing
|
|
1253
|
+
if (command !== 'close' && command !== 'land') {
|
|
1254
|
+
const unknownFlags = args.filter(arg => arg.startsWith('--') && !ALLOWED_FLAGS.includes(arg) && arg !== '--help');
|
|
1255
|
+
if (unknownFlags.length > 0) {
|
|
1256
|
+
logError(`Unknown flag: ${unknownFlags[0].slice(0, MAX_ARG_LENGTH)}`);
|
|
1257
|
+
console.log('Run "npx beth-copilot help" for usage information.');
|
|
1258
|
+
process.exit(1);
|
|
1259
|
+
}
|
|
1482
1260
|
}
|
|
1483
1261
|
|
|
1484
1262
|
switch (command) {
|
|
@@ -1505,6 +1283,28 @@ switch (command) {
|
|
|
1505
1283
|
await quickstart(options);
|
|
1506
1284
|
}
|
|
1507
1285
|
break;
|
|
1286
|
+
case 'close':
|
|
1287
|
+
{
|
|
1288
|
+
const { close } = await loadTsCommand('close');
|
|
1289
|
+
// Pass raw args after 'close' — the command handles its own parsing
|
|
1290
|
+
const closeArgs = process.argv.slice(3);
|
|
1291
|
+
await close(closeArgs);
|
|
1292
|
+
}
|
|
1293
|
+
break;
|
|
1294
|
+
case 'land':
|
|
1295
|
+
{
|
|
1296
|
+
const { land } = await loadTsCommand('land');
|
|
1297
|
+
// Pass raw args after 'land' — the command handles its own parsing
|
|
1298
|
+
const landArgs = process.argv.slice(3);
|
|
1299
|
+
await land(landArgs);
|
|
1300
|
+
}
|
|
1301
|
+
break;
|
|
1302
|
+
case 'pre-push-guard':
|
|
1303
|
+
{
|
|
1304
|
+
const { prePushGuard } = await loadTsCommand('pre-push-guard');
|
|
1305
|
+
await prePushGuard();
|
|
1306
|
+
}
|
|
1307
|
+
break;
|
|
1508
1308
|
case 'help':
|
|
1509
1309
|
case '--help':
|
|
1510
1310
|
case '-h':
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smoke.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/smoke.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|