@the-bearded-bear/claude-craft 7.3.0 → 7.4.0-next.cf176bf

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 CHANGED
@@ -531,8 +531,6 @@ Copy the appropriate bundle into your preferred AI platform's custom instruction
531
531
  - `/project:` - Project management (backlog, PRD, tech-spec, sprints, **batch processing, migration**)
532
532
  - `/sprint:` - **BMAD sprint management (status, transitions, routing, TDD)**
533
533
  - `/gate:` - **Quality gate validation (PRD, tech-spec, backlog, story, sprint)**
534
- - `/pm:` - **Product Manager commands (prd, vision, roadmap, prioritize)**
535
- - `/arch:` - **Architect commands (design, techspec, adr, api, security)**
536
534
  - `/common:` - Transversal commands (audit, changelog, CI/CD)
537
535
  - `/symfony:` - Symfony-specific (CRUD, migrations, Doctrine)
538
536
  - `/flutter:` - Flutter-specific (widgets, BLoC, performance)
@@ -545,7 +543,7 @@ Copy the appropriate bundle into your preferred AI platform's custom instruction
545
543
  - `/vuejs:` - Vue.js-specific (components, composables, Pinia)
546
544
  - `/php:` - PHP-specific (entities, value objects, use cases, Clean Architecture)
547
545
  - `/docker:` - Docker/Infrastructure (compose, debug, pipelines, architecture)
548
- - `/common:recette*` - **QA Recette** (acceptance testing, regression, Chrome automation)
546
+ - `/qa:*` - **QA Recette** (acceptance testing, regression, Chrome automation)
549
547
 
550
548
  ## Documentation
551
549
 
package/cli/index.js CHANGED
@@ -35,6 +35,9 @@ import { printHelp } from './lib/help.js';
35
35
  import { interactiveInstall, runInstallation } from './lib/installer.js';
36
36
  import { runRalph } from './lib/ralph.js';
37
37
  import { runCheck } from './lib/check.js';
38
+ import { runList } from './lib/list.js';
39
+ import { runDoctor } from './lib/doctor.js';
40
+ import { runUpdate } from './lib/update.js';
38
41
 
39
42
  // Flattener module
40
43
  import { flatten as flattenCodebaseFn } from './flattener.js';
@@ -172,6 +175,21 @@ class ClaudeCraftCLI {
172
175
  runCheck(this.config.targetPath);
173
176
  break;
174
177
 
178
+ case 'list':
179
+ printBanner(VERSION);
180
+ runList(this.config.targetPath);
181
+ break;
182
+
183
+ case 'doctor':
184
+ printBanner(VERSION);
185
+ runDoctor(this.config.targetPath);
186
+ break;
187
+
188
+ case 'update':
189
+ printBanner(VERSION);
190
+ runUpdate(this.config.targetPath, options, CLI_ROOT);
191
+ break;
192
+
175
193
  case 'init':
176
194
  printBanner(VERSION);
177
195
  console.log(`${c.cyan}Workflow initialization is available after installation.${c.reset}`);
package/cli/lib/check.js CHANGED
@@ -7,36 +7,7 @@ import fs from 'fs';
7
7
  import path from 'path';
8
8
  import c from './colors.js';
9
9
  import { detectProject } from './detect-project.js';
10
-
11
- /**
12
- * Count files matching a glob pattern in a directory (non-recursive).
13
- * @param {string} dir - Directory path
14
- * @param {string} ext - File extension (e.g. '.md')
15
- * @returns {number}
16
- */
17
- function countFiles(dir, ext) {
18
- try {
19
- return fs.readdirSync(dir).filter((f) => f.endsWith(ext)).length;
20
- } catch {
21
- return 0;
22
- }
23
- }
24
-
25
- /**
26
- * List subdirectories of a directory.
27
- * @param {string} dir - Directory path
28
- * @returns {string[]}
29
- */
30
- function listDirs(dir) {
31
- try {
32
- return fs
33
- .readdirSync(dir, { withFileTypes: true })
34
- .filter((d) => d.isDirectory())
35
- .map((d) => d.name);
36
- } catch {
37
- return [];
38
- }
39
- }
10
+ import { countFiles, listDirs } from './fs-utils.js';
40
11
 
41
12
  /**
42
13
  * Run the check command against a target directory.
@@ -0,0 +1,166 @@
1
+ /**
2
+ * CLI `doctor` command — environment diagnostics & installation health check.
3
+ * @module cli/lib/doctor
4
+ */
5
+
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import { execSync } from 'child_process';
9
+ import c from './colors.js';
10
+ import { listDirs } from './fs-utils.js';
11
+
12
+ /**
13
+ * Run a shell command and return the trimmed output, or null on failure.
14
+ * @param {string} cmd - Shell command to execute
15
+ * @returns {string|null}
16
+ */
17
+ function tryExec(cmd) {
18
+ try {
19
+ return execSync(cmd, { encoding: 'utf8', timeout: 10_000 }).trim();
20
+ } catch {
21
+ return null;
22
+ }
23
+ }
24
+
25
+ /**
26
+ * Run the doctor command against a target directory.
27
+ * @param {string} targetPath - Absolute path to the project directory
28
+ * @param {Object} [deps] - Injectable dependencies for testing
29
+ * @param {function} [deps.execFn] - Custom exec function
30
+ */
31
+ function runDoctor(targetPath, deps = {}) {
32
+ const exec = deps.execFn || tryExec;
33
+ let passed = 0;
34
+ let failed = 0;
35
+ let warned = 0;
36
+
37
+ console.log(`\n${c.bold}Claude Craft Doctor — Environment Diagnostics${c.reset}`);
38
+ console.log(`${c.dim}Directory: ${targetPath}${c.reset}\n`);
39
+
40
+ // 1. Node.js version >= 20
41
+ const nodeVer = process.version;
42
+ const major = parseInt(nodeVer.slice(1), 10);
43
+ if (major >= 20) {
44
+ console.log(` ${c.green}[OK]${c.reset} Node.js ${nodeVer}`);
45
+ passed++;
46
+ } else {
47
+ console.log(` ${c.red}[FAIL]${c.reset} Node.js ${nodeVer} — requires >= 20`);
48
+ failed++;
49
+ }
50
+
51
+ // 2. npm available
52
+ const npmVer = exec('npm --version');
53
+ if (npmVer) {
54
+ console.log(` ${c.green}[OK]${c.reset} npm ${npmVer}`);
55
+ passed++;
56
+ } else {
57
+ console.log(` ${c.red}[FAIL]${c.reset} npm not found`);
58
+ failed++;
59
+ }
60
+
61
+ // 3. Claude Code installed
62
+ const claudeVer = exec('claude --version');
63
+ if (claudeVer) {
64
+ console.log(` ${c.green}[OK]${c.reset} Claude Code ${claudeVer}`);
65
+ passed++;
66
+ } else {
67
+ console.log(` ${c.yellow}[WARN]${c.reset} Claude Code not found (optional for install, required for usage)`);
68
+ warned++;
69
+ }
70
+
71
+ // 4. Git available
72
+ const gitVer = exec('git --version');
73
+ if (gitVer) {
74
+ console.log(` ${c.green}[OK]${c.reset} ${gitVer}`);
75
+ passed++;
76
+ } else {
77
+ console.log(` ${c.red}[FAIL]${c.reset} git not found`);
78
+ failed++;
79
+ }
80
+
81
+ // 5. .claude/ structure integrity
82
+ const claudeDir = path.join(targetPath, '.claude');
83
+ if (fs.existsSync(claudeDir)) {
84
+ console.log(` ${c.green}[OK]${c.reset} .claude/ directory exists`);
85
+ passed++;
86
+
87
+ // Check required subdirs
88
+ const requiredDirs = ['commands', 'agents', 'references', 'skills'];
89
+ for (const dir of requiredDirs) {
90
+ if (fs.existsSync(path.join(claudeDir, dir))) {
91
+ console.log(` ${c.green}[OK]${c.reset} .claude/${dir}/`);
92
+ passed++;
93
+ } else {
94
+ console.log(` ${c.yellow}[WARN]${c.reset} .claude/${dir}/ missing`);
95
+ warned++;
96
+ }
97
+ }
98
+
99
+ // CLAUDE.md
100
+ if (fs.existsSync(path.join(claudeDir, 'CLAUDE.md'))) {
101
+ console.log(` ${c.green}[OK]${c.reset} .claude/CLAUDE.md`);
102
+ passed++;
103
+ } else {
104
+ console.log(` ${c.yellow}[WARN]${c.reset} .claude/CLAUDE.md missing`);
105
+ warned++;
106
+ }
107
+ } else {
108
+ console.log(` ${c.yellow}[WARN]${c.reset} .claude/ directory not found (not installed here)`);
109
+ warned++;
110
+ }
111
+
112
+ // 6. Shell scripts have execute permissions
113
+ const scriptsDir = path.join(targetPath, 'Dev', 'scripts');
114
+ if (fs.existsSync(scriptsDir)) {
115
+ try {
116
+ const files = fs.readdirSync(scriptsDir).filter((f) => f.endsWith('.sh'));
117
+ let execCount = 0;
118
+ let noExecCount = 0;
119
+ for (const f of files) {
120
+ try {
121
+ fs.accessSync(path.join(scriptsDir, f), fs.constants.X_OK);
122
+ execCount++;
123
+ } catch {
124
+ noExecCount++;
125
+ }
126
+ }
127
+ if (noExecCount === 0 && execCount > 0) {
128
+ console.log(` ${c.green}[OK]${c.reset} Shell scripts executable (${execCount} scripts)`);
129
+ passed++;
130
+ } else if (noExecCount > 0) {
131
+ console.log(` ${c.yellow}[WARN]${c.reset} ${noExecCount} script(s) missing execute permission`);
132
+ warned++;
133
+ }
134
+ } catch {
135
+ // scriptsDir not readable
136
+ }
137
+ }
138
+
139
+ // 7. i18n base dirs
140
+ const i18nBase = path.join(targetPath, 'Dev', 'i18n');
141
+ if (fs.existsSync(i18nBase)) {
142
+ const langs = listDirs(i18nBase);
143
+ if (langs.length > 0) {
144
+ console.log(` ${c.green}[OK]${c.reset} i18n base dirs: ${c.cyan}${langs.join(', ')}${c.reset}`);
145
+ passed++;
146
+ } else {
147
+ console.log(` ${c.yellow}[WARN]${c.reset} i18n/ exists but no language dirs found`);
148
+ warned++;
149
+ }
150
+ }
151
+
152
+ // Summary
153
+ console.log('');
154
+ if (failed === 0 && warned === 0) {
155
+ console.log(`${c.green}All checks passed! (${passed} OK)${c.reset}\n`);
156
+ } else if (failed === 0) {
157
+ console.log(`${c.green}${passed} passed${c.reset}, ${c.yellow}${warned} warning(s)${c.reset}\n`);
158
+ } else {
159
+ console.log(
160
+ `${c.green}${passed} passed${c.reset}, ${c.red}${failed} failed${c.reset}, ${c.yellow}${warned} warning(s)${c.reset}\n`
161
+ );
162
+ process.exitCode = 1;
163
+ }
164
+ }
165
+
166
+ export { runDoctor };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Shared filesystem utilities for CLI modules.
3
+ * @module cli/lib/fs-utils
4
+ */
5
+
6
+ import fs from 'fs';
7
+
8
+ /**
9
+ * Count files matching a given extension in a directory (non-recursive).
10
+ * @param {string} dir - Directory path
11
+ * @param {string} ext - File extension (e.g. '.md')
12
+ * @returns {number}
13
+ */
14
+ function countFiles(dir, ext) {
15
+ try {
16
+ return fs.readdirSync(dir).filter((f) => f.endsWith(ext)).length;
17
+ } catch {
18
+ return 0;
19
+ }
20
+ }
21
+
22
+ /**
23
+ * List subdirectories of a directory.
24
+ * @param {string} dir - Directory path
25
+ * @returns {string[]}
26
+ */
27
+ function listDirs(dir) {
28
+ try {
29
+ return fs
30
+ .readdirSync(dir, { withFileTypes: true })
31
+ .filter((d) => d.isDirectory())
32
+ .map((d) => d.name);
33
+ } catch {
34
+ return [];
35
+ }
36
+ }
37
+
38
+ export { countFiles, listDirs };
package/cli/lib/help.js CHANGED
@@ -24,6 +24,9 @@ const NAMESPACES = [
24
24
  { prefix: 'angular', desc: 'Angular: architecture, compliance, testing' },
25
25
  { prefix: 'laravel', desc: 'Laravel: architecture, compliance, testing' },
26
26
  { prefix: 'vuejs', desc: 'Vue.js: architecture, compliance, testing' },
27
+ { prefix: 'python', desc: 'Python: endpoints, async, typing, FastAPI' },
28
+ { prefix: 'reactnative', desc: 'React Native: screens, navigation, native modules' },
29
+ { prefix: 'php', desc: 'PHP: entities, value objects, use cases, Clean Architecture' },
27
30
  ];
28
31
 
29
32
  /**
@@ -38,6 +41,9 @@ ${c.bold}Commands:${c.reset}
38
41
  ${c.green}install <path>${c.reset} Install to specific directory
39
42
  ${c.green}init${c.reset} Initialize workflow in current project
40
43
  ${c.green}check${c.reset} Verify claude-craft installation
44
+ ${c.green}list${c.reset} List installed components
45
+ ${c.green}doctor${c.reset} Environment diagnostics
46
+ ${c.green}update${c.reset} Refresh existing installation
41
47
  ${c.green}flatten${c.reset} Generate flattened codebase summary
42
48
  ${c.green}ralph${c.reset} Run Ralph Wiggum continuous loop
43
49
  ${c.green}help${c.reset} Show this help message
@@ -52,7 +58,7 @@ ${c.bold}Options:${c.reset}
52
58
  ${c.yellow}--enterprise${c.reset} Enterprise track (platforms)
53
59
 
54
60
  ${c.bold}Available Namespaces:${c.reset}
55
- ${NAMESPACES.map((ns) => ` ${c.cyan}/${ns.prefix}:*${c.reset}`.padEnd(30 + c.cyan.length + c.reset.length) + `${ns.desc}`).join('\n')}
61
+ ${NAMESPACES.map((ns) => ` ${c.cyan}/${ns.prefix}:*${c.reset}`.padEnd(30 + c.cyan.length + c.reset.length) + ns.desc).join('\n')}
56
62
 
57
63
  ${c.dim}Example: /common:pre-commit-check, /workflow:init, /team:sprint${c.reset}
58
64
 
@@ -0,0 +1,103 @@
1
+ /**
2
+ * CLI `list` command — detailed listing of installed claude-craft components.
3
+ * @module cli/lib/list
4
+ */
5
+
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import c from './colors.js';
9
+ import { countFiles, listDirs } from './fs-utils.js';
10
+ import { detectProject } from './detect-project.js';
11
+
12
+ /**
13
+ * Run the list command against a target directory.
14
+ * @param {string} targetPath - Absolute path to the project directory
15
+ */
16
+ function runList(targetPath) {
17
+ const claudeDir = path.join(targetPath, '.claude');
18
+
19
+ console.log(`\n${c.bold}Claude Craft Installation — Detailed Listing${c.reset}`);
20
+ console.log(`${c.dim}Directory: ${targetPath}${c.reset}\n`);
21
+
22
+ if (!fs.existsSync(claudeDir)) {
23
+ console.log(`${c.red}No claude-craft installation detected.${c.reset}`);
24
+ console.log(`Run: npx @the-bearded-bear/claude-craft install ${targetPath}\n`);
25
+ process.exitCode = 1;
26
+ return;
27
+ }
28
+
29
+ // 1. Commands by namespace
30
+ const commandsDir = path.join(claudeDir, 'commands');
31
+ const namespaces = listDirs(commandsDir);
32
+ console.log(`${c.bold}Commands:${c.reset}`);
33
+ if (namespaces.length > 0) {
34
+ let totalCommands = 0;
35
+ for (const ns of namespaces) {
36
+ const count = countFiles(path.join(commandsDir, ns), '.md');
37
+ totalCommands += count;
38
+ console.log(` ${c.cyan}/${ns}:*${c.reset} — ${count} command(s)`);
39
+ }
40
+ console.log(` ${c.dim}Total: ${totalCommands} commands in ${namespaces.length} namespace(s)${c.reset}`);
41
+ } else {
42
+ console.log(` ${c.yellow}No namespaces found${c.reset}`);
43
+ }
44
+
45
+ // 2. Agents
46
+ const agentsDir = path.join(claudeDir, 'agents');
47
+ const agentCount = countFiles(agentsDir, '.md');
48
+ console.log(`\n${c.bold}Agents:${c.reset}`);
49
+ if (agentCount > 0) {
50
+ console.log(` ${agentCount} agent(s) in ${c.cyan}agents/${c.reset}`);
51
+ } else {
52
+ console.log(` ${c.yellow}No agents found${c.reset}`);
53
+ }
54
+
55
+ // 3. References (installed tech refs)
56
+ const refsDir = path.join(claudeDir, 'references');
57
+ const refDirs = listDirs(refsDir);
58
+ console.log(`\n${c.bold}References:${c.reset}`);
59
+ if (refDirs.length > 0) {
60
+ for (const ref of refDirs) {
61
+ console.log(` ${c.cyan}${ref}${c.reset}`);
62
+ }
63
+ } else {
64
+ console.log(` ${c.yellow}No tech references found${c.reset}`);
65
+ }
66
+
67
+ // 4. Skills
68
+ const skillsDir = path.join(claudeDir, 'skills');
69
+ const skillDirs = listDirs(skillsDir);
70
+ let totalSkills = 0;
71
+ console.log(`\n${c.bold}Skills:${c.reset}`);
72
+ for (const sd of skillDirs) {
73
+ const count = countFiles(path.join(skillsDir, sd), '.md');
74
+ totalSkills += count;
75
+ if (count > 0) {
76
+ console.log(` ${c.cyan}${sd}/${c.reset} — ${count} skill(s)`);
77
+ }
78
+ }
79
+ // Top-level skill files
80
+ const topSkills = countFiles(skillsDir, '.md');
81
+ totalSkills += topSkills;
82
+ if (topSkills > 0) {
83
+ console.log(` ${c.dim}(+ ${topSkills} top-level)${c.reset}`);
84
+ }
85
+ if (totalSkills === 0) {
86
+ console.log(` ${c.yellow}No skills found${c.reset}`);
87
+ } else {
88
+ console.log(` ${c.dim}Total: ${totalSkills} skill(s)${c.reset}`);
89
+ }
90
+
91
+ // 5. Tech detection
92
+ const detected = detectProject(targetPath);
93
+ console.log(`\n${c.bold}Detected Technologies:${c.reset}`);
94
+ if (detected.suggestedTechs.length > 0) {
95
+ console.log(` ${c.cyan}${detected.suggestedTechs.join(', ')}${c.reset} (complexity: ${detected.complexity})`);
96
+ } else {
97
+ console.log(` ${c.dim}No technology detected from project files${c.reset}`);
98
+ }
99
+
100
+ console.log('');
101
+ }
102
+
103
+ export { runList };
@@ -0,0 +1,112 @@
1
+ /**
2
+ * CLI `update` command — re-run install scripts to refresh an existing installation.
3
+ * @module cli/lib/update
4
+ */
5
+
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import { execSync } from 'child_process';
9
+ import c from './colors.js';
10
+ import { listDirs } from './fs-utils.js';
11
+ import { TECH_REGISTRY } from './tech-registry.js';
12
+
13
+ /**
14
+ * Run the update command against a target directory.
15
+ * @param {string} targetPath - Absolute path to the project directory
16
+ * @param {Object} options - CLI options
17
+ * @param {string} [options.lang] - Language override (default: 'en')
18
+ * @param {string} [options.tech] - Specific tech to update (if omitted, updates all detected)
19
+ * @param {string} cliRoot - Path to the CLI package root
20
+ */
21
+ function runUpdate(targetPath, options, cliRoot) {
22
+ const claudeDir = path.join(targetPath, '.claude');
23
+ const lang = options.lang || 'en';
24
+
25
+ console.log(`\n${c.bold}Claude Craft Update${c.reset}`);
26
+ console.log(`${c.dim}Directory: ${targetPath}${c.reset}\n`);
27
+
28
+ // Verify existing installation
29
+ if (!fs.existsSync(claudeDir)) {
30
+ console.log(`${c.red}No claude-craft installation detected.${c.reset}`);
31
+ console.log(`Run: npx @the-bearded-bear/claude-craft install ${targetPath}\n`);
32
+ process.exitCode = 1;
33
+ return;
34
+ }
35
+
36
+ // Determine techs to update
37
+ let techsToUpdate = [];
38
+
39
+ if (options.tech) {
40
+ // Explicit --tech flag
41
+ if (!TECH_REGISTRY[options.tech]) {
42
+ console.log(`${c.red}Unknown technology: ${options.tech}${c.reset}`);
43
+ console.log(`Available: ${Object.keys(TECH_REGISTRY).join(', ')}\n`);
44
+ process.exitCode = 1;
45
+ return;
46
+ }
47
+ techsToUpdate = [options.tech];
48
+ } else {
49
+ // Auto-detect from installed references
50
+ const refsDir = path.join(claudeDir, 'references');
51
+ const installedRefs = listDirs(refsDir);
52
+ techsToUpdate = installedRefs.filter((ref) => TECH_REGISTRY[ref]);
53
+ }
54
+
55
+ // Always refresh common rules
56
+ const scriptsDir = path.join(cliRoot, 'Dev', 'scripts');
57
+ const commonScript = path.join(scriptsDir, 'install-common-rules.sh');
58
+
59
+ let updated = 0;
60
+
61
+ if (fs.existsSync(commonScript)) {
62
+ console.log(` ${c.cyan}Refreshing common rules...${c.reset}`);
63
+ try {
64
+ execSync(`bash "${commonScript}" "${targetPath}" "${lang}" --force`, {
65
+ encoding: 'utf8',
66
+ timeout: 60_000,
67
+ stdio: 'pipe',
68
+ });
69
+ console.log(` ${c.green}[OK]${c.reset} Common rules updated`);
70
+ updated++;
71
+ } catch (e) {
72
+ console.log(` ${c.red}[FAIL]${c.reset} Common rules: ${e.message}`);
73
+ }
74
+ }
75
+
76
+ // Run tech-specific install scripts
77
+ for (const tech of techsToUpdate) {
78
+ const entry = TECH_REGISTRY[tech];
79
+ const script = path.join(scriptsDir, entry.installScript);
80
+
81
+ if (!fs.existsSync(script)) {
82
+ console.log(` ${c.yellow}[SKIP]${c.reset} ${entry.displayName} — install script not found`);
83
+ continue;
84
+ }
85
+
86
+ console.log(` ${c.cyan}Refreshing ${entry.displayName}...${c.reset}`);
87
+ try {
88
+ execSync(`bash "${script}" "${targetPath}" "${lang}" --force`, {
89
+ encoding: 'utf8',
90
+ timeout: 60_000,
91
+ stdio: 'pipe',
92
+ });
93
+ console.log(` ${c.green}[OK]${c.reset} ${entry.displayName} updated`);
94
+ updated++;
95
+ } catch (e) {
96
+ console.log(` ${c.red}[FAIL]${c.reset} ${entry.displayName}: ${e.message}`);
97
+ }
98
+ }
99
+
100
+ // Summary
101
+ console.log('');
102
+ if (updated > 0) {
103
+ console.log(`${c.green}Update complete — ${updated} component(s) refreshed.${c.reset}\n`);
104
+ } else if (techsToUpdate.length === 0) {
105
+ console.log(`${c.yellow}No tech references detected. Use --tech=NAME to specify.${c.reset}\n`);
106
+ } else {
107
+ console.log(`${c.red}Update failed — no components were refreshed.${c.reset}\n`);
108
+ process.exitCode = 1;
109
+ }
110
+ }
111
+
112
+ export { runUpdate };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@the-bearded-bear/claude-craft",
3
- "version": "7.3.0",
3
+ "version": "7.4.0-next.cf176bf",
4
4
  "description": "A comprehensive framework for AI-assisted development with Claude Code. Install standardized rules, agents, and commands for your projects.",
5
5
  "type": "module",
6
6
  "main": "cli/index.js",