@bugzy-ai/bugzy 1.2.1 → 1.4.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/README.md +30 -9
- package/dist/cli/index.cjs +549 -155
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +552 -158
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +96 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +96 -33
- package/dist/index.js.map +1 -1
- package/dist/subagents/index.cjs +6 -3
- package/dist/subagents/index.cjs.map +1 -1
- package/dist/subagents/index.js +6 -3
- package/dist/subagents/index.js.map +1 -1
- package/dist/subagents/metadata.cjs +6 -3
- package/dist/subagents/metadata.cjs.map +1 -1
- package/dist/subagents/metadata.js +6 -3
- package/dist/subagents/metadata.js.map +1 -1
- package/dist/tasks/index.cjs +28 -29
- package/dist/tasks/index.cjs.map +1 -1
- package/dist/tasks/index.js +28 -29
- package/dist/tasks/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/init/AGENTS.md +155 -0
package/dist/cli/index.js
CHANGED
|
@@ -560,7 +560,9 @@ Document all findings including:
|
|
|
560
560
|
\`\`\`
|
|
561
561
|
|
|
562
562
|
#### 3.2 Launch Test Runner Agent
|
|
563
|
-
|
|
563
|
+
{{INVOKE_TEST_RUNNER}}
|
|
564
|
+
|
|
565
|
+
Execute the exploration test case with special exploration instructions:
|
|
564
566
|
|
|
565
567
|
\`\`\`
|
|
566
568
|
Execute the exploration test case at ./test-cases/EXPLORATION-TEMP.md with focus on discovery and documentation.
|
|
@@ -1031,10 +1033,10 @@ Before invoking the agent, identify the test cases for the current area:
|
|
|
1031
1033
|
|
|
1032
1034
|
#### Step 2.2: Invoke test-code-generator Agent
|
|
1033
1035
|
|
|
1034
|
-
|
|
1036
|
+
{{INVOKE_TEST_CODE_GENERATOR}} for the current area with the following context:
|
|
1035
1037
|
|
|
1036
1038
|
**Agent Invocation:**
|
|
1037
|
-
"
|
|
1039
|
+
"Automate test cases for the [AREA_NAME] area.
|
|
1038
1040
|
|
|
1039
1041
|
**Context:**
|
|
1040
1042
|
- Area: [AREA_NAME]
|
|
@@ -1174,10 +1176,10 @@ Provide a comprehensive summary showing:
|
|
|
1174
1176
|
role: "documentation-researcher",
|
|
1175
1177
|
contentBlock: `#### 1.4 Gather Product Documentation
|
|
1176
1178
|
|
|
1177
|
-
|
|
1179
|
+
{{INVOKE_DOCUMENTATION_RESEARCHER}} to gather comprehensive product documentation:
|
|
1178
1180
|
|
|
1179
1181
|
\`\`\`
|
|
1180
|
-
|
|
1182
|
+
Explore all available product documentation, specifically focusing on:
|
|
1181
1183
|
- UI elements and workflows
|
|
1182
1184
|
- User interactions and navigation paths
|
|
1183
1185
|
- Form fields and validation rules
|
|
@@ -1191,10 +1193,9 @@ Use the documentation-researcher agent to explore all available product document
|
|
|
1191
1193
|
role: "team-communicator",
|
|
1192
1194
|
contentBlock: `### Step 4.5: Team Communication
|
|
1193
1195
|
|
|
1194
|
-
|
|
1196
|
+
{{INVOKE_TEAM_COMMUNICATOR}} to notify the product team about the new test cases and automated tests:
|
|
1195
1197
|
|
|
1196
1198
|
\`\`\`
|
|
1197
|
-
Use the team-communicator agent to:
|
|
1198
1199
|
1. Post an update about test case and automation creation
|
|
1199
1200
|
2. Provide summary of coverage:
|
|
1200
1201
|
- Number of manual test cases created
|
|
@@ -1463,10 +1464,10 @@ Provide a summary of:
|
|
|
1463
1464
|
role: "documentation-researcher",
|
|
1464
1465
|
contentBlock: `### Step 2: Gather comprehensive project documentation
|
|
1465
1466
|
|
|
1466
|
-
|
|
1467
|
+
{{INVOKE_DOCUMENTATION_RESEARCHER}} to explore and gather all available project information and other documentation sources. This ensures the test plan is based on complete and current information.
|
|
1467
1468
|
|
|
1468
1469
|
\`\`\`
|
|
1469
|
-
|
|
1470
|
+
Explore all available project documentation related to: $ARGUMENTS
|
|
1470
1471
|
|
|
1471
1472
|
Specifically gather:
|
|
1472
1473
|
- Product specifications and requirements
|
|
@@ -1491,10 +1492,9 @@ The agent will:
|
|
|
1491
1492
|
role: "team-communicator",
|
|
1492
1493
|
contentBlock: `### Step 7.5: Team Communication
|
|
1493
1494
|
|
|
1494
|
-
|
|
1495
|
+
{{INVOKE_TEAM_COMMUNICATOR}} to notify the product team about the new test plan:
|
|
1495
1496
|
|
|
1496
1497
|
\`\`\`
|
|
1497
|
-
Use the team-communicator agent to:
|
|
1498
1498
|
1. Post an update about the test plan creation
|
|
1499
1499
|
2. Provide a brief summary of coverage areas and key features
|
|
1500
1500
|
3. Mention any areas that need exploration or clarification
|
|
@@ -1747,7 +1747,7 @@ Classify the ambiguity level to determine appropriate response:
|
|
|
1747
1747
|
#### Clarification Approach by Severity
|
|
1748
1748
|
|
|
1749
1749
|
**For CRITICAL/HIGH ambiguity:**
|
|
1750
|
-
1. **
|
|
1750
|
+
1. **{{INVOKE_TEAM_COMMUNICATOR}} to ask specific questions**
|
|
1751
1751
|
2. **WAIT for response before proceeding**
|
|
1752
1752
|
3. **Document the clarification request in event history**
|
|
1753
1753
|
|
|
@@ -2020,7 +2020,7 @@ ${KNOWLEDGE_BASE_UPDATE_INSTRUCTIONS}`,
|
|
|
2020
2020
|
contentBlock: `#### 3.3 Use Documentation Researcher if Needed
|
|
2021
2021
|
For events mentioning unknown features or components:
|
|
2022
2022
|
\`\`\`
|
|
2023
|
-
|
|
2023
|
+
{{INVOKE_DOCUMENTATION_RESEARCHER}} to find information about: [component/feature]
|
|
2024
2024
|
\`\`\``
|
|
2025
2025
|
},
|
|
2026
2026
|
{
|
|
@@ -2029,7 +2029,7 @@ Use documentation-researcher agent to find information about: [component/feature
|
|
|
2029
2029
|
|
|
2030
2030
|
When an issue needs to be tracked (task type: report_bug or update_story):
|
|
2031
2031
|
\`\`\`
|
|
2032
|
-
|
|
2032
|
+
{{INVOKE_ISSUE_TRACKER}}
|
|
2033
2033
|
1. Check for duplicate issues in the tracking system
|
|
2034
2034
|
2. For bugs: Create detailed bug report with:
|
|
2035
2035
|
- Clear, descriptive title
|
|
@@ -2307,7 +2307,7 @@ For each failed test:
|
|
|
2307
2307
|
For each test classified as **[TEST ISSUE]**, use the test-debugger-fixer agent to automatically fix the test:
|
|
2308
2308
|
|
|
2309
2309
|
\`\`\`
|
|
2310
|
-
|
|
2310
|
+
{{INVOKE_TEST_DEBUGGER_FIXER}}
|
|
2311
2311
|
|
|
2312
2312
|
For each failed test classified as a test issue (not a product bug), provide:
|
|
2313
2313
|
- Test run timestamp: [from manifest.timestamp]
|
|
@@ -2402,7 +2402,7 @@ After triage in Step 5.1, for tests classified as **[PRODUCT BUG]**, use the iss
|
|
|
2402
2402
|
For each bug to report, use the issue-tracker agent:
|
|
2403
2403
|
|
|
2404
2404
|
\`\`\`
|
|
2405
|
-
|
|
2405
|
+
{{INVOKE_ISSUE_TRACKER}}
|
|
2406
2406
|
1. Check for duplicate bugs in the tracking system
|
|
2407
2407
|
- The agent will automatically search for similar existing issues
|
|
2408
2408
|
- It maintains memory of recently reported issues
|
|
@@ -2473,10 +2473,11 @@ After issue tracker agent completes, create a summary:
|
|
|
2473
2473
|
role: "team-communicator",
|
|
2474
2474
|
contentBlock: `### Step 6: Team Communication
|
|
2475
2475
|
|
|
2476
|
-
|
|
2476
|
+
{{INVOKE_TEAM_COMMUNICATOR}}
|
|
2477
|
+
|
|
2478
|
+
Notify the product team about test execution:
|
|
2477
2479
|
|
|
2478
2480
|
\`\`\`
|
|
2479
|
-
Use the team-communicator agent to:
|
|
2480
2481
|
1. Post test execution summary with key statistics
|
|
2481
2482
|
2. Highlight critical failures that need immediate attention
|
|
2482
2483
|
3. Share important learnings about product behavior
|
|
@@ -2820,7 +2821,7 @@ Read and analyze the JSON report:
|
|
|
2820
2821
|
For each test classified as **[TEST ISSUE]**, use the test-debugger-fixer agent to automatically fix the test:
|
|
2821
2822
|
|
|
2822
2823
|
\`\`\`
|
|
2823
|
-
|
|
2824
|
+
{{INVOKE_TEST_DEBUGGER_FIXER}}
|
|
2824
2825
|
|
|
2825
2826
|
For each failed test classified as a test issue (not a product bug), provide:
|
|
2826
2827
|
- Test file path: [from JSON report]
|
|
@@ -2861,7 +2862,7 @@ Classification guidelines:
|
|
|
2861
2862
|
#### 4A.4 Fix Test Issues Automatically
|
|
2862
2863
|
|
|
2863
2864
|
For tests classified as [TEST ISSUE]:
|
|
2864
|
-
-
|
|
2865
|
+
- {{INVOKE_TEST_DEBUGGER_FIXER}} to analyze and fix
|
|
2865
2866
|
- Agent debugs with browser if needed
|
|
2866
2867
|
- Applies fix (selector update, wait condition, assertion correction)
|
|
2867
2868
|
- Reruns test to verify fix (10x for flaky tests)
|
|
@@ -2877,7 +2878,7 @@ Track fixed tests with:
|
|
|
2877
2878
|
{{ISSUE_TRACKER_INSTRUCTIONS}}
|
|
2878
2879
|
|
|
2879
2880
|
For tests classified as [PRODUCT BUG]:
|
|
2880
|
-
-
|
|
2881
|
+
- {{INVOKE_ISSUE_TRACKER}} to create bug reports
|
|
2881
2882
|
- Agent checks for duplicates automatically
|
|
2882
2883
|
- Creates detailed report with:
|
|
2883
2884
|
- Title, description, reproduction steps
|
|
@@ -3193,10 +3194,10 @@ Format as comprehensive markdown report for terminal display:
|
|
|
3193
3194
|
|
|
3194
3195
|
{{TEAM_COMMUNICATOR_INSTRUCTIONS}}
|
|
3195
3196
|
|
|
3196
|
-
|
|
3197
|
+
{{INVOKE_TEAM_COMMUNICATOR}} to post concise results to Slack thread:
|
|
3197
3198
|
|
|
3198
3199
|
\`\`\`
|
|
3199
|
-
|
|
3200
|
+
Post verification results.
|
|
3200
3201
|
|
|
3201
3202
|
**Channel**: [from CHANGE_CONTEXT.slackChannel]
|
|
3202
3203
|
**Thread**: [from CHANGE_CONTEXT.slackThread]
|
|
@@ -3377,10 +3378,10 @@ A successful verification includes:
|
|
|
3377
3378
|
role: "documentation-researcher",
|
|
3378
3379
|
contentBlock: `#### Research Project Documentation
|
|
3379
3380
|
|
|
3380
|
-
|
|
3381
|
+
{{INVOKE_DOCUMENTATION_RESEARCHER}} to gather comprehensive context about the changed features:
|
|
3381
3382
|
|
|
3382
3383
|
\`\`\`
|
|
3383
|
-
|
|
3384
|
+
Explore project documentation related to the changes.
|
|
3384
3385
|
|
|
3385
3386
|
Specifically gather:
|
|
3386
3387
|
- Product specifications for affected features
|
|
@@ -3412,10 +3413,9 @@ Use this information to:
|
|
|
3412
3413
|
role: "issue-tracker",
|
|
3413
3414
|
contentBlock: `#### Log Product Bugs
|
|
3414
3415
|
|
|
3415
|
-
For tests classified as **[PRODUCT BUG]**,
|
|
3416
|
+
For tests classified as **[PRODUCT BUG]**, {{INVOKE_ISSUE_TRACKER}} to log bugs:
|
|
3416
3417
|
|
|
3417
3418
|
\`\`\`
|
|
3418
|
-
Use issue-tracker agent to:
|
|
3419
3419
|
1. Check for duplicate bugs in the tracking system
|
|
3420
3420
|
- The agent will automatically search for similar existing issues
|
|
3421
3421
|
- It maintains memory of recently reported issues
|
|
@@ -3464,10 +3464,9 @@ Use issue-tracker agent to:
|
|
|
3464
3464
|
role: "team-communicator",
|
|
3465
3465
|
contentBlock: `#### Team Communication
|
|
3466
3466
|
|
|
3467
|
-
|
|
3467
|
+
{{INVOKE_TEAM_COMMUNICATOR}} to share verification results (primarily for Slack trigger, but can be used for other triggers):
|
|
3468
3468
|
|
|
3469
3469
|
\`\`\`
|
|
3470
|
-
Use the team-communicator agent to:
|
|
3471
3470
|
1. Post verification results summary
|
|
3472
3471
|
2. Highlight critical failures that need immediate attention
|
|
3473
3472
|
3. Share bugs logged with issue tracker links
|
|
@@ -3590,13 +3589,14 @@ var init_tasks = __esm({
|
|
|
3590
3589
|
init_esm_shims();
|
|
3591
3590
|
import { Command } from "commander";
|
|
3592
3591
|
import { readFileSync as readFileSync5 } from "fs";
|
|
3593
|
-
import { join as
|
|
3592
|
+
import { join as join12, dirname as dirname7 } from "path";
|
|
3594
3593
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3595
3594
|
import chalk3 from "chalk";
|
|
3596
3595
|
|
|
3597
3596
|
// src/cli/commands/start.ts
|
|
3598
3597
|
init_esm_shims();
|
|
3599
3598
|
import { spawn } from "child_process";
|
|
3599
|
+
import * as path5 from "path";
|
|
3600
3600
|
import chalk from "chalk";
|
|
3601
3601
|
import ora from "ora";
|
|
3602
3602
|
|
|
@@ -3604,6 +3604,97 @@ import ora from "ora";
|
|
|
3604
3604
|
init_esm_shims();
|
|
3605
3605
|
import * as fs from "fs";
|
|
3606
3606
|
import * as path2 from "path";
|
|
3607
|
+
|
|
3608
|
+
// src/core/tool-profile.ts
|
|
3609
|
+
init_esm_shims();
|
|
3610
|
+
var DEFAULT_TOOL = "claude-code";
|
|
3611
|
+
var CLAUDE_CODE_PROFILE = {
|
|
3612
|
+
id: "claude-code",
|
|
3613
|
+
name: "Claude Code",
|
|
3614
|
+
cliCommand: "claude",
|
|
3615
|
+
commandsDir: ".claude/commands",
|
|
3616
|
+
agentsDir: ".claude/agents",
|
|
3617
|
+
mcpConfigPath: ".mcp.json",
|
|
3618
|
+
mcpFormat: "json",
|
|
3619
|
+
memoryFile: "CLAUDE.md",
|
|
3620
|
+
commandFrontmatter: true,
|
|
3621
|
+
agentFrontmatter: true,
|
|
3622
|
+
commandInvocationPrefix: "/",
|
|
3623
|
+
commandExtension: ".md",
|
|
3624
|
+
agentExtension: ".md"
|
|
3625
|
+
};
|
|
3626
|
+
var CURSOR_PROFILE = {
|
|
3627
|
+
id: "cursor",
|
|
3628
|
+
name: "Cursor",
|
|
3629
|
+
cliCommand: "cursor-agent",
|
|
3630
|
+
commandsDir: ".cursor/commands",
|
|
3631
|
+
agentsDir: ".cursor/agents",
|
|
3632
|
+
mcpConfigPath: ".cursor/mcp.json",
|
|
3633
|
+
mcpFormat: "json",
|
|
3634
|
+
memoryFile: "AGENTS.md",
|
|
3635
|
+
// Cursor now uses AGENTS.md (.cursorrules deprecated as of v0.45+)
|
|
3636
|
+
commandFrontmatter: false,
|
|
3637
|
+
// Cursor uses plain markdown
|
|
3638
|
+
agentFrontmatter: false,
|
|
3639
|
+
// Agent files are plain markdown for CLI invocation
|
|
3640
|
+
commandInvocationPrefix: "/",
|
|
3641
|
+
commandExtension: ".md",
|
|
3642
|
+
agentExtension: ".md"
|
|
3643
|
+
};
|
|
3644
|
+
var CODEX_PROFILE = {
|
|
3645
|
+
id: "codex",
|
|
3646
|
+
name: "Codex CLI",
|
|
3647
|
+
cliCommand: "codex",
|
|
3648
|
+
commandsDir: ".codex/prompts",
|
|
3649
|
+
// Codex uses prompts directory
|
|
3650
|
+
agentsDir: ".codex/agents",
|
|
3651
|
+
mcpConfigPath: ".codex/config.toml",
|
|
3652
|
+
// Project-local via CODEX_HOME
|
|
3653
|
+
mcpFormat: "toml",
|
|
3654
|
+
homeEnvVar: "CODEX_HOME",
|
|
3655
|
+
// Set to project root for project-local config
|
|
3656
|
+
memoryFile: "AGENTS.md",
|
|
3657
|
+
commandFrontmatter: true,
|
|
3658
|
+
// Codex prompts support frontmatter
|
|
3659
|
+
agentFrontmatter: false,
|
|
3660
|
+
// Agent files are plain markdown for CLI invocation
|
|
3661
|
+
commandInvocationPrefix: "/prompts:",
|
|
3662
|
+
commandExtension: ".md",
|
|
3663
|
+
agentExtension: ".md"
|
|
3664
|
+
};
|
|
3665
|
+
var TOOL_PROFILES = {
|
|
3666
|
+
"claude-code": CLAUDE_CODE_PROFILE,
|
|
3667
|
+
"cursor": CURSOR_PROFILE,
|
|
3668
|
+
"codex": CODEX_PROFILE
|
|
3669
|
+
};
|
|
3670
|
+
function getToolProfile(toolId) {
|
|
3671
|
+
const profile = TOOL_PROFILES[toolId];
|
|
3672
|
+
if (!profile) {
|
|
3673
|
+
throw new Error(`Unknown tool: ${toolId}`);
|
|
3674
|
+
}
|
|
3675
|
+
return profile;
|
|
3676
|
+
}
|
|
3677
|
+
function getToolOptions() {
|
|
3678
|
+
return [
|
|
3679
|
+
{
|
|
3680
|
+
value: "claude-code",
|
|
3681
|
+
label: "Claude Code (CLI or Cloud)",
|
|
3682
|
+
hint: "Anthropic's official CLI - recommended"
|
|
3683
|
+
},
|
|
3684
|
+
{
|
|
3685
|
+
value: "cursor",
|
|
3686
|
+
label: "Cursor (Experimental)",
|
|
3687
|
+
hint: "VS Code-based AI editor - experimental support"
|
|
3688
|
+
},
|
|
3689
|
+
{
|
|
3690
|
+
value: "codex",
|
|
3691
|
+
label: "Codex CLI (Experimental)",
|
|
3692
|
+
hint: "OpenAI's terminal-based agent - experimental support"
|
|
3693
|
+
}
|
|
3694
|
+
];
|
|
3695
|
+
}
|
|
3696
|
+
|
|
3697
|
+
// src/cli/utils/config.ts
|
|
3607
3698
|
async function loadConfig(configPath = ".bugzy/config.json") {
|
|
3608
3699
|
const fullPath = path2.join(process.cwd(), configPath);
|
|
3609
3700
|
if (!fs.existsSync(fullPath)) {
|
|
@@ -3612,6 +3703,9 @@ async function loadConfig(configPath = ".bugzy/config.json") {
|
|
|
3612
3703
|
try {
|
|
3613
3704
|
const content = fs.readFileSync(fullPath, "utf-8");
|
|
3614
3705
|
const config = JSON.parse(content);
|
|
3706
|
+
if (!config.tool) {
|
|
3707
|
+
config.tool = DEFAULT_TOOL;
|
|
3708
|
+
}
|
|
3615
3709
|
return config;
|
|
3616
3710
|
} catch (error) {
|
|
3617
3711
|
console.error(`Error loading config from ${fullPath}:`, error);
|
|
@@ -3636,15 +3730,19 @@ function configExists(configPath = ".bugzy/config.json") {
|
|
|
3636
3730
|
const fullPath = path2.join(process.cwd(), configPath);
|
|
3637
3731
|
return fs.existsSync(fullPath);
|
|
3638
3732
|
}
|
|
3639
|
-
function createDefaultConfig(projectName) {
|
|
3733
|
+
function createDefaultConfig(projectName, tool = DEFAULT_TOOL) {
|
|
3640
3734
|
return {
|
|
3641
3735
|
version: "1.0.0",
|
|
3736
|
+
tool,
|
|
3642
3737
|
project: {
|
|
3643
3738
|
name: projectName
|
|
3644
3739
|
},
|
|
3645
3740
|
subagents: {}
|
|
3646
3741
|
};
|
|
3647
3742
|
}
|
|
3743
|
+
function getToolFromConfig(config) {
|
|
3744
|
+
return config.tool || DEFAULT_TOOL;
|
|
3745
|
+
}
|
|
3648
3746
|
|
|
3649
3747
|
// src/cli/utils/env.ts
|
|
3650
3748
|
init_esm_shims();
|
|
@@ -3707,13 +3805,19 @@ function validateEnvVars(mcpServers, envVars) {
|
|
|
3707
3805
|
init_esm_shims();
|
|
3708
3806
|
import * as fs3 from "fs";
|
|
3709
3807
|
import * as path4 from "path";
|
|
3710
|
-
function validateProjectStructure() {
|
|
3808
|
+
async function validateProjectStructure() {
|
|
3809
|
+
const config = await loadConfig();
|
|
3810
|
+
const tool = config ? getToolFromConfig(config) : DEFAULT_TOOL;
|
|
3811
|
+
const toolProfile = getToolProfile(tool);
|
|
3711
3812
|
const requiredDirs = [
|
|
3712
3813
|
".bugzy",
|
|
3713
3814
|
".bugzy/runtime",
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3815
|
+
path4.dirname(toolProfile.commandsDir),
|
|
3816
|
+
// .claude, .cursor, or .codex
|
|
3817
|
+
toolProfile.commandsDir,
|
|
3818
|
+
// .claude/commands, .cursor/commands, .codex/prompts
|
|
3819
|
+
toolProfile.agentsDir
|
|
3820
|
+
// .claude/agents, .cursor/agents, .codex/agents
|
|
3717
3821
|
];
|
|
3718
3822
|
const requiredFiles = [
|
|
3719
3823
|
".bugzy/config.json",
|
|
@@ -3739,15 +3843,24 @@ function validateProjectStructure() {
|
|
|
3739
3843
|
}
|
|
3740
3844
|
return true;
|
|
3741
3845
|
}
|
|
3742
|
-
async function
|
|
3846
|
+
async function checkToolAvailable(command) {
|
|
3743
3847
|
const { spawn: spawn2 } = await import("child_process");
|
|
3848
|
+
const isWindows = process.platform === "win32";
|
|
3849
|
+
const checkCommand = isWindows ? "where" : "which";
|
|
3744
3850
|
return new Promise((resolve) => {
|
|
3745
|
-
const proc = spawn2(
|
|
3851
|
+
const proc = spawn2(checkCommand, [command], {
|
|
3852
|
+
shell: isWindows
|
|
3853
|
+
// Windows needs shell for 'where'
|
|
3854
|
+
});
|
|
3746
3855
|
proc.on("close", (code) => {
|
|
3747
|
-
|
|
3856
|
+
if (code !== 0) {
|
|
3857
|
+
console.warn(`Warning: Could not verify '${command}' is installed (${checkCommand} check failed). Continuing anyway...`);
|
|
3858
|
+
}
|
|
3859
|
+
resolve(true);
|
|
3748
3860
|
});
|
|
3749
3861
|
proc.on("error", () => {
|
|
3750
|
-
|
|
3862
|
+
console.warn(`Warning: Could not verify '${command}' is installed (${checkCommand} not available). Continuing anyway...`);
|
|
3863
|
+
resolve(true);
|
|
3751
3864
|
});
|
|
3752
3865
|
});
|
|
3753
3866
|
}
|
|
@@ -3787,9 +3900,11 @@ async function startSession(prompt) {
|
|
|
3787
3900
|
process.exit(1);
|
|
3788
3901
|
}
|
|
3789
3902
|
spinner.succeed(chalk.green("Configuration loaded"));
|
|
3903
|
+
const tool = getToolFromConfig(config);
|
|
3904
|
+
const toolProfile = getToolProfile(tool);
|
|
3790
3905
|
spinner = ora("Validating project structure").start();
|
|
3791
3906
|
try {
|
|
3792
|
-
validateProjectStructure();
|
|
3907
|
+
await validateProjectStructure();
|
|
3793
3908
|
spinner.succeed(chalk.green("Project structure validated"));
|
|
3794
3909
|
} catch (error) {
|
|
3795
3910
|
spinner.fail(chalk.red("Invalid project structure"));
|
|
@@ -3797,15 +3912,9 @@ async function startSession(prompt) {
|
|
|
3797
3912
|
console.log(chalk.yellow("\nRun"), chalk.cyan("bugzy setup"), chalk.yellow("to fix the project structure"));
|
|
3798
3913
|
process.exit(1);
|
|
3799
3914
|
}
|
|
3800
|
-
spinner = ora(
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
spinner.fail(chalk.red("Claude Code CLI not found"));
|
|
3804
|
-
console.log(chalk.yellow("\nPlease install Claude Code:"));
|
|
3805
|
-
console.log(chalk.cyan(" https://claude.com/claude-code"));
|
|
3806
|
-
process.exit(1);
|
|
3807
|
-
}
|
|
3808
|
-
spinner.succeed(chalk.green("Claude Code CLI found"));
|
|
3915
|
+
spinner = ora(`Checking ${toolProfile.name} availability`).start();
|
|
3916
|
+
await checkToolAvailable(toolProfile.cliCommand);
|
|
3917
|
+
spinner.succeed(chalk.green(`${toolProfile.name} CLI check complete`));
|
|
3809
3918
|
spinner = ora("Loading environment variables").start();
|
|
3810
3919
|
const envVars = loadEnvFiles();
|
|
3811
3920
|
const envCount = Object.keys(envVars).length;
|
|
@@ -3823,14 +3932,20 @@ async function startSession(prompt) {
|
|
|
3823
3932
|
process.exit(1);
|
|
3824
3933
|
}
|
|
3825
3934
|
spinner.succeed(chalk.green("All required MCP secrets present"));
|
|
3826
|
-
console.log(chalk.green.bold(
|
|
3935
|
+
console.log(chalk.green.bold(`
|
|
3936
|
+
\u{1F680} Launching ${toolProfile.name}...
|
|
3937
|
+
`));
|
|
3827
3938
|
const args = prompt ? [prompt] : [];
|
|
3828
|
-
const
|
|
3939
|
+
const spawnEnv = { ...process.env, ...envVars };
|
|
3940
|
+
if (toolProfile.homeEnvVar) {
|
|
3941
|
+
spawnEnv[toolProfile.homeEnvVar] = path5.join(process.cwd(), ".codex");
|
|
3942
|
+
}
|
|
3943
|
+
const child = spawn(toolProfile.cliCommand, args, {
|
|
3829
3944
|
cwd: process.cwd(),
|
|
3830
|
-
env:
|
|
3945
|
+
env: spawnEnv,
|
|
3831
3946
|
stdio: "inherit"
|
|
3832
3947
|
});
|
|
3833
|
-
|
|
3948
|
+
child.on("close", (code) => {
|
|
3834
3949
|
if (code === 0) {
|
|
3835
3950
|
console.log(chalk.green("\n\u2713 Session ended successfully"));
|
|
3836
3951
|
} else {
|
|
@@ -3838,15 +3953,16 @@ async function startSession(prompt) {
|
|
|
3838
3953
|
\u2713 Session ended (exit code: ${code})`));
|
|
3839
3954
|
}
|
|
3840
3955
|
});
|
|
3841
|
-
|
|
3842
|
-
console.error(chalk.red(
|
|
3956
|
+
child.on("error", (error) => {
|
|
3957
|
+
console.error(chalk.red(`
|
|
3958
|
+
\u2717 Error launching ${toolProfile.name}:`), error);
|
|
3843
3959
|
process.exit(1);
|
|
3844
3960
|
});
|
|
3845
3961
|
}
|
|
3846
3962
|
|
|
3847
3963
|
// src/cli/commands/setup.ts
|
|
3848
3964
|
init_esm_shims();
|
|
3849
|
-
import * as
|
|
3965
|
+
import * as path12 from "path";
|
|
3850
3966
|
import chalk2 from "chalk";
|
|
3851
3967
|
import inquirer from "inquirer";
|
|
3852
3968
|
import ora2 from "ora";
|
|
@@ -6413,8 +6529,8 @@ var SUBAGENTS = {
|
|
|
6413
6529
|
description: "Automatically create and track bugs and issues",
|
|
6414
6530
|
icon: "bot",
|
|
6415
6531
|
integrations: [
|
|
6416
|
-
INTEGRATIONS.linear,
|
|
6417
|
-
INTEGRATIONS.jira,
|
|
6532
|
+
// INTEGRATIONS.linear,
|
|
6533
|
+
// INTEGRATIONS.jira,
|
|
6418
6534
|
INTEGRATIONS["jira-server"],
|
|
6419
6535
|
INTEGRATIONS.notion,
|
|
6420
6536
|
INTEGRATIONS.slack
|
|
@@ -6428,7 +6544,10 @@ var SUBAGENTS = {
|
|
|
6428
6544
|
name: "Documentation Researcher",
|
|
6429
6545
|
description: "Search and retrieve information from your documentation",
|
|
6430
6546
|
icon: "file-search",
|
|
6431
|
-
integrations: [
|
|
6547
|
+
integrations: [
|
|
6548
|
+
INTEGRATIONS.notion
|
|
6549
|
+
// INTEGRATIONS.confluence
|
|
6550
|
+
],
|
|
6432
6551
|
model: "sonnet",
|
|
6433
6552
|
color: "cyan",
|
|
6434
6553
|
version: "1.0.0"
|
|
@@ -6481,27 +6600,31 @@ function buildSubagentConfig(role, integration) {
|
|
|
6481
6600
|
// src/cli/generators/structure.ts
|
|
6482
6601
|
init_esm_shims();
|
|
6483
6602
|
import * as fs4 from "fs";
|
|
6484
|
-
import * as
|
|
6485
|
-
async function createProjectStructure() {
|
|
6603
|
+
import * as path6 from "path";
|
|
6604
|
+
async function createProjectStructure(tool = DEFAULT_TOOL) {
|
|
6486
6605
|
const cwd = process.cwd();
|
|
6606
|
+
const toolProfile = getToolProfile(tool);
|
|
6487
6607
|
const bugzyDirs = [
|
|
6488
6608
|
".bugzy",
|
|
6489
6609
|
".bugzy/runtime",
|
|
6490
6610
|
".bugzy/runtime/templates"
|
|
6491
6611
|
];
|
|
6492
6612
|
for (const dir of bugzyDirs) {
|
|
6493
|
-
const dirPath =
|
|
6613
|
+
const dirPath = path6.join(cwd, dir);
|
|
6494
6614
|
if (!fs4.existsSync(dirPath)) {
|
|
6495
6615
|
fs4.mkdirSync(dirPath, { recursive: true });
|
|
6496
6616
|
}
|
|
6497
6617
|
}
|
|
6498
|
-
const
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6618
|
+
const toolDirs = [
|
|
6619
|
+
path6.dirname(toolProfile.commandsDir),
|
|
6620
|
+
// .claude, .cursor, or .codex
|
|
6621
|
+
toolProfile.commandsDir,
|
|
6622
|
+
// .claude/commands, .cursor/commands, .codex/prompts
|
|
6623
|
+
toolProfile.agentsDir
|
|
6624
|
+
// .claude/agents, .cursor/agents, .codex/agents
|
|
6502
6625
|
];
|
|
6503
|
-
for (const dir of
|
|
6504
|
-
const dirPath =
|
|
6626
|
+
for (const dir of toolDirs) {
|
|
6627
|
+
const dirPath = path6.join(cwd, dir);
|
|
6505
6628
|
if (!fs4.existsSync(dirPath)) {
|
|
6506
6629
|
fs4.mkdirSync(dirPath, { recursive: true });
|
|
6507
6630
|
}
|
|
@@ -6509,69 +6632,69 @@ async function createProjectStructure() {
|
|
|
6509
6632
|
await createRuntimeFiles();
|
|
6510
6633
|
}
|
|
6511
6634
|
function getTemplatesDir() {
|
|
6512
|
-
return
|
|
6635
|
+
return path6.join(__dirname, "../../templates/init");
|
|
6513
6636
|
}
|
|
6514
6637
|
async function createRuntimeFiles() {
|
|
6515
6638
|
const cwd = process.cwd();
|
|
6516
6639
|
const templatesDir = getTemplatesDir();
|
|
6517
|
-
const projectContextPath =
|
|
6640
|
+
const projectContextPath = path6.join(cwd, ".bugzy/runtime/project-context.md");
|
|
6518
6641
|
if (!fs4.existsSync(projectContextPath)) {
|
|
6519
|
-
const templatePath =
|
|
6642
|
+
const templatePath = path6.join(templatesDir, ".bugzy/runtime/project-context.md");
|
|
6520
6643
|
let content = fs4.readFileSync(templatePath, "utf-8");
|
|
6521
|
-
const projectName =
|
|
6644
|
+
const projectName = path6.basename(cwd);
|
|
6522
6645
|
content = content.replace(/\{\{PROJECT_NAME\}\}/g, projectName);
|
|
6523
6646
|
content = content.replace(/\{\{CUSTOMER_NAME\}\}/g, "[To be filled]");
|
|
6524
6647
|
content = content.replace(/\{\{BUG_TRACKING_SYSTEM\}\}/g, "[To be filled]");
|
|
6525
6648
|
content = content.replace(/\{\{DOCUMENTATION_SYSTEM\}\}/g, "[To be filled]");
|
|
6526
6649
|
fs4.writeFileSync(projectContextPath, content, "utf-8");
|
|
6527
6650
|
}
|
|
6528
|
-
const testPlanTemplatePath =
|
|
6651
|
+
const testPlanTemplatePath = path6.join(cwd, ".bugzy/runtime/templates/test-plan-template.md");
|
|
6529
6652
|
if (!fs4.existsSync(testPlanTemplatePath)) {
|
|
6530
|
-
const templatePath =
|
|
6653
|
+
const templatePath = path6.join(templatesDir, ".bugzy/runtime/templates/test-plan-template.md");
|
|
6531
6654
|
const content = fs4.readFileSync(templatePath, "utf-8");
|
|
6532
6655
|
fs4.writeFileSync(testPlanTemplatePath, content, "utf-8");
|
|
6533
6656
|
}
|
|
6534
|
-
const bestPracticesPath =
|
|
6657
|
+
const bestPracticesPath = path6.join(cwd, ".bugzy/runtime/testing-best-practices.md");
|
|
6535
6658
|
if (!fs4.existsSync(bestPracticesPath)) {
|
|
6536
|
-
const templatePath =
|
|
6659
|
+
const templatePath = path6.join(templatesDir, ".bugzy/runtime/testing-best-practices.md");
|
|
6537
6660
|
const content = fs4.readFileSync(templatePath, "utf-8");
|
|
6538
6661
|
fs4.writeFileSync(bestPracticesPath, content, "utf-8");
|
|
6539
6662
|
}
|
|
6540
|
-
const testResultSchemaPath =
|
|
6663
|
+
const testResultSchemaPath = path6.join(cwd, ".bugzy/runtime/templates/test-result-schema.md");
|
|
6541
6664
|
if (!fs4.existsSync(testResultSchemaPath)) {
|
|
6542
|
-
const templatePath =
|
|
6665
|
+
const templatePath = path6.join(templatesDir, ".bugzy/runtime/templates/test-result-schema.md");
|
|
6543
6666
|
if (fs4.existsSync(templatePath)) {
|
|
6544
6667
|
const content = fs4.readFileSync(templatePath, "utf-8");
|
|
6545
6668
|
fs4.writeFileSync(testResultSchemaPath, content, "utf-8");
|
|
6546
6669
|
}
|
|
6547
6670
|
}
|
|
6548
|
-
const knowledgeBasePath =
|
|
6671
|
+
const knowledgeBasePath = path6.join(cwd, ".bugzy/runtime/knowledge-base.md");
|
|
6549
6672
|
if (!fs4.existsSync(knowledgeBasePath)) {
|
|
6550
|
-
const templatePath =
|
|
6673
|
+
const templatePath = path6.join(templatesDir, ".bugzy/runtime/knowledge-base.md");
|
|
6551
6674
|
if (fs4.existsSync(templatePath)) {
|
|
6552
6675
|
const content = fs4.readFileSync(templatePath, "utf-8");
|
|
6553
6676
|
fs4.writeFileSync(knowledgeBasePath, content, "utf-8");
|
|
6554
6677
|
}
|
|
6555
6678
|
}
|
|
6556
|
-
const knowledgeMaintenancePath =
|
|
6679
|
+
const knowledgeMaintenancePath = path6.join(cwd, ".bugzy/runtime/knowledge-maintenance-guide.md");
|
|
6557
6680
|
if (!fs4.existsSync(knowledgeMaintenancePath)) {
|
|
6558
|
-
const templatePath =
|
|
6681
|
+
const templatePath = path6.join(templatesDir, ".bugzy/runtime/knowledge-maintenance-guide.md");
|
|
6559
6682
|
if (fs4.existsSync(templatePath)) {
|
|
6560
6683
|
const content = fs4.readFileSync(templatePath, "utf-8");
|
|
6561
6684
|
fs4.writeFileSync(knowledgeMaintenancePath, content, "utf-8");
|
|
6562
6685
|
}
|
|
6563
6686
|
}
|
|
6564
|
-
const subagentMemoryPath =
|
|
6687
|
+
const subagentMemoryPath = path6.join(cwd, ".bugzy/runtime/subagent-memory-guide.md");
|
|
6565
6688
|
if (!fs4.existsSync(subagentMemoryPath)) {
|
|
6566
|
-
const templatePath =
|
|
6689
|
+
const templatePath = path6.join(templatesDir, ".bugzy/runtime/subagent-memory-guide.md");
|
|
6567
6690
|
if (fs4.existsSync(templatePath)) {
|
|
6568
6691
|
const content = fs4.readFileSync(templatePath, "utf-8");
|
|
6569
6692
|
fs4.writeFileSync(subagentMemoryPath, content, "utf-8");
|
|
6570
6693
|
}
|
|
6571
6694
|
}
|
|
6572
|
-
const testExecutionStrategyPath =
|
|
6695
|
+
const testExecutionStrategyPath = path6.join(cwd, ".bugzy/runtime/test-execution-strategy.md");
|
|
6573
6696
|
if (!fs4.existsSync(testExecutionStrategyPath)) {
|
|
6574
|
-
const templatePath =
|
|
6697
|
+
const templatePath = path6.join(templatesDir, ".bugzy/runtime/test-execution-strategy.md");
|
|
6575
6698
|
if (fs4.existsSync(templatePath)) {
|
|
6576
6699
|
const content = fs4.readFileSync(templatePath, "utf-8");
|
|
6577
6700
|
fs4.writeFileSync(testExecutionStrategyPath, content, "utf-8");
|
|
@@ -6581,18 +6704,28 @@ async function createRuntimeFiles() {
|
|
|
6581
6704
|
async function generateClaudeMd() {
|
|
6582
6705
|
const cwd = process.cwd();
|
|
6583
6706
|
const templatesDir = getTemplatesDir();
|
|
6584
|
-
const claudeMdPath =
|
|
6707
|
+
const claudeMdPath = path6.join(cwd, "CLAUDE.md");
|
|
6585
6708
|
if (!fs4.existsSync(claudeMdPath)) {
|
|
6586
|
-
const templatePath =
|
|
6709
|
+
const templatePath = path6.join(templatesDir, "CLAUDE.md");
|
|
6587
6710
|
const content = fs4.readFileSync(templatePath, "utf-8");
|
|
6588
6711
|
fs4.writeFileSync(claudeMdPath, content, "utf-8");
|
|
6589
6712
|
}
|
|
6590
6713
|
}
|
|
6714
|
+
async function generateAgentsMd() {
|
|
6715
|
+
const cwd = process.cwd();
|
|
6716
|
+
const templatesDir = getTemplatesDir();
|
|
6717
|
+
const agentsMdPath = path6.join(cwd, "AGENTS.md");
|
|
6718
|
+
if (!fs4.existsSync(agentsMdPath)) {
|
|
6719
|
+
const templatePath = path6.join(templatesDir, "AGENTS.md");
|
|
6720
|
+
const content = fs4.readFileSync(templatePath, "utf-8");
|
|
6721
|
+
fs4.writeFileSync(agentsMdPath, content, "utf-8");
|
|
6722
|
+
}
|
|
6723
|
+
}
|
|
6591
6724
|
async function updateGitignore() {
|
|
6592
6725
|
const cwd = process.cwd();
|
|
6593
|
-
const gitignorePath =
|
|
6726
|
+
const gitignorePath = path6.join(cwd, ".gitignore");
|
|
6594
6727
|
const templatesDir = getTemplatesDir();
|
|
6595
|
-
const templatePath =
|
|
6728
|
+
const templatePath = path6.join(templatesDir, ".gitignore-template");
|
|
6596
6729
|
const bugzyEntries = fs4.readFileSync(templatePath, "utf-8");
|
|
6597
6730
|
if (fs4.existsSync(gitignorePath)) {
|
|
6598
6731
|
const content = fs4.readFileSync(gitignorePath, "utf-8");
|
|
@@ -6608,7 +6741,7 @@ async function updateGitignore() {
|
|
|
6608
6741
|
init_esm_shims();
|
|
6609
6742
|
init_tasks();
|
|
6610
6743
|
import * as fs5 from "fs";
|
|
6611
|
-
import * as
|
|
6744
|
+
import * as path7 from "path";
|
|
6612
6745
|
|
|
6613
6746
|
// src/core/task-builder.ts
|
|
6614
6747
|
init_esm_shims();
|
|
@@ -6657,22 +6790,80 @@ function buildTaskDefinition(taskSlug, projectSubAgents) {
|
|
|
6657
6790
|
};
|
|
6658
6791
|
}
|
|
6659
6792
|
|
|
6793
|
+
// src/core/tool-strings.ts
|
|
6794
|
+
init_esm_shims();
|
|
6795
|
+
var TOOL_STRINGS = {
|
|
6796
|
+
"claude-code": {
|
|
6797
|
+
INVOKE_TEST_RUNNER: "Use the test-runner subagent to execute the tests",
|
|
6798
|
+
INVOKE_TEST_DEBUGGER_FIXER: "Use the test-debugger-fixer subagent to debug and fix the failing test",
|
|
6799
|
+
INVOKE_TEST_CODE_GENERATOR: "Use the test-code-generator subagent to generate automated test code",
|
|
6800
|
+
INVOKE_TEAM_COMMUNICATOR: "Use the team-communicator subagent to notify the team",
|
|
6801
|
+
INVOKE_ISSUE_TRACKER: "Use the issue-tracker subagent to create or update issues",
|
|
6802
|
+
INVOKE_DOCUMENTATION_RESEARCHER: "Use the documentation-researcher subagent to search and gather documentation"
|
|
6803
|
+
},
|
|
6804
|
+
"cursor": {
|
|
6805
|
+
INVOKE_TEST_RUNNER: 'Run the test-runner agent:\n```bash\ncursor-agent -p "$(cat .cursor/agents/test-runner.md)" --output-format text\n```',
|
|
6806
|
+
INVOKE_TEST_DEBUGGER_FIXER: 'Run the test-debugger-fixer agent:\n```bash\ncursor-agent -p "$(cat .cursor/agents/test-debugger-fixer.md)" --output-format text\n```',
|
|
6807
|
+
INVOKE_TEST_CODE_GENERATOR: 'Run the test-code-generator agent:\n```bash\ncursor-agent -p "$(cat .cursor/agents/test-code-generator.md)" --output-format text\n```',
|
|
6808
|
+
INVOKE_TEAM_COMMUNICATOR: 'Run the team-communicator agent:\n```bash\ncursor-agent -p "$(cat .cursor/agents/team-communicator.md)" --output-format text\n```',
|
|
6809
|
+
INVOKE_ISSUE_TRACKER: 'Run the issue-tracker agent:\n```bash\ncursor-agent -p "$(cat .cursor/agents/issue-tracker.md)" --output-format text\n```',
|
|
6810
|
+
INVOKE_DOCUMENTATION_RESEARCHER: 'Run the documentation-researcher agent:\n```bash\ncursor-agent -p "$(cat .cursor/agents/documentation-researcher.md)" --output-format text\n```'
|
|
6811
|
+
},
|
|
6812
|
+
"codex": {
|
|
6813
|
+
INVOKE_TEST_RUNNER: 'Run the test-runner agent:\n```bash\ncodex -p "$(cat .codex/agents/test-runner.md)"\n```',
|
|
6814
|
+
INVOKE_TEST_DEBUGGER_FIXER: 'Run the test-debugger-fixer agent:\n```bash\ncodex -p "$(cat .codex/agents/test-debugger-fixer.md)"\n```',
|
|
6815
|
+
INVOKE_TEST_CODE_GENERATOR: 'Run the test-code-generator agent:\n```bash\ncodex -p "$(cat .codex/agents/test-code-generator.md)"\n```',
|
|
6816
|
+
INVOKE_TEAM_COMMUNICATOR: 'Run the team-communicator agent:\n```bash\ncodex -p "$(cat .codex/agents/team-communicator.md)"\n```',
|
|
6817
|
+
INVOKE_ISSUE_TRACKER: 'Run the issue-tracker agent:\n```bash\ncodex -p "$(cat .codex/agents/issue-tracker.md)"\n```',
|
|
6818
|
+
INVOKE_DOCUMENTATION_RESEARCHER: 'Run the documentation-researcher agent:\n```bash\ncodex -p "$(cat .codex/agents/documentation-researcher.md)"\n```'
|
|
6819
|
+
}
|
|
6820
|
+
};
|
|
6821
|
+
function getToolString(toolId, key) {
|
|
6822
|
+
const toolStrings = TOOL_STRINGS[toolId];
|
|
6823
|
+
if (!toolStrings) {
|
|
6824
|
+
throw new Error(`Unknown tool: ${toolId}`);
|
|
6825
|
+
}
|
|
6826
|
+
const value = toolStrings[key];
|
|
6827
|
+
if (!value) {
|
|
6828
|
+
throw new Error(`Unknown string key: ${key} for tool: ${toolId}`);
|
|
6829
|
+
}
|
|
6830
|
+
return value;
|
|
6831
|
+
}
|
|
6832
|
+
function replaceInvocationPlaceholders(content, toolId) {
|
|
6833
|
+
let result = content;
|
|
6834
|
+
const keys = [
|
|
6835
|
+
"INVOKE_TEST_RUNNER",
|
|
6836
|
+
"INVOKE_TEST_DEBUGGER_FIXER",
|
|
6837
|
+
"INVOKE_TEST_CODE_GENERATOR",
|
|
6838
|
+
"INVOKE_TEAM_COMMUNICATOR",
|
|
6839
|
+
"INVOKE_ISSUE_TRACKER",
|
|
6840
|
+
"INVOKE_DOCUMENTATION_RESEARCHER"
|
|
6841
|
+
];
|
|
6842
|
+
for (const key of keys) {
|
|
6843
|
+
const placeholder = `{{${key}}}`;
|
|
6844
|
+
const replacement = getToolString(toolId, key);
|
|
6845
|
+
result = result.replace(new RegExp(placeholder, "g"), replacement);
|
|
6846
|
+
}
|
|
6847
|
+
return result;
|
|
6848
|
+
}
|
|
6849
|
+
|
|
6660
6850
|
// src/cli/generators/commands.ts
|
|
6661
6851
|
var COMMAND_FILTER = {
|
|
6662
6852
|
// Cloud-only commands (skip in local environment)
|
|
6663
6853
|
"handle-message": false,
|
|
6664
6854
|
"process-event": false
|
|
6665
6855
|
};
|
|
6666
|
-
async function generateCommands(subagents) {
|
|
6856
|
+
async function generateCommands(subagents, tool = DEFAULT_TOOL) {
|
|
6667
6857
|
const cwd = process.cwd();
|
|
6668
|
-
const
|
|
6858
|
+
const toolProfile = getToolProfile(tool);
|
|
6859
|
+
const commandsDir = path7.join(cwd, toolProfile.commandsDir);
|
|
6669
6860
|
if (!fs5.existsSync(commandsDir)) {
|
|
6670
6861
|
fs5.mkdirSync(commandsDir, { recursive: true });
|
|
6671
6862
|
}
|
|
6672
6863
|
const existingFiles = fs5.readdirSync(commandsDir);
|
|
6673
6864
|
for (const file of existingFiles) {
|
|
6674
6865
|
if (file.endsWith(".md")) {
|
|
6675
|
-
fs5.unlinkSync(
|
|
6866
|
+
fs5.unlinkSync(path7.join(commandsDir, file));
|
|
6676
6867
|
}
|
|
6677
6868
|
}
|
|
6678
6869
|
const projectSubAgents = Object.entries(subagents).map(
|
|
@@ -6686,18 +6877,35 @@ async function generateCommands(subagents) {
|
|
|
6686
6877
|
const outputSlug = typeof filterValue === "string" ? filterValue : slug;
|
|
6687
6878
|
try {
|
|
6688
6879
|
const taskDef = buildTaskDefinition(slug, projectSubAgents);
|
|
6689
|
-
const
|
|
6690
|
-
const
|
|
6880
|
+
const processedContent = replaceInvocationPlaceholders(taskDef.content, tool);
|
|
6881
|
+
const content = formatCommandMarkdown(taskDef.frontmatter, processedContent, toolProfile.commandFrontmatter);
|
|
6882
|
+
const fileName = `${outputSlug}${toolProfile.commandExtension}`;
|
|
6883
|
+
const filePath = path7.join(commandsDir, fileName);
|
|
6691
6884
|
fs5.writeFileSync(filePath, content, "utf-8");
|
|
6692
6885
|
} catch (error) {
|
|
6693
|
-
const
|
|
6694
|
-
const
|
|
6886
|
+
const processedContent = replaceInvocationPlaceholders(template.baseContent, tool);
|
|
6887
|
+
const content = formatCommandMarkdown(template.frontmatter, processedContent, toolProfile.commandFrontmatter);
|
|
6888
|
+
const fileName = `${outputSlug}${toolProfile.commandExtension}`;
|
|
6889
|
+
const filePath = path7.join(commandsDir, fileName);
|
|
6695
6890
|
fs5.writeFileSync(filePath, content, "utf-8");
|
|
6696
6891
|
console.warn(`Warning: Generated ${outputSlug} without required subagents: ${error.message}`);
|
|
6697
6892
|
}
|
|
6698
6893
|
}
|
|
6699
6894
|
}
|
|
6700
|
-
function formatCommandMarkdown(frontmatter, content) {
|
|
6895
|
+
function formatCommandMarkdown(frontmatter, content, includeFrontmatter) {
|
|
6896
|
+
if (!includeFrontmatter) {
|
|
6897
|
+
const lines2 = [];
|
|
6898
|
+
if (frontmatter.description) {
|
|
6899
|
+
lines2.push(`# ${frontmatter.description}`);
|
|
6900
|
+
lines2.push("");
|
|
6901
|
+
}
|
|
6902
|
+
if (frontmatter["argument-hint"]) {
|
|
6903
|
+
lines2.push(`**Arguments**: ${frontmatter["argument-hint"]}`);
|
|
6904
|
+
lines2.push("");
|
|
6905
|
+
}
|
|
6906
|
+
lines2.push(content);
|
|
6907
|
+
return lines2.join("\n");
|
|
6908
|
+
}
|
|
6701
6909
|
const lines = ["---"];
|
|
6702
6910
|
for (const [key, value] of Object.entries(frontmatter)) {
|
|
6703
6911
|
if (value !== void 0 && value !== null) {
|
|
@@ -6714,17 +6922,18 @@ function formatCommandMarkdown(frontmatter, content) {
|
|
|
6714
6922
|
// src/cli/generators/agents.ts
|
|
6715
6923
|
init_esm_shims();
|
|
6716
6924
|
import * as fs6 from "fs";
|
|
6717
|
-
import * as
|
|
6718
|
-
async function generateAgents(subagents) {
|
|
6925
|
+
import * as path8 from "path";
|
|
6926
|
+
async function generateAgents(subagents, tool = DEFAULT_TOOL) {
|
|
6719
6927
|
const cwd = process.cwd();
|
|
6720
|
-
const
|
|
6928
|
+
const toolProfile = getToolProfile(tool);
|
|
6929
|
+
const agentsDir = path8.join(cwd, toolProfile.agentsDir);
|
|
6721
6930
|
if (!fs6.existsSync(agentsDir)) {
|
|
6722
6931
|
fs6.mkdirSync(agentsDir, { recursive: true });
|
|
6723
6932
|
}
|
|
6724
6933
|
const existingFiles = fs6.readdirSync(agentsDir);
|
|
6725
6934
|
for (const file of existingFiles) {
|
|
6726
6935
|
if (file.endsWith(".md")) {
|
|
6727
|
-
fs6.unlinkSync(
|
|
6936
|
+
fs6.unlinkSync(path8.join(agentsDir, file));
|
|
6728
6937
|
}
|
|
6729
6938
|
}
|
|
6730
6939
|
for (const [role, integration] of Object.entries(subagents)) {
|
|
@@ -6733,12 +6942,16 @@ async function generateAgents(subagents) {
|
|
|
6733
6942
|
console.warn(`Warning: Could not load template for ${role} with ${integration}`);
|
|
6734
6943
|
continue;
|
|
6735
6944
|
}
|
|
6736
|
-
const content = formatAgentMarkdown(config.frontmatter, config.content);
|
|
6737
|
-
const
|
|
6945
|
+
const content = formatAgentMarkdown(config.frontmatter, config.content, toolProfile.agentFrontmatter);
|
|
6946
|
+
const fileName = `${role}${toolProfile.agentExtension}`;
|
|
6947
|
+
const filePath = path8.join(agentsDir, fileName);
|
|
6738
6948
|
fs6.writeFileSync(filePath, content, "utf-8");
|
|
6739
6949
|
}
|
|
6740
6950
|
}
|
|
6741
|
-
function formatAgentMarkdown(frontmatter, content) {
|
|
6951
|
+
function formatAgentMarkdown(frontmatter, content, includeFrontmatter) {
|
|
6952
|
+
if (!includeFrontmatter) {
|
|
6953
|
+
return content;
|
|
6954
|
+
}
|
|
6742
6955
|
const lines = ["---"];
|
|
6743
6956
|
for (const [key, value] of Object.entries(frontmatter)) {
|
|
6744
6957
|
if (value !== void 0 && value !== null) {
|
|
@@ -6759,7 +6972,8 @@ function formatAgentMarkdown(frontmatter, content) {
|
|
|
6759
6972
|
// src/cli/generators/mcp.ts
|
|
6760
6973
|
init_esm_shims();
|
|
6761
6974
|
import * as fs7 from "fs";
|
|
6762
|
-
import * as
|
|
6975
|
+
import * as path9 from "path";
|
|
6976
|
+
import { execSync } from "child_process";
|
|
6763
6977
|
|
|
6764
6978
|
// src/mcp/index.ts
|
|
6765
6979
|
init_esm_shims();
|
|
@@ -6769,6 +6983,7 @@ var MCP_SERVERS = {
|
|
|
6769
6983
|
name: "Slack",
|
|
6770
6984
|
description: "Slack MCP server for messaging and channel operations",
|
|
6771
6985
|
requiresCredentials: true,
|
|
6986
|
+
npmPackages: ["simple-slack-mcp-server"],
|
|
6772
6987
|
config: {
|
|
6773
6988
|
command: "slack-mcp-server",
|
|
6774
6989
|
args: [],
|
|
@@ -6782,6 +6997,7 @@ var MCP_SERVERS = {
|
|
|
6782
6997
|
name: "Microsoft Teams",
|
|
6783
6998
|
description: "Microsoft Teams MCP server for messaging and channel operations",
|
|
6784
6999
|
requiresCredentials: true,
|
|
7000
|
+
npmPackages: ["@bugzy-ai/teams-mcp-server"],
|
|
6785
7001
|
config: {
|
|
6786
7002
|
command: "teams-mcp-server",
|
|
6787
7003
|
args: [],
|
|
@@ -6795,6 +7011,7 @@ var MCP_SERVERS = {
|
|
|
6795
7011
|
name: "Playwright",
|
|
6796
7012
|
description: "Playwright MCP server for browser automation",
|
|
6797
7013
|
requiresCredentials: false,
|
|
7014
|
+
npmPackages: ["@playwright/mcp"],
|
|
6798
7015
|
config: {
|
|
6799
7016
|
command: "mcp-server-playwright",
|
|
6800
7017
|
args: [
|
|
@@ -6819,6 +7036,7 @@ var MCP_SERVERS = {
|
|
|
6819
7036
|
name: "Notion",
|
|
6820
7037
|
description: "Notion MCP server for documentation",
|
|
6821
7038
|
requiresCredentials: true,
|
|
7039
|
+
npmPackages: ["@notionhq/notion-mcp-server"],
|
|
6822
7040
|
config: {
|
|
6823
7041
|
command: "notion-mcp-server",
|
|
6824
7042
|
args: [],
|
|
@@ -6832,6 +7050,7 @@ var MCP_SERVERS = {
|
|
|
6832
7050
|
name: "Jira Server (On-Prem)",
|
|
6833
7051
|
description: "Jira Server MCP via tunnel for on-premise instances",
|
|
6834
7052
|
requiresCredentials: true,
|
|
7053
|
+
npmPackages: ["@mcp-tunnel/wrapper", "@bugzy-ai/jira-mcp-server"],
|
|
6835
7054
|
config: {
|
|
6836
7055
|
command: "mcp-tunnel",
|
|
6837
7056
|
args: ["--server", "jira-mcp-server"],
|
|
@@ -6928,12 +7147,59 @@ function buildMCPConfig(requiredServers, target = "container") {
|
|
|
6928
7147
|
}
|
|
6929
7148
|
|
|
6930
7149
|
// src/cli/generators/mcp.ts
|
|
6931
|
-
async function generateMCPConfig(mcpServers) {
|
|
7150
|
+
async function generateMCPConfig(mcpServers, tool = DEFAULT_TOOL) {
|
|
6932
7151
|
const cwd = process.cwd();
|
|
6933
|
-
const
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
|
|
7152
|
+
const toolProfile = getToolProfile(tool);
|
|
7153
|
+
if (toolProfile.mcpFormat === "json") {
|
|
7154
|
+
const mcpConfigPath = path9.join(cwd, toolProfile.mcpConfigPath);
|
|
7155
|
+
const mcpDir = path9.dirname(mcpConfigPath);
|
|
7156
|
+
if (!fs7.existsSync(mcpDir)) {
|
|
7157
|
+
fs7.mkdirSync(mcpDir, { recursive: true });
|
|
7158
|
+
}
|
|
7159
|
+
const mcpConfig = buildMCPConfig(mcpServers, "local");
|
|
7160
|
+
const content = JSON.stringify(mcpConfig, null, 2);
|
|
7161
|
+
fs7.writeFileSync(mcpConfigPath, content, "utf-8");
|
|
7162
|
+
} else if (toolProfile.mcpFormat === "toml") {
|
|
7163
|
+
return;
|
|
7164
|
+
}
|
|
7165
|
+
}
|
|
7166
|
+
function buildCodexMCPCommand(serverName) {
|
|
7167
|
+
const serverTemplate = MCP_SERVERS[serverName];
|
|
7168
|
+
if (!serverTemplate) {
|
|
7169
|
+
throw new Error(`Unknown MCP server: ${serverName}`);
|
|
7170
|
+
}
|
|
7171
|
+
const args = ["mcp", "add", `bugzy-${serverName}`];
|
|
7172
|
+
const envVars = [];
|
|
7173
|
+
if (serverTemplate.config.env) {
|
|
7174
|
+
for (const [key, value] of Object.entries(serverTemplate.config.env)) {
|
|
7175
|
+
const match = value.match(/\$\{([A-Z_]+)\}/);
|
|
7176
|
+
if (match) {
|
|
7177
|
+
args.push("--env", `${key}=$${match[1]}`);
|
|
7178
|
+
envVars.push(match[1]);
|
|
7179
|
+
}
|
|
7180
|
+
}
|
|
7181
|
+
}
|
|
7182
|
+
args.push("--", serverTemplate.config.command);
|
|
7183
|
+
if (serverTemplate.config.args?.length) {
|
|
7184
|
+
args.push(...serverTemplate.config.args);
|
|
7185
|
+
}
|
|
7186
|
+
return { args, envVars };
|
|
7187
|
+
}
|
|
7188
|
+
async function getConfiguredCodexMCPServers() {
|
|
7189
|
+
try {
|
|
7190
|
+
const output = execSync("codex mcp list", {
|
|
7191
|
+
encoding: "utf-8",
|
|
7192
|
+
env: { ...process.env, CODEX_HOME: path9.join(process.cwd(), ".codex") },
|
|
7193
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
7194
|
+
});
|
|
7195
|
+
const lines = output.split("\n");
|
|
7196
|
+
return lines.filter((line) => line.includes("bugzy-")).map((line) => {
|
|
7197
|
+
const match = line.match(/bugzy-([a-z-]+)/);
|
|
7198
|
+
return match ? match[1] : null;
|
|
7199
|
+
}).filter((name) => name !== null);
|
|
7200
|
+
} catch {
|
|
7201
|
+
return [];
|
|
7202
|
+
}
|
|
6937
7203
|
}
|
|
6938
7204
|
function getMCPServersFromSubagents(subagents) {
|
|
6939
7205
|
const mcps = /* @__PURE__ */ new Set();
|
|
@@ -6943,13 +7209,16 @@ function getMCPServersFromSubagents(subagents) {
|
|
|
6943
7209
|
return Array.from(mcps);
|
|
6944
7210
|
}
|
|
6945
7211
|
|
|
7212
|
+
// src/cli/commands/setup.ts
|
|
7213
|
+
import { execSync as execSync3 } from "child_process";
|
|
7214
|
+
|
|
6946
7215
|
// src/cli/generators/env.ts
|
|
6947
7216
|
init_esm_shims();
|
|
6948
7217
|
import * as fs8 from "fs";
|
|
6949
|
-
import * as
|
|
7218
|
+
import * as path10 from "path";
|
|
6950
7219
|
async function generateEnvExample(mcpServers) {
|
|
6951
7220
|
const cwd = process.cwd();
|
|
6952
|
-
const envExamplePath =
|
|
7221
|
+
const envExamplePath = path10.join(cwd, ".env.example");
|
|
6953
7222
|
const header = `# ============================================
|
|
6954
7223
|
# Bugzy OSS - Environment Variables
|
|
6955
7224
|
# ============================================
|
|
@@ -6975,11 +7244,13 @@ function getMCPEnvConfig(serverName) {
|
|
|
6975
7244
|
const configs = {
|
|
6976
7245
|
slack: `
|
|
6977
7246
|
# Slack MCP Server
|
|
6978
|
-
#
|
|
7247
|
+
# Setup guide: https://github.com/bugzy-ai/bugzy/blob/main/docs/slack-setup.md
|
|
7248
|
+
# Required scopes: channels:read, chat:write, chat:write.public, reactions:write
|
|
6979
7249
|
SLACK_ACCESS_TOKEN=`,
|
|
6980
7250
|
notion: `
|
|
6981
7251
|
# Notion MCP Server
|
|
6982
|
-
#
|
|
7252
|
+
# Setup guide: https://github.com/bugzy-ai/bugzy/blob/main/docs/notion-setup.md
|
|
7253
|
+
# Requires: Internal Integration Token (ntn_* or secret_*)
|
|
6983
7254
|
NOTION_TOKEN=`,
|
|
6984
7255
|
linear: `
|
|
6985
7256
|
# Linear MCP Server
|
|
@@ -7009,8 +7280,8 @@ GITHUB_TOKEN=`
|
|
|
7009
7280
|
// src/cli/generators/scaffold-playwright.ts
|
|
7010
7281
|
init_esm_shims();
|
|
7011
7282
|
import * as fs9 from "fs";
|
|
7012
|
-
import * as
|
|
7013
|
-
import { execSync } from "child_process";
|
|
7283
|
+
import * as path11 from "path";
|
|
7284
|
+
import { execSync as execSync2 } from "child_process";
|
|
7014
7285
|
async function scaffoldPlaywrightProject(options) {
|
|
7015
7286
|
const { projectName, targetDir, skipInstall = false } = options;
|
|
7016
7287
|
console.log("\n\u{1F3AD} Scaffolding Playwright test automation project...\n");
|
|
@@ -7043,7 +7314,7 @@ async function createDirectoryStructure(targetDir) {
|
|
|
7043
7314
|
"test-runs"
|
|
7044
7315
|
];
|
|
7045
7316
|
for (const dir of directories) {
|
|
7046
|
-
const fullPath =
|
|
7317
|
+
const fullPath = path11.join(targetDir, dir);
|
|
7047
7318
|
if (!fs9.existsSync(fullPath)) {
|
|
7048
7319
|
fs9.mkdirSync(fullPath, { recursive: true });
|
|
7049
7320
|
console.log(` \u2713 Created ${dir}/`);
|
|
@@ -7052,11 +7323,11 @@ async function createDirectoryStructure(targetDir) {
|
|
|
7052
7323
|
}
|
|
7053
7324
|
async function copyTemplateFiles(targetDir, projectName) {
|
|
7054
7325
|
const possiblePaths = [
|
|
7055
|
-
|
|
7326
|
+
path11.join(__dirname, "../../templates/playwright"),
|
|
7056
7327
|
// When running from dist
|
|
7057
|
-
|
|
7328
|
+
path11.join(process.cwd(), "templates/playwright"),
|
|
7058
7329
|
// When running from project root
|
|
7059
|
-
|
|
7330
|
+
path11.join(__dirname, "../../../templates/playwright")
|
|
7060
7331
|
// When running tests
|
|
7061
7332
|
];
|
|
7062
7333
|
let templatesDir = "";
|
|
@@ -7069,9 +7340,9 @@ async function copyTemplateFiles(targetDir, projectName) {
|
|
|
7069
7340
|
if (!templatesDir) {
|
|
7070
7341
|
throw new Error("Templates directory not found. Searched paths: " + possiblePaths.join(", "));
|
|
7071
7342
|
}
|
|
7072
|
-
const initTemplatesDir =
|
|
7073
|
-
const testRunsReadmeSrc =
|
|
7074
|
-
const testRunsReadmeDest =
|
|
7343
|
+
const initTemplatesDir = path11.join(__dirname, "../../templates/init");
|
|
7344
|
+
const testRunsReadmeSrc = path11.join(initTemplatesDir, "test-runs/README.md");
|
|
7345
|
+
const testRunsReadmeDest = path11.join(targetDir, "test-runs/README.md");
|
|
7075
7346
|
if (fs9.existsSync(testRunsReadmeSrc)) {
|
|
7076
7347
|
const content = fs9.readFileSync(testRunsReadmeSrc, "utf-8");
|
|
7077
7348
|
fs9.writeFileSync(testRunsReadmeDest, content, "utf-8");
|
|
@@ -7115,8 +7386,8 @@ async function copyTemplateFiles(targetDir, projectName) {
|
|
|
7115
7386
|
}
|
|
7116
7387
|
];
|
|
7117
7388
|
for (const template of templates) {
|
|
7118
|
-
const srcPath =
|
|
7119
|
-
const destPath =
|
|
7389
|
+
const srcPath = path11.join(templatesDir, template.src);
|
|
7390
|
+
const destPath = path11.join(targetDir, template.dest);
|
|
7120
7391
|
if (fs9.existsSync(srcPath)) {
|
|
7121
7392
|
let content = fs9.readFileSync(srcPath, "utf-8");
|
|
7122
7393
|
if (template.process) {
|
|
@@ -7126,7 +7397,7 @@ async function copyTemplateFiles(targetDir, projectName) {
|
|
|
7126
7397
|
DATE: (/* @__PURE__ */ new Date()).toISOString().split("T")[0]
|
|
7127
7398
|
});
|
|
7128
7399
|
}
|
|
7129
|
-
const destDir =
|
|
7400
|
+
const destDir = path11.dirname(destPath);
|
|
7130
7401
|
if (!fs9.existsSync(destDir)) {
|
|
7131
7402
|
fs9.mkdirSync(destDir, { recursive: true });
|
|
7132
7403
|
}
|
|
@@ -7146,7 +7417,7 @@ function processTemplate(content, values) {
|
|
|
7146
7417
|
return processed;
|
|
7147
7418
|
}
|
|
7148
7419
|
async function updateGitignore2(targetDir) {
|
|
7149
|
-
const gitignorePath =
|
|
7420
|
+
const gitignorePath = path11.join(targetDir, ".gitignore");
|
|
7150
7421
|
const playwrightEntries = `
|
|
7151
7422
|
# Playwright
|
|
7152
7423
|
test-results/
|
|
@@ -7166,7 +7437,7 @@ tests/.auth/
|
|
|
7166
7437
|
}
|
|
7167
7438
|
}
|
|
7168
7439
|
async function createPackageJson(targetDir, projectName) {
|
|
7169
|
-
const packageJsonPath =
|
|
7440
|
+
const packageJsonPath = path11.join(targetDir, "package.json");
|
|
7170
7441
|
const recommendedDeps = {
|
|
7171
7442
|
"@playwright/test": "^1.48.0",
|
|
7172
7443
|
"@types/node": "^20.0.0",
|
|
@@ -7222,7 +7493,7 @@ async function installDependencies(targetDir) {
|
|
|
7222
7493
|
console.log(`
|
|
7223
7494
|
\u{1F4E6} Installing dependencies using ${packageManager}...`);
|
|
7224
7495
|
const installCommand = packageManager === "pnpm" ? "pnpm install" : packageManager === "yarn" ? "yarn install" : "npm install";
|
|
7225
|
-
|
|
7496
|
+
execSync2(installCommand, {
|
|
7226
7497
|
cwd: targetDir,
|
|
7227
7498
|
stdio: "inherit"
|
|
7228
7499
|
});
|
|
@@ -7233,17 +7504,17 @@ async function installDependencies(targetDir) {
|
|
|
7233
7504
|
}
|
|
7234
7505
|
}
|
|
7235
7506
|
function detectPackageManager(targetDir) {
|
|
7236
|
-
if (fs9.existsSync(
|
|
7507
|
+
if (fs9.existsSync(path11.join(targetDir, "pnpm-lock.yaml"))) {
|
|
7237
7508
|
return "pnpm";
|
|
7238
7509
|
}
|
|
7239
|
-
if (fs9.existsSync(
|
|
7510
|
+
if (fs9.existsSync(path11.join(targetDir, "yarn.lock"))) {
|
|
7240
7511
|
return "yarn";
|
|
7241
7512
|
}
|
|
7242
7513
|
return "npm";
|
|
7243
7514
|
}
|
|
7244
7515
|
function isPlaywrightScaffolded(targetDir) {
|
|
7245
|
-
const playwrightConfig =
|
|
7246
|
-
const testsDir =
|
|
7516
|
+
const playwrightConfig = path11.join(targetDir, "playwright.config.ts");
|
|
7517
|
+
const testsDir = path11.join(targetDir, "tests");
|
|
7247
7518
|
return fs9.existsSync(playwrightConfig) && fs9.existsSync(testsDir);
|
|
7248
7519
|
}
|
|
7249
7520
|
|
|
@@ -7287,9 +7558,26 @@ async function setupProject(cliArgs = []) {
|
|
|
7287
7558
|
async function firstTimeSetup(cliSubagents) {
|
|
7288
7559
|
console.log(getBanner());
|
|
7289
7560
|
console.log(chalk2.cyan(" Project Setup\n"));
|
|
7561
|
+
const toolOptions = getToolOptions();
|
|
7562
|
+
const { selectedTool } = await inquirer.prompt([{
|
|
7563
|
+
type: "list",
|
|
7564
|
+
name: "selectedTool",
|
|
7565
|
+
message: "Which AI coding assistant do you use?",
|
|
7566
|
+
choices: toolOptions.map((opt) => ({
|
|
7567
|
+
name: opt.hint ? `${opt.label} - ${chalk2.gray(opt.hint)}` : opt.label,
|
|
7568
|
+
value: opt.value
|
|
7569
|
+
})),
|
|
7570
|
+
default: DEFAULT_TOOL
|
|
7571
|
+
}]);
|
|
7572
|
+
const tool = selectedTool;
|
|
7573
|
+
const toolProfile = getToolProfile(tool);
|
|
7574
|
+
console.log(chalk2.gray(`
|
|
7575
|
+
\u2713 Using ${toolProfile.name}
|
|
7576
|
+
`));
|
|
7290
7577
|
let spinner = ora2("Creating project structure").start();
|
|
7291
|
-
await createProjectStructure();
|
|
7292
|
-
|
|
7578
|
+
await createProjectStructure(tool);
|
|
7579
|
+
const toolDirName = path12.dirname(toolProfile.commandsDir);
|
|
7580
|
+
spinner.succeed(chalk2.green(`Created .bugzy/ and ${toolDirName}/ directories`));
|
|
7293
7581
|
const subagents = {};
|
|
7294
7582
|
if (cliSubagents) {
|
|
7295
7583
|
console.log(chalk2.cyan("\nConfiguring subagents from CLI arguments:\n"));
|
|
@@ -7346,16 +7634,48 @@ async function firstTimeSetup(cliSubagents) {
|
|
|
7346
7634
|
}
|
|
7347
7635
|
}
|
|
7348
7636
|
}
|
|
7637
|
+
const mcpServers = getMCPServersFromSubagents(subagents);
|
|
7638
|
+
const packagesToInstall = [...new Set(
|
|
7639
|
+
mcpServers.flatMap((s) => MCP_SERVERS[s]?.npmPackages ?? [])
|
|
7640
|
+
)];
|
|
7641
|
+
if (packagesToInstall.length > 0) {
|
|
7642
|
+
console.log(chalk2.cyan("\nMCP Server Packages Required:\n"));
|
|
7643
|
+
packagesToInstall.forEach((pkg) => console.log(chalk2.white(` \u2022 ${pkg}`)));
|
|
7644
|
+
const { installMCP } = await inquirer.prompt([{
|
|
7645
|
+
type: "confirm",
|
|
7646
|
+
name: "installMCP",
|
|
7647
|
+
message: "Install MCP packages globally now?",
|
|
7648
|
+
default: true
|
|
7649
|
+
}]);
|
|
7650
|
+
if (installMCP) {
|
|
7651
|
+
const spinner2 = ora2("Installing MCP packages").start();
|
|
7652
|
+
try {
|
|
7653
|
+
execSync3(`npm install -g ${packagesToInstall.join(" ")}`, { stdio: "pipe" });
|
|
7654
|
+
spinner2.succeed(chalk2.green("MCP packages installed"));
|
|
7655
|
+
} catch (e) {
|
|
7656
|
+
spinner2.fail(chalk2.red("Some packages failed to install"));
|
|
7657
|
+
console.log(chalk2.yellow("\nInstall manually: npm install -g " + packagesToInstall.join(" ")));
|
|
7658
|
+
}
|
|
7659
|
+
} else {
|
|
7660
|
+
console.log(chalk2.yellow("\n\u26A0\uFE0F MCP servers will not work until packages are installed:"));
|
|
7661
|
+
console.log(chalk2.white(` npm install -g ${packagesToInstall.join(" ")}
|
|
7662
|
+
`));
|
|
7663
|
+
}
|
|
7664
|
+
}
|
|
7349
7665
|
spinner = ora2("Saving configuration").start();
|
|
7350
|
-
const projectName =
|
|
7351
|
-
const config = createDefaultConfig(projectName);
|
|
7666
|
+
const projectName = path12.basename(process.cwd());
|
|
7667
|
+
const config = createDefaultConfig(projectName, tool);
|
|
7352
7668
|
config.subagents = subagents;
|
|
7353
7669
|
saveConfig(config);
|
|
7354
7670
|
spinner.succeed(chalk2.green("Saved to .bugzy/config.json"));
|
|
7355
|
-
await regenerateAll(subagents);
|
|
7356
|
-
spinner = ora2(
|
|
7357
|
-
|
|
7358
|
-
|
|
7671
|
+
await regenerateAll(subagents, tool);
|
|
7672
|
+
spinner = ora2(`Creating ${toolProfile.memoryFile}`).start();
|
|
7673
|
+
if (tool === "claude-code") {
|
|
7674
|
+
await generateClaudeMd();
|
|
7675
|
+
} else {
|
|
7676
|
+
await generateAgentsMd();
|
|
7677
|
+
}
|
|
7678
|
+
spinner.succeed(chalk2.green(`Created ${toolProfile.memoryFile}`));
|
|
7359
7679
|
spinner = ora2("Updating .gitignore").start();
|
|
7360
7680
|
await updateGitignore();
|
|
7361
7681
|
spinner.succeed(chalk2.green("Updated .gitignore"));
|
|
@@ -7367,11 +7687,23 @@ async function firstTimeSetup(cliSubagents) {
|
|
|
7367
7687
|
});
|
|
7368
7688
|
}
|
|
7369
7689
|
console.log(chalk2.green.bold("\n\u2705 Setup complete!\n"));
|
|
7690
|
+
console.log(chalk2.cyan("\u{1F4CB} Project Context:"));
|
|
7691
|
+
console.log(chalk2.white(" Edit .bugzy/runtime/project-context.md to help the AI understand your project:"));
|
|
7692
|
+
console.log(chalk2.gray(" \u2022 Project description and tech stack"));
|
|
7693
|
+
console.log(chalk2.gray(" \u2022 Team communication channels"));
|
|
7694
|
+
console.log(chalk2.gray(" \u2022 Bug tracking workflow"));
|
|
7695
|
+
console.log(chalk2.gray(" \u2022 Testing conventions\n"));
|
|
7370
7696
|
console.log(chalk2.yellow("Next steps:"));
|
|
7371
7697
|
console.log(chalk2.white("1. cp .env.example .env"));
|
|
7372
7698
|
console.log(chalk2.white("2. Edit .env and add your API tokens"));
|
|
7373
|
-
|
|
7374
|
-
|
|
7699
|
+
if (subagents["test-runner"]) {
|
|
7700
|
+
console.log(chalk2.white("3. npx playwright install (install browser binaries)"));
|
|
7701
|
+
console.log(chalk2.white("4. Edit .bugzy/runtime/project-context.md"));
|
|
7702
|
+
console.log(chalk2.white("5. Run:"), chalk2.cyan("bugzy"));
|
|
7703
|
+
} else {
|
|
7704
|
+
console.log(chalk2.white("3. Edit .bugzy/runtime/project-context.md"));
|
|
7705
|
+
console.log(chalk2.white("4. Run:"), chalk2.cyan("bugzy"));
|
|
7706
|
+
}
|
|
7375
7707
|
console.log();
|
|
7376
7708
|
}
|
|
7377
7709
|
async function reconfigureProject() {
|
|
@@ -7382,11 +7714,38 @@ async function reconfigureProject() {
|
|
|
7382
7714
|
console.error(chalk2.red("Error: Could not load existing configuration"));
|
|
7383
7715
|
process.exit(1);
|
|
7384
7716
|
}
|
|
7717
|
+
const currentTool = getToolFromConfig(existingConfig);
|
|
7718
|
+
const currentToolProfile = getToolProfile(currentTool);
|
|
7385
7719
|
console.log(chalk2.gray("Current configuration:"));
|
|
7720
|
+
console.log(chalk2.gray(` Tool: ${currentToolProfile.name}`));
|
|
7386
7721
|
for (const [role, integration] of Object.entries(existingConfig.subagents)) {
|
|
7387
7722
|
console.log(chalk2.gray(` \u2022 ${role}: ${integration}`));
|
|
7388
7723
|
}
|
|
7389
7724
|
console.log();
|
|
7725
|
+
const toolOptions = getToolOptions();
|
|
7726
|
+
const { changeTool } = await inquirer.prompt([{
|
|
7727
|
+
type: "confirm",
|
|
7728
|
+
name: "changeTool",
|
|
7729
|
+
message: `Keep using ${currentToolProfile.name}?`,
|
|
7730
|
+
default: true
|
|
7731
|
+
}]);
|
|
7732
|
+
let tool = currentTool;
|
|
7733
|
+
if (!changeTool) {
|
|
7734
|
+
const { selectedTool } = await inquirer.prompt([{
|
|
7735
|
+
type: "list",
|
|
7736
|
+
name: "selectedTool",
|
|
7737
|
+
message: "Which AI coding assistant do you want to use?",
|
|
7738
|
+
choices: toolOptions.map((opt) => ({
|
|
7739
|
+
name: opt.hint ? `${opt.label} - ${chalk2.gray(opt.hint)}` : opt.label,
|
|
7740
|
+
value: opt.value
|
|
7741
|
+
})),
|
|
7742
|
+
default: currentTool
|
|
7743
|
+
}]);
|
|
7744
|
+
tool = selectedTool;
|
|
7745
|
+
console.log(chalk2.gray(`
|
|
7746
|
+
\u2713 Switching to ${getToolProfile(tool).name}
|
|
7747
|
+
`));
|
|
7748
|
+
}
|
|
7390
7749
|
const allSubAgents = getAllSubAgents();
|
|
7391
7750
|
const newSubagents = {};
|
|
7392
7751
|
for (const subagent of allSubAgents) {
|
|
@@ -7462,13 +7821,19 @@ async function reconfigureProject() {
|
|
|
7462
7821
|
}
|
|
7463
7822
|
}
|
|
7464
7823
|
let spinner = ora2("Updating configuration").start();
|
|
7824
|
+
existingConfig.tool = tool;
|
|
7465
7825
|
existingConfig.subagents = newSubagents;
|
|
7466
7826
|
await saveConfig(existingConfig);
|
|
7467
7827
|
spinner.succeed(chalk2.green("Updated .bugzy/config.json"));
|
|
7468
|
-
await regenerateAll(newSubagents);
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7828
|
+
await regenerateAll(newSubagents, tool);
|
|
7829
|
+
const toolProfile = getToolProfile(tool);
|
|
7830
|
+
spinner = ora2(`Creating ${toolProfile.memoryFile}`).start();
|
|
7831
|
+
if (tool === "claude-code") {
|
|
7832
|
+
await generateClaudeMd();
|
|
7833
|
+
} else {
|
|
7834
|
+
await generateAgentsMd();
|
|
7835
|
+
}
|
|
7836
|
+
spinner.succeed(chalk2.green(`Created ${toolProfile.memoryFile}`));
|
|
7472
7837
|
console.log(chalk2.green.bold("\n\u2705 Reconfiguration complete!\n"));
|
|
7473
7838
|
console.log(chalk2.yellow("Next steps:"));
|
|
7474
7839
|
console.log(chalk2.white("1. Check .env.example for new required secrets"));
|
|
@@ -7476,23 +7841,52 @@ async function reconfigureProject() {
|
|
|
7476
7841
|
console.log(chalk2.white("3. Run:"), chalk2.cyan("bugzy"));
|
|
7477
7842
|
console.log();
|
|
7478
7843
|
}
|
|
7479
|
-
async function regenerateAll(subagents) {
|
|
7844
|
+
async function regenerateAll(subagents, tool = DEFAULT_TOOL) {
|
|
7845
|
+
const toolProfile = getToolProfile(tool);
|
|
7480
7846
|
let spinner = ora2("Generating task commands").start();
|
|
7481
|
-
await generateCommands(subagents);
|
|
7847
|
+
await generateCommands(subagents, tool);
|
|
7482
7848
|
const taskCount = Object.keys((init_tasks(), __toCommonJS(tasks_exports)).TASK_TEMPLATES).length;
|
|
7483
|
-
spinner.succeed(chalk2.green(`Generated ${taskCount} task commands in .
|
|
7849
|
+
spinner.succeed(chalk2.green(`Generated ${taskCount} task commands in ${toolProfile.commandsDir}/`));
|
|
7484
7850
|
spinner = ora2("Generating subagent configurations").start();
|
|
7485
|
-
await generateAgents(subagents);
|
|
7851
|
+
await generateAgents(subagents, tool);
|
|
7486
7852
|
const subagentCount = Object.keys(subagents).length;
|
|
7487
|
-
spinner.succeed(chalk2.green(`Generated ${subagentCount} subagent configurations in .
|
|
7853
|
+
spinner.succeed(chalk2.green(`Generated ${subagentCount} subagent configurations in ${toolProfile.agentsDir}/`));
|
|
7488
7854
|
spinner = ora2("Generating MCP configuration").start();
|
|
7489
7855
|
const mcpServers = getMCPServersFromSubagents(subagents);
|
|
7490
|
-
await generateMCPConfig(mcpServers);
|
|
7491
|
-
|
|
7856
|
+
await generateMCPConfig(mcpServers, tool);
|
|
7857
|
+
if (toolProfile.mcpFormat === "json") {
|
|
7858
|
+
spinner.succeed(chalk2.green(`Generated ${toolProfile.mcpConfigPath} (${mcpServers.length} servers)`));
|
|
7859
|
+
} else if (toolProfile.mcpFormat === "toml") {
|
|
7860
|
+
spinner.succeed(chalk2.green("MCP configuration ready"));
|
|
7861
|
+
await setupCodexMCP(mcpServers);
|
|
7862
|
+
}
|
|
7492
7863
|
spinner = ora2("Creating environment template").start();
|
|
7493
7864
|
await generateEnvExample(mcpServers);
|
|
7494
7865
|
spinner.succeed(chalk2.green("Created .env.example"));
|
|
7495
7866
|
}
|
|
7867
|
+
async function setupCodexMCP(mcpServers) {
|
|
7868
|
+
const existingServers = await getConfiguredCodexMCPServers();
|
|
7869
|
+
const newServers = mcpServers.filter((s) => !existingServers.includes(s));
|
|
7870
|
+
if (newServers.length === 0) {
|
|
7871
|
+
console.log(chalk2.gray("\n\u2713 All MCP servers already configured"));
|
|
7872
|
+
return;
|
|
7873
|
+
}
|
|
7874
|
+
console.log();
|
|
7875
|
+
for (const serverName of newServers) {
|
|
7876
|
+
const spinner = ora2(`Configuring ${serverName}`).start();
|
|
7877
|
+
try {
|
|
7878
|
+
const { args } = buildCodexMCPCommand(serverName);
|
|
7879
|
+
execSync3(["codex", ...args].join(" "), {
|
|
7880
|
+
stdio: "pipe",
|
|
7881
|
+
env: { ...process.env, CODEX_HOME: path12.join(process.cwd(), ".codex") }
|
|
7882
|
+
});
|
|
7883
|
+
spinner.succeed(chalk2.green(`Configured ${serverName}`));
|
|
7884
|
+
} catch (error) {
|
|
7885
|
+
spinner.fail(chalk2.red(`Failed to configure ${serverName}`));
|
|
7886
|
+
console.error(chalk2.gray(error.message));
|
|
7887
|
+
}
|
|
7888
|
+
}
|
|
7889
|
+
}
|
|
7496
7890
|
|
|
7497
7891
|
// src/cli/index.ts
|
|
7498
7892
|
process.on("uncaughtException", (error) => {
|
|
@@ -7503,9 +7897,9 @@ process.on("unhandledRejection", (reason) => {
|
|
|
7503
7897
|
console.error(chalk3.red("\n\u2717 Error:"), reason?.message || reason);
|
|
7504
7898
|
process.exit(1);
|
|
7505
7899
|
});
|
|
7506
|
-
var __dirname2 =
|
|
7900
|
+
var __dirname2 = dirname7(fileURLToPath2(import.meta.url));
|
|
7507
7901
|
var packageJson = JSON.parse(
|
|
7508
|
-
readFileSync5(
|
|
7902
|
+
readFileSync5(join12(__dirname2, "../../package.json"), "utf-8")
|
|
7509
7903
|
);
|
|
7510
7904
|
if (process.argv.includes("-v") || process.argv.includes("--version")) {
|
|
7511
7905
|
console.log(getBanner());
|