@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 +1 -3
- package/cli/index.js +18 -0
- package/cli/lib/check.js +1 -30
- package/cli/lib/doctor.js +166 -0
- package/cli/lib/fs-utils.js +38 -0
- package/cli/lib/help.js +7 -1
- package/cli/lib/list.js +103 -0
- package/cli/lib/update.js +112 -0
- package/package.json +1 -1
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
|
-
- `/
|
|
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) +
|
|
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
|
|
package/cli/lib/list.js
ADDED
|
@@ -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
|
+
"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",
|