@cregis-dev/cckit 0.6.6 → 0.6.8
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
package/src/commands/init.js
CHANGED
|
@@ -1,174 +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 { 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
|
+
/**
|
|
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, VERSION } 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
|
+
}
|
package/src/commands/status.js
CHANGED
|
@@ -1,125 +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
|
-
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
|
-
}
|
|
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
|
+
}
|