@codebakers/cli 3.5.0 → 3.5.1

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.
@@ -8,8 +8,12 @@ const chalk_1 = __importDefault(require("chalk"));
8
8
  const fs_1 = require("fs");
9
9
  const path_1 = require("path");
10
10
  const config_js_1 = require("../config.js");
11
+ const api_js_1 = require("../lib/api.js");
11
12
  async function status() {
12
- console.log(chalk_1.default.blue('\n CodeBakers Status\n'));
13
+ console.log(chalk_1.default.blue('\n CodeBakers Status (v6.0)\n'));
14
+ // Show version
15
+ const version = (0, api_js_1.getCliVersion)();
16
+ console.log(chalk_1.default.gray(` CLI Version: ${version}\n`));
13
17
  // Check login status
14
18
  const apiKey = (0, config_js_1.getApiKey)();
15
19
  if (apiKey) {
@@ -18,7 +22,7 @@ async function status() {
18
22
  }
19
23
  else {
20
24
  console.log(chalk_1.default.red(' ✗ Not logged in'));
21
- console.log(chalk_1.default.gray(' Run `codebakers login` to authenticate'));
25
+ console.log(chalk_1.default.gray(' Run `codebakers setup` to authenticate'));
22
26
  }
23
27
  console.log('');
24
28
  // Check installation status in current directory
@@ -29,21 +33,45 @@ async function status() {
29
33
  const hasCursorRules = (0, fs_1.existsSync)(cursorrules);
30
34
  const hasClaudeMd = (0, fs_1.existsSync)(claudemd);
31
35
  const hasClaudeDir = (0, fs_1.existsSync)(claudeDir);
32
- if (hasCursorRules || hasClaudeMd || hasClaudeDir) {
33
- console.log(chalk_1.default.green(' ✓ Patterns installed in this directory'));
34
- if (hasCursorRules) {
35
- console.log(chalk_1.default.gray(' - .cursorrules (Cursor IDE)'));
36
- }
37
- if (hasClaudeMd) {
38
- console.log(chalk_1.default.gray(' - CLAUDE.md (Claude Code)'));
36
+ // Check version of installed files
37
+ let isV6 = false;
38
+ if (hasClaudeMd) {
39
+ const content = (0, fs_1.readFileSync)(claudemd, 'utf-8');
40
+ isV6 = content.includes('discover_patterns') || content.includes('v6.0');
41
+ }
42
+ if (hasCursorRules || hasClaudeMd) {
43
+ if (isV6) {
44
+ console.log(chalk_1.default.green(' ✓ CodeBakers v6.0 installed'));
45
+ console.log(chalk_1.default.gray(' - CLAUDE.md (Claude Code gateway)'));
46
+ console.log(chalk_1.default.gray(' - .cursorrules (Cursor IDE gateway)'));
47
+ console.log(chalk_1.default.cyan('\n v6.0 Features:'));
48
+ console.log(chalk_1.default.gray(' - Server-side patterns (always up-to-date)'));
49
+ console.log(chalk_1.default.gray(' - AI calls discover_patterns before coding'));
50
+ console.log(chalk_1.default.gray(' - Usage tracking & compliance'));
39
51
  }
40
- if (hasClaudeDir) {
41
- console.log(chalk_1.default.gray(' - .claude/ (Pattern modules)'));
52
+ else {
53
+ console.log(chalk_1.default.yellow(' CodeBakers v5 installed (legacy)'));
54
+ if (hasCursorRules) {
55
+ console.log(chalk_1.default.gray(' - .cursorrules'));
56
+ }
57
+ if (hasClaudeMd) {
58
+ console.log(chalk_1.default.gray(' - CLAUDE.md'));
59
+ }
60
+ if (hasClaudeDir) {
61
+ console.log(chalk_1.default.gray(' - .claude/ (local modules)'));
62
+ }
63
+ console.log(chalk_1.default.yellow('\n Upgrade to v6.0:'));
64
+ console.log(chalk_1.default.gray(' Run `codebakers go` to upgrade'));
42
65
  }
43
66
  }
44
67
  else {
45
- console.log(chalk_1.default.yellow(' ○ Patterns not installed in this directory'));
46
- console.log(chalk_1.default.gray(' Run `codebakers install` to install'));
68
+ console.log(chalk_1.default.yellow(' ○ CodeBakers not installed in this directory'));
69
+ console.log(chalk_1.default.gray(' Run `codebakers go` to install'));
70
+ }
71
+ // Warn about legacy folder
72
+ if (hasClaudeDir && isV6) {
73
+ console.log(chalk_1.default.yellow('\n ⚠ Legacy .claude/ folder found'));
74
+ console.log(chalk_1.default.gray(' This can be removed - v6.0 uses server-side patterns'));
47
75
  }
48
76
  console.log('');
49
77
  }
@@ -1062,13 +1062,13 @@ class CodeBakersServer {
1062
1062
  },
1063
1063
  {
1064
1064
  name: 'update_patterns',
1065
- description: 'Download and update CodeBakers pattern files from the server. Use when user says "upgrade codebakers", "update patterns", "download latest patterns", "sync codebakers", or when patterns are missing or outdated. This tool fetches the latest CLAUDE.md router and all .claude/ module files from the server and writes them to disk.',
1065
+ description: 'Update to CodeBakers v6.0 server-enforced patterns. Use when user says "upgrade codebakers", "update patterns", or "sync codebakers". In v6.0, patterns are server-side - this tool installs minimal bootstrap files (CLAUDE.md and .cursorrules) and removes old .claude/ folder if present.',
1066
1066
  inputSchema: {
1067
1067
  type: 'object',
1068
1068
  properties: {
1069
1069
  force: {
1070
1070
  type: 'boolean',
1071
- description: 'Force update even if already at latest version (default: false)',
1071
+ description: 'Force reinstall even if already on v6.0 (default: false)',
1072
1072
  },
1073
1073
  },
1074
1074
  },
@@ -2372,35 +2372,66 @@ Or if user declines, call without fullDeploy:
2372
2372
  catch {
2373
2373
  // Use default
2374
2374
  }
2375
- results.push(`# 🎨 Adding CodeBakers to: ${projectName}\n`);
2376
- // Check if already initialized
2377
- if (fs.existsSync(path.join(cwd, 'CLAUDE.md'))) {
2378
- results.push('⚠️ CLAUDE.md already exists. Updating patterns...\n');
2375
+ results.push(`# 🎨 Adding CodeBakers v6.0 to: ${projectName}\n`);
2376
+ // v6.0 bootstrap content - minimal files, patterns from server
2377
+ const V6_CLAUDE_MD = `# CodeBakers v6.0
2378
+
2379
+ **MANDATORY: Before writing ANY code, call the \`discover_patterns\` MCP tool.**
2380
+
2381
+ \`\`\`
2382
+ Tool: discover_patterns
2383
+ Args: { task: "description of what you're building" }
2384
+ \`\`\`
2385
+
2386
+ The server will return:
2387
+ - All coding patterns and rules you must follow
2388
+ - Test requirements
2389
+ - Validation instructions
2390
+
2391
+ **You cannot write code without calling this tool first. The server tracks compliance.**
2392
+
2393
+ ---
2394
+ *CodeBakers v6.0 - Server-Enforced*
2395
+ `;
2396
+ const V6_CURSORRULES = `# CodeBakers v6.0
2397
+
2398
+ MANDATORY: Before writing ANY code, call the discover_patterns MCP tool.
2399
+
2400
+ Tool: discover_patterns
2401
+ Args: { task: "description of what you're building" }
2402
+
2403
+ The server returns all patterns, rules, and test requirements.
2404
+ You cannot write code without calling this tool first.
2405
+ `;
2406
+ // Check if already v6
2407
+ const claudeMdPath = path.join(cwd, 'CLAUDE.md');
2408
+ if (fs.existsSync(claudeMdPath)) {
2409
+ const content = fs.readFileSync(claudeMdPath, 'utf-8');
2410
+ if (content.includes('v6.0') && content.includes('discover_patterns')) {
2411
+ results.push('✓ CodeBakers v6.0 already installed\n');
2412
+ results.push('Patterns are server-enforced. Just call `discover_patterns` before coding!');
2413
+ return {
2414
+ content: [{ type: 'text', text: results.join('\n') }],
2415
+ };
2416
+ }
2417
+ results.push('⚠️ Upgrading to v6.0 (server-enforced patterns)...\n');
2379
2418
  }
2380
2419
  try {
2381
- const response = await fetch(`${this.apiUrl}/api/content`, {
2382
- method: 'GET',
2383
- headers: this.getAuthHeaders(),
2384
- });
2385
- if (!response.ok) {
2386
- throw new Error('Failed to fetch patterns from API');
2387
- }
2388
- const content = await response.json();
2389
- // Write CLAUDE.md
2390
- if (content.router) {
2391
- fs.writeFileSync(path.join(cwd, 'CLAUDE.md'), content.router);
2392
- results.push('✓ Created/Updated CLAUDE.md');
2393
- }
2394
- // Write pattern modules
2395
- if (content.modules && Object.keys(content.modules).length > 0) {
2396
- const modulesDir = path.join(cwd, '.claude');
2397
- if (!fs.existsSync(modulesDir)) {
2398
- fs.mkdirSync(modulesDir, { recursive: true });
2420
+ // Write v6.0 bootstrap files
2421
+ fs.writeFileSync(claudeMdPath, V6_CLAUDE_MD);
2422
+ results.push('✓ Created CLAUDE.md (v6.0 bootstrap)');
2423
+ fs.writeFileSync(path.join(cwd, '.cursorrules'), V6_CURSORRULES);
2424
+ results.push('✓ Created .cursorrules (v6.0 bootstrap)');
2425
+ // Remove old .claude folder if it exists (v5 → v6 migration)
2426
+ const claudeDir = path.join(cwd, '.claude');
2427
+ if (fs.existsSync(claudeDir)) {
2428
+ try {
2429
+ fs.rmSync(claudeDir, { recursive: true, force: true });
2430
+ results.push('✓ Removed .claude/ folder (patterns now server-side)');
2399
2431
  }
2400
- for (const [name, data] of Object.entries(content.modules)) {
2401
- fs.writeFileSync(path.join(modulesDir, name), data);
2432
+ catch {
2433
+ results.push('⚠️ Could not remove .claude/ folder - please delete manually');
2402
2434
  }
2403
- results.push(`✓ Installed ${Object.keys(content.modules).length} pattern modules (v${content.version})`);
2404
2435
  }
2405
2436
  // Create PRD if doesn't exist
2406
2437
  const date = new Date().toISOString().split('T')[0];
@@ -2419,39 +2450,29 @@ Or if user declines, call without fullDeploy:
2419
2450
  `);
2420
2451
  results.push('✓ Created PRD.md template');
2421
2452
  }
2422
- // Create PROJECT-STATE if doesn't exist
2423
- const statePath = path.join(cwd, 'PROJECT-STATE.md');
2424
- if (!fs.existsSync(statePath)) {
2425
- fs.writeFileSync(statePath, `# PROJECT STATE
2426
- # Last Updated: ${date}
2427
-
2428
- ## Project Info
2429
- name: ${projectName}
2430
- phase: development
2431
-
2432
- ## In Progress
2433
- ## Completed
2434
- ## Next Up
2435
- `);
2436
- results.push('✓ Created PROJECT-STATE.md');
2437
- }
2438
- // Update .gitignore
2439
- const gitignorePath = path.join(cwd, '.gitignore');
2440
- if (fs.existsSync(gitignorePath)) {
2441
- const gitignore = fs.readFileSync(gitignorePath, 'utf-8');
2442
- if (!gitignore.includes('.claude/')) {
2443
- fs.writeFileSync(gitignorePath, gitignore + '\n# CodeBakers\n.claude/\n');
2444
- results.push('✓ Updated .gitignore');
2453
+ // Update .codebakers.json
2454
+ const stateFile = path.join(cwd, '.codebakers.json');
2455
+ let state = {};
2456
+ if (fs.existsSync(stateFile)) {
2457
+ try {
2458
+ state = JSON.parse(fs.readFileSync(stateFile, 'utf-8'));
2459
+ }
2460
+ catch {
2461
+ // Ignore errors
2445
2462
  }
2446
2463
  }
2464
+ state.version = '6.0';
2465
+ state.serverEnforced = true;
2466
+ state.updatedAt = new Date().toISOString();
2467
+ fs.writeFileSync(stateFile, JSON.stringify(state, null, 2));
2447
2468
  results.push('\n---\n');
2448
- results.push('## ✅ CodeBakers Patterns Installed!\n');
2449
- results.push('The AI now has access to production patterns for:');
2450
- results.push('- Authentication, Database, API design');
2451
- results.push('- Frontend components, Forms, Validation');
2452
- results.push('- Payments, Email, Real-time features');
2453
- results.push('- And 30+ more specialized patterns\n');
2454
- results.push('Just describe what you want to build!');
2469
+ results.push('## ✅ CodeBakers v6.0 Installed!\n');
2470
+ results.push('**How it works now:**');
2471
+ results.push('1. Call `discover_patterns` before writing code');
2472
+ results.push('2. Server returns all patterns and rules');
2473
+ results.push('3. Call `validate_complete` before marking done');
2474
+ results.push('4. Server verifies compliance\n');
2475
+ results.push('No local pattern files needed - everything is server-side!');
2455
2476
  }
2456
2477
  catch (error) {
2457
2478
  const message = error instanceof Error ? error.message : 'Unknown error';
@@ -5517,7 +5538,7 @@ ${handlers.join('\n')}
5517
5538
  `;
5518
5539
  }
5519
5540
  /**
5520
- * Download and update CodeBakers patterns from server
5541
+ * Update to CodeBakers v6.0 - server-enforced patterns
5521
5542
  * This is the MCP equivalent of the `codebakers upgrade` CLI command
5522
5543
  */
5523
5544
  async handleUpdatePatterns(args) {
@@ -5525,54 +5546,63 @@ ${handlers.join('\n')}
5525
5546
  const cwd = process.cwd();
5526
5547
  const claudeMdPath = path.join(cwd, 'CLAUDE.md');
5527
5548
  const claudeDir = path.join(cwd, '.claude');
5528
- const versionPath = path.join(claudeDir, '.version.json');
5529
- let response = `# 🔄 CodeBakers Pattern Update\n\n`;
5549
+ const codebakersJson = path.join(cwd, '.codebakers.json');
5550
+ let response = `# 🔄 CodeBakers v6.0 Update\n\n`;
5551
+ // v6.0 bootstrap content
5552
+ const V6_CLAUDE_MD = `# CodeBakers v6.0
5553
+
5554
+ **MANDATORY: Before writing ANY code, call the \`discover_patterns\` MCP tool.**
5555
+
5556
+ \`\`\`
5557
+ Tool: discover_patterns
5558
+ Args: { task: "description of what you're building" }
5559
+ \`\`\`
5560
+
5561
+ The server will return:
5562
+ - All coding patterns and rules you must follow
5563
+ - Test requirements
5564
+ - Validation instructions
5565
+
5566
+ **You cannot write code without calling this tool first. The server tracks compliance.**
5567
+
5568
+ ---
5569
+ *CodeBakers v6.0 - Server-Enforced*
5570
+ `;
5571
+ const V6_CURSORRULES = `# CodeBakers v6.0
5572
+
5573
+ MANDATORY: Before writing ANY code, call the discover_patterns MCP tool.
5574
+
5575
+ Tool: discover_patterns
5576
+ Args: { task: "description of what you're building" }
5577
+
5578
+ The server returns all patterns, rules, and test requirements.
5579
+ You cannot write code without calling this tool first.
5580
+ `;
5530
5581
  try {
5531
5582
  // Check current version
5532
5583
  let currentVersion = null;
5533
- let currentModuleCount = 0;
5534
- if (fs.existsSync(versionPath)) {
5535
- try {
5536
- const versionInfo = JSON.parse(fs.readFileSync(versionPath, 'utf-8'));
5537
- currentVersion = versionInfo.version;
5538
- currentModuleCount = versionInfo.moduleCount || 0;
5539
- }
5540
- catch {
5541
- // Ignore parse errors
5542
- }
5584
+ let isV6 = false;
5585
+ if (fs.existsSync(claudeMdPath)) {
5586
+ const content = fs.readFileSync(claudeMdPath, 'utf-8');
5587
+ isV6 = content.includes('v6.0') && content.includes('discover_patterns');
5543
5588
  }
5544
- // Count current modules
5545
- if (fs.existsSync(claudeDir)) {
5589
+ if (fs.existsSync(codebakersJson)) {
5546
5590
  try {
5547
- const files = fs.readdirSync(claudeDir).filter(f => f.endsWith('.md'));
5548
- currentModuleCount = files.length;
5591
+ const state = JSON.parse(fs.readFileSync(codebakersJson, 'utf-8'));
5592
+ currentVersion = state.version || null;
5549
5593
  }
5550
5594
  catch {
5551
- // Ignore read errors
5595
+ // Ignore parse errors
5552
5596
  }
5553
5597
  }
5554
5598
  response += `## Current Status\n`;
5555
5599
  response += `- Version: ${currentVersion || 'Unknown'}\n`;
5556
- response += `- Modules: ${currentModuleCount}\n\n`;
5557
- // Fetch latest version info first
5558
- const versionResponse = await fetch(`${this.apiUrl}/api/content/version`, {
5559
- headers: this.getAuthHeaders(),
5560
- });
5561
- if (!versionResponse.ok) {
5562
- throw new Error('Failed to check version from server');
5563
- }
5564
- const latestInfo = await versionResponse.json();
5565
- const latestVersion = latestInfo.version;
5566
- const latestModuleCount = latestInfo.moduleCount || 0;
5567
- response += `## Server Status\n`;
5568
- response += `- Latest Version: ${latestVersion}\n`;
5569
- response += `- Available Modules: ${latestModuleCount}\n\n`;
5570
- // Check if update needed
5571
- const needsUpdate = force || !currentVersion || currentVersion !== latestVersion || currentModuleCount < latestModuleCount;
5572
- if (!needsUpdate) {
5573
- response += `✅ **Already up to date!**\n\n`;
5574
- response += `Your patterns are current (v${latestVersion} with ${latestModuleCount} modules).\n`;
5575
- response += `Use \`force: true\` to re-download anyway.\n`;
5600
+ response += `- v6.0 (Server-Enforced): ${isV6 ? 'Yes ✓' : 'No'}\n\n`;
5601
+ // Check if already on v6
5602
+ if (isV6 && !force) {
5603
+ response += `✅ **Already on v6.0!**\n\n`;
5604
+ response += `Your patterns are server-enforced. Just use \`discover_patterns\` before coding.\n`;
5605
+ response += `Use \`force: true\` to reinstall bootstrap files.\n`;
5576
5606
  response += this.getUpdateNotice();
5577
5607
  return {
5578
5608
  content: [{
@@ -5581,65 +5611,54 @@ ${handlers.join('\n')}
5581
5611
  }],
5582
5612
  };
5583
5613
  }
5584
- response += `## Downloading Updates...\n\n`;
5585
- // Fetch full content
5586
- const contentResponse = await fetch(`${this.apiUrl}/api/content`, {
5587
- headers: this.getAuthHeaders(),
5588
- });
5589
- if (!contentResponse.ok) {
5590
- const error = await contentResponse.json().catch(() => ({}));
5591
- throw new Error(error.error || error.message || 'Failed to fetch patterns');
5592
- }
5593
- const content = await contentResponse.json();
5594
- const moduleCount = content.modules ? Object.keys(content.modules).length : 0;
5595
- // Create .claude directory if needed
5596
- if (!fs.existsSync(claudeDir)) {
5597
- fs.mkdirSync(claudeDir, { recursive: true });
5598
- response += `✓ Created .claude/ directory\n`;
5599
- }
5600
- // Update CLAUDE.md router
5601
- if (content.router) {
5602
- fs.writeFileSync(claudeMdPath, content.router);
5603
- response += `✓ Updated CLAUDE.md (router)\n`;
5614
+ response += `## Upgrading to v6.0...\n\n`;
5615
+ // Write v6.0 bootstrap files
5616
+ fs.writeFileSync(claudeMdPath, V6_CLAUDE_MD);
5617
+ response += `✓ Updated CLAUDE.md (v6.0 bootstrap)\n`;
5618
+ fs.writeFileSync(path.join(cwd, '.cursorrules'), V6_CURSORRULES);
5619
+ response += `✓ Updated .cursorrules (v6.0 bootstrap)\n`;
5620
+ // Remove old .claude folder (v5 v6 migration)
5621
+ if (fs.existsSync(claudeDir)) {
5622
+ try {
5623
+ fs.rmSync(claudeDir, { recursive: true, force: true });
5624
+ response += `✓ Removed .claude/ folder (patterns now server-side)\n`;
5625
+ }
5626
+ catch {
5627
+ response += `⚠️ Could not remove .claude/ folder - please delete manually\n`;
5628
+ }
5604
5629
  }
5605
- // Update all modules
5606
- if (content.modules && moduleCount > 0) {
5607
- for (const [name, data] of Object.entries(content.modules)) {
5608
- fs.writeFileSync(path.join(claudeDir, name), data);
5630
+ // Update .codebakers.json
5631
+ let state = {};
5632
+ if (fs.existsSync(codebakersJson)) {
5633
+ try {
5634
+ state = JSON.parse(fs.readFileSync(codebakersJson, 'utf-8'));
5635
+ }
5636
+ catch {
5637
+ // Ignore errors
5609
5638
  }
5610
- response += `✓ Updated ${moduleCount} modules in .claude/\n`;
5611
5639
  }
5612
- // Save version info
5613
- const newVersionInfo = {
5614
- version: content.version || latestVersion,
5615
- moduleCount,
5616
- installedAt: currentVersion ? undefined : new Date().toISOString(),
5617
- updatedAt: new Date().toISOString(),
5618
- cliVersion: (0, api_js_1.getCliVersion)(),
5619
- };
5620
- fs.writeFileSync(versionPath, JSON.stringify(newVersionInfo, null, 2));
5621
- response += `✓ Saved version info\n`;
5622
- // Confirm download to server (non-blocking analytics)
5623
- this.confirmDownload(content.version || latestVersion, moduleCount).catch(() => { });
5624
- response += `\n## Update Complete!\n\n`;
5625
- response += `- **From:** v${currentVersion || 'none'} (${currentModuleCount} modules)\n`;
5626
- response += `- **To:** v${content.version || latestVersion} (${moduleCount} modules)\n\n`;
5627
- if (moduleCount > currentModuleCount) {
5628
- response += `🆕 **${moduleCount - currentModuleCount} new modules added!**\n\n`;
5629
- }
5630
- response += `Your patterns are now up to date. The new patterns will be used in your next response.\n`;
5640
+ state.version = '6.0';
5641
+ state.serverEnforced = true;
5642
+ state.updatedAt = new Date().toISOString();
5643
+ fs.writeFileSync(codebakersJson, JSON.stringify(state, null, 2));
5644
+ response += `✓ Updated .codebakers.json\n`;
5645
+ // Confirm to server (non-blocking analytics)
5646
+ this.confirmDownload('6.0', 0).catch(() => { });
5647
+ response += `\n## ✅ Upgrade Complete!\n\n`;
5648
+ response += `**What changed in v6.0:**\n`;
5649
+ response += `- No local pattern files (.claude/ folder removed)\n`;
5650
+ response += `- All patterns fetched from server in real-time\n`;
5651
+ response += `- Server tracks compliance via discover_patterns/validate_complete\n\n`;
5652
+ response += `**How to use:**\n`;
5653
+ response += `1. Call \`discover_patterns\` before writing any code\n`;
5654
+ response += `2. Follow the patterns returned by server\n`;
5655
+ response += `3. Call \`validate_complete\` before marking done\n`;
5631
5656
  }
5632
5657
  catch (error) {
5633
5658
  const message = error instanceof Error ? error.message : 'Unknown error';
5634
5659
  response += `\n## ❌ Update Failed\n\n`;
5635
5660
  response += `Error: ${message}\n\n`;
5636
- if (message.includes('401') || message.includes('Invalid') || message.includes('expired')) {
5637
- response += `Your API key may be invalid or expired.\n`;
5638
- response += `Run \`codebakers setup\` in terminal to reconfigure.\n`;
5639
- }
5640
- else {
5641
- response += `Please try again or run \`codebakers upgrade\` in terminal.\n`;
5642
- }
5661
+ response += `Please try again or run \`codebakers upgrade\` in terminal.\n`;
5643
5662
  }
5644
5663
  // Add CLI update notice if available
5645
5664
  response += this.getUpdateNotice();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codebakers/cli",
3
- "version": "3.5.0",
3
+ "version": "3.5.1",
4
4
  "description": "CodeBakers CLI - Production patterns for AI-assisted development",
5
5
  "main": "dist/index.js",
6
6
  "bin": {