@cregis-dev/cckit 0.6.6 → 0.6.7
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/LICENSE +21 -21
- package/bin/cckit.js +3 -3
- package/package.json +53 -53
- package/registry.json +145 -145
- package/src/cli.js +79 -79
- package/src/commands/init.js +174 -174
- package/src/commands/status.js +125 -125
- package/src/commands/update.js +192 -192
- package/src/core/config.js +82 -75
- package/src/core/orchestrator.js +79 -79
- package/src/core/registry.js +60 -60
- package/src/steps/add-plugin.js +148 -116
- package/src/steps/configure-user.js +181 -181
- package/src/steps/enable-plugins.js +97 -97
- package/src/steps/install-bmad.js +85 -85
- package/src/steps/install-mcp.js +70 -70
- package/src/steps/install-rules.js +69 -69
- package/src/steps/install-skills.js +56 -56
- package/src/utils/compare-versions.js +106 -106
- package/src/utils/fs.js +33 -33
- package/src/utils/logger.js +16 -16
- package/src/utils/manifest.js +101 -101
- package/src/utils/prompt.js +41 -41
- package/templates/mcp/claude-code/.mcp.json +40 -40
- package/templates/rules/README.md +103 -103
- package/templates/rules/common/agents.md +49 -49
- package/templates/rules/common/coding-style.md +48 -48
- package/templates/rules/common/development-workflow.md +37 -37
- package/templates/rules/common/git-workflow.md +24 -24
- package/templates/rules/common/hooks.md +30 -30
- package/templates/rules/common/patterns.md +31 -31
- package/templates/rules/common/performance.md +55 -55
- package/templates/rules/common/security.md +29 -29
- package/templates/rules/common/testing.md +29 -29
- package/templates/rules/golang/coding-style.md +32 -32
- package/templates/rules/golang/hooks.md +17 -17
- package/templates/rules/golang/patterns.md +45 -45
- package/templates/rules/golang/security.md +34 -34
- package/templates/rules/golang/testing.md +31 -31
- package/templates/rules/python/coding-style.md +42 -42
- package/templates/rules/python/hooks.md +19 -19
- package/templates/rules/python/patterns.md +39 -39
- package/templates/rules/python/security.md +30 -30
- package/templates/rules/python/testing.md +38 -38
- package/templates/rules/swift/coding-style.md +47 -47
- package/templates/rules/swift/hooks.md +20 -20
- package/templates/rules/swift/patterns.md +66 -66
- package/templates/rules/swift/security.md +33 -33
- package/templates/rules/swift/testing.md +45 -45
- package/templates/rules/typescript/coding-style.md +65 -65
- package/templates/rules/typescript/hooks.md +22 -22
- package/templates/rules/typescript/patterns.md +52 -52
- package/templates/rules/typescript/security.md +28 -28
- package/templates/rules/typescript/testing.md +18 -18
|
@@ -1,85 +1,85 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Step: Install BMAD methodology via `npx bmad-method install`.
|
|
3
|
-
*
|
|
4
|
-
* Spawns the BMAD CLI as a child process with stdio inherited
|
|
5
|
-
* so the user sees real-time output.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { spawn } from 'node:child_process'
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* @param {object} opts
|
|
12
|
-
* @param {string} opts.targetDir - Project root
|
|
13
|
-
* @param {object} opts.bmadConfig - { command, args, outputDirs } from registry
|
|
14
|
-
* @param {object} [opts.config] - User config (communication_language, document_output_language)
|
|
15
|
-
* @param {boolean} opts.skip - Skip this step
|
|
16
|
-
* @param {object} logger
|
|
17
|
-
* @param {object} [_deps] - Injectable dependencies for testing
|
|
18
|
-
* @returns {Promise<import('../core/orchestrator.js').StepResult>}
|
|
19
|
-
*/
|
|
20
|
-
export async function installBmad(opts, logger, _deps = {}) {
|
|
21
|
-
if (opts.skip) {
|
|
22
|
-
return { stepId: 'install-bmad', name: 'Install BMAD', success: true, skipped: true, details: {} }
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const { spawnFn = spawn } = _deps
|
|
26
|
-
const { command, args: baseArgs } = opts.bmadConfig
|
|
27
|
-
|
|
28
|
-
// Override language args from user config if provided
|
|
29
|
-
const args = [...baseArgs]
|
|
30
|
-
if (opts.config) {
|
|
31
|
-
const langMap = {
|
|
32
|
-
'--communication-language': opts.config.communication_language,
|
|
33
|
-
'--document-output-language': opts.config.document_output_language,
|
|
34
|
-
}
|
|
35
|
-
for (const [flag, value] of Object.entries(langMap)) {
|
|
36
|
-
if (!value) continue
|
|
37
|
-
const idx = args.indexOf(flag)
|
|
38
|
-
if (idx !== -1) {
|
|
39
|
-
args[idx + 1] = value
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
logger.info(` Running: ${command} ${args.join(' ')}`)
|
|
45
|
-
|
|
46
|
-
return new Promise((resolve) => {
|
|
47
|
-
const child = spawnFn(command, args, {
|
|
48
|
-
cwd: opts.targetDir,
|
|
49
|
-
stdio: 'inherit',
|
|
50
|
-
shell: true,
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
child.on('close', (code) => {
|
|
54
|
-
if (code === 0) {
|
|
55
|
-
resolve({
|
|
56
|
-
stepId: 'install-bmad',
|
|
57
|
-
name: 'Install BMAD',
|
|
58
|
-
success: true,
|
|
59
|
-
skipped: false,
|
|
60
|
-
details: { outputDirs: opts.bmadConfig.outputDirs },
|
|
61
|
-
})
|
|
62
|
-
} else {
|
|
63
|
-
resolve({
|
|
64
|
-
stepId: 'install-bmad',
|
|
65
|
-
name: 'Install BMAD',
|
|
66
|
-
success: false,
|
|
67
|
-
skipped: false,
|
|
68
|
-
details: {},
|
|
69
|
-
error: `npx bmad-method exited with code ${code}`,
|
|
70
|
-
})
|
|
71
|
-
}
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
child.on('error', (err) => {
|
|
75
|
-
resolve({
|
|
76
|
-
stepId: 'install-bmad',
|
|
77
|
-
name: 'Install BMAD',
|
|
78
|
-
success: false,
|
|
79
|
-
skipped: false,
|
|
80
|
-
details: {},
|
|
81
|
-
error: `Failed to spawn: ${err.message}`,
|
|
82
|
-
})
|
|
83
|
-
})
|
|
84
|
-
})
|
|
85
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Step: Install BMAD methodology via `npx bmad-method install`.
|
|
3
|
+
*
|
|
4
|
+
* Spawns the BMAD CLI as a child process with stdio inherited
|
|
5
|
+
* so the user sees real-time output.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { spawn } from 'node:child_process'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {object} opts
|
|
12
|
+
* @param {string} opts.targetDir - Project root
|
|
13
|
+
* @param {object} opts.bmadConfig - { command, args, outputDirs } from registry
|
|
14
|
+
* @param {object} [opts.config] - User config (communication_language, document_output_language)
|
|
15
|
+
* @param {boolean} opts.skip - Skip this step
|
|
16
|
+
* @param {object} logger
|
|
17
|
+
* @param {object} [_deps] - Injectable dependencies for testing
|
|
18
|
+
* @returns {Promise<import('../core/orchestrator.js').StepResult>}
|
|
19
|
+
*/
|
|
20
|
+
export async function installBmad(opts, logger, _deps = {}) {
|
|
21
|
+
if (opts.skip) {
|
|
22
|
+
return { stepId: 'install-bmad', name: 'Install BMAD', success: true, skipped: true, details: {} }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const { spawnFn = spawn } = _deps
|
|
26
|
+
const { command, args: baseArgs } = opts.bmadConfig
|
|
27
|
+
|
|
28
|
+
// Override language args from user config if provided
|
|
29
|
+
const args = [...baseArgs]
|
|
30
|
+
if (opts.config) {
|
|
31
|
+
const langMap = {
|
|
32
|
+
'--communication-language': opts.config.communication_language,
|
|
33
|
+
'--document-output-language': opts.config.document_output_language,
|
|
34
|
+
}
|
|
35
|
+
for (const [flag, value] of Object.entries(langMap)) {
|
|
36
|
+
if (!value) continue
|
|
37
|
+
const idx = args.indexOf(flag)
|
|
38
|
+
if (idx !== -1) {
|
|
39
|
+
args[idx + 1] = value
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
logger.info(` Running: ${command} ${args.join(' ')}`)
|
|
45
|
+
|
|
46
|
+
return new Promise((resolve) => {
|
|
47
|
+
const child = spawnFn(command, args, {
|
|
48
|
+
cwd: opts.targetDir,
|
|
49
|
+
stdio: 'inherit',
|
|
50
|
+
shell: true,
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
child.on('close', (code) => {
|
|
54
|
+
if (code === 0) {
|
|
55
|
+
resolve({
|
|
56
|
+
stepId: 'install-bmad',
|
|
57
|
+
name: 'Install BMAD',
|
|
58
|
+
success: true,
|
|
59
|
+
skipped: false,
|
|
60
|
+
details: { outputDirs: opts.bmadConfig.outputDirs },
|
|
61
|
+
})
|
|
62
|
+
} else {
|
|
63
|
+
resolve({
|
|
64
|
+
stepId: 'install-bmad',
|
|
65
|
+
name: 'Install BMAD',
|
|
66
|
+
success: false,
|
|
67
|
+
skipped: false,
|
|
68
|
+
details: {},
|
|
69
|
+
error: `npx bmad-method exited with code ${code}`,
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
child.on('error', (err) => {
|
|
75
|
+
resolve({
|
|
76
|
+
stepId: 'install-bmad',
|
|
77
|
+
name: 'Install BMAD',
|
|
78
|
+
success: false,
|
|
79
|
+
skipped: false,
|
|
80
|
+
details: {},
|
|
81
|
+
error: `Failed to spawn: ${err.message}`,
|
|
82
|
+
})
|
|
83
|
+
})
|
|
84
|
+
})
|
|
85
|
+
}
|
package/src/steps/install-mcp.js
CHANGED
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Step: Install MCP configuration.
|
|
3
|
-
*
|
|
4
|
-
* Copies the bundled `.mcp.json` template to the project root.
|
|
5
|
-
* Uses `overwrite: false` to preserve user modifications.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import path from 'node:path'
|
|
9
|
-
import { fileURLToPath } from 'node:url'
|
|
10
|
-
import fse from 'fs-extra'
|
|
11
|
-
import { computeFileHash } from '../utils/fs.js'
|
|
12
|
-
|
|
13
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
14
|
-
const CCKIT_ROOT = path.resolve(__dirname, '../..')
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* @param {object} opts
|
|
18
|
-
* @param {string} opts.targetDir - Project root
|
|
19
|
-
* @param {object} opts.mcpConfig - { template, target } from registry
|
|
20
|
-
* @param {boolean} opts.skip - Skip this step
|
|
21
|
-
* @param {boolean} [opts.forceOverwrite] - Overwrite existing file
|
|
22
|
-
* @param {object} logger
|
|
23
|
-
* @returns {Promise<import('../core/orchestrator.js').StepResult>}
|
|
24
|
-
*/
|
|
25
|
-
export async function installMcp(opts, logger) {
|
|
26
|
-
if (opts.skip) {
|
|
27
|
-
return { stepId: 'install-mcp', name: 'Install MCP Config', success: true, skipped: true, details: {} }
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const srcPath = path.resolve(CCKIT_ROOT, opts.mcpConfig.template)
|
|
31
|
-
const destPath = path.join(opts.targetDir, opts.mcpConfig.target)
|
|
32
|
-
|
|
33
|
-
if (!await fse.pathExists(srcPath)) {
|
|
34
|
-
return {
|
|
35
|
-
stepId: 'install-mcp',
|
|
36
|
-
name: 'Install MCP Config',
|
|
37
|
-
success: false,
|
|
38
|
-
skipped: false,
|
|
39
|
-
details: {},
|
|
40
|
-
error: `MCP template not found at ${opts.mcpConfig.template}`,
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Don't overwrite user-modified file unless forced
|
|
45
|
-
if (!opts.forceOverwrite && await fse.pathExists(destPath)) {
|
|
46
|
-
const hash = await computeFileHash(destPath)
|
|
47
|
-
logger.info(` ${opts.mcpConfig.target} already exists, skipping (use --force to overwrite)`)
|
|
48
|
-
return {
|
|
49
|
-
stepId: 'install-mcp',
|
|
50
|
-
name: 'Install MCP Config',
|
|
51
|
-
success: true,
|
|
52
|
-
skipped: false,
|
|
53
|
-
details: { target: opts.mcpConfig.target, hash, preserved: true },
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
await fse.ensureDir(path.dirname(destPath))
|
|
58
|
-
await fse.copy(srcPath, destPath)
|
|
59
|
-
|
|
60
|
-
const hash = await computeFileHash(destPath)
|
|
61
|
-
logger.debug(`Installed MCP config to ${opts.mcpConfig.target}`)
|
|
62
|
-
|
|
63
|
-
return {
|
|
64
|
-
stepId: 'install-mcp',
|
|
65
|
-
name: 'Install MCP Config',
|
|
66
|
-
success: true,
|
|
67
|
-
skipped: false,
|
|
68
|
-
details: { target: opts.mcpConfig.target, hash },
|
|
69
|
-
}
|
|
70
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Step: Install MCP configuration.
|
|
3
|
+
*
|
|
4
|
+
* Copies the bundled `.mcp.json` template to the project root.
|
|
5
|
+
* Uses `overwrite: false` to preserve user modifications.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import path from 'node:path'
|
|
9
|
+
import { fileURLToPath } from 'node:url'
|
|
10
|
+
import fse from 'fs-extra'
|
|
11
|
+
import { computeFileHash } from '../utils/fs.js'
|
|
12
|
+
|
|
13
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
14
|
+
const CCKIT_ROOT = path.resolve(__dirname, '../..')
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {object} opts
|
|
18
|
+
* @param {string} opts.targetDir - Project root
|
|
19
|
+
* @param {object} opts.mcpConfig - { template, target } from registry
|
|
20
|
+
* @param {boolean} opts.skip - Skip this step
|
|
21
|
+
* @param {boolean} [opts.forceOverwrite] - Overwrite existing file
|
|
22
|
+
* @param {object} logger
|
|
23
|
+
* @returns {Promise<import('../core/orchestrator.js').StepResult>}
|
|
24
|
+
*/
|
|
25
|
+
export async function installMcp(opts, logger) {
|
|
26
|
+
if (opts.skip) {
|
|
27
|
+
return { stepId: 'install-mcp', name: 'Install MCP Config', success: true, skipped: true, details: {} }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const srcPath = path.resolve(CCKIT_ROOT, opts.mcpConfig.template)
|
|
31
|
+
const destPath = path.join(opts.targetDir, opts.mcpConfig.target)
|
|
32
|
+
|
|
33
|
+
if (!await fse.pathExists(srcPath)) {
|
|
34
|
+
return {
|
|
35
|
+
stepId: 'install-mcp',
|
|
36
|
+
name: 'Install MCP Config',
|
|
37
|
+
success: false,
|
|
38
|
+
skipped: false,
|
|
39
|
+
details: {},
|
|
40
|
+
error: `MCP template not found at ${opts.mcpConfig.template}`,
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Don't overwrite user-modified file unless forced
|
|
45
|
+
if (!opts.forceOverwrite && await fse.pathExists(destPath)) {
|
|
46
|
+
const hash = await computeFileHash(destPath)
|
|
47
|
+
logger.info(` ${opts.mcpConfig.target} already exists, skipping (use --force to overwrite)`)
|
|
48
|
+
return {
|
|
49
|
+
stepId: 'install-mcp',
|
|
50
|
+
name: 'Install MCP Config',
|
|
51
|
+
success: true,
|
|
52
|
+
skipped: false,
|
|
53
|
+
details: { target: opts.mcpConfig.target, hash, preserved: true },
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
await fse.ensureDir(path.dirname(destPath))
|
|
58
|
+
await fse.copy(srcPath, destPath)
|
|
59
|
+
|
|
60
|
+
const hash = await computeFileHash(destPath)
|
|
61
|
+
logger.debug(`Installed MCP config to ${opts.mcpConfig.target}`)
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
stepId: 'install-mcp',
|
|
65
|
+
name: 'Install MCP Config',
|
|
66
|
+
success: true,
|
|
67
|
+
skipped: false,
|
|
68
|
+
details: { target: opts.mcpConfig.target, hash },
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Step: Install ECC rules via template copy.
|
|
3
|
-
*
|
|
4
|
-
* Copies the bundled rules template to `.claude/rules/`.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import path from 'node:path'
|
|
8
|
-
import fse from 'fs-extra'
|
|
9
|
-
import { listFiles } from '../utils/fs.js'
|
|
10
|
-
import { fileURLToPath } from 'node:url'
|
|
11
|
-
|
|
12
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @param {object} opts
|
|
16
|
-
* @param {string} opts.targetDir - Project root
|
|
17
|
-
* @param {object} opts.rulesConfig - { template, target }
|
|
18
|
-
* @param {boolean} opts.skip - Skip this step
|
|
19
|
-
* @param {object} logger
|
|
20
|
-
* @param {object} [_deps] - Injectable dependencies
|
|
21
|
-
* @returns {Promise<import('../core/orchestrator.js').StepResult>}
|
|
22
|
-
*/
|
|
23
|
-
export async function installRules(opts, logger, _deps = {}) {
|
|
24
|
-
if (opts.skip) {
|
|
25
|
-
return { stepId: 'install-rules', name: 'Install ECC Rules', success: true, skipped: true, details: {} }
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const { template, target } = opts.rulesConfig
|
|
29
|
-
|
|
30
|
-
try {
|
|
31
|
-
// Resolve template path - use absolute path if provided, otherwise relative to cckit package
|
|
32
|
-
const templatePath = path.resolve(__dirname, '../../', template)
|
|
33
|
-
const destDir = path.join(opts.targetDir, target)
|
|
34
|
-
|
|
35
|
-
if (!await fse.pathExists(templatePath)) {
|
|
36
|
-
return {
|
|
37
|
-
stepId: 'install-rules',
|
|
38
|
-
name: 'Install ECC Rules',
|
|
39
|
-
success: false,
|
|
40
|
-
skipped: false,
|
|
41
|
-
details: {},
|
|
42
|
-
error: `Rules template not found: ${templatePath}`,
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
await fse.ensureDir(destDir)
|
|
47
|
-
await fse.copy(templatePath, destDir, { overwrite: true })
|
|
48
|
-
|
|
49
|
-
const files = await listFiles(destDir)
|
|
50
|
-
logger.debug(`Copied ${files.length} rule files to ${target}`)
|
|
51
|
-
|
|
52
|
-
return {
|
|
53
|
-
stepId: 'install-rules',
|
|
54
|
-
name: 'Install ECC Rules',
|
|
55
|
-
success: true,
|
|
56
|
-
skipped: false,
|
|
57
|
-
details: { files: files.length, target },
|
|
58
|
-
}
|
|
59
|
-
} catch (err) {
|
|
60
|
-
return {
|
|
61
|
-
stepId: 'install-rules',
|
|
62
|
-
name: 'Install ECC Rules',
|
|
63
|
-
success: false,
|
|
64
|
-
skipped: false,
|
|
65
|
-
details: {},
|
|
66
|
-
error: err.message,
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Step: Install ECC rules via template copy.
|
|
3
|
+
*
|
|
4
|
+
* Copies the bundled rules template to `.claude/rules/`.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import path from 'node:path'
|
|
8
|
+
import fse from 'fs-extra'
|
|
9
|
+
import { listFiles } from '../utils/fs.js'
|
|
10
|
+
import { fileURLToPath } from 'node:url'
|
|
11
|
+
|
|
12
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {object} opts
|
|
16
|
+
* @param {string} opts.targetDir - Project root
|
|
17
|
+
* @param {object} opts.rulesConfig - { template, target }
|
|
18
|
+
* @param {boolean} opts.skip - Skip this step
|
|
19
|
+
* @param {object} logger
|
|
20
|
+
* @param {object} [_deps] - Injectable dependencies
|
|
21
|
+
* @returns {Promise<import('../core/orchestrator.js').StepResult>}
|
|
22
|
+
*/
|
|
23
|
+
export async function installRules(opts, logger, _deps = {}) {
|
|
24
|
+
if (opts.skip) {
|
|
25
|
+
return { stepId: 'install-rules', name: 'Install ECC Rules', success: true, skipped: true, details: {} }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const { template, target } = opts.rulesConfig
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
// Resolve template path - use absolute path if provided, otherwise relative to cckit package
|
|
32
|
+
const templatePath = path.resolve(__dirname, '../../', template)
|
|
33
|
+
const destDir = path.join(opts.targetDir, target)
|
|
34
|
+
|
|
35
|
+
if (!await fse.pathExists(templatePath)) {
|
|
36
|
+
return {
|
|
37
|
+
stepId: 'install-rules',
|
|
38
|
+
name: 'Install ECC Rules',
|
|
39
|
+
success: false,
|
|
40
|
+
skipped: false,
|
|
41
|
+
details: {},
|
|
42
|
+
error: `Rules template not found: ${templatePath}`,
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
await fse.ensureDir(destDir)
|
|
47
|
+
await fse.copy(templatePath, destDir, { overwrite: true })
|
|
48
|
+
|
|
49
|
+
const files = await listFiles(destDir)
|
|
50
|
+
logger.debug(`Copied ${files.length} rule files to ${target}`)
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
stepId: 'install-rules',
|
|
54
|
+
name: 'Install ECC Rules',
|
|
55
|
+
success: true,
|
|
56
|
+
skipped: false,
|
|
57
|
+
details: { files: files.length, target },
|
|
58
|
+
}
|
|
59
|
+
} catch (err) {
|
|
60
|
+
return {
|
|
61
|
+
stepId: 'install-rules',
|
|
62
|
+
name: 'Install ECC Rules',
|
|
63
|
+
success: false,
|
|
64
|
+
skipped: false,
|
|
65
|
+
details: {},
|
|
66
|
+
error: err.message,
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Step: Install skills via `npx skills add`.
|
|
3
|
-
*
|
|
4
|
-
* Iterates over skill entries from the registry and runs
|
|
5
|
-
* `npx skills add <repo> --skill <id>` for each.
|
|
6
|
-
* Individual failures do not abort the overall step.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { execFile } from 'node:child_process'
|
|
10
|
-
import { promisify } from 'node:util'
|
|
11
|
-
|
|
12
|
-
const execFileAsync = promisify(execFile)
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @param {object} opts
|
|
16
|
-
* @param {string} opts.targetDir - Project root
|
|
17
|
-
* @param {Array<{id: string, repo: string, skill: string}>} opts.skills - Skill definitions
|
|
18
|
-
* @param {boolean} opts.skip - Skip this step
|
|
19
|
-
* @param {object} logger
|
|
20
|
-
* @param {object} [_deps] - Injectable dependencies
|
|
21
|
-
* @returns {Promise<import('../core/orchestrator.js').StepResult>}
|
|
22
|
-
*/
|
|
23
|
-
export async function installSkills(opts, logger, _deps = {}) {
|
|
24
|
-
if (opts.skip) {
|
|
25
|
-
return { stepId: 'install-skills', name: 'Install Skills', success: true, skipped: true, details: {} }
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const { execFileFn = execFileAsync } = _deps
|
|
29
|
-
const results = []
|
|
30
|
-
|
|
31
|
-
for (const skillDef of opts.skills) {
|
|
32
|
-
logger.info(` Installing skill: ${skillDef.id}`)
|
|
33
|
-
try {
|
|
34
|
-
// Use installCommand from registry if available, otherwise fallback to basic command
|
|
35
|
-
const installCmd = skillDef.installCommand || `npx skills add ${skillDef.repo} --skill ${skillDef.skill} -y -a claude-code`
|
|
36
|
-
await execFileFn(installCmd, [], {
|
|
37
|
-
cwd: opts.targetDir,
|
|
38
|
-
shell: true,
|
|
39
|
-
})
|
|
40
|
-
results.push({ id: skillDef.id, success: true })
|
|
41
|
-
logger.debug(` Skill "${skillDef.id}" installed successfully`)
|
|
42
|
-
} catch (err) {
|
|
43
|
-
results.push({ id: skillDef.id, success: false, error: err.message })
|
|
44
|
-
logger.warn(`Skill "${skillDef.id}" failed: ${err.message}`)
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const allSuccess = results.every(r => r.success)
|
|
49
|
-
return {
|
|
50
|
-
stepId: 'install-skills',
|
|
51
|
-
name: 'Install Skills',
|
|
52
|
-
success: allSuccess,
|
|
53
|
-
skipped: false,
|
|
54
|
-
details: { results },
|
|
55
|
-
}
|
|
56
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Step: Install skills via `npx skills add`.
|
|
3
|
+
*
|
|
4
|
+
* Iterates over skill entries from the registry and runs
|
|
5
|
+
* `npx skills add <repo> --skill <id>` for each.
|
|
6
|
+
* Individual failures do not abort the overall step.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { execFile } from 'node:child_process'
|
|
10
|
+
import { promisify } from 'node:util'
|
|
11
|
+
|
|
12
|
+
const execFileAsync = promisify(execFile)
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {object} opts
|
|
16
|
+
* @param {string} opts.targetDir - Project root
|
|
17
|
+
* @param {Array<{id: string, repo: string, skill: string}>} opts.skills - Skill definitions
|
|
18
|
+
* @param {boolean} opts.skip - Skip this step
|
|
19
|
+
* @param {object} logger
|
|
20
|
+
* @param {object} [_deps] - Injectable dependencies
|
|
21
|
+
* @returns {Promise<import('../core/orchestrator.js').StepResult>}
|
|
22
|
+
*/
|
|
23
|
+
export async function installSkills(opts, logger, _deps = {}) {
|
|
24
|
+
if (opts.skip) {
|
|
25
|
+
return { stepId: 'install-skills', name: 'Install Skills', success: true, skipped: true, details: {} }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const { execFileFn = execFileAsync } = _deps
|
|
29
|
+
const results = []
|
|
30
|
+
|
|
31
|
+
for (const skillDef of opts.skills) {
|
|
32
|
+
logger.info(` Installing skill: ${skillDef.id}`)
|
|
33
|
+
try {
|
|
34
|
+
// Use installCommand from registry if available, otherwise fallback to basic command
|
|
35
|
+
const installCmd = skillDef.installCommand || `npx skills add ${skillDef.repo} --skill ${skillDef.skill} -y -a claude-code`
|
|
36
|
+
await execFileFn(installCmd, [], {
|
|
37
|
+
cwd: opts.targetDir,
|
|
38
|
+
shell: true,
|
|
39
|
+
})
|
|
40
|
+
results.push({ id: skillDef.id, success: true })
|
|
41
|
+
logger.debug(` Skill "${skillDef.id}" installed successfully`)
|
|
42
|
+
} catch (err) {
|
|
43
|
+
results.push({ id: skillDef.id, success: false, error: err.message })
|
|
44
|
+
logger.warn(`Skill "${skillDef.id}" failed: ${err.message}`)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const allSuccess = results.every(r => r.success)
|
|
49
|
+
return {
|
|
50
|
+
stepId: 'install-skills',
|
|
51
|
+
name: 'Install Skills',
|
|
52
|
+
success: allSuccess,
|
|
53
|
+
skipped: false,
|
|
54
|
+
details: { results },
|
|
55
|
+
}
|
|
56
|
+
}
|