@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 CHANGED
@@ -73,17 +73,20 @@ cp -r .claude ~/.claude/
73
73
 
74
74
  ```bash
75
75
  # Use a workflow command
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
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/ # 53 skill packages (SKILL.md + scripts/references/assets)
95
- │ │ ├── mk-*/ # 14 workflow commands (/mk-brainstorm, /mk-selftest, etc.)
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); use `--domain` flag to extract and document domain knowledge |
128
- | `/mk-research` | Deep multi-source research on technical topics |
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
- # Initialize new skill
215
- .claude/skills/skill-creator/scripts/init_skill.py <skill-name> --path <output-directory>
219
+ # Create new skill (recommended)
220
+ /mk-skill-creator
216
221
 
217
- # Package for distribution
218
- .claude/skills/skill-creator/scripts/package_skill.py <path/to/skill-folder>
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanhcan148/mk",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "CLI to install and manage MyClaudeKit (.claude/) in your projects",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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(
@@ -13,6 +13,7 @@ export const MANIFEST_FILENAME = '.mk-manifest.json';
13
13
  */
14
14
  export const COPY_FILTER_PATTERNS = [
15
15
  '__pycache__',
16
+ '.pytest_cache',
16
17
  '.pyc',
17
18
  '.pyo',
18
19
  'node_modules',
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/).