@khanhcan148/mk 0.1.9 → 0.1.10
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 +25 -19
- package/package.json +1 -1
- package/src/commands/update.js +78 -3
- package/src/lib/constants.js +1 -0
- package/src/lib/copy.js +25 -0
package/README.md
CHANGED
|
@@ -73,17 +73,20 @@ cp -r .claude ~/.claude/
|
|
|
73
73
|
|
|
74
74
|
```bash
|
|
75
75
|
# Use a workflow command
|
|
76
|
-
/mk-init
|
|
77
|
-
/mk-brainstorm
|
|
78
|
-
/mk-plan
|
|
79
|
-
/mk-implement
|
|
80
|
-
/mk-test
|
|
81
|
-
/mk-review
|
|
82
|
-
/mk-debug
|
|
83
|
-
/mk-security
|
|
84
|
-
/mk-db
|
|
85
|
-
/mk-docs
|
|
86
|
-
/mk-git
|
|
76
|
+
/mk-init # Bootstrap new project
|
|
77
|
+
/mk-brainstorm # Explore options, debate trade-offs
|
|
78
|
+
/mk-plan # Create implementation plan
|
|
79
|
+
/mk-implement # End-to-end feature delivery
|
|
80
|
+
/mk-test # Run tests and validate
|
|
81
|
+
/mk-review # Code quality review
|
|
82
|
+
/mk-debug # Debug issues
|
|
83
|
+
/mk-security # Security scan and audit
|
|
84
|
+
/mk-db # Database operations
|
|
85
|
+
/mk-docs # Generate documentation
|
|
86
|
+
/mk-git # Git operations
|
|
87
|
+
/mk-audit # Code archaeology chain: orientation, testing, heatmap, breaking-change analysis, technical debt, domain extraction
|
|
88
|
+
/mk-skill-creator # Create and scaffold new Claude Code skills with automated validation
|
|
89
|
+
/mk-selftest # Self-validation checks on kit agents, skills, docs, workflows
|
|
87
90
|
```
|
|
88
91
|
|
|
89
92
|
## Structure
|
|
@@ -91,8 +94,8 @@ cp -r .claude ~/.claude/
|
|
|
91
94
|
```
|
|
92
95
|
├── .claude/
|
|
93
96
|
│ ├── agents/ # 29 agents (5 primary + 24 utility: implementers, quality, docs, specialized, concerns)
|
|
94
|
-
│ ├── skills/ #
|
|
95
|
-
│ │ ├── mk-*/ #
|
|
97
|
+
│ ├── skills/ # 58 skill packages (SKILL.md + scripts/references/assets)
|
|
98
|
+
│ │ ├── mk-*/ # 16 workflow commands (/mk-audit, /mk-brainstorm, /mk-skill-creator, /mk-selftest, etc.)
|
|
96
99
|
│ │ └── ... # Domain skills (frontend, backend, testing, etc.)
|
|
97
100
|
│ └── workflows/ # Development protocols
|
|
98
101
|
├── bin/ # CLI entry point (mk command)
|
|
@@ -124,8 +127,8 @@ User → /mk-* command (skill) → spawns utility agents → agents use knowledg
|
|
|
124
127
|
| Command | Purpose |
|
|
125
128
|
|---------|---------|
|
|
126
129
|
| `/mk-init` | Full project bootstrap from conception to deployment; includes brownfield detection (Phase 0 gate) and adoption workflow (B1-B4.5 stages) |
|
|
127
|
-
| `/mk-brainstorm` | Ideation, requirements exploration, structured debate (analyzer opus agent)
|
|
128
|
-
| `/mk-
|
|
130
|
+
| `/mk-brainstorm` | Ideation, requirements exploration, structured debate (analyzer opus agent) |
|
|
131
|
+
| `/mk-audit` | Code archaeology chain: orientation report, characterization testing, topology heatmap, breaking-change analysis, technical debt dashboard, domain extraction |
|
|
129
132
|
| `/mk-plan` | Create implementation plans with phases and tasks (opus) |
|
|
130
133
|
| `/mk-design` | UI/UX wireframes, design systems, mockups |
|
|
131
134
|
| `/mk-implement` | End-to-end feature delivery (sonnet) |
|
|
@@ -136,6 +139,8 @@ User → /mk-* command (skill) → spawns utility agents → agents use knowledg
|
|
|
136
139
|
| `/mk-db` | Database operations: diagnose, optimize, design, migrate |
|
|
137
140
|
| `/mk-docs` | Generate and update project documentation |
|
|
138
141
|
| `/mk-git` | Git operations: branch, commit, push, PR, merge |
|
|
142
|
+
| `/mk-research` | Deep multi-source research on technical topics |
|
|
143
|
+
| `/mk-skill-creator` | Create and scaffold new Claude Code skills with automated SKILL.md, scripts, references, and agent |
|
|
139
144
|
| `/mk-selftest` | Run self-validation checks on kit agents, skills, docs, and workflows |
|
|
140
145
|
|
|
141
146
|
## Primary Agents
|
|
@@ -211,11 +216,12 @@ Each skill contains:
|
|
|
211
216
|
- `assets/` (optional) - Templates, images
|
|
212
217
|
|
|
213
218
|
```bash
|
|
214
|
-
#
|
|
215
|
-
|
|
219
|
+
# Create new skill (recommended)
|
|
220
|
+
/mk-skill-creator
|
|
216
221
|
|
|
217
|
-
#
|
|
218
|
-
.claude/skills/skill-creator/scripts/
|
|
222
|
+
# Or use scripts directly
|
|
223
|
+
.claude/skills/mk-skill-creator/scripts/init_skill.py <skill-name> --path <output-directory>
|
|
224
|
+
.claude/skills/mk-skill-creator/scripts/package_skill.py <path/to/skill-folder>
|
|
219
225
|
```
|
|
220
226
|
|
|
221
227
|
## Documentation
|
package/package.json
CHANGED
package/src/commands/update.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { createInterface } from 'node:readline';
|
|
3
|
-
import { existsSync, unlinkSync, copyFileSync, mkdirSync, readFileSync } from 'node:fs';
|
|
4
|
-
import { join, dirname, resolve } from 'node:path';
|
|
3
|
+
import { existsSync, unlinkSync, copyFileSync, mkdirSync, readFileSync, rmdirSync, readdirSync } from 'node:fs';
|
|
4
|
+
import { join, dirname, resolve, sep } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { readManifest, updateManifest, diffManifest } from '../lib/manifest.js';
|
|
7
7
|
import { computeChecksum } from '../lib/checksum.js';
|
|
8
|
-
import { copyKitFiles } from '../lib/copy.js';
|
|
8
|
+
import { copyKitFiles, collectDiskFiles } from '../lib/copy.js';
|
|
9
9
|
import { resolveTargetDir, resolveManifestPath, deriveProjectRoot, assertSafePath } from '../lib/paths.js';
|
|
10
10
|
import { resolveTokenOrLogin } from '../lib/auth.js';
|
|
11
11
|
import { writeToken, readStoredToken } from '../lib/config.js';
|
|
@@ -167,6 +167,58 @@ export async function runUpdate(params = {}) {
|
|
|
167
167
|
delete newFiles[relPath];
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
// Orphan cleanup: files on disk (in kit subdirs) that are not in the new source
|
|
171
|
+
const diskFiles = collectDiskFiles(targetDir);
|
|
172
|
+
const orphans = [];
|
|
173
|
+
const orphanParentDirs = new Set();
|
|
174
|
+
for (const relPath of diskFiles) {
|
|
175
|
+
if (relPath in sourceFiles) continue; // present in new source — keep
|
|
176
|
+
const absPath = join(projectRoot, relPath);
|
|
177
|
+
try {
|
|
178
|
+
assertSafePath(absPath, claudeRoot, `orphan "${relPath}"`);
|
|
179
|
+
} catch (err) {
|
|
180
|
+
process.stderr.write(`Warning: Skipping unsafe orphan path: ${err.message}\n`);
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
unlinkSync(absPath);
|
|
185
|
+
orphans.push(relPath);
|
|
186
|
+
orphanParentDirs.add(dirname(absPath));
|
|
187
|
+
} catch {
|
|
188
|
+
// Already missing — skip
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Clean up empty directories bottom-up after orphan deletion
|
|
193
|
+
const resolvedTarget = resolve(targetDir);
|
|
194
|
+
const sortedOrphanDirs = [...orphanParentDirs].sort((a, b) => {
|
|
195
|
+
return b.split(/[/\\]/).length - a.split(/[/\\]/).length;
|
|
196
|
+
});
|
|
197
|
+
for (const dir of sortedOrphanDirs) {
|
|
198
|
+
if (isEmptyDir(dir)) {
|
|
199
|
+
try {
|
|
200
|
+
rmdirSync(dir);
|
|
201
|
+
let current = dirname(dir);
|
|
202
|
+
let prev = dir;
|
|
203
|
+
while (current !== prev && isEmptyDir(current)) {
|
|
204
|
+
const resolvedCurrent = resolve(current);
|
|
205
|
+
if (resolvedCurrent === resolvedTarget || !resolvedCurrent.startsWith(resolvedTarget + sep)) {
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
try {
|
|
209
|
+
rmdirSync(current);
|
|
210
|
+
} catch {
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
prev = current;
|
|
214
|
+
current = dirname(current);
|
|
215
|
+
}
|
|
216
|
+
} catch {
|
|
217
|
+
// Non-empty or permission error — skip
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
170
222
|
// Update manifest with new file map.
|
|
171
223
|
// Use explicitVersion when provided (e.g. release.version from updateAction);
|
|
172
224
|
// fall back to pkg.version for direct runUpdate calls or main-branch fallback downloads.
|
|
@@ -178,10 +230,24 @@ export async function runUpdate(params = {}) {
|
|
|
178
230
|
removed: diff.removed,
|
|
179
231
|
conflicts: skippedConflicts,
|
|
180
232
|
unchanged: diff.unchanged,
|
|
233
|
+
orphans,
|
|
181
234
|
upToDate: false
|
|
182
235
|
};
|
|
183
236
|
}
|
|
184
237
|
|
|
238
|
+
/**
|
|
239
|
+
* Check if a directory is empty.
|
|
240
|
+
* @param {string} dir
|
|
241
|
+
* @returns {boolean}
|
|
242
|
+
*/
|
|
243
|
+
function isEmptyDir(dir) {
|
|
244
|
+
try {
|
|
245
|
+
return readdirSync(dir).length === 0;
|
|
246
|
+
} catch {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
185
251
|
/**
|
|
186
252
|
* CLI action handler for 'mk update'.
|
|
187
253
|
* Checks GitHub Releases for a newer version, prompts the user, then downloads
|
|
@@ -305,6 +371,15 @@ export async function updateAction(options = {}, deps = {}) {
|
|
|
305
371
|
}
|
|
306
372
|
if (result.removed.length > 0) {
|
|
307
373
|
process.stdout.write(chalk.yellow(`Removed: ${result.removed.length} files\n`));
|
|
374
|
+
for (const f of result.removed) {
|
|
375
|
+
process.stdout.write(` Removed: ${f}\n`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
if (result.orphans && result.orphans.length > 0) {
|
|
379
|
+
process.stdout.write(chalk.yellow(`Cleaned: ${result.orphans.length} orphan files\n`));
|
|
380
|
+
for (const f of result.orphans) {
|
|
381
|
+
process.stdout.write(` Cleaned: ${f}\n`);
|
|
382
|
+
}
|
|
308
383
|
}
|
|
309
384
|
if (result.conflicts.length > 0) {
|
|
310
385
|
process.stdout.write(
|
package/src/lib/constants.js
CHANGED
package/src/lib/copy.js
CHANGED
|
@@ -52,6 +52,31 @@ function collectFiles(dir) {
|
|
|
52
52
|
return results;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Collect all kit-managed files currently on disk under targetDir (.claude/).
|
|
57
|
+
* Only walks KIT_SUBDIRS (agents/, skills/, workflows/).
|
|
58
|
+
* Returns relative paths in the form `.claude/agents/foo.md`.
|
|
59
|
+
* Applies shouldFilter to exclude filtered patterns.
|
|
60
|
+
*
|
|
61
|
+
* @param {string} targetDir - Absolute path to target .claude/
|
|
62
|
+
* @returns {string[]} relative paths (relative to project root, e.g. `.claude/agents/foo.md`)
|
|
63
|
+
*/
|
|
64
|
+
export function collectDiskFiles(targetDir) {
|
|
65
|
+
const results = [];
|
|
66
|
+
for (const subdir of KIT_SUBDIRS) {
|
|
67
|
+
const subdirAbs = join(targetDir, subdir);
|
|
68
|
+
if (!existsSync(subdirAbs)) continue;
|
|
69
|
+
const files = collectFiles(subdirAbs);
|
|
70
|
+
for (const absPath of files) {
|
|
71
|
+
if (shouldFilter(absPath)) continue;
|
|
72
|
+
const relFromSubdir = relative(subdirAbs, absPath);
|
|
73
|
+
const relPath = join('.claude', subdir, relFromSubdir).replace(/\\/g, '/');
|
|
74
|
+
results.push(relPath);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return results;
|
|
78
|
+
}
|
|
79
|
+
|
|
55
80
|
/**
|
|
56
81
|
* Copy kit files from sourceDir (.claude/) to targetDir (.claude/).
|
|
57
82
|
* Only copies KIT_SUBDIRS (agents/, skills/, workflows/).
|