@bugzy-ai/bugzy 1.2.0 → 1.3.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.
@@ -568,7 +568,9 @@ Document all findings including:
568
568
  \`\`\`
569
569
 
570
570
  #### 3.2 Launch Test Runner Agent
571
- Invoke the test-runner agent with special exploration instructions:
571
+ {{INVOKE_TEST_RUNNER}}
572
+
573
+ Execute the exploration test case with special exploration instructions:
572
574
 
573
575
  \`\`\`
574
576
  Execute the exploration test case at ./test-cases/EXPLORATION-TEMP.md with focus on discovery and documentation.
@@ -1039,10 +1041,10 @@ Before invoking the agent, identify the test cases for the current area:
1039
1041
 
1040
1042
  #### Step 2.2: Invoke test-code-generator Agent
1041
1043
 
1042
- Use the test-code-generator agent for the current area with the following context:
1044
+ {{INVOKE_TEST_CODE_GENERATOR}} for the current area with the following context:
1043
1045
 
1044
1046
  **Agent Invocation:**
1045
- "Use the test-code-generator agent to automate test cases for the [AREA_NAME] area.
1047
+ "Automate test cases for the [AREA_NAME] area.
1046
1048
 
1047
1049
  **Context:**
1048
1050
  - Area: [AREA_NAME]
@@ -1182,10 +1184,10 @@ Provide a comprehensive summary showing:
1182
1184
  role: "documentation-researcher",
1183
1185
  contentBlock: `#### 1.4 Gather Product Documentation
1184
1186
 
1185
- Use the documentation-researcher agent to gather comprehensive product documentation:
1187
+ {{INVOKE_DOCUMENTATION_RESEARCHER}} to gather comprehensive product documentation:
1186
1188
 
1187
1189
  \`\`\`
1188
- Use the documentation-researcher agent to explore all available product documentation, specifically focusing on:
1190
+ Explore all available product documentation, specifically focusing on:
1189
1191
  - UI elements and workflows
1190
1192
  - User interactions and navigation paths
1191
1193
  - Form fields and validation rules
@@ -1199,10 +1201,9 @@ Use the documentation-researcher agent to explore all available product document
1199
1201
  role: "team-communicator",
1200
1202
  contentBlock: `### Step 4.5: Team Communication
1201
1203
 
1202
- Use the team-communicator agent to notify the product team about the new test cases and automated tests:
1204
+ {{INVOKE_TEAM_COMMUNICATOR}} to notify the product team about the new test cases and automated tests:
1203
1205
 
1204
1206
  \`\`\`
1205
- Use the team-communicator agent to:
1206
1207
  1. Post an update about test case and automation creation
1207
1208
  2. Provide summary of coverage:
1208
1209
  - Number of manual test cases created
@@ -1471,10 +1472,10 @@ Provide a summary of:
1471
1472
  role: "documentation-researcher",
1472
1473
  contentBlock: `### Step 2: Gather comprehensive project documentation
1473
1474
 
1474
- Use the documentation-researcher agent to explore and gather all available project information and other documentation sources. This ensures the test plan is based on complete and current information.
1475
+ {{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.
1475
1476
 
1476
1477
  \`\`\`
1477
- Use the documentation-researcher agent to explore all available project documentation related to: $ARGUMENTS
1478
+ Explore all available project documentation related to: $ARGUMENTS
1478
1479
 
1479
1480
  Specifically gather:
1480
1481
  - Product specifications and requirements
@@ -1499,10 +1500,9 @@ The agent will:
1499
1500
  role: "team-communicator",
1500
1501
  contentBlock: `### Step 7.5: Team Communication
1501
1502
 
1502
- Use the team-communicator agent to notify the product team about the new test plan:
1503
+ {{INVOKE_TEAM_COMMUNICATOR}} to notify the product team about the new test plan:
1503
1504
 
1504
1505
  \`\`\`
1505
- Use the team-communicator agent to:
1506
1506
  1. Post an update about the test plan creation
1507
1507
  2. Provide a brief summary of coverage areas and key features
1508
1508
  3. Mention any areas that need exploration or clarification
@@ -1755,7 +1755,7 @@ Classify the ambiguity level to determine appropriate response:
1755
1755
  #### Clarification Approach by Severity
1756
1756
 
1757
1757
  **For CRITICAL/HIGH ambiguity:**
1758
- 1. **Use team-communicator to ask specific questions**
1758
+ 1. **{{INVOKE_TEAM_COMMUNICATOR}} to ask specific questions**
1759
1759
  2. **WAIT for response before proceeding**
1760
1760
  3. **Document the clarification request in event history**
1761
1761
 
@@ -2028,7 +2028,7 @@ ${KNOWLEDGE_BASE_UPDATE_INSTRUCTIONS}`,
2028
2028
  contentBlock: `#### 3.3 Use Documentation Researcher if Needed
2029
2029
  For events mentioning unknown features or components:
2030
2030
  \`\`\`
2031
- Use documentation-researcher agent to find information about: [component/feature]
2031
+ {{INVOKE_DOCUMENTATION_RESEARCHER}} to find information about: [component/feature]
2032
2032
  \`\`\``
2033
2033
  },
2034
2034
  {
@@ -2037,7 +2037,7 @@ Use documentation-researcher agent to find information about: [component/feature
2037
2037
 
2038
2038
  When an issue needs to be tracked (task type: report_bug or update_story):
2039
2039
  \`\`\`
2040
- Use issue-tracker agent to:
2040
+ {{INVOKE_ISSUE_TRACKER}}
2041
2041
  1. Check for duplicate issues in the tracking system
2042
2042
  2. For bugs: Create detailed bug report with:
2043
2043
  - Clear, descriptive title
@@ -2315,7 +2315,7 @@ For each failed test:
2315
2315
  For each test classified as **[TEST ISSUE]**, use the test-debugger-fixer agent to automatically fix the test:
2316
2316
 
2317
2317
  \`\`\`
2318
- Use the test-debugger-fixer agent to fix test issues:
2318
+ {{INVOKE_TEST_DEBUGGER_FIXER}}
2319
2319
 
2320
2320
  For each failed test classified as a test issue (not a product bug), provide:
2321
2321
  - Test run timestamp: [from manifest.timestamp]
@@ -2410,7 +2410,7 @@ After triage in Step 5.1, for tests classified as **[PRODUCT BUG]**, use the iss
2410
2410
  For each bug to report, use the issue-tracker agent:
2411
2411
 
2412
2412
  \`\`\`
2413
- Use issue-tracker agent to:
2413
+ {{INVOKE_ISSUE_TRACKER}}
2414
2414
  1. Check for duplicate bugs in the tracking system
2415
2415
  - The agent will automatically search for similar existing issues
2416
2416
  - It maintains memory of recently reported issues
@@ -2481,10 +2481,11 @@ After issue tracker agent completes, create a summary:
2481
2481
  role: "team-communicator",
2482
2482
  contentBlock: `### Step 6: Team Communication
2483
2483
 
2484
- Use the team-communicator agent to notify the product team about test execution:
2484
+ {{INVOKE_TEAM_COMMUNICATOR}}
2485
+
2486
+ Notify the product team about test execution:
2485
2487
 
2486
2488
  \`\`\`
2487
- Use the team-communicator agent to:
2488
2489
  1. Post test execution summary with key statistics
2489
2490
  2. Highlight critical failures that need immediate attention
2490
2491
  3. Share important learnings about product behavior
@@ -2828,7 +2829,7 @@ Read and analyze the JSON report:
2828
2829
  For each test classified as **[TEST ISSUE]**, use the test-debugger-fixer agent to automatically fix the test:
2829
2830
 
2830
2831
  \`\`\`
2831
- Use the test-debugger-fixer agent to fix test issues:
2832
+ {{INVOKE_TEST_DEBUGGER_FIXER}}
2832
2833
 
2833
2834
  For each failed test classified as a test issue (not a product bug), provide:
2834
2835
  - Test file path: [from JSON report]
@@ -2869,7 +2870,7 @@ Classification guidelines:
2869
2870
  #### 4A.4 Fix Test Issues Automatically
2870
2871
 
2871
2872
  For tests classified as [TEST ISSUE]:
2872
- - Use test-debugger-fixer agent to analyze and fix
2873
+ - {{INVOKE_TEST_DEBUGGER_FIXER}} to analyze and fix
2873
2874
  - Agent debugs with browser if needed
2874
2875
  - Applies fix (selector update, wait condition, assertion correction)
2875
2876
  - Reruns test to verify fix (10x for flaky tests)
@@ -2885,7 +2886,7 @@ Track fixed tests with:
2885
2886
  {{ISSUE_TRACKER_INSTRUCTIONS}}
2886
2887
 
2887
2888
  For tests classified as [PRODUCT BUG]:
2888
- - Use issue-tracker agent to create bug reports
2889
+ - {{INVOKE_ISSUE_TRACKER}} to create bug reports
2889
2890
  - Agent checks for duplicates automatically
2890
2891
  - Creates detailed report with:
2891
2892
  - Title, description, reproduction steps
@@ -3201,10 +3202,10 @@ Format as comprehensive markdown report for terminal display:
3201
3202
 
3202
3203
  {{TEAM_COMMUNICATOR_INSTRUCTIONS}}
3203
3204
 
3204
- Use team-communicator agent to post concise results to Slack thread:
3205
+ {{INVOKE_TEAM_COMMUNICATOR}} to post concise results to Slack thread:
3205
3206
 
3206
3207
  \`\`\`
3207
- Use the team-communicator agent to post verification results.
3208
+ Post verification results.
3208
3209
 
3209
3210
  **Channel**: [from CHANGE_CONTEXT.slackChannel]
3210
3211
  **Thread**: [from CHANGE_CONTEXT.slackThread]
@@ -3385,10 +3386,10 @@ A successful verification includes:
3385
3386
  role: "documentation-researcher",
3386
3387
  contentBlock: `#### Research Project Documentation
3387
3388
 
3388
- Use the documentation-researcher agent to gather comprehensive context about the changed features:
3389
+ {{INVOKE_DOCUMENTATION_RESEARCHER}} to gather comprehensive context about the changed features:
3389
3390
 
3390
3391
  \`\`\`
3391
- Use the documentation-researcher agent to explore project documentation related to the changes.
3392
+ Explore project documentation related to the changes.
3392
3393
 
3393
3394
  Specifically gather:
3394
3395
  - Product specifications for affected features
@@ -3420,10 +3421,9 @@ Use this information to:
3420
3421
  role: "issue-tracker",
3421
3422
  contentBlock: `#### Log Product Bugs
3422
3423
 
3423
- For tests classified as **[PRODUCT BUG]**, use the issue-tracker agent to log bugs:
3424
+ For tests classified as **[PRODUCT BUG]**, {{INVOKE_ISSUE_TRACKER}} to log bugs:
3424
3425
 
3425
3426
  \`\`\`
3426
- Use issue-tracker agent to:
3427
3427
  1. Check for duplicate bugs in the tracking system
3428
3428
  - The agent will automatically search for similar existing issues
3429
3429
  - It maintains memory of recently reported issues
@@ -3472,10 +3472,9 @@ Use issue-tracker agent to:
3472
3472
  role: "team-communicator",
3473
3473
  contentBlock: `#### Team Communication
3474
3474
 
3475
- Use the team-communicator agent to share verification results (primarily for Slack trigger, but can be used for other triggers):
3475
+ {{INVOKE_TEAM_COMMUNICATOR}} to share verification results (primarily for Slack trigger, but can be used for other triggers):
3476
3476
 
3477
3477
  \`\`\`
3478
- Use the team-communicator agent to:
3479
3478
  1. Post verification results summary
3480
3479
  2. Highlight critical failures that need immediate attention
3481
3480
  3. Share bugs logged with issue tracker links
@@ -3605,6 +3604,7 @@ var import_chalk3 = __toESM(require("chalk"), 1);
3605
3604
  // src/cli/commands/start.ts
3606
3605
  init_cjs_shims();
3607
3606
  var import_child_process = require("child_process");
3607
+ var path4 = __toESM(require("path"), 1);
3608
3608
  var import_chalk = __toESM(require("chalk"), 1);
3609
3609
  var import_ora = __toESM(require("ora"), 1);
3610
3610
 
@@ -3612,6 +3612,97 @@ var import_ora = __toESM(require("ora"), 1);
3612
3612
  init_cjs_shims();
3613
3613
  var fs = __toESM(require("fs"), 1);
3614
3614
  var path = __toESM(require("path"), 1);
3615
+
3616
+ // src/core/tool-profile.ts
3617
+ init_cjs_shims();
3618
+ var DEFAULT_TOOL = "claude-code";
3619
+ var CLAUDE_CODE_PROFILE = {
3620
+ id: "claude-code",
3621
+ name: "Claude Code",
3622
+ cliCommand: "claude",
3623
+ commandsDir: ".claude/commands",
3624
+ agentsDir: ".claude/agents",
3625
+ mcpConfigPath: ".mcp.json",
3626
+ mcpFormat: "json",
3627
+ memoryFile: "CLAUDE.md",
3628
+ commandFrontmatter: true,
3629
+ agentFrontmatter: true,
3630
+ commandInvocationPrefix: "/",
3631
+ commandExtension: ".md",
3632
+ agentExtension: ".md"
3633
+ };
3634
+ var CURSOR_PROFILE = {
3635
+ id: "cursor",
3636
+ name: "Cursor",
3637
+ cliCommand: "cursor-agent",
3638
+ commandsDir: ".cursor/commands",
3639
+ agentsDir: ".cursor/agents",
3640
+ mcpConfigPath: ".cursor/mcp.json",
3641
+ mcpFormat: "json",
3642
+ memoryFile: "AGENTS.md",
3643
+ // Cursor now uses AGENTS.md (.cursorrules deprecated as of v0.45+)
3644
+ commandFrontmatter: false,
3645
+ // Cursor uses plain markdown
3646
+ agentFrontmatter: false,
3647
+ // Agent files are plain markdown for CLI invocation
3648
+ commandInvocationPrefix: "/",
3649
+ commandExtension: ".md",
3650
+ agentExtension: ".md"
3651
+ };
3652
+ var CODEX_PROFILE = {
3653
+ id: "codex",
3654
+ name: "Codex CLI",
3655
+ cliCommand: "codex",
3656
+ commandsDir: ".codex/prompts",
3657
+ // Codex uses prompts directory
3658
+ agentsDir: ".codex/agents",
3659
+ mcpConfigPath: ".codex/config.toml",
3660
+ // Project-local via CODEX_HOME
3661
+ mcpFormat: "toml",
3662
+ homeEnvVar: "CODEX_HOME",
3663
+ // Set to project root for project-local config
3664
+ memoryFile: "AGENTS.md",
3665
+ commandFrontmatter: true,
3666
+ // Codex prompts support frontmatter
3667
+ agentFrontmatter: false,
3668
+ // Agent files are plain markdown for CLI invocation
3669
+ commandInvocationPrefix: "/prompts:",
3670
+ commandExtension: ".md",
3671
+ agentExtension: ".md"
3672
+ };
3673
+ var TOOL_PROFILES = {
3674
+ "claude-code": CLAUDE_CODE_PROFILE,
3675
+ "cursor": CURSOR_PROFILE,
3676
+ "codex": CODEX_PROFILE
3677
+ };
3678
+ function getToolProfile(toolId) {
3679
+ const profile = TOOL_PROFILES[toolId];
3680
+ if (!profile) {
3681
+ throw new Error(`Unknown tool: ${toolId}`);
3682
+ }
3683
+ return profile;
3684
+ }
3685
+ function getToolOptions() {
3686
+ return [
3687
+ {
3688
+ value: "claude-code",
3689
+ label: "Claude Code (CLI or Cloud)",
3690
+ hint: "Anthropic's official CLI - recommended"
3691
+ },
3692
+ {
3693
+ value: "cursor",
3694
+ label: "Cursor (Experimental)",
3695
+ hint: "VS Code-based AI editor - experimental support"
3696
+ },
3697
+ {
3698
+ value: "codex",
3699
+ label: "Codex CLI (Experimental)",
3700
+ hint: "OpenAI's terminal-based agent - experimental support"
3701
+ }
3702
+ ];
3703
+ }
3704
+
3705
+ // src/cli/utils/config.ts
3615
3706
  async function loadConfig(configPath = ".bugzy/config.json") {
3616
3707
  const fullPath = path.join(process.cwd(), configPath);
3617
3708
  if (!fs.existsSync(fullPath)) {
@@ -3620,6 +3711,9 @@ async function loadConfig(configPath = ".bugzy/config.json") {
3620
3711
  try {
3621
3712
  const content = fs.readFileSync(fullPath, "utf-8");
3622
3713
  const config = JSON.parse(content);
3714
+ if (!config.tool) {
3715
+ config.tool = DEFAULT_TOOL;
3716
+ }
3623
3717
  return config;
3624
3718
  } catch (error) {
3625
3719
  console.error(`Error loading config from ${fullPath}:`, error);
@@ -3644,15 +3738,19 @@ function configExists(configPath = ".bugzy/config.json") {
3644
3738
  const fullPath = path.join(process.cwd(), configPath);
3645
3739
  return fs.existsSync(fullPath);
3646
3740
  }
3647
- function createDefaultConfig(projectName) {
3741
+ function createDefaultConfig(projectName, tool = DEFAULT_TOOL) {
3648
3742
  return {
3649
3743
  version: "1.0.0",
3744
+ tool,
3650
3745
  project: {
3651
3746
  name: projectName
3652
3747
  },
3653
3748
  subagents: {}
3654
3749
  };
3655
3750
  }
3751
+ function getToolFromConfig(config) {
3752
+ return config.tool || DEFAULT_TOOL;
3753
+ }
3656
3754
 
3657
3755
  // src/cli/utils/env.ts
3658
3756
  init_cjs_shims();
@@ -3715,13 +3813,19 @@ function validateEnvVars(mcpServers, envVars) {
3715
3813
  init_cjs_shims();
3716
3814
  var fs3 = __toESM(require("fs"), 1);
3717
3815
  var path3 = __toESM(require("path"), 1);
3718
- function validateProjectStructure() {
3816
+ async function validateProjectStructure() {
3817
+ const config = await loadConfig();
3818
+ const tool = config ? getToolFromConfig(config) : DEFAULT_TOOL;
3819
+ const toolProfile = getToolProfile(tool);
3719
3820
  const requiredDirs = [
3720
3821
  ".bugzy",
3721
3822
  ".bugzy/runtime",
3722
- ".claude",
3723
- ".claude/commands",
3724
- ".claude/agents"
3823
+ path3.dirname(toolProfile.commandsDir),
3824
+ // .claude, .cursor, or .codex
3825
+ toolProfile.commandsDir,
3826
+ // .claude/commands, .cursor/commands, .codex/prompts
3827
+ toolProfile.agentsDir
3828
+ // .claude/agents, .cursor/agents, .codex/agents
3725
3829
  ];
3726
3830
  const requiredFiles = [
3727
3831
  ".bugzy/config.json",
@@ -3747,10 +3851,10 @@ function validateProjectStructure() {
3747
3851
  }
3748
3852
  return true;
3749
3853
  }
3750
- async function checkClaudeAvailable() {
3854
+ async function checkToolAvailable(command) {
3751
3855
  const { spawn: spawn2 } = await import("child_process");
3752
3856
  return new Promise((resolve) => {
3753
- const proc = spawn2("which", ["claude"]);
3857
+ const proc = spawn2("which", [command]);
3754
3858
  proc.on("close", (code) => {
3755
3859
  resolve(code === 0);
3756
3860
  });
@@ -3795,9 +3899,11 @@ async function startSession(prompt) {
3795
3899
  process.exit(1);
3796
3900
  }
3797
3901
  spinner.succeed(import_chalk.default.green("Configuration loaded"));
3902
+ const tool = getToolFromConfig(config);
3903
+ const toolProfile = getToolProfile(tool);
3798
3904
  spinner = (0, import_ora.default)("Validating project structure").start();
3799
3905
  try {
3800
- validateProjectStructure();
3906
+ await validateProjectStructure();
3801
3907
  spinner.succeed(import_chalk.default.green("Project structure validated"));
3802
3908
  } catch (error) {
3803
3909
  spinner.fail(import_chalk.default.red("Invalid project structure"));
@@ -3805,15 +3911,22 @@ async function startSession(prompt) {
3805
3911
  console.log(import_chalk.default.yellow("\nRun"), import_chalk.default.cyan("bugzy setup"), import_chalk.default.yellow("to fix the project structure"));
3806
3912
  process.exit(1);
3807
3913
  }
3808
- spinner = (0, import_ora.default)("Checking Claude Code availability").start();
3809
- const claudeAvailable = await checkClaudeAvailable();
3810
- if (!claudeAvailable) {
3811
- spinner.fail(import_chalk.default.red("Claude Code CLI not found"));
3812
- console.log(import_chalk.default.yellow("\nPlease install Claude Code:"));
3813
- console.log(import_chalk.default.cyan(" https://claude.com/claude-code"));
3914
+ spinner = (0, import_ora.default)(`Checking ${toolProfile.name} availability`).start();
3915
+ const toolAvailable = await checkToolAvailable(toolProfile.cliCommand);
3916
+ if (!toolAvailable) {
3917
+ spinner.fail(import_chalk.default.red(`${toolProfile.name} CLI not found`));
3918
+ console.log(import_chalk.default.yellow(`
3919
+ Please install ${toolProfile.name}:`));
3920
+ if (tool === "claude-code") {
3921
+ console.log(import_chalk.default.cyan(" https://claude.com/claude-code"));
3922
+ } else if (tool === "cursor") {
3923
+ console.log(import_chalk.default.cyan(" https://www.cursor.com/"));
3924
+ } else if (tool === "codex") {
3925
+ console.log(import_chalk.default.cyan(" npm install -g @openai/codex"));
3926
+ }
3814
3927
  process.exit(1);
3815
3928
  }
3816
- spinner.succeed(import_chalk.default.green("Claude Code CLI found"));
3929
+ spinner.succeed(import_chalk.default.green(`${toolProfile.name} CLI found`));
3817
3930
  spinner = (0, import_ora.default)("Loading environment variables").start();
3818
3931
  const envVars = loadEnvFiles();
3819
3932
  const envCount = Object.keys(envVars).length;
@@ -3831,14 +3944,20 @@ async function startSession(prompt) {
3831
3944
  process.exit(1);
3832
3945
  }
3833
3946
  spinner.succeed(import_chalk.default.green("All required MCP secrets present"));
3834
- console.log(import_chalk.default.green.bold("\n\u{1F680} Launching Claude Code...\n"));
3947
+ console.log(import_chalk.default.green.bold(`
3948
+ \u{1F680} Launching ${toolProfile.name}...
3949
+ `));
3835
3950
  const args = prompt ? [prompt] : [];
3836
- const claude = (0, import_child_process.spawn)("claude", args, {
3951
+ const spawnEnv = { ...process.env, ...envVars };
3952
+ if (toolProfile.homeEnvVar) {
3953
+ spawnEnv[toolProfile.homeEnvVar] = path4.join(process.cwd(), ".codex");
3954
+ }
3955
+ const child = (0, import_child_process.spawn)(toolProfile.cliCommand, args, {
3837
3956
  cwd: process.cwd(),
3838
- env: { ...process.env, ...envVars },
3957
+ env: spawnEnv,
3839
3958
  stdio: "inherit"
3840
3959
  });
3841
- claude.on("close", (code) => {
3960
+ child.on("close", (code) => {
3842
3961
  if (code === 0) {
3843
3962
  console.log(import_chalk.default.green("\n\u2713 Session ended successfully"));
3844
3963
  } else {
@@ -3846,15 +3965,16 @@ async function startSession(prompt) {
3846
3965
  \u2713 Session ended (exit code: ${code})`));
3847
3966
  }
3848
3967
  });
3849
- claude.on("error", (error) => {
3850
- console.error(import_chalk.default.red("\n\u2717 Error launching Claude Code:"), error);
3968
+ child.on("error", (error) => {
3969
+ console.error(import_chalk.default.red(`
3970
+ \u2717 Error launching ${toolProfile.name}:`), error);
3851
3971
  process.exit(1);
3852
3972
  });
3853
3973
  }
3854
3974
 
3855
3975
  // src/cli/commands/setup.ts
3856
3976
  init_cjs_shims();
3857
- var path10 = __toESM(require("path"), 1);
3977
+ var path11 = __toESM(require("path"), 1);
3858
3978
  var import_chalk2 = __toESM(require("chalk"), 1);
3859
3979
  var import_inquirer = __toESM(require("inquirer"), 1);
3860
3980
  var import_ora2 = __toESM(require("ora"), 1);
@@ -6489,27 +6609,31 @@ function buildSubagentConfig(role, integration) {
6489
6609
  // src/cli/generators/structure.ts
6490
6610
  init_cjs_shims();
6491
6611
  var fs4 = __toESM(require("fs"), 1);
6492
- var path4 = __toESM(require("path"), 1);
6493
- async function createProjectStructure() {
6612
+ var path5 = __toESM(require("path"), 1);
6613
+ async function createProjectStructure(tool = DEFAULT_TOOL) {
6494
6614
  const cwd = process.cwd();
6615
+ const toolProfile = getToolProfile(tool);
6495
6616
  const bugzyDirs = [
6496
6617
  ".bugzy",
6497
6618
  ".bugzy/runtime",
6498
6619
  ".bugzy/runtime/templates"
6499
6620
  ];
6500
6621
  for (const dir of bugzyDirs) {
6501
- const dirPath = path4.join(cwd, dir);
6622
+ const dirPath = path5.join(cwd, dir);
6502
6623
  if (!fs4.existsSync(dirPath)) {
6503
6624
  fs4.mkdirSync(dirPath, { recursive: true });
6504
6625
  }
6505
6626
  }
6506
- const claudeDirs = [
6507
- ".claude",
6508
- ".claude/commands",
6509
- ".claude/agents"
6627
+ const toolDirs = [
6628
+ path5.dirname(toolProfile.commandsDir),
6629
+ // .claude, .cursor, or .codex
6630
+ toolProfile.commandsDir,
6631
+ // .claude/commands, .cursor/commands, .codex/prompts
6632
+ toolProfile.agentsDir
6633
+ // .claude/agents, .cursor/agents, .codex/agents
6510
6634
  ];
6511
- for (const dir of claudeDirs) {
6512
- const dirPath = path4.join(cwd, dir);
6635
+ for (const dir of toolDirs) {
6636
+ const dirPath = path5.join(cwd, dir);
6513
6637
  if (!fs4.existsSync(dirPath)) {
6514
6638
  fs4.mkdirSync(dirPath, { recursive: true });
6515
6639
  }
@@ -6517,69 +6641,69 @@ async function createProjectStructure() {
6517
6641
  await createRuntimeFiles();
6518
6642
  }
6519
6643
  function getTemplatesDir() {
6520
- return path4.join(__dirname, "../../templates/init");
6644
+ return path5.join(__dirname, "../../templates/init");
6521
6645
  }
6522
6646
  async function createRuntimeFiles() {
6523
6647
  const cwd = process.cwd();
6524
6648
  const templatesDir = getTemplatesDir();
6525
- const projectContextPath = path4.join(cwd, ".bugzy/runtime/project-context.md");
6649
+ const projectContextPath = path5.join(cwd, ".bugzy/runtime/project-context.md");
6526
6650
  if (!fs4.existsSync(projectContextPath)) {
6527
- const templatePath = path4.join(templatesDir, ".bugzy/runtime/project-context.md");
6651
+ const templatePath = path5.join(templatesDir, ".bugzy/runtime/project-context.md");
6528
6652
  let content = fs4.readFileSync(templatePath, "utf-8");
6529
- const projectName = path4.basename(cwd);
6653
+ const projectName = path5.basename(cwd);
6530
6654
  content = content.replace(/\{\{PROJECT_NAME\}\}/g, projectName);
6531
6655
  content = content.replace(/\{\{CUSTOMER_NAME\}\}/g, "[To be filled]");
6532
6656
  content = content.replace(/\{\{BUG_TRACKING_SYSTEM\}\}/g, "[To be filled]");
6533
6657
  content = content.replace(/\{\{DOCUMENTATION_SYSTEM\}\}/g, "[To be filled]");
6534
6658
  fs4.writeFileSync(projectContextPath, content, "utf-8");
6535
6659
  }
6536
- const testPlanTemplatePath = path4.join(cwd, ".bugzy/runtime/templates/test-plan-template.md");
6660
+ const testPlanTemplatePath = path5.join(cwd, ".bugzy/runtime/templates/test-plan-template.md");
6537
6661
  if (!fs4.existsSync(testPlanTemplatePath)) {
6538
- const templatePath = path4.join(templatesDir, ".bugzy/runtime/templates/test-plan-template.md");
6662
+ const templatePath = path5.join(templatesDir, ".bugzy/runtime/templates/test-plan-template.md");
6539
6663
  const content = fs4.readFileSync(templatePath, "utf-8");
6540
6664
  fs4.writeFileSync(testPlanTemplatePath, content, "utf-8");
6541
6665
  }
6542
- const bestPracticesPath = path4.join(cwd, ".bugzy/runtime/testing-best-practices.md");
6666
+ const bestPracticesPath = path5.join(cwd, ".bugzy/runtime/testing-best-practices.md");
6543
6667
  if (!fs4.existsSync(bestPracticesPath)) {
6544
- const templatePath = path4.join(templatesDir, ".bugzy/runtime/testing-best-practices.md");
6668
+ const templatePath = path5.join(templatesDir, ".bugzy/runtime/testing-best-practices.md");
6545
6669
  const content = fs4.readFileSync(templatePath, "utf-8");
6546
6670
  fs4.writeFileSync(bestPracticesPath, content, "utf-8");
6547
6671
  }
6548
- const testResultSchemaPath = path4.join(cwd, ".bugzy/runtime/templates/test-result-schema.md");
6672
+ const testResultSchemaPath = path5.join(cwd, ".bugzy/runtime/templates/test-result-schema.md");
6549
6673
  if (!fs4.existsSync(testResultSchemaPath)) {
6550
- const templatePath = path4.join(templatesDir, ".bugzy/runtime/templates/test-result-schema.md");
6674
+ const templatePath = path5.join(templatesDir, ".bugzy/runtime/templates/test-result-schema.md");
6551
6675
  if (fs4.existsSync(templatePath)) {
6552
6676
  const content = fs4.readFileSync(templatePath, "utf-8");
6553
6677
  fs4.writeFileSync(testResultSchemaPath, content, "utf-8");
6554
6678
  }
6555
6679
  }
6556
- const knowledgeBasePath = path4.join(cwd, ".bugzy/runtime/knowledge-base.md");
6680
+ const knowledgeBasePath = path5.join(cwd, ".bugzy/runtime/knowledge-base.md");
6557
6681
  if (!fs4.existsSync(knowledgeBasePath)) {
6558
- const templatePath = path4.join(templatesDir, ".bugzy/runtime/knowledge-base.md");
6682
+ const templatePath = path5.join(templatesDir, ".bugzy/runtime/knowledge-base.md");
6559
6683
  if (fs4.existsSync(templatePath)) {
6560
6684
  const content = fs4.readFileSync(templatePath, "utf-8");
6561
6685
  fs4.writeFileSync(knowledgeBasePath, content, "utf-8");
6562
6686
  }
6563
6687
  }
6564
- const knowledgeMaintenancePath = path4.join(cwd, ".bugzy/runtime/knowledge-maintenance-guide.md");
6688
+ const knowledgeMaintenancePath = path5.join(cwd, ".bugzy/runtime/knowledge-maintenance-guide.md");
6565
6689
  if (!fs4.existsSync(knowledgeMaintenancePath)) {
6566
- const templatePath = path4.join(templatesDir, ".bugzy/runtime/knowledge-maintenance-guide.md");
6690
+ const templatePath = path5.join(templatesDir, ".bugzy/runtime/knowledge-maintenance-guide.md");
6567
6691
  if (fs4.existsSync(templatePath)) {
6568
6692
  const content = fs4.readFileSync(templatePath, "utf-8");
6569
6693
  fs4.writeFileSync(knowledgeMaintenancePath, content, "utf-8");
6570
6694
  }
6571
6695
  }
6572
- const subagentMemoryPath = path4.join(cwd, ".bugzy/runtime/subagent-memory-guide.md");
6696
+ const subagentMemoryPath = path5.join(cwd, ".bugzy/runtime/subagent-memory-guide.md");
6573
6697
  if (!fs4.existsSync(subagentMemoryPath)) {
6574
- const templatePath = path4.join(templatesDir, ".bugzy/runtime/subagent-memory-guide.md");
6698
+ const templatePath = path5.join(templatesDir, ".bugzy/runtime/subagent-memory-guide.md");
6575
6699
  if (fs4.existsSync(templatePath)) {
6576
6700
  const content = fs4.readFileSync(templatePath, "utf-8");
6577
6701
  fs4.writeFileSync(subagentMemoryPath, content, "utf-8");
6578
6702
  }
6579
6703
  }
6580
- const testExecutionStrategyPath = path4.join(cwd, ".bugzy/runtime/test-execution-strategy.md");
6704
+ const testExecutionStrategyPath = path5.join(cwd, ".bugzy/runtime/test-execution-strategy.md");
6581
6705
  if (!fs4.existsSync(testExecutionStrategyPath)) {
6582
- const templatePath = path4.join(templatesDir, ".bugzy/runtime/test-execution-strategy.md");
6706
+ const templatePath = path5.join(templatesDir, ".bugzy/runtime/test-execution-strategy.md");
6583
6707
  if (fs4.existsSync(templatePath)) {
6584
6708
  const content = fs4.readFileSync(templatePath, "utf-8");
6585
6709
  fs4.writeFileSync(testExecutionStrategyPath, content, "utf-8");
@@ -6589,18 +6713,28 @@ async function createRuntimeFiles() {
6589
6713
  async function generateClaudeMd() {
6590
6714
  const cwd = process.cwd();
6591
6715
  const templatesDir = getTemplatesDir();
6592
- const claudeMdPath = path4.join(cwd, "CLAUDE.md");
6716
+ const claudeMdPath = path5.join(cwd, "CLAUDE.md");
6593
6717
  if (!fs4.existsSync(claudeMdPath)) {
6594
- const templatePath = path4.join(templatesDir, "CLAUDE.md");
6718
+ const templatePath = path5.join(templatesDir, "CLAUDE.md");
6595
6719
  const content = fs4.readFileSync(templatePath, "utf-8");
6596
6720
  fs4.writeFileSync(claudeMdPath, content, "utf-8");
6597
6721
  }
6598
6722
  }
6723
+ async function generateAgentsMd() {
6724
+ const cwd = process.cwd();
6725
+ const templatesDir = getTemplatesDir();
6726
+ const agentsMdPath = path5.join(cwd, "AGENTS.md");
6727
+ if (!fs4.existsSync(agentsMdPath)) {
6728
+ const templatePath = path5.join(templatesDir, "AGENTS.md");
6729
+ const content = fs4.readFileSync(templatePath, "utf-8");
6730
+ fs4.writeFileSync(agentsMdPath, content, "utf-8");
6731
+ }
6732
+ }
6599
6733
  async function updateGitignore() {
6600
6734
  const cwd = process.cwd();
6601
- const gitignorePath = path4.join(cwd, ".gitignore");
6735
+ const gitignorePath = path5.join(cwd, ".gitignore");
6602
6736
  const templatesDir = getTemplatesDir();
6603
- const templatePath = path4.join(templatesDir, ".gitignore-template");
6737
+ const templatePath = path5.join(templatesDir, ".gitignore-template");
6604
6738
  const bugzyEntries = fs4.readFileSync(templatePath, "utf-8");
6605
6739
  if (fs4.existsSync(gitignorePath)) {
6606
6740
  const content = fs4.readFileSync(gitignorePath, "utf-8");
@@ -6615,7 +6749,7 @@ async function updateGitignore() {
6615
6749
  // src/cli/generators/commands.ts
6616
6750
  init_cjs_shims();
6617
6751
  var fs5 = __toESM(require("fs"), 1);
6618
- var path5 = __toESM(require("path"), 1);
6752
+ var path6 = __toESM(require("path"), 1);
6619
6753
  init_tasks();
6620
6754
 
6621
6755
  // src/core/task-builder.ts
@@ -6665,22 +6799,80 @@ function buildTaskDefinition(taskSlug, projectSubAgents) {
6665
6799
  };
6666
6800
  }
6667
6801
 
6802
+ // src/core/tool-strings.ts
6803
+ init_cjs_shims();
6804
+ var TOOL_STRINGS = {
6805
+ "claude-code": {
6806
+ INVOKE_TEST_RUNNER: "Use the test-runner subagent to execute the tests",
6807
+ INVOKE_TEST_DEBUGGER_FIXER: "Use the test-debugger-fixer subagent to debug and fix the failing test",
6808
+ INVOKE_TEST_CODE_GENERATOR: "Use the test-code-generator subagent to generate automated test code",
6809
+ INVOKE_TEAM_COMMUNICATOR: "Use the team-communicator subagent to notify the team",
6810
+ INVOKE_ISSUE_TRACKER: "Use the issue-tracker subagent to create or update issues",
6811
+ INVOKE_DOCUMENTATION_RESEARCHER: "Use the documentation-researcher subagent to search and gather documentation"
6812
+ },
6813
+ "cursor": {
6814
+ INVOKE_TEST_RUNNER: 'Run the test-runner agent:\n```bash\ncursor-agent -p "$(cat .cursor/agents/test-runner.md)" --output-format text\n```',
6815
+ 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```',
6816
+ 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```',
6817
+ INVOKE_TEAM_COMMUNICATOR: 'Run the team-communicator agent:\n```bash\ncursor-agent -p "$(cat .cursor/agents/team-communicator.md)" --output-format text\n```',
6818
+ INVOKE_ISSUE_TRACKER: 'Run the issue-tracker agent:\n```bash\ncursor-agent -p "$(cat .cursor/agents/issue-tracker.md)" --output-format text\n```',
6819
+ INVOKE_DOCUMENTATION_RESEARCHER: 'Run the documentation-researcher agent:\n```bash\ncursor-agent -p "$(cat .cursor/agents/documentation-researcher.md)" --output-format text\n```'
6820
+ },
6821
+ "codex": {
6822
+ INVOKE_TEST_RUNNER: 'Run the test-runner agent:\n```bash\ncodex -p "$(cat .codex/agents/test-runner.md)"\n```',
6823
+ INVOKE_TEST_DEBUGGER_FIXER: 'Run the test-debugger-fixer agent:\n```bash\ncodex -p "$(cat .codex/agents/test-debugger-fixer.md)"\n```',
6824
+ INVOKE_TEST_CODE_GENERATOR: 'Run the test-code-generator agent:\n```bash\ncodex -p "$(cat .codex/agents/test-code-generator.md)"\n```',
6825
+ INVOKE_TEAM_COMMUNICATOR: 'Run the team-communicator agent:\n```bash\ncodex -p "$(cat .codex/agents/team-communicator.md)"\n```',
6826
+ INVOKE_ISSUE_TRACKER: 'Run the issue-tracker agent:\n```bash\ncodex -p "$(cat .codex/agents/issue-tracker.md)"\n```',
6827
+ INVOKE_DOCUMENTATION_RESEARCHER: 'Run the documentation-researcher agent:\n```bash\ncodex -p "$(cat .codex/agents/documentation-researcher.md)"\n```'
6828
+ }
6829
+ };
6830
+ function getToolString(toolId, key) {
6831
+ const toolStrings = TOOL_STRINGS[toolId];
6832
+ if (!toolStrings) {
6833
+ throw new Error(`Unknown tool: ${toolId}`);
6834
+ }
6835
+ const value = toolStrings[key];
6836
+ if (!value) {
6837
+ throw new Error(`Unknown string key: ${key} for tool: ${toolId}`);
6838
+ }
6839
+ return value;
6840
+ }
6841
+ function replaceInvocationPlaceholders(content, toolId) {
6842
+ let result = content;
6843
+ const keys = [
6844
+ "INVOKE_TEST_RUNNER",
6845
+ "INVOKE_TEST_DEBUGGER_FIXER",
6846
+ "INVOKE_TEST_CODE_GENERATOR",
6847
+ "INVOKE_TEAM_COMMUNICATOR",
6848
+ "INVOKE_ISSUE_TRACKER",
6849
+ "INVOKE_DOCUMENTATION_RESEARCHER"
6850
+ ];
6851
+ for (const key of keys) {
6852
+ const placeholder = `{{${key}}}`;
6853
+ const replacement = getToolString(toolId, key);
6854
+ result = result.replace(new RegExp(placeholder, "g"), replacement);
6855
+ }
6856
+ return result;
6857
+ }
6858
+
6668
6859
  // src/cli/generators/commands.ts
6669
6860
  var COMMAND_FILTER = {
6670
6861
  // Cloud-only commands (skip in local environment)
6671
6862
  "handle-message": false,
6672
6863
  "process-event": false
6673
6864
  };
6674
- async function generateCommands(subagents) {
6865
+ async function generateCommands(subagents, tool = DEFAULT_TOOL) {
6675
6866
  const cwd = process.cwd();
6676
- const commandsDir = path5.join(cwd, ".claude", "commands");
6867
+ const toolProfile = getToolProfile(tool);
6868
+ const commandsDir = path6.join(cwd, toolProfile.commandsDir);
6677
6869
  if (!fs5.existsSync(commandsDir)) {
6678
6870
  fs5.mkdirSync(commandsDir, { recursive: true });
6679
6871
  }
6680
6872
  const existingFiles = fs5.readdirSync(commandsDir);
6681
6873
  for (const file of existingFiles) {
6682
6874
  if (file.endsWith(".md")) {
6683
- fs5.unlinkSync(path5.join(commandsDir, file));
6875
+ fs5.unlinkSync(path6.join(commandsDir, file));
6684
6876
  }
6685
6877
  }
6686
6878
  const projectSubAgents = Object.entries(subagents).map(
@@ -6694,18 +6886,35 @@ async function generateCommands(subagents) {
6694
6886
  const outputSlug = typeof filterValue === "string" ? filterValue : slug;
6695
6887
  try {
6696
6888
  const taskDef = buildTaskDefinition(slug, projectSubAgents);
6697
- const content = formatCommandMarkdown(taskDef.frontmatter, taskDef.content);
6698
- const filePath = path5.join(commandsDir, `${outputSlug}.md`);
6889
+ const processedContent = replaceInvocationPlaceholders(taskDef.content, tool);
6890
+ const content = formatCommandMarkdown(taskDef.frontmatter, processedContent, toolProfile.commandFrontmatter);
6891
+ const fileName = `${outputSlug}${toolProfile.commandExtension}`;
6892
+ const filePath = path6.join(commandsDir, fileName);
6699
6893
  fs5.writeFileSync(filePath, content, "utf-8");
6700
6894
  } catch (error) {
6701
- const content = formatCommandMarkdown(template.frontmatter, template.baseContent);
6702
- const filePath = path5.join(commandsDir, `${outputSlug}.md`);
6895
+ const processedContent = replaceInvocationPlaceholders(template.baseContent, tool);
6896
+ const content = formatCommandMarkdown(template.frontmatter, processedContent, toolProfile.commandFrontmatter);
6897
+ const fileName = `${outputSlug}${toolProfile.commandExtension}`;
6898
+ const filePath = path6.join(commandsDir, fileName);
6703
6899
  fs5.writeFileSync(filePath, content, "utf-8");
6704
6900
  console.warn(`Warning: Generated ${outputSlug} without required subagents: ${error.message}`);
6705
6901
  }
6706
6902
  }
6707
6903
  }
6708
- function formatCommandMarkdown(frontmatter, content) {
6904
+ function formatCommandMarkdown(frontmatter, content, includeFrontmatter) {
6905
+ if (!includeFrontmatter) {
6906
+ const lines2 = [];
6907
+ if (frontmatter.description) {
6908
+ lines2.push(`# ${frontmatter.description}`);
6909
+ lines2.push("");
6910
+ }
6911
+ if (frontmatter["argument-hint"]) {
6912
+ lines2.push(`**Arguments**: ${frontmatter["argument-hint"]}`);
6913
+ lines2.push("");
6914
+ }
6915
+ lines2.push(content);
6916
+ return lines2.join("\n");
6917
+ }
6709
6918
  const lines = ["---"];
6710
6919
  for (const [key, value] of Object.entries(frontmatter)) {
6711
6920
  if (value !== void 0 && value !== null) {
@@ -6722,17 +6931,18 @@ function formatCommandMarkdown(frontmatter, content) {
6722
6931
  // src/cli/generators/agents.ts
6723
6932
  init_cjs_shims();
6724
6933
  var fs6 = __toESM(require("fs"), 1);
6725
- var path6 = __toESM(require("path"), 1);
6726
- async function generateAgents(subagents) {
6934
+ var path7 = __toESM(require("path"), 1);
6935
+ async function generateAgents(subagents, tool = DEFAULT_TOOL) {
6727
6936
  const cwd = process.cwd();
6728
- const agentsDir = path6.join(cwd, ".claude", "agents");
6937
+ const toolProfile = getToolProfile(tool);
6938
+ const agentsDir = path7.join(cwd, toolProfile.agentsDir);
6729
6939
  if (!fs6.existsSync(agentsDir)) {
6730
6940
  fs6.mkdirSync(agentsDir, { recursive: true });
6731
6941
  }
6732
6942
  const existingFiles = fs6.readdirSync(agentsDir);
6733
6943
  for (const file of existingFiles) {
6734
6944
  if (file.endsWith(".md")) {
6735
- fs6.unlinkSync(path6.join(agentsDir, file));
6945
+ fs6.unlinkSync(path7.join(agentsDir, file));
6736
6946
  }
6737
6947
  }
6738
6948
  for (const [role, integration] of Object.entries(subagents)) {
@@ -6741,12 +6951,16 @@ async function generateAgents(subagents) {
6741
6951
  console.warn(`Warning: Could not load template for ${role} with ${integration}`);
6742
6952
  continue;
6743
6953
  }
6744
- const content = formatAgentMarkdown(config.frontmatter, config.content);
6745
- const filePath = path6.join(agentsDir, `${role}.md`);
6954
+ const content = formatAgentMarkdown(config.frontmatter, config.content, toolProfile.agentFrontmatter);
6955
+ const fileName = `${role}${toolProfile.agentExtension}`;
6956
+ const filePath = path7.join(agentsDir, fileName);
6746
6957
  fs6.writeFileSync(filePath, content, "utf-8");
6747
6958
  }
6748
6959
  }
6749
- function formatAgentMarkdown(frontmatter, content) {
6960
+ function formatAgentMarkdown(frontmatter, content, includeFrontmatter) {
6961
+ if (!includeFrontmatter) {
6962
+ return content;
6963
+ }
6750
6964
  const lines = ["---"];
6751
6965
  for (const [key, value] of Object.entries(frontmatter)) {
6752
6966
  if (value !== void 0 && value !== null) {
@@ -6767,7 +6981,8 @@ function formatAgentMarkdown(frontmatter, content) {
6767
6981
  // src/cli/generators/mcp.ts
6768
6982
  init_cjs_shims();
6769
6983
  var fs7 = __toESM(require("fs"), 1);
6770
- var path7 = __toESM(require("path"), 1);
6984
+ var path8 = __toESM(require("path"), 1);
6985
+ var import_child_process2 = require("child_process");
6771
6986
 
6772
6987
  // src/mcp/index.ts
6773
6988
  init_cjs_shims();
@@ -6936,12 +7151,59 @@ function buildMCPConfig(requiredServers, target = "container") {
6936
7151
  }
6937
7152
 
6938
7153
  // src/cli/generators/mcp.ts
6939
- async function generateMCPConfig(mcpServers) {
7154
+ async function generateMCPConfig(mcpServers, tool = DEFAULT_TOOL) {
6940
7155
  const cwd = process.cwd();
6941
- const mcpConfigPath = path7.join(cwd, ".mcp.json");
6942
- const mcpConfig = buildMCPConfig(mcpServers, "local");
6943
- const content = JSON.stringify(mcpConfig, null, 2);
6944
- fs7.writeFileSync(mcpConfigPath, content, "utf-8");
7156
+ const toolProfile = getToolProfile(tool);
7157
+ if (toolProfile.mcpFormat === "json") {
7158
+ const mcpConfigPath = path8.join(cwd, toolProfile.mcpConfigPath);
7159
+ const mcpDir = path8.dirname(mcpConfigPath);
7160
+ if (!fs7.existsSync(mcpDir)) {
7161
+ fs7.mkdirSync(mcpDir, { recursive: true });
7162
+ }
7163
+ const mcpConfig = buildMCPConfig(mcpServers, "local");
7164
+ const content = JSON.stringify(mcpConfig, null, 2);
7165
+ fs7.writeFileSync(mcpConfigPath, content, "utf-8");
7166
+ } else if (toolProfile.mcpFormat === "toml") {
7167
+ return;
7168
+ }
7169
+ }
7170
+ function buildCodexMCPCommand(serverName) {
7171
+ const serverTemplate = MCP_SERVERS[serverName];
7172
+ if (!serverTemplate) {
7173
+ throw new Error(`Unknown MCP server: ${serverName}`);
7174
+ }
7175
+ const args = ["mcp", "add", `bugzy-${serverName}`];
7176
+ const envVars = [];
7177
+ if (serverTemplate.config.env) {
7178
+ for (const [key, value] of Object.entries(serverTemplate.config.env)) {
7179
+ const match = value.match(/\$\{([A-Z_]+)\}/);
7180
+ if (match) {
7181
+ args.push("--env", `${key}=$${match[1]}`);
7182
+ envVars.push(match[1]);
7183
+ }
7184
+ }
7185
+ }
7186
+ args.push("--", serverTemplate.config.command);
7187
+ if (serverTemplate.config.args?.length) {
7188
+ args.push(...serverTemplate.config.args);
7189
+ }
7190
+ return { args, envVars };
7191
+ }
7192
+ async function getConfiguredCodexMCPServers() {
7193
+ try {
7194
+ const output = (0, import_child_process2.execSync)("codex mcp list", {
7195
+ encoding: "utf-8",
7196
+ env: { ...process.env, CODEX_HOME: path8.join(process.cwd(), ".codex") },
7197
+ stdio: ["pipe", "pipe", "pipe"]
7198
+ });
7199
+ const lines = output.split("\n");
7200
+ return lines.filter((line) => line.includes("bugzy-")).map((line) => {
7201
+ const match = line.match(/bugzy-([a-z-]+)/);
7202
+ return match ? match[1] : null;
7203
+ }).filter((name) => name !== null);
7204
+ } catch {
7205
+ return [];
7206
+ }
6945
7207
  }
6946
7208
  function getMCPServersFromSubagents(subagents) {
6947
7209
  const mcps = /* @__PURE__ */ new Set();
@@ -6951,13 +7213,16 @@ function getMCPServersFromSubagents(subagents) {
6951
7213
  return Array.from(mcps);
6952
7214
  }
6953
7215
 
7216
+ // src/cli/commands/setup.ts
7217
+ var import_child_process4 = require("child_process");
7218
+
6954
7219
  // src/cli/generators/env.ts
6955
7220
  init_cjs_shims();
6956
7221
  var fs8 = __toESM(require("fs"), 1);
6957
- var path8 = __toESM(require("path"), 1);
7222
+ var path9 = __toESM(require("path"), 1);
6958
7223
  async function generateEnvExample(mcpServers) {
6959
7224
  const cwd = process.cwd();
6960
- const envExamplePath = path8.join(cwd, ".env.example");
7225
+ const envExamplePath = path9.join(cwd, ".env.example");
6961
7226
  const header = `# ============================================
6962
7227
  # Bugzy OSS - Environment Variables
6963
7228
  # ============================================
@@ -7017,8 +7282,8 @@ GITHUB_TOKEN=`
7017
7282
  // src/cli/generators/scaffold-playwright.ts
7018
7283
  init_cjs_shims();
7019
7284
  var fs9 = __toESM(require("fs"), 1);
7020
- var path9 = __toESM(require("path"), 1);
7021
- var import_child_process2 = require("child_process");
7285
+ var path10 = __toESM(require("path"), 1);
7286
+ var import_child_process3 = require("child_process");
7022
7287
  async function scaffoldPlaywrightProject(options) {
7023
7288
  const { projectName, targetDir, skipInstall = false } = options;
7024
7289
  console.log("\n\u{1F3AD} Scaffolding Playwright test automation project...\n");
@@ -7051,7 +7316,7 @@ async function createDirectoryStructure(targetDir) {
7051
7316
  "test-runs"
7052
7317
  ];
7053
7318
  for (const dir of directories) {
7054
- const fullPath = path9.join(targetDir, dir);
7319
+ const fullPath = path10.join(targetDir, dir);
7055
7320
  if (!fs9.existsSync(fullPath)) {
7056
7321
  fs9.mkdirSync(fullPath, { recursive: true });
7057
7322
  console.log(` \u2713 Created ${dir}/`);
@@ -7060,11 +7325,11 @@ async function createDirectoryStructure(targetDir) {
7060
7325
  }
7061
7326
  async function copyTemplateFiles(targetDir, projectName) {
7062
7327
  const possiblePaths = [
7063
- path9.join(__dirname, "../../templates/playwright"),
7328
+ path10.join(__dirname, "../../templates/playwright"),
7064
7329
  // When running from dist
7065
- path9.join(process.cwd(), "templates/playwright"),
7330
+ path10.join(process.cwd(), "templates/playwright"),
7066
7331
  // When running from project root
7067
- path9.join(__dirname, "../../../templates/playwright")
7332
+ path10.join(__dirname, "../../../templates/playwright")
7068
7333
  // When running tests
7069
7334
  ];
7070
7335
  let templatesDir = "";
@@ -7077,9 +7342,9 @@ async function copyTemplateFiles(targetDir, projectName) {
7077
7342
  if (!templatesDir) {
7078
7343
  throw new Error("Templates directory not found. Searched paths: " + possiblePaths.join(", "));
7079
7344
  }
7080
- const initTemplatesDir = path9.join(__dirname, "../../templates/init");
7081
- const testRunsReadmeSrc = path9.join(initTemplatesDir, "test-runs/README.md");
7082
- const testRunsReadmeDest = path9.join(targetDir, "test-runs/README.md");
7345
+ const initTemplatesDir = path10.join(__dirname, "../../templates/init");
7346
+ const testRunsReadmeSrc = path10.join(initTemplatesDir, "test-runs/README.md");
7347
+ const testRunsReadmeDest = path10.join(targetDir, "test-runs/README.md");
7083
7348
  if (fs9.existsSync(testRunsReadmeSrc)) {
7084
7349
  const content = fs9.readFileSync(testRunsReadmeSrc, "utf-8");
7085
7350
  fs9.writeFileSync(testRunsReadmeDest, content, "utf-8");
@@ -7123,8 +7388,8 @@ async function copyTemplateFiles(targetDir, projectName) {
7123
7388
  }
7124
7389
  ];
7125
7390
  for (const template of templates) {
7126
- const srcPath = path9.join(templatesDir, template.src);
7127
- const destPath = path9.join(targetDir, template.dest);
7391
+ const srcPath = path10.join(templatesDir, template.src);
7392
+ const destPath = path10.join(targetDir, template.dest);
7128
7393
  if (fs9.existsSync(srcPath)) {
7129
7394
  let content = fs9.readFileSync(srcPath, "utf-8");
7130
7395
  if (template.process) {
@@ -7134,7 +7399,7 @@ async function copyTemplateFiles(targetDir, projectName) {
7134
7399
  DATE: (/* @__PURE__ */ new Date()).toISOString().split("T")[0]
7135
7400
  });
7136
7401
  }
7137
- const destDir = path9.dirname(destPath);
7402
+ const destDir = path10.dirname(destPath);
7138
7403
  if (!fs9.existsSync(destDir)) {
7139
7404
  fs9.mkdirSync(destDir, { recursive: true });
7140
7405
  }
@@ -7154,7 +7419,7 @@ function processTemplate(content, values) {
7154
7419
  return processed;
7155
7420
  }
7156
7421
  async function updateGitignore2(targetDir) {
7157
- const gitignorePath = path9.join(targetDir, ".gitignore");
7422
+ const gitignorePath = path10.join(targetDir, ".gitignore");
7158
7423
  const playwrightEntries = `
7159
7424
  # Playwright
7160
7425
  test-results/
@@ -7174,7 +7439,7 @@ tests/.auth/
7174
7439
  }
7175
7440
  }
7176
7441
  async function createPackageJson(targetDir, projectName) {
7177
- const packageJsonPath = path9.join(targetDir, "package.json");
7442
+ const packageJsonPath = path10.join(targetDir, "package.json");
7178
7443
  const recommendedDeps = {
7179
7444
  "@playwright/test": "^1.48.0",
7180
7445
  "@types/node": "^20.0.0",
@@ -7230,7 +7495,7 @@ async function installDependencies(targetDir) {
7230
7495
  console.log(`
7231
7496
  \u{1F4E6} Installing dependencies using ${packageManager}...`);
7232
7497
  const installCommand = packageManager === "pnpm" ? "pnpm install" : packageManager === "yarn" ? "yarn install" : "npm install";
7233
- (0, import_child_process2.execSync)(installCommand, {
7498
+ (0, import_child_process3.execSync)(installCommand, {
7234
7499
  cwd: targetDir,
7235
7500
  stdio: "inherit"
7236
7501
  });
@@ -7241,17 +7506,17 @@ async function installDependencies(targetDir) {
7241
7506
  }
7242
7507
  }
7243
7508
  function detectPackageManager(targetDir) {
7244
- if (fs9.existsSync(path9.join(targetDir, "pnpm-lock.yaml"))) {
7509
+ if (fs9.existsSync(path10.join(targetDir, "pnpm-lock.yaml"))) {
7245
7510
  return "pnpm";
7246
7511
  }
7247
- if (fs9.existsSync(path9.join(targetDir, "yarn.lock"))) {
7512
+ if (fs9.existsSync(path10.join(targetDir, "yarn.lock"))) {
7248
7513
  return "yarn";
7249
7514
  }
7250
7515
  return "npm";
7251
7516
  }
7252
7517
  function isPlaywrightScaffolded(targetDir) {
7253
- const playwrightConfig = path9.join(targetDir, "playwright.config.ts");
7254
- const testsDir = path9.join(targetDir, "tests");
7518
+ const playwrightConfig = path10.join(targetDir, "playwright.config.ts");
7519
+ const testsDir = path10.join(targetDir, "tests");
7255
7520
  return fs9.existsSync(playwrightConfig) && fs9.existsSync(testsDir);
7256
7521
  }
7257
7522
 
@@ -7295,9 +7560,26 @@ async function setupProject(cliArgs = []) {
7295
7560
  async function firstTimeSetup(cliSubagents) {
7296
7561
  console.log(getBanner());
7297
7562
  console.log(import_chalk2.default.cyan(" Project Setup\n"));
7563
+ const toolOptions = getToolOptions();
7564
+ const { selectedTool } = await import_inquirer.default.prompt([{
7565
+ type: "list",
7566
+ name: "selectedTool",
7567
+ message: "Which AI coding assistant do you use?",
7568
+ choices: toolOptions.map((opt) => ({
7569
+ name: opt.hint ? `${opt.label} - ${import_chalk2.default.gray(opt.hint)}` : opt.label,
7570
+ value: opt.value
7571
+ })),
7572
+ default: DEFAULT_TOOL
7573
+ }]);
7574
+ const tool = selectedTool;
7575
+ const toolProfile = getToolProfile(tool);
7576
+ console.log(import_chalk2.default.gray(`
7577
+ \u2713 Using ${toolProfile.name}
7578
+ `));
7298
7579
  let spinner = (0, import_ora2.default)("Creating project structure").start();
7299
- await createProjectStructure();
7300
- spinner.succeed(import_chalk2.default.green("Created .bugzy/ and .claude/ directories"));
7580
+ await createProjectStructure(tool);
7581
+ const toolDirName = path11.dirname(toolProfile.commandsDir);
7582
+ spinner.succeed(import_chalk2.default.green(`Created .bugzy/ and ${toolDirName}/ directories`));
7301
7583
  const subagents = {};
7302
7584
  if (cliSubagents) {
7303
7585
  console.log(import_chalk2.default.cyan("\nConfiguring subagents from CLI arguments:\n"));
@@ -7355,15 +7637,19 @@ async function firstTimeSetup(cliSubagents) {
7355
7637
  }
7356
7638
  }
7357
7639
  spinner = (0, import_ora2.default)("Saving configuration").start();
7358
- const projectName = path10.basename(process.cwd());
7359
- const config = createDefaultConfig(projectName);
7640
+ const projectName = path11.basename(process.cwd());
7641
+ const config = createDefaultConfig(projectName, tool);
7360
7642
  config.subagents = subagents;
7361
7643
  saveConfig(config);
7362
7644
  spinner.succeed(import_chalk2.default.green("Saved to .bugzy/config.json"));
7363
- await regenerateAll(subagents);
7364
- spinner = (0, import_ora2.default)("Creating CLAUDE.md").start();
7365
- await generateClaudeMd();
7366
- spinner.succeed(import_chalk2.default.green("Created CLAUDE.md"));
7645
+ await regenerateAll(subagents, tool);
7646
+ spinner = (0, import_ora2.default)(`Creating ${toolProfile.memoryFile}`).start();
7647
+ if (tool === "claude-code") {
7648
+ await generateClaudeMd();
7649
+ } else {
7650
+ await generateAgentsMd();
7651
+ }
7652
+ spinner.succeed(import_chalk2.default.green(`Created ${toolProfile.memoryFile}`));
7367
7653
  spinner = (0, import_ora2.default)("Updating .gitignore").start();
7368
7654
  await updateGitignore();
7369
7655
  spinner.succeed(import_chalk2.default.green("Updated .gitignore"));
@@ -7390,11 +7676,38 @@ async function reconfigureProject() {
7390
7676
  console.error(import_chalk2.default.red("Error: Could not load existing configuration"));
7391
7677
  process.exit(1);
7392
7678
  }
7679
+ const currentTool = getToolFromConfig(existingConfig);
7680
+ const currentToolProfile = getToolProfile(currentTool);
7393
7681
  console.log(import_chalk2.default.gray("Current configuration:"));
7682
+ console.log(import_chalk2.default.gray(` Tool: ${currentToolProfile.name}`));
7394
7683
  for (const [role, integration] of Object.entries(existingConfig.subagents)) {
7395
7684
  console.log(import_chalk2.default.gray(` \u2022 ${role}: ${integration}`));
7396
7685
  }
7397
7686
  console.log();
7687
+ const toolOptions = getToolOptions();
7688
+ const { changeTool } = await import_inquirer.default.prompt([{
7689
+ type: "confirm",
7690
+ name: "changeTool",
7691
+ message: `Keep using ${currentToolProfile.name}?`,
7692
+ default: true
7693
+ }]);
7694
+ let tool = currentTool;
7695
+ if (!changeTool) {
7696
+ const { selectedTool } = await import_inquirer.default.prompt([{
7697
+ type: "list",
7698
+ name: "selectedTool",
7699
+ message: "Which AI coding assistant do you want to use?",
7700
+ choices: toolOptions.map((opt) => ({
7701
+ name: opt.hint ? `${opt.label} - ${import_chalk2.default.gray(opt.hint)}` : opt.label,
7702
+ value: opt.value
7703
+ })),
7704
+ default: currentTool
7705
+ }]);
7706
+ tool = selectedTool;
7707
+ console.log(import_chalk2.default.gray(`
7708
+ \u2713 Switching to ${getToolProfile(tool).name}
7709
+ `));
7710
+ }
7398
7711
  const allSubAgents = getAllSubAgents();
7399
7712
  const newSubagents = {};
7400
7713
  for (const subagent of allSubAgents) {
@@ -7470,13 +7783,19 @@ async function reconfigureProject() {
7470
7783
  }
7471
7784
  }
7472
7785
  let spinner = (0, import_ora2.default)("Updating configuration").start();
7786
+ existingConfig.tool = tool;
7473
7787
  existingConfig.subagents = newSubagents;
7474
7788
  await saveConfig(existingConfig);
7475
7789
  spinner.succeed(import_chalk2.default.green("Updated .bugzy/config.json"));
7476
- await regenerateAll(newSubagents);
7477
- spinner = (0, import_ora2.default)("Creating CLAUDE.md").start();
7478
- await generateClaudeMd();
7479
- spinner.succeed(import_chalk2.default.green("Created CLAUDE.md"));
7790
+ await regenerateAll(newSubagents, tool);
7791
+ const toolProfile = getToolProfile(tool);
7792
+ spinner = (0, import_ora2.default)(`Creating ${toolProfile.memoryFile}`).start();
7793
+ if (tool === "claude-code") {
7794
+ await generateClaudeMd();
7795
+ } else {
7796
+ await generateAgentsMd();
7797
+ }
7798
+ spinner.succeed(import_chalk2.default.green(`Created ${toolProfile.memoryFile}`));
7480
7799
  console.log(import_chalk2.default.green.bold("\n\u2705 Reconfiguration complete!\n"));
7481
7800
  console.log(import_chalk2.default.yellow("Next steps:"));
7482
7801
  console.log(import_chalk2.default.white("1. Check .env.example for new required secrets"));
@@ -7484,23 +7803,52 @@ async function reconfigureProject() {
7484
7803
  console.log(import_chalk2.default.white("3. Run:"), import_chalk2.default.cyan("bugzy"));
7485
7804
  console.log();
7486
7805
  }
7487
- async function regenerateAll(subagents) {
7806
+ async function regenerateAll(subagents, tool = DEFAULT_TOOL) {
7807
+ const toolProfile = getToolProfile(tool);
7488
7808
  let spinner = (0, import_ora2.default)("Generating task commands").start();
7489
- await generateCommands(subagents);
7809
+ await generateCommands(subagents, tool);
7490
7810
  const taskCount = Object.keys((init_tasks(), __toCommonJS(tasks_exports)).TASK_TEMPLATES).length;
7491
- spinner.succeed(import_chalk2.default.green(`Generated ${taskCount} task commands in .claude/commands/`));
7811
+ spinner.succeed(import_chalk2.default.green(`Generated ${taskCount} task commands in ${toolProfile.commandsDir}/`));
7492
7812
  spinner = (0, import_ora2.default)("Generating subagent configurations").start();
7493
- await generateAgents(subagents);
7813
+ await generateAgents(subagents, tool);
7494
7814
  const subagentCount = Object.keys(subagents).length;
7495
- spinner.succeed(import_chalk2.default.green(`Generated ${subagentCount} subagent configurations in .claude/agents/`));
7815
+ spinner.succeed(import_chalk2.default.green(`Generated ${subagentCount} subagent configurations in ${toolProfile.agentsDir}/`));
7496
7816
  spinner = (0, import_ora2.default)("Generating MCP configuration").start();
7497
7817
  const mcpServers = getMCPServersFromSubagents(subagents);
7498
- await generateMCPConfig(mcpServers);
7499
- spinner.succeed(import_chalk2.default.green(`Generated .mcp.json (${mcpServers.length} servers)`));
7818
+ await generateMCPConfig(mcpServers, tool);
7819
+ if (toolProfile.mcpFormat === "json") {
7820
+ spinner.succeed(import_chalk2.default.green(`Generated ${toolProfile.mcpConfigPath} (${mcpServers.length} servers)`));
7821
+ } else if (toolProfile.mcpFormat === "toml") {
7822
+ spinner.succeed(import_chalk2.default.green("MCP configuration ready"));
7823
+ await setupCodexMCP(mcpServers);
7824
+ }
7500
7825
  spinner = (0, import_ora2.default)("Creating environment template").start();
7501
7826
  await generateEnvExample(mcpServers);
7502
7827
  spinner.succeed(import_chalk2.default.green("Created .env.example"));
7503
7828
  }
7829
+ async function setupCodexMCP(mcpServers) {
7830
+ const existingServers = await getConfiguredCodexMCPServers();
7831
+ const newServers = mcpServers.filter((s) => !existingServers.includes(s));
7832
+ if (newServers.length === 0) {
7833
+ console.log(import_chalk2.default.gray("\n\u2713 All MCP servers already configured"));
7834
+ return;
7835
+ }
7836
+ console.log();
7837
+ for (const serverName of newServers) {
7838
+ const spinner = (0, import_ora2.default)(`Configuring ${serverName}`).start();
7839
+ try {
7840
+ const { args } = buildCodexMCPCommand(serverName);
7841
+ (0, import_child_process4.execSync)(["codex", ...args].join(" "), {
7842
+ stdio: "pipe",
7843
+ env: { ...process.env, CODEX_HOME: path11.join(process.cwd(), ".codex") }
7844
+ });
7845
+ spinner.succeed(import_chalk2.default.green(`Configured ${serverName}`));
7846
+ } catch (error) {
7847
+ spinner.fail(import_chalk2.default.red(`Failed to configure ${serverName}`));
7848
+ console.error(import_chalk2.default.gray(error.message));
7849
+ }
7850
+ }
7851
+ }
7504
7852
 
7505
7853
  // src/cli/index.ts
7506
7854
  process.on("uncaughtException", (error) => {