@cregis-dev/cckit 0.6.5 → 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.
Files changed (52) hide show
  1. package/README.md +221 -221
  2. package/package.json +1 -1
  3. package/registry.json +145 -128
  4. package/src/cli.js +79 -79
  5. package/src/commands/init.js +174 -161
  6. package/src/commands/status.js +125 -85
  7. package/src/commands/update.js +192 -151
  8. package/src/core/config.js +82 -74
  9. package/src/core/orchestrator.js +79 -79
  10. package/src/core/registry.js +60 -60
  11. package/src/steps/add-plugin.js +148 -0
  12. package/src/steps/configure-user.js +181 -181
  13. package/src/steps/enable-plugins.js +97 -97
  14. package/src/steps/install-bmad.js +85 -85
  15. package/src/steps/install-mcp.js +70 -70
  16. package/src/steps/install-rules.js +69 -69
  17. package/src/steps/install-skills.js +56 -56
  18. package/src/utils/compare-versions.js +106 -0
  19. package/src/utils/fs.js +33 -33
  20. package/src/utils/manifest.js +101 -99
  21. package/src/utils/prompt.js +41 -41
  22. package/templates/mcp/claude-code/.mcp.json +40 -40
  23. package/templates/rules/README.md +103 -103
  24. package/templates/rules/common/agents.md +49 -49
  25. package/templates/rules/common/coding-style.md +48 -48
  26. package/templates/rules/common/development-workflow.md +37 -37
  27. package/templates/rules/common/git-workflow.md +24 -24
  28. package/templates/rules/common/hooks.md +30 -30
  29. package/templates/rules/common/patterns.md +31 -31
  30. package/templates/rules/common/performance.md +55 -55
  31. package/templates/rules/common/security.md +29 -29
  32. package/templates/rules/common/testing.md +29 -29
  33. package/templates/rules/golang/coding-style.md +32 -32
  34. package/templates/rules/golang/hooks.md +17 -17
  35. package/templates/rules/golang/patterns.md +45 -45
  36. package/templates/rules/golang/security.md +34 -34
  37. package/templates/rules/golang/testing.md +31 -31
  38. package/templates/rules/python/coding-style.md +42 -42
  39. package/templates/rules/python/hooks.md +19 -19
  40. package/templates/rules/python/patterns.md +39 -39
  41. package/templates/rules/python/security.md +30 -30
  42. package/templates/rules/python/testing.md +38 -38
  43. package/templates/rules/swift/coding-style.md +47 -47
  44. package/templates/rules/swift/hooks.md +20 -20
  45. package/templates/rules/swift/patterns.md +66 -66
  46. package/templates/rules/swift/security.md +33 -33
  47. package/templates/rules/swift/testing.md +45 -45
  48. package/templates/rules/typescript/coding-style.md +65 -65
  49. package/templates/rules/typescript/hooks.md +22 -22
  50. package/templates/rules/typescript/patterns.md +52 -52
  51. package/templates/rules/typescript/security.md +28 -28
  52. package/templates/rules/typescript/testing.md +18 -18
@@ -1,161 +1,174 @@
1
- /**
2
- * init command — orchestrate installation of all components.
3
- *
4
- * Flow: load registry → merge config → build steps → orchestrate → write manifest
5
- */
6
-
7
- import path from 'node:path'
8
- import fse from 'fs-extra'
9
- import { loadRegistry, resolvePlugins, resolveModelId } from '../core/registry.js'
10
- import { mergeConfig, DEFAULT_API_URL } from '../core/config.js'
11
- import { orchestrate } from '../core/orchestrator.js'
12
- import { MANIFEST_REL, buildManifest, writeManifest } from '../utils/manifest.js'
13
- import { createLogger } from '../utils/logger.js'
14
- import { enablePlugins } from '../steps/enable-plugins.js'
15
- import { installBmad } from '../steps/install-bmad.js'
16
- import { installRules } from '../steps/install-rules.js'
17
- import { installSkills } from '../steps/install-skills.js'
18
- import { installMcp } from '../steps/install-mcp.js'
19
- import { configureUser } from '../steps/configure-user.js'
20
-
21
- const SCAFFOLD_DIRS = [
22
- '_bmad-output/planning-artifacts',
23
- '_bmad-output/implementation-artifacts',
24
- '_bmad-output/test-artifacts',
25
- 'docs'
26
- ]
27
-
28
- const VERSION = '0.5.0'
29
-
30
- /**
31
- * Run the init command.
32
- *
33
- * @param {object} opts - Commander options
34
- * @param {object} [_deps] - Injectable dependencies for testing
35
- * @returns {Promise<import('../core/orchestrator.js').RunReport>}
36
- */
37
- export async function runInit(opts = {}, _deps = {}) {
38
- const targetDir = path.resolve(opts.dir || process.cwd())
39
- const logger = _deps.logger || createLogger({ debug: opts.debug })
40
-
41
- // Guard: already installed
42
- const manifestPath = path.join(targetDir, MANIFEST_REL)
43
- if (await fse.pathExists(manifestPath)) {
44
- throw new Error(
45
- `cckit is already installed in this project. ` +
46
- `Found existing manifest at ${MANIFEST_REL}. ` +
47
- `Use "cckit update" to modify your installation.`
48
- )
49
- }
50
-
51
- logger.banner('cckit init')
52
-
53
- // Load registry and merge config
54
- const registry = _deps.registry || await loadRegistry()
55
- const config = mergeConfig(opts)
56
- logger.debug(`Config: ${JSON.stringify(config, null, 2)}`)
57
-
58
- // Resolve plugins
59
- const plugins = resolvePlugins(registry, config)
60
-
61
- // Resolve model ID
62
- const userSettings = registry.userSettings || {}
63
- const modelId = resolveModelId(userSettings, config.model)
64
-
65
- // Build step list
66
- const steps = [
67
- {
68
- id: 'configure-user',
69
- fn: _deps.configureUser || configureUser,
70
- opts: {
71
- apiUrl: config.apiUrl || userSettings.apiUrl || DEFAULT_API_URL,
72
- apiKey: config.apiKey,
73
- forceApiKey: config.forceApiKey,
74
- model: config.model, // CLI alias (e.g. 'kimi'), used for prompting
75
- modelId, // Resolved ID (e.g. 'Kimi-K2.5'), used for env vars
76
- modelEnvKeys: userSettings.modelEnvKeys || [],
77
- yes: opts.yes,
78
- skip: false,
79
- },
80
- },
81
- {
82
- id: 'enable-plugins',
83
- fn: _deps.enablePlugins || enablePlugins,
84
- opts: {
85
- targetDir,
86
- plugins,
87
- skip: config.plugins === 'none',
88
- },
89
- },
90
- {
91
- id: 'install-bmad',
92
- fn: _deps.installBmad || installBmad,
93
- opts: {
94
- targetDir,
95
- bmadConfig: registry.bmad,
96
- // Only pass explicit CLI overrides (not defaults) to avoid overwriting registry defaults
97
- config: {
98
- communication_language: opts.communicationLanguage || undefined,
99
- document_output_language: opts.docLanguage || undefined,
100
- },
101
- skip: config.excludeGroups.includes('bmad'),
102
- },
103
- },
104
- {
105
- id: 'install-rules',
106
- fn: _deps.installRules || installRules,
107
- opts: {
108
- targetDir,
109
- rulesConfig: registry.rules,
110
- skip: config.excludeGroups.includes('ecc'),
111
- },
112
- },
113
- {
114
- id: 'install-skills',
115
- fn: _deps.installSkills || installSkills,
116
- opts: {
117
- targetDir,
118
- skills: registry.skills || [],
119
- skip: config.skipSkills || false,
120
- },
121
- },
122
- {
123
- id: 'install-mcp',
124
- fn: _deps.installMcp || installMcp,
125
- opts: {
126
- targetDir,
127
- mcpConfig: registry.mcp,
128
- skip: config.excludeGroups.includes('mcp'),
129
- },
130
- },
131
- ]
132
-
133
- // Orchestrate
134
- const report = await orchestrate(steps, logger)
135
-
136
- // Scaffold directories
137
- await Promise.all(SCAFFOLD_DIRS.map(dir => {
138
- logger.debug(`Creating scaffold: ${dir}`)
139
- return fse.ensureDir(path.join(targetDir, dir))
140
- }))
141
-
142
- // Write manifest
143
- const manifest = buildManifest({ config, report, version: VERSION })
144
- await writeManifest(targetDir, manifest)
145
- logger.success(`Manifest written to ${MANIFEST_REL}`)
146
-
147
- // Summary
148
- logger.newline()
149
- logger.banner('Init complete!')
150
-
151
- const successCount = report.steps.filter(s => s.success && !s.skipped).length
152
- const skipCount = report.steps.filter(s => s.skipped).length
153
- const failCount = report.steps.filter(s => !s.success && !s.skipped).length
154
-
155
- logger.info(` Successful: ${successCount} steps`)
156
- if (skipCount > 0) logger.info(` Skipped: ${skipCount} steps`)
157
- if (failCount > 0) logger.warn(`Failed: ${failCount} steps`)
158
- logger.newline()
159
-
160
- return report
161
- }
1
+ /**
2
+ * init command — orchestrate installation of all components.
3
+ *
4
+ * Flow: load registry → merge config → build steps → orchestrate → write manifest
5
+ */
6
+
7
+ import path from 'node:path'
8
+ import fse from 'fs-extra'
9
+ import { loadRegistry, resolvePlugins, resolveModelId } from '../core/registry.js'
10
+ import { mergeConfig, DEFAULT_API_URL } from '../core/config.js'
11
+ import { orchestrate } from '../core/orchestrator.js'
12
+ import { MANIFEST_REL, buildManifest, writeManifest } from '../utils/manifest.js'
13
+ import { createLogger } from '../utils/logger.js'
14
+ import { enablePlugins } from '../steps/enable-plugins.js'
15
+ import { addPlugin } from '../steps/add-plugin.js'
16
+ import { installBmad } from '../steps/install-bmad.js'
17
+ import { installRules } from '../steps/install-rules.js'
18
+ import { installSkills } from '../steps/install-skills.js'
19
+ import { installMcp } from '../steps/install-mcp.js'
20
+ import { configureUser } from '../steps/configure-user.js'
21
+
22
+ const SCAFFOLD_DIRS = [
23
+ '_bmad-output/planning-artifacts',
24
+ '_bmad-output/implementation-artifacts',
25
+ '_bmad-output/test-artifacts',
26
+ 'docs'
27
+ ]
28
+
29
+ const VERSION = '0.5.0'
30
+
31
+ /**
32
+ * Run the init command.
33
+ *
34
+ * @param {object} opts - Commander options
35
+ * @param {object} [_deps] - Injectable dependencies for testing
36
+ * @returns {Promise<import('../core/orchestrator.js').RunReport>}
37
+ */
38
+ export async function runInit(opts = {}, _deps = {}) {
39
+ const targetDir = path.resolve(opts.dir || process.cwd())
40
+ const logger = _deps.logger || createLogger({ debug: opts.debug })
41
+
42
+ // Guard: already installed
43
+ const manifestPath = path.join(targetDir, MANIFEST_REL)
44
+ if (await fse.pathExists(manifestPath)) {
45
+ throw new Error(
46
+ `cckit is already installed in this project. ` +
47
+ `Found existing manifest at ${MANIFEST_REL}. ` +
48
+ `Use "cckit update" to modify your installation.`
49
+ )
50
+ }
51
+
52
+ logger.banner('cckit init')
53
+
54
+ // Load registry and merge config
55
+ const registry = _deps.registry || await loadRegistry()
56
+ const config = mergeConfig(opts)
57
+ const versions = registry.versions || {}
58
+ logger.debug(`Config: ${JSON.stringify(config, null, 2)}`)
59
+ logger.debug(`Versions: ${JSON.stringify(versions, null, 2)}`)
60
+
61
+ // Resolve plugins
62
+ const plugins = resolvePlugins(registry, config)
63
+
64
+ // Resolve model ID
65
+ const userSettings = registry.userSettings || {}
66
+ const modelId = resolveModelId(userSettings, config.model)
67
+
68
+ // Build step list
69
+ const steps = [
70
+ {
71
+ id: 'configure-user',
72
+ fn: _deps.configureUser || configureUser,
73
+ opts: {
74
+ apiUrl: config.apiUrl || userSettings.apiUrl || DEFAULT_API_URL,
75
+ apiKey: config.apiKey,
76
+ forceApiKey: config.forceApiKey,
77
+ model: config.model, // CLI alias (e.g. 'kimi'), used for prompting
78
+ modelId, // Resolved ID (e.g. 'Kimi-K2.5'), used for env vars
79
+ modelEnvKeys: userSettings.modelEnvKeys || [],
80
+ yes: opts.yes,
81
+ skip: false,
82
+ },
83
+ },
84
+ {
85
+ id: 'enable-plugins',
86
+ fn: _deps.enablePlugins || enablePlugins,
87
+ opts: {
88
+ targetDir,
89
+ plugins,
90
+ skip: config.plugins === 'none',
91
+ },
92
+ },
93
+ // Test: CLI-based plugin installation for project-scoped plugins
94
+ {
95
+ id: 'add-plugin',
96
+ fn: _deps.addPlugin || addPlugin,
97
+ opts: {
98
+ targetDir,
99
+ plugins,
100
+ skip: config.plugins === 'none' || !config.cliPlugins,
101
+ },
102
+ },
103
+ {
104
+ id: 'install-bmad',
105
+ fn: _deps.installBmad || installBmad,
106
+ opts: {
107
+ targetDir,
108
+ bmadConfig: registry.bmad,
109
+ // Only pass explicit CLI overrides (not defaults) to avoid overwriting registry defaults
110
+ config: {
111
+ communication_language: opts.communicationLanguage || undefined,
112
+ document_output_language: opts.docLanguage || undefined,
113
+ },
114
+ skip: config.excludeGroups.includes('bmad'),
115
+ },
116
+ },
117
+ {
118
+ id: 'install-rules',
119
+ fn: _deps.installRules || installRules,
120
+ opts: {
121
+ targetDir,
122
+ rulesConfig: registry.rules,
123
+ skip: config.excludeGroups.includes('ecc'),
124
+ },
125
+ },
126
+ {
127
+ id: 'install-skills',
128
+ fn: _deps.installSkills || installSkills,
129
+ opts: {
130
+ targetDir,
131
+ skills: registry.skills || [],
132
+ skip: config.skipSkills || false,
133
+ },
134
+ },
135
+ {
136
+ id: 'install-mcp',
137
+ fn: _deps.installMcp || installMcp,
138
+ opts: {
139
+ targetDir,
140
+ mcpConfig: registry.mcp,
141
+ skip: config.excludeGroups.includes('mcp'),
142
+ },
143
+ },
144
+ ]
145
+
146
+ // Orchestrate
147
+ const report = await orchestrate(steps, logger)
148
+
149
+ // Scaffold directories
150
+ await Promise.all(SCAFFOLD_DIRS.map(dir => {
151
+ logger.debug(`Creating scaffold: ${dir}`)
152
+ return fse.ensureDir(path.join(targetDir, dir))
153
+ }))
154
+
155
+ // Write manifest
156
+ const manifest = buildManifest({ config, report, version: VERSION, versions })
157
+ await writeManifest(targetDir, manifest)
158
+ logger.success(`Manifest written to ${MANIFEST_REL}`)
159
+
160
+ // Summary
161
+ logger.newline()
162
+ logger.banner('Init complete!')
163
+
164
+ const successCount = report.steps.filter(s => s.success && !s.skipped).length
165
+ const skipCount = report.steps.filter(s => s.skipped).length
166
+ const failCount = report.steps.filter(s => !s.success && !s.skipped).length
167
+
168
+ logger.info(` Successful: ${successCount} steps`)
169
+ if (skipCount > 0) logger.info(` Skipped: ${skipCount} steps`)
170
+ if (failCount > 0) logger.warn(`Failed: ${failCount} steps`)
171
+ logger.newline()
172
+
173
+ return report
174
+ }
@@ -1,85 +1,125 @@
1
- /**
2
- * status command — display installation state from manifest.
3
- */
4
-
5
- import path from 'node:path'
6
- import chalk from 'chalk'
7
- import { readManifest, isLegacyManifest } from '../utils/manifest.js'
8
-
9
- /**
10
- * @param {object} opts
11
- * @param {string} [opts.dir] - Target directory
12
- * @returns {Promise<object>}
13
- */
14
- export async function runStatus(opts = {}) {
15
- const targetDir = path.resolve(opts.dir || process.cwd())
16
-
17
- let manifest
18
- try {
19
- manifest = await readManifest(targetDir)
20
- } catch {
21
- const msg = 'cckit is not installed in this directory. Run `cckit init` first.'
22
- console.log(`\n ${chalk.yellow('!')} ${msg}\n`)
23
- return { installed: false, output: msg }
24
- }
25
-
26
- // Legacy manifest check
27
- if (isLegacyManifest(manifest)) {
28
- const msg = 'Legacy manifest detected (v1). Please run `cckit init` to reinstall with the new format.'
29
- console.log(`\n ${chalk.yellow('!')} ${msg}\n`)
30
- return { installed: true, legacy: true, output: msg }
31
- }
32
-
33
- const lines = []
34
- lines.push('')
35
- lines.push(chalk.bold('cckit installation status'))
36
- lines.push('')
37
-
38
- // Step results
39
- const steps = manifest.cckit?.steps || []
40
- const header = `${'Step'.padEnd(20)} ${'Status'.padEnd(12)} ${'Details'.padEnd(40)}`
41
- lines.push(header)
42
- lines.push('-'.repeat(72))
43
-
44
- for (const step of steps) {
45
- const status = step.skipped
46
- ? chalk.gray('skipped')
47
- : step.success
48
- ? chalk.green('ok')
49
- : chalk.red('failed')
50
-
51
- let detail = ''
52
- if (step.skipped) {
53
- detail = '-'
54
- } else if (step.error) {
55
- detail = chalk.red(step.error.slice(0, 38))
56
- } else if (step.details) {
57
- const d = step.details
58
- if (d.enabledKeys) detail = `${d.enabledKeys.length} plugins`
59
- else if (d.outputDirs) detail = d.outputDirs.join(', ')
60
- else if (d.files) detail = `${d.files} files -> ${d.target}`
61
- else if (d.results) {
62
- const ok = d.results.filter(r => r.success).length
63
- detail = `${ok}/${d.results.length} skills`
64
- } else if (d.target) detail = d.target
65
- }
66
-
67
- lines.push(`${(step.stepId || '-').padEnd(20)} ${status.padEnd(21)} ${detail}`)
68
- }
69
-
70
- lines.push('')
71
- lines.push(`Directory: ${targetDir}`)
72
- lines.push(`Install date: ${manifest.cckit?.installedAt || '-'}`)
73
- lines.push(`cckit version: ${manifest.cckit?.version || '-'}`)
74
-
75
- if (manifest.cckit?.lastUpdated) {
76
- lines.push(`Last updated: ${manifest.cckit.lastUpdated}`)
77
- }
78
-
79
- lines.push('')
80
-
81
- const output = lines.join('\n')
82
- console.log(output)
83
-
84
- return { installed: true, cckit: manifest.cckit, output }
85
- }
1
+ /**
2
+ * status command — display installation state from manifest.
3
+ */
4
+
5
+ import path from 'node:path'
6
+ import chalk from 'chalk'
7
+ import { readManifest, isLegacyManifest } from '../utils/manifest.js'
8
+ import { compareVersions } from '../utils/compare-versions.js'
9
+ import { loadRegistry } from '../core/registry.js'
10
+
11
+ /**
12
+ * @param {object} opts
13
+ * @param {string} [opts.dir] - Target directory
14
+ * @returns {Promise<object>}
15
+ */
16
+ export async function runStatus(opts = {}) {
17
+ const targetDir = path.resolve(opts.dir || process.cwd())
18
+
19
+ let manifest
20
+ try {
21
+ manifest = await readManifest(targetDir)
22
+ } catch {
23
+ const msg = 'cckit is not installed in this directory. Run `cckit init` first.'
24
+ console.log(`\n ${chalk.yellow('!')} ${msg}\n`)
25
+ return { installed: false, output: msg }
26
+ }
27
+
28
+ // Legacy manifest check
29
+ if (isLegacyManifest(manifest)) {
30
+ const msg = 'Legacy manifest detected (v1). Please run `cckit init` to reinstall with the new format.'
31
+ console.log(`\n ${chalk.yellow('!')} ${msg}\n`)
32
+ return { installed: true, legacy: true, output: msg }
33
+ }
34
+
35
+ // Load registry and compare versions
36
+ let registry
37
+ let needsUpdate = false
38
+ let components = {}
39
+ try {
40
+ registry = await loadRegistry()
41
+ const result = compareVersions(manifest, registry)
42
+ needsUpdate = result.needsUpdate
43
+ components = result.components
44
+ } catch {
45
+ // Registry load failed - skip version check
46
+ }
47
+
48
+ const lines = []
49
+ lines.push('')
50
+ lines.push(chalk.bold('cckit installation status'))
51
+ lines.push('')
52
+
53
+ // Component versions
54
+ const installedVersions = manifest.cckit?.config?.versions || {}
55
+ const versionHeader = `${'Component'.padEnd(22)} ${'Installed'.padEnd(12)} ${'Latest'.padEnd(12)} ${'Status'.padEnd(24)}`
56
+ lines.push(chalk.bold(versionHeader))
57
+ lines.push('-'.repeat(70))
58
+
59
+ for (const [stepId, info] of Object.entries(components)) {
60
+ const current = installedVersions[info.versionKey] || 'none'
61
+ const latest = info.latest
62
+ const hasUpdate = current !== latest
63
+
64
+ const versionStatus = hasUpdate
65
+ ? chalk.yellow(`update (${current} -> ${latest})`)
66
+ : chalk.green('up to date')
67
+
68
+ lines.push(`${stepId.padEnd(22)} ${current.padEnd(12)} ${latest.padEnd(12)} ${versionStatus}`)
69
+ }
70
+
71
+ if (needsUpdate) {
72
+ lines.push('')
73
+ lines.push(chalk.yellow(' Updates available. Run "cckit update" to update.'))
74
+ }
75
+
76
+ lines.push('')
77
+ lines.push(chalk.bold('Step Results:'))
78
+ const header = `${'Step'.padEnd(20)} ${'Status'.padEnd(12)} ${'Details'.padEnd(40)}`
79
+ lines.push(header)
80
+ lines.push('-'.repeat(72))
81
+
82
+ // Step results
83
+ const steps = manifest.cckit?.steps || []
84
+ for (const step of steps) {
85
+ const status = step.skipped
86
+ ? chalk.gray('skipped')
87
+ : step.success
88
+ ? chalk.green('ok')
89
+ : chalk.red('failed')
90
+
91
+ let detail = ''
92
+ if (step.skipped) {
93
+ detail = '-'
94
+ } else if (step.error) {
95
+ detail = chalk.red(step.error.slice(0, 38))
96
+ } else if (step.details) {
97
+ const d = step.details
98
+ if (d.enabledKeys) detail = `${d.enabledKeys.length} plugins`
99
+ else if (d.outputDirs) detail = d.outputDirs.join(', ')
100
+ else if (d.files) detail = `${d.files} files -> ${d.target}`
101
+ else if (d.results) {
102
+ const ok = d.results.filter(r => r.success).length
103
+ detail = `${ok}/${d.results.length} skills`
104
+ } else if (d.target) detail = d.target
105
+ }
106
+
107
+ lines.push(`${(step.stepId || '-').padEnd(20)} ${status.padEnd(21)} ${detail}`)
108
+ }
109
+
110
+ lines.push('')
111
+ lines.push(`Directory: ${targetDir}`)
112
+ lines.push(`Install date: ${manifest.cckit?.installedAt || '-'}`)
113
+ lines.push(`cckit version: ${manifest.cckit?.version || '-'}`)
114
+
115
+ if (manifest.cckit?.lastUpdated) {
116
+ lines.push(`Last updated: ${manifest.cckit.lastUpdated}`)
117
+ }
118
+
119
+ lines.push('')
120
+
121
+ const output = lines.join('\n')
122
+ console.log(output)
123
+
124
+ return { installed: true, cckit: manifest.cckit, output, needsUpdate, components }
125
+ }