sumulige-claude 1.2.0 → 1.3.0

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 (77) hide show
  1. package/.claude/.kickoff-hint.txt +3 -2
  2. package/.claude/AGENTS.md +6 -6
  3. package/.claude/CLAUDE.md +138 -0
  4. package/.claude/README.md +234 -43
  5. package/.claude/USAGE.md +175 -0
  6. package/.claude/boris-optimizations.md +167 -0
  7. package/.claude/commands/fix.md +83 -0
  8. package/.claude/commands/plan.md +88 -0
  9. package/.claude/commands/refactor.md +102 -0
  10. package/.claude/commands/todos.md +6 -41
  11. package/.claude/hooks/code-formatter.cjs +2 -7
  12. package/.claude/hooks/conversation-logger.cjs +222 -0
  13. package/.claude/hooks/multi-session.cjs +3 -9
  14. package/.claude/hooks/pre-push.cjs +3 -2
  15. package/.claude/hooks/project-kickoff.cjs +198 -20
  16. package/.claude/hooks/rag-skill-loader.cjs +0 -7
  17. package/.claude/hooks/session-restore.cjs +0 -0
  18. package/.claude/hooks/session-save.cjs +0 -0
  19. package/.claude/hooks/thinking-silent.cjs +3 -9
  20. package/.claude/hooks/todo-manager.cjs +142 -269
  21. package/.claude/hooks/verify-work.cjs +4 -10
  22. package/.claude/rag/skill-index.json +147 -8
  23. package/.claude/rules/coding-style.md +119 -0
  24. package/.claude/rules/hooks.md +288 -0
  25. package/.claude/rules/performance.md +78 -0
  26. package/.claude/rules/security.md +56 -0
  27. package/.claude/rules/testing.md +89 -0
  28. package/.claude/settings.json +115 -0
  29. package/.claude/settings.local.json +19 -1
  30. package/.claude/skills/SKILLS.md +145 -0
  31. package/.claude/skills/design-brain/SKILL.md +190 -0
  32. package/.claude/skills/design-brain/metadata.yaml +26 -0
  33. package/.claude/skills/examples/README.md +47 -0
  34. package/.claude/skills/examples/basic-task.md +67 -0
  35. package/.claude/skills/examples/bug-fix-workflow.md +92 -0
  36. package/.claude/skills/examples/feature-development.md +81 -0
  37. package/.claude/skills/manus-kickoff/SKILL.md +128 -0
  38. package/.claude/skills/manus-kickoff/examples/basic.md +84 -0
  39. package/.claude/skills/manus-kickoff/metadata.yaml +33 -0
  40. package/.claude/skills/manus-kickoff/templates/PROJECT_KICKOFF.md +89 -0
  41. package/.claude/skills/manus-kickoff/templates/PROJECT_PROPOSAL.md +227 -0
  42. package/.claude/skills/manus-kickoff/templates/TASK_PLAN.md +121 -0
  43. package/.claude/skills/quality-guard/SKILL.md +138 -0
  44. package/.claude/skills/quality-guard/metadata.yaml +27 -0
  45. package/.claude/skills/quick-fix/SKILL.md +138 -0
  46. package/.claude/skills/quick-fix/metadata.yaml +26 -0
  47. package/.claude/skills/test-master/SKILL.md +186 -0
  48. package/.claude/skills/test-master/metadata.yaml +29 -0
  49. package/.claude/templates/PROJECT_KICKOFF.md +89 -0
  50. package/.claude/templates/PROJECT_PROPOSAL.md +227 -0
  51. package/.claude/templates/TASK_PLAN.md +121 -0
  52. package/.claude-plugin/marketplace.json +2 -2
  53. package/AGENTS.md +49 -7
  54. package/CHANGELOG.md +56 -2
  55. package/CLAUDE-template.md +114 -0
  56. package/README.md +73 -1
  57. package/config/official-skills.json +2 -2
  58. package/development/knowledge-base/.index.clean.json +1 -0
  59. package/jest.config.js +3 -1
  60. package/lib/commands.js +1626 -1207
  61. package/lib/marketplace.js +1 -0
  62. package/package.json +1 -1
  63. package/project-paradigm.md +313 -0
  64. package/prompts/how-to-find.md +163 -0
  65. package/tests/commands.test.js +940 -17
  66. package/tests/config-schema.test.js +425 -0
  67. package/tests/marketplace.test.js +330 -214
  68. package/tests/sync-external.test.js +214 -0
  69. package/tests/update-registry.test.js +251 -0
  70. package/tests/utils.test.js +12 -8
  71. package/tests/web-search.test.js +392 -0
  72. package/thinkinglens-silent.md +138 -0
  73. package/.claude/skills/api-tester/SKILL.md +0 -90
  74. package/.claude/skills/api-tester/examples/basic.md +0 -3
  75. package/.claude/skills/api-tester/metadata.yaml +0 -30
  76. package/.claude/skills/api-tester/templates/default.md +0 -3
  77. package/.claude/skills/template/SKILL.md +0 -6
package/lib/commands.js CHANGED
@@ -4,15 +4,22 @@
4
4
  * Extracted from cli.js for better organization
5
5
  */
6
6
 
7
- const fs = require('fs');
8
- const path = require('path');
9
- const { execSync } = require('child_process');
10
- const { loadConfig, CONFIG_DIR, CONFIG_FILE, SKILLS_DIR, ensureDir, saveConfig } = require('./config');
11
- const { copyRecursive, toTitleCase, CopyMode } = require('./utils');
12
- const { runMigrations, TEMPLATE_VERSION } = require('./migrations');
13
- const { checkUpdate, getCurrentVersion } = require('./version-check');
14
-
15
- const TEMPLATE_DIR = path.join(__dirname, '../template');
7
+ const fs = require("fs");
8
+ const path = require("path");
9
+ const { execSync } = require("child_process");
10
+ const {
11
+ loadConfig,
12
+ CONFIG_DIR,
13
+ CONFIG_FILE,
14
+ SKILLS_DIR,
15
+ ensureDir,
16
+ saveConfig,
17
+ } = require("./config");
18
+ const { copyRecursive, toTitleCase, CopyMode } = require("./utils");
19
+ const { runMigrations, TEMPLATE_VERSION } = require("./migrations");
20
+ const { checkUpdate, getCurrentVersion } = require("./version-check");
21
+
22
+ const TEMPLATE_DIR = path.join(__dirname, "../template");
16
23
 
17
24
  // ============================================================================
18
25
  // Helper Functions
@@ -30,7 +37,11 @@ function countFiles(dirPath) {
30
37
  const fullPath = path.join(dirPath, entry.name);
31
38
  if (entry.isDirectory()) {
32
39
  // Skip certain directories
33
- if (entry.name !== 'node_modules' && entry.name !== '.git' && entry.name !== 'sessions') {
40
+ if (
41
+ entry.name !== "node_modules" &&
42
+ entry.name !== ".git" &&
43
+ entry.name !== "sessions"
44
+ ) {
34
45
  count += countFiles(fullPath);
35
46
  }
36
47
  } else {
@@ -76,8 +87,15 @@ function copySingleFile(srcPath, destPath, mode, backupDir, displayName) {
76
87
  case CopyMode.BACKUP:
77
88
  default:
78
89
  // Backup then overwrite
79
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('T')[0];
80
- const backupFileName = path.basename(destPath).replace(/\.[^.]+$/, '') + '.' + timestamp + '.bak';
90
+ const timestamp = new Date()
91
+ .toISOString()
92
+ .replace(/[:.]/g, "-")
93
+ .split("T")[0];
94
+ const backupFileName =
95
+ path.basename(destPath).replace(/\.[^.]+$/, "") +
96
+ "." +
97
+ timestamp +
98
+ ".bak";
81
99
  const backupPath = path.join(backupDir, backupFileName);
82
100
 
83
101
  fs.mkdirSync(backupDir, { recursive: true });
@@ -96,7 +114,7 @@ function copySingleFile(srcPath, destPath, mode, backupDir, displayName) {
96
114
  * @param {string} filePath - File path
97
115
  */
98
116
  function setExecutablePermission(filePath) {
99
- if (filePath.endsWith('.sh') || filePath.endsWith('.cjs')) {
117
+ if (filePath.endsWith(".sh") || filePath.endsWith(".cjs")) {
100
118
  try {
101
119
  fs.chmodSync(filePath, 0o755);
102
120
  } catch (e) {
@@ -112,13 +130,13 @@ function setExecutablePermission(filePath) {
112
130
  const commands = {
113
131
  // -------------------------------------------------------------------------
114
132
  init: (...args) => {
115
- const isInteractive = args.includes('--interactive') || args.includes('-i');
133
+ const isInteractive = args.includes("--interactive") || args.includes("-i");
116
134
 
117
135
  if (isInteractive) {
118
- return commands['init:interactive']();
136
+ return commands["init:interactive"]();
119
137
  }
120
138
 
121
- console.log('🚀 Initializing Sumulige Claude...');
139
+ console.log("🚀 Initializing Sumulige Claude...");
122
140
 
123
141
  // Create config directory
124
142
  ensureDir(CONFIG_DIR);
@@ -126,36 +144,38 @@ const commands = {
126
144
  // Create config file
127
145
  if (!fs.existsSync(CONFIG_FILE)) {
128
146
  saveConfig(loadConfig());
129
- console.log('✅ Created config:', CONFIG_FILE);
147
+ console.log("✅ Created config:", CONFIG_FILE);
130
148
  } else {
131
- console.log('ℹ️ Config already exists:', CONFIG_FILE);
149
+ console.log("ℹ️ Config already exists:", CONFIG_FILE);
132
150
  }
133
151
 
134
152
  // Create skills directory
135
153
  ensureDir(SKILLS_DIR);
136
- console.log('✅ Created skills directory:', SKILLS_DIR);
154
+ console.log("✅ Created skills directory:", SKILLS_DIR);
137
155
 
138
156
  // Install openskills if not installed
139
157
  try {
140
- execSync('openskills --version', { stdio: 'ignore' });
141
- console.log('✅ OpenSkills already installed');
158
+ execSync("openskills --version", { stdio: "ignore" });
159
+ console.log("✅ OpenSkills already installed");
142
160
  } catch {
143
- console.log('📦 Installing OpenSkills...');
161
+ console.log("📦 Installing OpenSkills...");
144
162
  try {
145
- execSync('npm i -g openskills', { stdio: 'inherit' });
146
- console.log('✅ OpenSkills installed');
163
+ execSync("npm i -g openskills", { stdio: "inherit" });
164
+ console.log("✅ OpenSkills installed");
147
165
  } catch (e) {
148
- console.log('⚠️ Failed to install OpenSkills. Run: npm i -g openskills');
166
+ console.log(
167
+ "⚠️ Failed to install OpenSkills. Run: npm i -g openskills",
168
+ );
149
169
  }
150
170
  }
151
171
 
152
- console.log('');
153
- console.log('🎉 Sumulige Claude initialized!');
154
- console.log('');
155
- console.log('Next steps:');
156
- console.log(' smc sync # Sync to current project');
157
- console.log(' smc skills:official # View available skills');
158
- console.log(' smc init --interactive # Interactive setup');
172
+ console.log("");
173
+ console.log("🎉 Sumulige Claude initialized!");
174
+ console.log("");
175
+ console.log("Next steps:");
176
+ console.log(" smc sync # Sync to current project");
177
+ console.log(" smc skills:official # View available skills");
178
+ console.log(" smc init --interactive # Interactive setup");
159
179
  },
160
180
 
161
181
  // -------------------------------------------------------------------------
@@ -170,155 +190,160 @@ const commands = {
170
190
  },
171
191
 
172
192
  // -------------------------------------------------------------------------
173
- 'init:interactive': () => {
174
- const readline = require('readline');
193
+ "init:interactive": () => {
194
+ const readline = require("readline");
175
195
  const COLORS = {
176
- reset: '\x1b[0m',
177
- green: '\x1b[32m',
178
- blue: '\x1b[34m',
179
- yellow: '\x1b[33m',
180
- gray: '\x1b[90m',
181
- cyan: '\x1b[36m'
196
+ reset: "\x1b[0m",
197
+ green: "\x1b[32m",
198
+ blue: "\x1b[34m",
199
+ yellow: "\x1b[33m",
200
+ gray: "\x1b[90m",
201
+ cyan: "\x1b[36m",
182
202
  };
183
203
 
184
- const log = (msg, color = 'reset') => {
204
+ const log = (msg, color = "reset") => {
185
205
  console.log(`${COLORS[color]}${msg}${COLORS.reset}`);
186
206
  };
187
207
 
188
208
  const rl = readline.createInterface({
189
209
  input: process.stdin,
190
- output: process.stdout
210
+ output: process.stdout,
191
211
  });
192
212
 
193
213
  const question = (prompt) => {
194
- return new Promise(resolve => {
214
+ return new Promise((resolve) => {
195
215
  rl.question(prompt, resolve);
196
216
  });
197
217
  };
198
218
 
199
219
  (async () => {
200
- log('', 'gray');
201
- log('🎯 SMC Interactive Setup', 'blue');
202
- log('=====================================', 'gray');
203
- log('', 'gray');
220
+ log("", "gray");
221
+ log("🎯 SMC Interactive Setup", "blue");
222
+ log("=====================================", "gray");
223
+ log("", "gray");
204
224
 
205
225
  // Step 1: Create config
206
- log('Step 1: Configuration', 'cyan');
226
+ log("Step 1: Configuration", "cyan");
207
227
  ensureDir(CONFIG_DIR);
208
228
  if (!fs.existsSync(CONFIG_FILE)) {
209
229
  saveConfig(loadConfig());
210
- log('✅ Created config', 'green');
230
+ log("✅ Created config", "green");
211
231
  } else {
212
- log('✅ Config exists', 'green');
232
+ log("✅ Config exists", "green");
213
233
  }
214
- log('', 'gray');
234
+ log("", "gray");
215
235
 
216
236
  // Step 2: Install OpenSkills
217
- log('Step 2: OpenSkills', 'cyan');
237
+ log("Step 2: OpenSkills", "cyan");
218
238
  try {
219
- execSync('openskills --version', { stdio: 'ignore' });
220
- log('✅ OpenSkills already installed', 'green');
239
+ execSync("openskills --version", { stdio: "ignore" });
240
+ log("✅ OpenSkills already installed", "green");
221
241
  } catch {
222
- log('Installing OpenSkills...', 'gray');
242
+ log("Installing OpenSkills...", "gray");
223
243
  try {
224
- execSync('npm i -g openskills', { stdio: 'pipe' });
225
- log('✅ OpenSkills installed', 'green');
244
+ execSync("npm i -g openskills", { stdio: "pipe" });
245
+ log("✅ OpenSkills installed", "green");
226
246
  } catch (e) {
227
- log('⚠️ Failed to install OpenSkills', 'yellow');
247
+ log("⚠️ Failed to install OpenSkills", "yellow");
228
248
  }
229
249
  }
230
- log('', 'gray');
250
+ log("", "gray");
231
251
 
232
252
  // Step 3: Select skills to install
233
- log('Step 3: Choose Skills to Install', 'cyan');
234
- log('', 'gray');
235
- log('Available skill groups:', 'gray');
236
- log(' 1. 📄 Documents (docx, pdf, pptx, xlsx)', 'gray');
237
- log(' 2. 🎨 Creative (frontend-design, algorithmic-art)', 'gray');
238
- log(' 3. 🛠️ Development (mcp-builder, webapp-testing)', 'gray');
239
- log(' 4. 📋 Workflow (doc-coauthoring, internal-comms)', 'gray');
240
- log(' 5. ✨ All recommended skills', 'gray');
241
- log(' 6. ⏭️ Skip skill installation', 'gray');
242
- log('', 'gray');
243
-
244
- const skillChoice = await question('Select (1-6) [default: 6]: ');
253
+ log("Step 3: Choose Skills to Install", "cyan");
254
+ log("", "gray");
255
+ log("Available skill groups:", "gray");
256
+ log(" 1. 📄 Documents (docx, pdf, pptx, xlsx)", "gray");
257
+ log(" 2. 🎨 Creative (frontend-design, algorithmic-art)", "gray");
258
+ log(" 3. 🛠️ Development (mcp-builder, webapp-testing)", "gray");
259
+ log(" 4. 📋 Workflow (doc-coauthoring, internal-comms)", "gray");
260
+ log(" 5. ✨ All recommended skills", "gray");
261
+ log(" 6. ⏭️ Skip skill installation", "gray");
262
+ log("", "gray");
263
+
264
+ const skillChoice = await question("Select (1-6) [default: 6]: ");
245
265
 
246
266
  const installSkills = async (source) => {
247
267
  try {
248
- execSync(`openskills install ${source} -y`, { stdio: 'pipe' });
249
- execSync('openskills sync -y', { stdio: 'pipe' });
250
- log('✅ Skills installed', 'green');
268
+ execSync(`openskills install ${source} -y`, { stdio: "pipe" });
269
+ execSync("openskills sync -y", { stdio: "pipe" });
270
+ log("✅ Skills installed", "green");
251
271
  } catch (e) {
252
- log('⚠️ Skill installation failed', 'yellow');
272
+ log("⚠️ Skill installation failed", "yellow");
253
273
  }
254
274
  };
255
275
 
256
276
  switch (skillChoice.trim()) {
257
- case '1':
258
- log('Installing document skills...', 'gray');
259
- await installSkills('anthropics/skills');
277
+ case "1":
278
+ log("Installing document skills...", "gray");
279
+ await installSkills("anthropics/skills");
260
280
  break;
261
- case '2':
262
- log('Installing creative skills...', 'gray');
263
- await installSkills('anthropics/skills');
281
+ case "2":
282
+ log("Installing creative skills...", "gray");
283
+ await installSkills("anthropics/skills");
264
284
  break;
265
- case '3':
266
- log('Installing development skills...', 'gray');
267
- await installSkills('anthropics/skills');
285
+ case "3":
286
+ log("Installing development skills...", "gray");
287
+ await installSkills("anthropics/skills");
268
288
  break;
269
- case '4':
270
- log('Installing workflow skills...', 'gray');
271
- await installSkills('anthropics/skills');
289
+ case "4":
290
+ log("Installing workflow skills...", "gray");
291
+ await installSkills("anthropics/skills");
272
292
  break;
273
- case '5':
274
- log('Installing all recommended skills...', 'gray');
275
- await installSkills('anthropics/skills');
293
+ case "5":
294
+ log("Installing all recommended skills...", "gray");
295
+ await installSkills("anthropics/skills");
276
296
  break;
277
297
  default:
278
- log('⏭️ Skipped skill installation', 'yellow');
298
+ log("⏭️ Skipped skill installation", "yellow");
279
299
  break;
280
300
  }
281
- log('', 'gray');
301
+ log("", "gray");
282
302
 
283
303
  // Step 4: Sync to current project
284
- log('Step 4: Sync to Current Project', 'cyan');
285
- const shouldSync = await question('Sync .claude/ to current directory? [Y/n]: ');
286
- if (shouldSync.toLowerCase() !== 'n') {
304
+ log("Step 4: Sync to Current Project", "cyan");
305
+ const shouldSync = await question(
306
+ "Sync .claude/ to current directory? [Y/n]: ",
307
+ );
308
+ if (shouldSync.toLowerCase() !== "n") {
287
309
  try {
288
- execSync('smc sync', { stdio: 'inherit' });
310
+ execSync("smc sync", { stdio: "inherit" });
289
311
  } catch (e) {
290
- log('⚠️ Sync failed (this is normal if not in a project directory)', 'yellow');
312
+ log(
313
+ "⚠️ Sync failed (this is normal if not in a project directory)",
314
+ "yellow",
315
+ );
291
316
  }
292
317
  } else {
293
- log('⏭️ Skipped sync', 'yellow');
318
+ log("⏭️ Skipped sync", "yellow");
294
319
  }
295
- log('', 'gray');
320
+ log("", "gray");
296
321
 
297
322
  rl.close();
298
323
 
299
- log('=====================================', 'gray');
300
- log('🎉 Setup complete!', 'green');
301
- log('', 'gray');
302
- log('Useful commands:', 'gray');
303
- log(' smc status Show configuration status', 'gray');
304
- log(' smc skills:official List available skills', 'gray');
305
- log(' smc doctor Check system health', 'gray');
306
- log('', 'gray');
324
+ log("=====================================", "gray");
325
+ log("🎉 Setup complete!", "green");
326
+ log("", "gray");
327
+ log("Useful commands:", "gray");
328
+ log(" smc status Show configuration status", "gray");
329
+ log(" smc skills:official List available skills", "gray");
330
+ log(" smc doctor Check system health", "gray");
331
+ log("", "gray");
307
332
  })();
308
333
  },
309
334
 
310
335
  // -------------------------------------------------------------------------
311
336
  sync: async (...args) => {
312
- const forceCheckUpdate = args.includes('--check-update');
337
+ const forceCheckUpdate = args.includes("--check-update");
313
338
 
314
- console.log('🔄 Syncing Sumulige Claude to current project...');
315
- console.log('');
339
+ console.log("🔄 Syncing Sumulige Claude to current project...");
340
+ console.log("");
316
341
 
317
342
  const projectDir = process.cwd();
318
- const projectConfigDir = path.join(projectDir, '.claude');
319
- const agentsFile = path.join(projectConfigDir, 'AGENTS.md');
320
- const readmeFile = path.join(projectConfigDir, 'README.md');
321
- const templateReadme = path.join(TEMPLATE_DIR, '.claude', 'README.md');
343
+ const projectConfigDir = path.join(projectDir, ".claude");
344
+ const agentsFile = path.join(projectConfigDir, "AGENTS.md");
345
+ const readmeFile = path.join(projectConfigDir, "README.md");
346
+ const templateReadme = path.join(TEMPLATE_DIR, ".claude", "README.md");
322
347
 
323
348
  // Create .claude directory
324
349
  ensureDir(projectConfigDir);
@@ -327,13 +352,13 @@ const commands = {
327
352
  const result = runMigrations(projectDir);
328
353
  if (result.migrations.length > 0) {
329
354
  console.log(`📦 Migrating project template → v${TEMPLATE_VERSION}`);
330
- result.migrations.forEach(m => {
355
+ result.migrations.forEach((m) => {
331
356
  console.log(` ✅ ${m.description}`);
332
357
  });
333
- console.log('');
358
+ console.log("");
334
359
  }
335
360
 
336
- console.log('✅ Created .claude directory');
361
+ console.log("✅ Created .claude directory");
337
362
 
338
363
  // Sync config
339
364
  const config = loadConfig();
@@ -341,17 +366,19 @@ const commands = {
341
366
  // Generate AGENTS.md
342
367
  const agentsMd = generateAgentsMd(config);
343
368
  fs.writeFileSync(agentsFile, agentsMd);
344
- console.log('✅ Created AGENTS.md');
369
+ console.log("✅ Created AGENTS.md");
345
370
 
346
371
  // Silently sync README.md if template updated
347
372
  if (fs.existsSync(templateReadme)) {
348
- const templateContent = fs.readFileSync(templateReadme, 'utf-8');
373
+ const templateContent = fs.readFileSync(templateReadme, "utf-8");
349
374
  let needsUpdate = true;
350
375
 
351
376
  if (fs.existsSync(readmeFile)) {
352
- const existingContent = fs.readFileSync(readmeFile, 'utf-8');
353
- const templateVersion = templateContent.match(/@version:\s*(\d+\.\d+\.\d+)/)?.[1] || '0.0.0';
354
- const existingVersion = existingContent.match(/@version:\s*(\d+\.\d+\.\d+)/)?.[1] || '0.0.0';
377
+ const existingContent = fs.readFileSync(readmeFile, "utf-8");
378
+ const templateVersion =
379
+ templateContent.match(/@version:\s*(\d+\.\d+\.\d+)/)?.[1] || "0.0.0";
380
+ const existingVersion =
381
+ existingContent.match(/@version:\s*(\d+\.\d+\.\d+)/)?.[1] || "0.0.0";
355
382
  needsUpdate = templateVersion !== existingVersion;
356
383
  }
357
384
 
@@ -361,8 +388,8 @@ const commands = {
361
388
  }
362
389
 
363
390
  // Sync todos directory structure
364
- const todosTemplateDir = path.join(TEMPLATE_DIR, 'development', 'todos');
365
- const todosProjectDir = path.join(projectDir, 'development', 'todos');
391
+ const todosTemplateDir = path.join(TEMPLATE_DIR, "development", "todos");
392
+ const todosProjectDir = path.join(projectDir, "development", "todos");
366
393
 
367
394
  if (fs.existsSync(todosTemplateDir)) {
368
395
  copyRecursive(todosTemplateDir, todosProjectDir);
@@ -370,14 +397,14 @@ const commands = {
370
397
 
371
398
  // Sync skills
372
399
  try {
373
- execSync('openskills sync -y', { stdio: 'pipe' });
374
- console.log('✅ Synced skills');
400
+ execSync("openskills sync -y", { stdio: "pipe" });
401
+ console.log("✅ Synced skills");
375
402
  } catch (e) {
376
- console.log('⚠️ Failed to sync skills');
403
+ console.log("⚠️ Failed to sync skills");
377
404
  }
378
405
 
379
- console.log('');
380
- console.log('✅ Sync complete!');
406
+ console.log("");
407
+ console.log("✅ Sync complete!");
381
408
 
382
409
  // Check for updates (sync is already a network operation)
383
410
  await checkUpdate({ force: forceCheckUpdate, silent: false });
@@ -385,168 +412,211 @@ const commands = {
385
412
 
386
413
  // -------------------------------------------------------------------------
387
414
  migrate: () => {
388
- console.log('🔧 Migrating project to latest format...');
389
- console.log('');
415
+ console.log("🔧 Migrating project to latest format...");
416
+ console.log("");
390
417
 
391
418
  const projectDir = process.cwd();
392
- const settingsFile = path.join(projectDir, '.claude', 'settings.json');
419
+ const settingsFile = path.join(projectDir, ".claude", "settings.json");
393
420
 
394
421
  if (!fs.existsSync(settingsFile)) {
395
- console.log('⚠️ No settings.json found in .claude/');
396
- console.log(' Run: smc template');
422
+ console.log("⚠️ No settings.json found in .claude/");
423
+ console.log(" Run: smc template");
397
424
  return;
398
425
  }
399
426
 
400
427
  let settings;
401
428
  try {
402
- settings = JSON.parse(fs.readFileSync(settingsFile, 'utf-8'));
429
+ settings = JSON.parse(fs.readFileSync(settingsFile, "utf-8"));
403
430
  } catch (e) {
404
- console.log('❌ Invalid JSON in settings.json');
431
+ console.log("❌ Invalid JSON in settings.json");
405
432
  return;
406
433
  }
407
434
 
408
435
  // 检测旧格式
409
- const isOldFormat = settings.matcher || (settings.hooks && typeof settings.hooks === 'object');
436
+ const isOldFormat =
437
+ settings.matcher ||
438
+ (settings.hooks && typeof settings.hooks === "object");
410
439
 
411
440
  if (!isOldFormat) {
412
- console.log('✅ Already using latest format');
441
+ console.log("✅ Already using latest format");
413
442
  return;
414
443
  }
415
444
 
416
445
  // 读取新模板
417
- const templateSettings = path.join(TEMPLATE_DIR, '.claude', 'settings.json');
446
+ const templateSettings = path.join(
447
+ TEMPLATE_DIR,
448
+ ".claude",
449
+ "settings.json",
450
+ );
418
451
  if (!fs.existsSync(templateSettings)) {
419
- console.log('❌ Template settings.json not found');
452
+ console.log("❌ Template settings.json not found");
420
453
  return;
421
454
  }
422
455
 
423
- const newSettings = fs.readFileSync(templateSettings, 'utf-8');
456
+ const newSettings = fs.readFileSync(templateSettings, "utf-8");
424
457
  fs.writeFileSync(settingsFile, newSettings);
425
458
 
426
- console.log('✅ Migrated settings.json to latest format');
427
- console.log('');
428
- console.log('Changes:');
459
+ console.log("✅ Migrated settings.json to latest format");
460
+ console.log("");
461
+ console.log("Changes:");
429
462
  console.log(' - Old format: {"matcher": "...", "hooks": [...]}');
430
- console.log(' - New format: {"UserPromptSubmit": [...], "PostToolUse": [...]}');
431
- console.log('');
432
- console.log('ℹ️ Hooks will now work correctly!');
463
+ console.log(
464
+ ' - New format: {"UserPromptSubmit": [...], "PostToolUse": [...]}',
465
+ );
466
+ console.log("");
467
+ console.log("ℹ️ Hooks will now work correctly!");
433
468
  },
434
469
 
435
470
  // -------------------------------------------------------------------------
436
471
  agent: (task) => {
437
472
  if (!task) {
438
- console.log('Usage: sumulige-claude agent <task>');
439
- console.log('');
473
+ console.log("Usage: sumulige-claude agent <task>");
474
+ console.log("");
440
475
  console.log('Example: sumulige-claude agent "Build a React dashboard"');
441
476
  return;
442
477
  }
443
478
 
444
479
  const config = loadConfig();
445
- console.log('🤖 Starting Agent Orchestration...');
446
- console.log('');
447
- console.log('Task:', task);
448
- console.log('');
449
- console.log('Available Agents:');
480
+ console.log("🤖 Starting Agent Orchestration...");
481
+ console.log("");
482
+ console.log("Task:", task);
483
+ console.log("");
484
+ console.log("Available Agents:");
450
485
  Object.entries(config.agents).forEach(([name, agent]) => {
451
486
  const model = agent.model || config.model;
452
487
  console.log(` - ${name}: ${model} (${agent.role})`);
453
488
  });
454
- console.log('');
455
- console.log('💡 In Claude Code, use /skill <name> to invoke specific agent capabilities');
489
+ console.log("");
490
+ console.log(
491
+ "💡 In Claude Code, use /skill <name> to invoke specific agent capabilities",
492
+ );
456
493
  },
457
494
 
458
495
  // -------------------------------------------------------------------------
459
496
  status: () => {
460
497
  const config = loadConfig();
461
- console.log('📊 Sumulige Claude Status');
462
- console.log('');
463
- console.log('Config:', CONFIG_FILE);
464
- console.log('');
465
- console.log('Agents:');
498
+ console.log("📊 Sumulige Claude Status");
499
+ console.log("");
500
+ console.log("Config:", CONFIG_FILE);
501
+ console.log("");
502
+ console.log("Agents:");
466
503
  Object.entries(config.agents).forEach(([name, agent]) => {
467
504
  const model = agent.model || config.model;
468
505
  console.log(` ${name.padEnd(12)} ${model.padEnd(20)} (${agent.role})`);
469
506
  });
470
- console.log('');
471
- console.log('Skills:', config.skills.join(', '));
472
- console.log('');
473
- console.log('ThinkingLens:', config.thinkingLens.enabled ? '✅ Enabled' : '❌ Disabled');
474
- console.log('');
507
+ console.log("");
508
+ console.log("Skills:", config.skills.join(", "));
509
+ console.log("");
510
+ console.log(
511
+ "ThinkingLens:",
512
+ config.thinkingLens.enabled ? "✅ Enabled" : "❌ Disabled",
513
+ );
514
+ console.log("");
475
515
 
476
516
  // Show project todos status
477
517
  const projectDir = process.cwd();
478
- const todosIndex = path.join(projectDir, 'development', 'todos', 'INDEX.md');
518
+ const todosIndex = path.join(
519
+ projectDir,
520
+ "development",
521
+ "todos",
522
+ "INDEX.md",
523
+ );
479
524
 
480
525
  if (fs.existsSync(todosIndex)) {
481
- const content = fs.readFileSync(todosIndex, 'utf-8');
526
+ const content = fs.readFileSync(todosIndex, "utf-8");
482
527
 
483
528
  const totalMatch = content.match(/Total:\s+`([^`]+)`\s+(\d+)%/);
484
- const p0Match = content.match(/P0[^`]*`([^`]+)`\s+(\d+)%\s+\((\d+)\/(\d+)\)/);
485
- const p1Match = content.match(/P1[^`]*`([^`]+)`\s+(\d+)%\s+\((\d+)\/(\d+)\)/);
486
- const p2Match = content.match(/P2[^`]*`([^`]+)`\s+(\d+)%\s+\((\d+)\/(\d+)\)/);
529
+ const p0Match = content.match(
530
+ /P0[^`]*`([^`]+)`\s+(\d+)%\s+\((\d+)\/(\d+)\)/,
531
+ );
532
+ const p1Match = content.match(
533
+ /P1[^`]*`([^`]+)`\s+(\d+)%\s+\((\d+)\/(\d+)\)/,
534
+ );
535
+ const p2Match = content.match(
536
+ /P2[^`]*`([^`]+)`\s+(\d+)%\s+\((\d+)\/(\d+)\)/,
537
+ );
487
538
 
488
- const activeMatch = content.match(/\|\s+🚧 进行中[^|]*\|\s+`active\/`\s+\|\s+(\d+)/);
489
- const completedMatch = content.match(/\|\s+✅ 已完成[^|]*\|\s+`completed\/`\s+\|\s+(\d+)/);
490
- const backlogMatch = content.match(/\|\s+📋 待办[^|]*\|\s+`backlog\/`\s+\|\s+(\d+)/);
539
+ const activeMatch = content.match(
540
+ /\|\s+🚧 进行中[^|]*\|\s+`active\/`\s+\|\s+(\d+)/,
541
+ );
542
+ const completedMatch = content.match(
543
+ /\|\s+✅ 已完成[^|]*\|\s+`completed\/`\s+\|\s+(\d+)/,
544
+ );
545
+ const backlogMatch = content.match(
546
+ /\|\s+📋 待办[^|]*\|\s+`backlog\/`\s+\|\s+(\d+)/,
547
+ );
491
548
 
492
- console.log('📋 Project Tasks:');
493
- console.log('');
549
+ console.log("📋 Project Tasks:");
550
+ console.log("");
494
551
  if (totalMatch) {
495
552
  console.log(` Total: ${totalMatch[1]} ${totalMatch[2]}%`);
496
553
  }
497
554
  if (p0Match) {
498
- console.log(` P0: ${p0Match[1]} ${p0Match[2]}% (${p0Match[3]}/${p0Match[4]})`);
555
+ console.log(
556
+ ` P0: ${p0Match[1]} ${p0Match[2]}% (${p0Match[3]}/${p0Match[4]})`,
557
+ );
499
558
  }
500
559
  if (p1Match) {
501
- console.log(` P1: ${p1Match[1]} ${p1Match[2]}% (${p1Match[3]}/${p1Match[4]})`);
560
+ console.log(
561
+ ` P1: ${p1Match[1]} ${p1Match[2]}% (${p1Match[3]}/${p1Match[4]})`,
562
+ );
502
563
  }
503
564
  if (p2Match) {
504
- console.log(` P2: ${p2Match[1]} ${p2Match[2]}% (${p2Match[3]}/${p2Match[4]})`);
565
+ console.log(
566
+ ` P2: ${p2Match[1]} ${p2Match[2]}% (${p2Match[3]}/${p2Match[4]})`,
567
+ );
505
568
  }
506
- console.log('');
569
+ console.log("");
507
570
  console.log(` 🚧 Active: ${activeMatch ? activeMatch[1] : 0}`);
508
571
  console.log(` ✅ Completed: ${completedMatch ? completedMatch[1] : 0}`);
509
572
  console.log(` 📋 Backlog: ${backlogMatch ? backlogMatch[1] : 0}`);
510
- console.log('');
573
+ console.log("");
511
574
  console.log(` View: cat development/todos/INDEX.md`);
512
575
  } else {
513
- console.log('📋 Project Tasks: (not initialized)');
514
- console.log(' Run: node .claude/hooks/todo-manager.cjs --force');
576
+ console.log("📋 Project Tasks: (not initialized)");
577
+ console.log(" Run: node .claude/hooks/todo-manager.cjs --force");
515
578
  }
516
579
  },
517
580
 
518
581
  // -------------------------------------------------------------------------
519
- 'skill:list': () => {
582
+ "skill:list": () => {
520
583
  try {
521
- const result = execSync('openskills list', { encoding: 'utf-8' });
584
+ const result = execSync("openskills list", { encoding: "utf-8" });
522
585
  console.log(result);
523
586
  } catch (e) {
524
- console.log('⚠️ OpenSkills not installed. Run: npm i -g openskills');
587
+ console.log("⚠️ OpenSkills not installed. Run: npm i -g openskills");
525
588
  }
526
589
  },
527
590
 
528
591
  // -------------------------------------------------------------------------
529
- 'skill:create': (skillName) => {
592
+ "skill:create": (skillName) => {
530
593
  if (!skillName) {
531
- console.log('Usage: sumulige-claude skill:create <skill-name>');
532
- console.log('');
533
- console.log('Example: sumulige-claude skill:create api-tester');
534
- console.log('');
535
- console.log('The skill will be created at:');
536
- console.log(' .claude/skills/<skill-name>/');
594
+ console.log("Usage: sumulige-claude skill:create <skill-name>");
595
+ console.log("");
596
+ console.log("Example: sumulige-claude skill:create api-tester");
597
+ console.log("");
598
+ console.log("The skill will be created at:");
599
+ console.log(" .claude/skills/<skill-name>/");
537
600
  return;
538
601
  }
539
602
 
540
603
  // Validate skill name (kebab-case)
541
604
  if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(skillName)) {
542
- console.log('❌ Invalid skill name. Use kebab-case (e.g., api-tester, code-reviewer)');
605
+ console.log(
606
+ "❌ Invalid skill name. Use kebab-case (e.g., api-tester, code-reviewer)",
607
+ );
543
608
  return;
544
609
  }
545
610
 
546
611
  const projectDir = process.cwd();
547
- const skillsDir = path.join(projectDir, '.claude', 'skills');
612
+ const skillsDir = path.join(projectDir, ".claude", "skills");
548
613
  const skillDir = path.join(skillsDir, skillName);
549
- const templateDir = path.join(TEMPLATE_DIR, '.claude', 'skills', 'template');
614
+ const templateDir = path.join(
615
+ TEMPLATE_DIR,
616
+ ".claude",
617
+ "skills",
618
+ "template",
619
+ );
550
620
 
551
621
  // Check if skill already exists
552
622
  if (fs.existsSync(skillDir)) {
@@ -555,75 +625,80 @@ const commands = {
555
625
  }
556
626
 
557
627
  console.log(`📝 Creating skill: ${skillName}`);
558
- console.log('');
628
+ console.log("");
559
629
 
560
630
  // Create skill directory structure
561
- fs.mkdirSync(path.join(skillDir, 'templates'), { recursive: true });
562
- fs.mkdirSync(path.join(skillDir, 'examples'), { recursive: true });
563
- console.log('✅ Created directory structure');
631
+ fs.mkdirSync(path.join(skillDir, "templates"), { recursive: true });
632
+ fs.mkdirSync(path.join(skillDir, "examples"), { recursive: true });
633
+ console.log("✅ Created directory structure");
564
634
 
565
635
  // Copy template files
566
636
  if (fs.existsSync(templateDir)) {
567
- const skillTemplate = fs.readFileSync(path.join(templateDir, 'SKILL.md'), 'utf-8');
568
- const metadataTemplate = fs.readFileSync(path.join(templateDir, 'metadata.yaml'), 'utf-8');
637
+ const skillTemplate = fs.readFileSync(
638
+ path.join(templateDir, "SKILL.md"),
639
+ "utf-8",
640
+ );
641
+ const metadataTemplate = fs.readFileSync(
642
+ path.join(templateDir, "metadata.yaml"),
643
+ "utf-8",
644
+ );
569
645
 
570
646
  // Replace placeholders
571
- const date = new Date().toISOString().split('T')[0];
647
+ const date = new Date().toISOString().split("T")[0];
572
648
  let skillContent = skillTemplate
573
- .replace(/Skill Name/g, toTitleCase(skillName.replace(/-/g, ' ')))
649
+ .replace(/Skill Name/g, toTitleCase(skillName.replace(/-/g, " ")))
574
650
  .replace(/{current-date}/g, date)
575
651
  .replace(/skill-name/g, skillName);
576
652
 
577
- let metadataContent = metadataTemplate
578
- .replace(/skill-name/g, skillName);
653
+ let metadataContent = metadataTemplate.replace(/skill-name/g, skillName);
579
654
 
580
- fs.writeFileSync(path.join(skillDir, 'SKILL.md'), skillContent);
581
- fs.writeFileSync(path.join(skillDir, 'metadata.yaml'), metadataContent);
582
- console.log('✅ Created SKILL.md and metadata.yaml');
655
+ fs.writeFileSync(path.join(skillDir, "SKILL.md"), skillContent);
656
+ fs.writeFileSync(path.join(skillDir, "metadata.yaml"), metadataContent);
657
+ console.log("✅ Created SKILL.md and metadata.yaml");
583
658
  }
584
659
 
585
660
  // Create example templates
586
661
  fs.writeFileSync(
587
- path.join(skillDir, 'templates', 'default.md'),
588
- `# Default Template for ${skillName}\n\nReplace this with your actual template.\n`
662
+ path.join(skillDir, "templates", "default.md"),
663
+ `# Default Template for ${skillName}\n\nReplace this with your actual template.\n`,
589
664
  );
590
665
  fs.writeFileSync(
591
- path.join(skillDir, 'examples', 'basic.md'),
592
- `# Basic Example for ${skillName}\n\nReplace this with your actual example.\n`
666
+ path.join(skillDir, "examples", "basic.md"),
667
+ `# Basic Example for ${skillName}\n\nReplace this with your actual example.\n`,
593
668
  );
594
- console.log('✅ Created templates and examples');
669
+ console.log("✅ Created templates and examples");
595
670
 
596
671
  // Update RAG index
597
- const ragDir = path.join(projectDir, '.claude', 'rag');
598
- const ragIndexFile = path.join(ragDir, 'skill-index.json');
672
+ const ragDir = path.join(projectDir, ".claude", "rag");
673
+ const ragIndexFile = path.join(ragDir, "skill-index.json");
599
674
  let ragIndex = { skills: [], auto_load: { enabled: true } };
600
675
 
601
676
  ensureDir(ragDir);
602
677
 
603
678
  if (fs.existsSync(ragIndexFile)) {
604
679
  try {
605
- ragIndex = JSON.parse(fs.readFileSync(ragIndexFile, 'utf-8'));
606
- } catch (e) { }
680
+ ragIndex = JSON.parse(fs.readFileSync(ragIndexFile, "utf-8"));
681
+ } catch (e) {}
607
682
  }
608
683
 
609
684
  // Add new skill to index
610
685
  const newSkill = {
611
686
  name: skillName,
612
687
  description: `TODO: Add description for ${skillName}`,
613
- keywords: [skillName.replace(/-/g, ' ')],
614
- path: `.claude/skills/${skillName}/SKILL.md`
688
+ keywords: [skillName.replace(/-/g, " ")],
689
+ path: `.claude/skills/${skillName}/SKILL.md`,
615
690
  };
616
691
 
617
692
  // Avoid duplicates
618
- if (!ragIndex.skills.some(s => s.name === skillName)) {
693
+ if (!ragIndex.skills.some((s) => s.name === skillName)) {
619
694
  ragIndex.skills.push(newSkill);
620
695
  fs.writeFileSync(ragIndexFile, JSON.stringify(ragIndex, null, 2));
621
- console.log('✅ Updated RAG skill index');
696
+ console.log("✅ Updated RAG skill index");
622
697
  }
623
698
 
624
- console.log('');
625
- console.log('✅ Skill created successfully!');
626
- console.log('');
699
+ console.log("");
700
+ console.log("✅ Skill created successfully!");
701
+ console.log("");
627
702
  console.log(`Next steps:`);
628
703
  console.log(` 1. Edit .claude/skills/${skillName}/SKILL.md`);
629
704
  console.log(` 2. Add your templates and examples`);
@@ -631,12 +706,12 @@ const commands = {
631
706
  },
632
707
 
633
708
  // -------------------------------------------------------------------------
634
- 'skill:check': (skillName) => {
709
+ "skill:check": (skillName) => {
635
710
  const projectDir = process.cwd();
636
- const skillsDir = path.join(projectDir, '.claude', 'skills');
711
+ const skillsDir = path.join(projectDir, ".claude", "skills");
637
712
 
638
- console.log('🔍 Checking skill dependencies...');
639
- console.log('');
713
+ console.log("🔍 Checking skill dependencies...");
714
+ console.log("");
640
715
 
641
716
  const checkSkill = (name, visited = new Set()) => {
642
717
  if (visited.has(name)) {
@@ -646,7 +721,7 @@ const commands = {
646
721
  visited.add(name);
647
722
 
648
723
  const skillDir = path.join(skillsDir, name);
649
- const metadataFile = path.join(skillDir, 'metadata.yaml');
724
+ const metadataFile = path.join(skillDir, "metadata.yaml");
650
725
 
651
726
  if (!fs.existsSync(skillDir)) {
652
727
  console.log(`❌ Skill "${name}" not found`);
@@ -661,13 +736,13 @@ const commands = {
661
736
  // Simple YAML parser (basic key: value format only)
662
737
  const parseSimpleYaml = (content) => {
663
738
  const result = {};
664
- content.split('\n').forEach(line => {
739
+ content.split("\n").forEach((line) => {
665
740
  const match = line.match(/^(\w+):\s*(.*)$/);
666
741
  if (match) {
667
742
  const value = match[2].trim();
668
- if (value === '[]') {
743
+ if (value === "[]") {
669
744
  result[match[1]] = [];
670
- } else if (value.startsWith('[')) {
745
+ } else if (value.startsWith("[")) {
671
746
  try {
672
747
  result[match[1]] = JSON.parse(value.replace(/'/g, '"'));
673
748
  } catch (e) {
@@ -681,7 +756,7 @@ const commands = {
681
756
  return result;
682
757
  };
683
758
 
684
- const metadata = parseSimpleYaml(fs.readFileSync(metadataFile, 'utf-8'));
759
+ const metadata = parseSimpleYaml(fs.readFileSync(metadataFile, "utf-8"));
685
760
  const deps = metadata.dependencies || [];
686
761
 
687
762
  if (deps.length === 0) {
@@ -690,7 +765,7 @@ const commands = {
690
765
  }
691
766
 
692
767
  console.log(`📦 ${name} depends on:`);
693
- deps.forEach(dep => {
768
+ deps.forEach((dep) => {
694
769
  const depDir = path.join(skillsDir, dep);
695
770
  if (fs.existsSync(depDir)) {
696
771
  console.log(` ✅ ${dep}`);
@@ -706,30 +781,34 @@ const commands = {
706
781
  } else {
707
782
  // Check all skills
708
783
  const allSkills = fs.existsSync(skillsDir)
709
- ? fs.readdirSync(skillsDir).filter(f => {
710
- const dir = path.join(skillsDir, f);
711
- return fs.statSync(dir).isDirectory() && f !== 'template' && f !== 'examples';
712
- })
784
+ ? fs.readdirSync(skillsDir).filter((f) => {
785
+ const dir = path.join(skillsDir, f);
786
+ return (
787
+ fs.statSync(dir).isDirectory() &&
788
+ f !== "template" &&
789
+ f !== "examples"
790
+ );
791
+ })
713
792
  : [];
714
793
 
715
794
  console.log(`Found ${allSkills.length} skills\n`);
716
- allSkills.forEach(skill => checkSkill(skill));
795
+ allSkills.forEach((skill) => checkSkill(skill));
717
796
  }
718
797
  },
719
798
 
720
799
  // -------------------------------------------------------------------------
721
- 'skill:install': (source) => {
800
+ "skill:install": (source) => {
722
801
  if (!source) {
723
- console.log('Usage: sumulige-claude skill:install <source>');
724
- console.log('Example: sumulige-claude skill:install anthropics/skills');
802
+ console.log("Usage: sumulige-claude skill:install <source>");
803
+ console.log("Example: sumulige-claude skill:install anthropics/skills");
725
804
  return;
726
805
  }
727
806
  try {
728
- execSync(`openskills install ${source} -y`, { stdio: 'inherit' });
729
- execSync('openskills sync -y', { stdio: 'pipe' });
730
- console.log('✅ Skill installed and synced');
807
+ execSync(`openskills install ${source} -y`, { stdio: "inherit" });
808
+ execSync("openskills sync -y", { stdio: "pipe" });
809
+ console.log("✅ Skill installed and synced");
731
810
  } catch (e) {
732
- console.log('❌ Failed to install skill');
811
+ console.log("❌ Failed to install skill");
733
812
  }
734
813
  },
735
814
 
@@ -737,142 +816,181 @@ const commands = {
737
816
  template: (...args) => {
738
817
  // Parse arguments
739
818
  let targetPath = process.cwd();
740
- let copyMode = CopyMode.BACKUP; // Default: backup before overwrite
819
+ let copyMode = CopyMode.BACKUP; // Default: backup before overwrite
741
820
  let showHelp = false;
742
821
 
743
822
  for (const arg of args) {
744
- if (arg === '--safe') {
823
+ if (arg === "--safe") {
745
824
  copyMode = CopyMode.SAFE;
746
- } else if (arg === '--force') {
825
+ } else if (arg === "--force") {
747
826
  copyMode = CopyMode.FORCE;
748
- } else if (arg === '--help' || arg === '-h') {
827
+ } else if (arg === "--help" || arg === "-h") {
749
828
  showHelp = true;
750
- } else if (!arg.startsWith('--')) {
829
+ } else if (!arg.startsWith("--")) {
751
830
  targetPath = path.resolve(arg);
752
831
  }
753
832
  }
754
833
 
755
834
  // Show help message
756
835
  if (showHelp) {
757
- console.log('');
758
- console.log('📋 smc template - Deploy Claude Code project template');
759
- console.log('');
760
- console.log('USAGE:');
761
- console.log(' smc template [path] [options]');
762
- console.log('');
763
- console.log('ARGUMENTS:');
764
- console.log(' path Target directory (default: current directory)');
765
- console.log('');
766
- console.log('OPTIONS:');
767
- console.log(' --safe Skip existing files (no overwrite)');
768
- console.log(' --force Overwrite without backup (use for new projects)');
769
- console.log(' --help, -h Show this help message');
770
- console.log('');
771
- console.log('DEFAULT BEHAVIOR:');
772
- console.log(' Backup existing files before overwriting.');
773
- console.log(' Backups stored in: .claude/backup/');
774
- console.log(' Backup format: filename.YYYY-MM-DD.bak');
775
- console.log('');
776
- console.log('EXAMPLES:');
777
- console.log(' smc template # Deploy to current dir (with backup)');
778
- console.log(' smc template ./my-project # Deploy to specific dir');
779
- console.log(' smc template --safe # Skip existing files');
780
- console.log(' smc template --force # Overwrite everything');
781
- console.log('');
782
- console.log('COMPARISON:');
783
- console.log(' smc template = Full deployment (overwrites with backup)');
784
- console.log(' smc sync = Incremental update (only adds missing)');
785
- console.log('');
836
+ console.log("");
837
+ console.log("📋 smc template - Deploy Claude Code project template");
838
+ console.log("");
839
+ console.log("USAGE:");
840
+ console.log(" smc template [path] [options]");
841
+ console.log("");
842
+ console.log("ARGUMENTS:");
843
+ console.log(
844
+ " path Target directory (default: current directory)",
845
+ );
846
+ console.log("");
847
+ console.log("OPTIONS:");
848
+ console.log(" --safe Skip existing files (no overwrite)");
849
+ console.log(
850
+ " --force Overwrite without backup (use for new projects)",
851
+ );
852
+ console.log(" --help, -h Show this help message");
853
+ console.log("");
854
+ console.log("DEFAULT BEHAVIOR:");
855
+ console.log(" Backup existing files before overwriting.");
856
+ console.log(" Backups stored in: .claude/backup/");
857
+ console.log(" Backup format: filename.YYYY-MM-DD.bak");
858
+ console.log("");
859
+ console.log("EXAMPLES:");
860
+ console.log(
861
+ " smc template # Deploy to current dir (with backup)",
862
+ );
863
+ console.log(" smc template ./my-project # Deploy to specific dir");
864
+ console.log(" smc template --safe # Skip existing files");
865
+ console.log(" smc template --force # Overwrite everything");
866
+ console.log("");
867
+ console.log("COMPARISON:");
868
+ console.log(" smc template = Full deployment (overwrites with backup)");
869
+ console.log(" smc sync = Incremental update (only adds missing)");
870
+ console.log("");
786
871
  return;
787
872
  }
788
873
 
789
874
  const targetDir = targetPath;
790
- const backupDir = path.join(targetDir, '.claude', 'backup');
875
+ const backupDir = path.join(targetDir, ".claude", "backup");
791
876
  const stats = { copied: 0, skipped: 0, backedup: 0, backups: [] };
792
877
 
793
- console.log('🚀 Initializing Claude Code project template...');
794
- console.log(' Target:', targetDir);
795
- console.log(' Mode:', copyMode === CopyMode.SAFE ? 'SAFE (skip existing)' :
796
- copyMode === CopyMode.FORCE ? 'FORCE (overwrite)' :
797
- 'BACKUP (backup before overwrite)');
798
- console.log('');
878
+ console.log("🚀 Initializing Claude Code project template...");
879
+ console.log(" Target:", targetDir);
880
+ console.log(
881
+ " Mode:",
882
+ copyMode === CopyMode.SAFE
883
+ ? "SAFE (skip existing)"
884
+ : copyMode === CopyMode.FORCE
885
+ ? "FORCE (overwrite)"
886
+ : "BACKUP (backup before overwrite)",
887
+ );
888
+ console.log("");
799
889
 
800
890
  // Warn if existing .claude directory found
801
- const existingClaudeDir = path.join(targetDir, '.claude');
891
+ const existingClaudeDir = path.join(targetDir, ".claude");
802
892
  if (fs.existsSync(existingClaudeDir)) {
803
893
  if (copyMode === CopyMode.FORCE) {
804
- console.log('⚠️ Existing .claude/ directory found -- will be overwritten!');
805
- console.log('');
894
+ console.log(
895
+ "⚠️ Existing .claude/ directory found -- will be overwritten!",
896
+ );
897
+ console.log("");
806
898
  } else if (copyMode === CopyMode.BACKUP) {
807
- console.log('ℹ️ Existing files will be backed up to: .claude/backup/');
808
- console.log('');
899
+ console.log("ℹ️ Existing files will be backed up to: .claude/backup/");
900
+ console.log("");
809
901
  }
810
902
  }
811
903
 
812
904
  // Check template directory exists
813
905
  if (!fs.existsSync(TEMPLATE_DIR)) {
814
- console.log('❌ Template not found at:', TEMPLATE_DIR);
815
- console.log(' Please reinstall sumulige-claude');
906
+ console.log("❌ Template not found at:", TEMPLATE_DIR);
907
+ console.log(" Please reinstall sumulige-claude");
816
908
  process.exit(1);
817
909
  }
818
910
 
819
911
  // Create directory structure
820
- console.log('📁 Creating directory structure...');
912
+ console.log("📁 Creating directory structure...");
821
913
  const dirs = [
822
- path.join(targetDir, '.claude'),
823
- path.join(targetDir, 'prompts'),
824
- path.join(targetDir, 'development/todos/active'),
825
- path.join(targetDir, 'development/todos/completed'),
826
- path.join(targetDir, 'development/todos/backlog'),
827
- path.join(targetDir, 'development/todos/archived'),
828
- backupDir
914
+ path.join(targetDir, ".claude"),
915
+ path.join(targetDir, "prompts"),
916
+ path.join(targetDir, "development/todos/active"),
917
+ path.join(targetDir, "development/todos/completed"),
918
+ path.join(targetDir, "development/todos/backlog"),
919
+ path.join(targetDir, "development/todos/archived"),
920
+ backupDir,
829
921
  ];
830
922
 
831
923
  dirs.forEach(ensureDir);
832
- console.log(' ✅ Directories created');
833
- console.log('');
924
+ console.log(" ✅ Directories created");
925
+ console.log("");
834
926
 
835
927
  // Copy files
836
- console.log('📋 Copying template files...');
928
+ console.log("📋 Copying template files...");
837
929
 
838
- const claudeTemplateDir = path.join(TEMPLATE_DIR, '.claude');
839
- const targetClaudeDir = path.join(targetDir, '.claude');
930
+ const claudeTemplateDir = path.join(TEMPLATE_DIR, ".claude");
931
+ const targetClaudeDir = path.join(targetDir, ".claude");
840
932
 
841
933
  // Files to copy
842
934
  const filesToCopy = [
843
- { src: 'CLAUDE-template.md', dest: 'CLAUDE.md', name: '.claude/CLAUDE.md' },
844
- { src: 'README.md', dest: 'README.md', name: '.claude/README.md' },
845
- { src: 'settings.json', dest: 'settings.json', name: '.claude/settings.json' },
846
- { src: 'boris-optimizations.md', dest: 'boris-optimizations.md', name: '.claude/boris-optimizations.md' }
935
+ {
936
+ src: "CLAUDE-template.md",
937
+ dest: "CLAUDE.md",
938
+ name: ".claude/CLAUDE.md",
939
+ },
940
+ { src: "README.md", dest: "README.md", name: ".claude/README.md" },
941
+ {
942
+ src: "settings.json",
943
+ dest: "settings.json",
944
+ name: ".claude/settings.json",
945
+ },
946
+ {
947
+ src: "boris-optimizations.md",
948
+ dest: "boris-optimizations.md",
949
+ name: ".claude/boris-optimizations.md",
950
+ },
847
951
  ];
848
952
 
849
953
  filesToCopy.forEach(({ src, dest, name }) => {
850
954
  const srcPath = path.join(claudeTemplateDir, src);
851
955
  const destPath = path.join(targetClaudeDir, dest);
852
956
  if (fs.existsSync(srcPath)) {
853
- const action = copySingleFile(srcPath, destPath, copyMode, backupDir, name);
854
- if (action === 'copied') stats.copied++;
855
- else if (action === 'skipped') stats.skipped++;
856
- else if (action === 'backedup') { stats.copied++; stats.backedup++; }
957
+ const action = copySingleFile(
958
+ srcPath,
959
+ destPath,
960
+ copyMode,
961
+ backupDir,
962
+ name,
963
+ );
964
+ if (action === "copied") stats.copied++;
965
+ else if (action === "skipped") stats.skipped++;
966
+ else if (action === "backedup") {
967
+ stats.copied++;
968
+ stats.backedup++;
969
+ }
857
970
  }
858
971
  });
859
972
 
860
973
  // Directories to copy recursively
861
974
  const dirsToCopy = [
862
- { src: 'hooks', name: '.claude/hooks/' },
863
- { src: 'commands', name: '.claude/commands/' },
864
- { src: 'skills', name: '.claude/skills/' },
865
- { src: 'templates', name: '.claude/templates/' },
866
- { src: 'thinking-routes', name: '.claude/thinking-routes/' },
867
- { src: 'rag', name: '.claude/rag/' }
975
+ { src: "hooks", name: ".claude/hooks/" },
976
+ { src: "commands", name: ".claude/commands/" },
977
+ { src: "skills", name: ".claude/skills/" },
978
+ { src: "templates", name: ".claude/templates/" },
979
+ { src: "thinking-routes", name: ".claude/thinking-routes/" },
980
+ { src: "rag", name: ".claude/rag/" },
868
981
  ];
869
982
 
870
983
  dirsToCopy.forEach(({ src, name }) => {
871
984
  const srcPath = path.join(claudeTemplateDir, src);
872
985
  if (fs.existsSync(srcPath)) {
873
- const result = copyRecursive(srcPath, path.join(targetClaudeDir, src), copyMode, backupDir);
986
+ const result = copyRecursive(
987
+ srcPath,
988
+ path.join(targetClaudeDir, src),
989
+ copyMode,
990
+ backupDir,
991
+ );
874
992
  const fileCount = result.copied + result.skipped + result.backedup;
875
- const suffix = result.skipped > 0 ? ` (${result.skipped} skipped)` : '';
993
+ const suffix = result.skipped > 0 ? ` (${result.skipped} skipped)` : "";
876
994
  console.log(` ✅ ${name} (${fileCount} files${suffix})`);
877
995
  stats.copied += result.copied;
878
996
  stats.skipped += result.skipped;
@@ -881,11 +999,16 @@ const commands = {
881
999
  });
882
1000
 
883
1001
  // Copy prompts
884
- const promptsDir = path.join(TEMPLATE_DIR, 'prompts');
1002
+ const promptsDir = path.join(TEMPLATE_DIR, "prompts");
885
1003
  if (fs.existsSync(promptsDir)) {
886
- const result = copyRecursive(promptsDir, path.join(targetDir, 'prompts'), copyMode, backupDir);
1004
+ const result = copyRecursive(
1005
+ promptsDir,
1006
+ path.join(targetDir, "prompts"),
1007
+ copyMode,
1008
+ backupDir,
1009
+ );
887
1010
  const fileCount = result.copied + result.skipped + result.backedup;
888
- const suffix = result.skipped > 0 ? ` (${result.skipped} skipped)` : '';
1011
+ const suffix = result.skipped > 0 ? ` (${result.skipped} skipped)` : "";
889
1012
  console.log(` ✅ prompts/ (${fileCount} files${suffix})`);
890
1013
  stats.copied += result.copied;
891
1014
  stats.skipped += result.skipped;
@@ -893,11 +1016,16 @@ const commands = {
893
1016
  }
894
1017
 
895
1018
  // Copy todos
896
- const todosDir = path.join(TEMPLATE_DIR, 'development', 'todos');
1019
+ const todosDir = path.join(TEMPLATE_DIR, "development", "todos");
897
1020
  if (fs.existsSync(todosDir)) {
898
- const result = copyRecursive(todosDir, path.join(targetDir, 'development', 'todos'), copyMode, backupDir);
1021
+ const result = copyRecursive(
1022
+ todosDir,
1023
+ path.join(targetDir, "development", "todos"),
1024
+ copyMode,
1025
+ backupDir,
1026
+ );
899
1027
  const fileCount = result.copied + result.skipped + result.backedup;
900
- const suffix = result.skipped > 0 ? ` (${result.skipped} skipped)` : '';
1028
+ const suffix = result.skipped > 0 ? ` (${result.skipped} skipped)` : "";
901
1029
  console.log(` ✅ development/todos/ (${fileCount} files${suffix})`);
902
1030
  stats.copied += result.copied;
903
1031
  stats.skipped += result.skipped;
@@ -905,41 +1033,54 @@ const commands = {
905
1033
  }
906
1034
 
907
1035
  // Root files
908
- const rootFiles = ['project-paradigm.md', 'thinkinglens-silent.md', 'CLAUDE-template.md'];
909
- rootFiles.forEach(file => {
1036
+ const rootFiles = [
1037
+ "project-paradigm.md",
1038
+ "thinkinglens-silent.md",
1039
+ "CLAUDE-template.md",
1040
+ ];
1041
+ rootFiles.forEach((file) => {
910
1042
  const src = path.join(TEMPLATE_DIR, file);
911
1043
  const dest = path.join(targetDir, file);
912
1044
  if (fs.existsSync(src)) {
913
1045
  const action = copySingleFile(src, dest, copyMode, backupDir, file);
914
- if (action === 'copied') stats.copied++;
915
- else if (action === 'skipped') stats.skipped++;
916
- else if (action === 'backedup') { stats.copied++; stats.backedup++; }
1046
+ if (action === "copied") stats.copied++;
1047
+ else if (action === "skipped") stats.skipped++;
1048
+ else if (action === "backedup") {
1049
+ stats.copied++;
1050
+ stats.backedup++;
1051
+ }
917
1052
  }
918
1053
  });
919
1054
 
920
1055
  // Create memory files
921
- console.log('');
922
- console.log('📝 Creating memory files...');
923
- if (!fs.existsSync(path.join(targetClaudeDir, 'MEMORY.md'))) {
924
- fs.writeFileSync(path.join(targetClaudeDir, 'MEMORY.md'), '# Memory\n\n<!-- Project memory updated by AI -->\n');
925
- console.log(' ✅ MEMORY.md');
1056
+ console.log("");
1057
+ console.log("📝 Creating memory files...");
1058
+ if (!fs.existsSync(path.join(targetClaudeDir, "MEMORY.md"))) {
1059
+ fs.writeFileSync(
1060
+ path.join(targetClaudeDir, "MEMORY.md"),
1061
+ "# Memory\n\n<!-- Project memory updated by AI -->\n",
1062
+ );
1063
+ console.log(" ✅ MEMORY.md");
926
1064
  } else {
927
- console.log(' ⊝ MEMORY.md (already exists)');
1065
+ console.log(" ⊝ MEMORY.md (already exists)");
928
1066
  }
929
- if (!fs.existsSync(path.join(targetClaudeDir, 'PROJECT_LOG.md'))) {
930
- fs.writeFileSync(path.join(targetClaudeDir, 'PROJECT_LOG.md'), '# Project Log\n\n<!-- Build history and decisions -->\n');
931
- console.log(' ✅ PROJECT_LOG.md');
1067
+ if (!fs.existsSync(path.join(targetClaudeDir, "PROJECT_LOG.md"))) {
1068
+ fs.writeFileSync(
1069
+ path.join(targetClaudeDir, "PROJECT_LOG.md"),
1070
+ "# Project Log\n\n<!-- Build history and decisions -->\n",
1071
+ );
1072
+ console.log(" ✅ PROJECT_LOG.md");
932
1073
  } else {
933
- console.log(' ⊝ PROJECT_LOG.md (already exists)');
1074
+ console.log(" ⊝ PROJECT_LOG.md (already exists)");
934
1075
  }
935
1076
 
936
1077
  // Create ANCHORS.md
937
- const anchorsPath = path.join(targetClaudeDir, 'ANCHORS.md');
1078
+ const anchorsPath = path.join(targetClaudeDir, "ANCHORS.md");
938
1079
  if (!fs.existsSync(anchorsPath)) {
939
1080
  const anchorsContent = `# [Project Name] - Skill Anchors Index
940
1081
 
941
1082
  > This file is auto-maintained by AI as a quick index for the skill system
942
- > Last updated: ${new Date().toISOString().split('T')[0]}
1083
+ > Last updated: ${new Date().toISOString().split("T")[0]}
943
1084
 
944
1085
  ---
945
1086
 
@@ -976,19 +1117,19 @@ const commands = {
976
1117
 
977
1118
  `;
978
1119
  fs.writeFileSync(anchorsPath, anchorsContent);
979
- console.log(' ✅ .claude/ANCHORS.md');
1120
+ console.log(" ✅ .claude/ANCHORS.md");
980
1121
  } else {
981
- console.log(' ⊝ .claude/ANCHORS.md (already exists)');
1122
+ console.log(" ⊝ .claude/ANCHORS.md (already exists)");
982
1123
  }
983
1124
 
984
1125
  // Write version file
985
- const { setProjectVersion } = require('./migrations');
1126
+ const { setProjectVersion } = require("./migrations");
986
1127
  setProjectVersion(targetDir, TEMPLATE_VERSION);
987
1128
  console.log(` ✅ .claude/.version (v${TEMPLATE_VERSION})`);
988
1129
 
989
1130
  // Show summary
990
- console.log('');
991
- console.log('📊 Summary:');
1131
+ console.log("");
1132
+ console.log("📊 Summary:");
992
1133
  console.log(` ✅ Copied: ${stats.copied} files`);
993
1134
  if (stats.skipped > 0) {
994
1135
  console.log(` ⊝ Skipped: ${stats.skipped} files (already exist)`);
@@ -998,62 +1139,68 @@ const commands = {
998
1139
  }
999
1140
 
1000
1141
  // Initialize Sumulige Claude if installed
1001
- console.log('');
1002
- console.log('🤖 Initializing Sumulige Claude...');
1142
+ console.log("");
1143
+ console.log("🤖 Initializing Sumulige Claude...");
1003
1144
  try {
1004
- execSync('sumulige-claude sync', { cwd: targetDir, stdio: 'pipe' });
1005
- console.log(' ✅ Sumulige Claude synced');
1145
+ execSync("sumulige-claude sync", { cwd: targetDir, stdio: "pipe" });
1146
+ console.log(" ✅ Sumulige Claude synced");
1006
1147
  } catch (e) {
1007
- console.log(' ⚠️ Sumulige Claude not available (run: npm i -g sumulige-claude)');
1008
- }
1009
-
1010
- console.log('');
1011
- console.log('✅ Template initialization complete!');
1012
- console.log('');
1013
- console.log('📦 What was included:');
1014
- console.log(' • AI autonomous memory system (ThinkingLens)');
1015
- console.log(' • Slash commands (/commit, /test, /review, etc.)');
1016
- console.log(' • Skills system with templates');
1017
- console.log(' • RAG dynamic skill index');
1018
- console.log(' • Hooks for automation');
1019
- console.log(' • TODO management system v2.0 (R-D-T lifecycle)');
1020
- console.log('');
1021
- console.log('Next steps:');
1022
- console.log(' 1. Edit .claude/CLAUDE.md with your project info');
1023
- console.log(' 2. Run: claude # Start Claude Code');
1024
- console.log(' 3. Try: /commit, /test, /review');
1025
- console.log('');
1026
- },
1148
+ console.log(
1149
+ " ⚠️ Sumulige Claude not available (run: npm i -g sumulige-claude)",
1150
+ );
1151
+ }
1027
1152
 
1153
+ console.log("");
1154
+ console.log("✅ Template initialization complete!");
1155
+ console.log("");
1156
+ console.log("📦 What was included:");
1157
+ console.log(" • AI autonomous memory system (ThinkingLens)");
1158
+ console.log(" • Slash commands (/commit, /test, /review, etc.)");
1159
+ console.log(" • Skills system with templates");
1160
+ console.log(" • RAG dynamic skill index");
1161
+ console.log(" • Hooks for automation");
1162
+ console.log(" • TODO management system v2.0 (R-D-T lifecycle)");
1163
+ console.log("");
1164
+ console.log("Next steps:");
1165
+ console.log(" 1. Edit .claude/CLAUDE.md with your project info");
1166
+ console.log(" 2. Run: claude # Start Claude Code");
1167
+ console.log(" 3. Try: /commit, /test, /review");
1168
+ console.log("");
1169
+ },
1028
1170
 
1029
1171
  // -------------------------------------------------------------------------
1030
1172
  kickoff: () => {
1031
1173
  const projectDir = process.cwd();
1032
- const kickoffFile = path.join(projectDir, 'PROJECT_KICKOFF.md');
1033
- const hintFile = path.join(projectDir, '.claude', '.kickoff-hint.txt');
1174
+ const kickoffFile = path.join(projectDir, "PROJECT_KICKOFF.md");
1175
+ const hintFile = path.join(projectDir, ".claude", ".kickoff-hint.txt");
1034
1176
 
1035
- console.log('🚀 Project Kickoff - Manus 风格项目启动');
1036
- console.log('');
1177
+ console.log("🚀 Project Kickoff - Manus 风格项目启动");
1178
+ console.log("");
1037
1179
 
1038
1180
  if (fs.existsSync(kickoffFile)) {
1039
- console.log('ℹ️ 项目已经完成启动流程');
1040
- console.log(' 文件:', kickoffFile);
1041
- console.log('');
1042
- console.log('如需重新规划,请先删除以下文件:');
1043
- console.log(' - PROJECT_KICKOFF.md');
1044
- console.log(' - TASK_PLAN.md');
1045
- console.log(' - PROJECT_PROPOSAL.md');
1181
+ console.log("ℹ️ 项目已经完成启动流程");
1182
+ console.log(" 文件:", kickoffFile);
1183
+ console.log("");
1184
+ console.log("如需重新规划,请先删除以下文件:");
1185
+ console.log(" - PROJECT_KICKOFF.md");
1186
+ console.log(" - TASK_PLAN.md");
1187
+ console.log(" - PROJECT_PROPOSAL.md");
1046
1188
  return;
1047
1189
  }
1048
1190
 
1049
1191
  // Run kickoff hook
1050
- const kickoffHook = path.join(projectDir, '.claude', 'hooks', 'project-kickoff.cjs');
1192
+ const kickoffHook = path.join(
1193
+ projectDir,
1194
+ ".claude",
1195
+ "hooks",
1196
+ "project-kickoff.cjs",
1197
+ );
1051
1198
  if (fs.existsSync(kickoffHook)) {
1052
1199
  try {
1053
1200
  execSync(`node "${kickoffHook}"`, {
1054
1201
  cwd: projectDir,
1055
1202
  env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir },
1056
- stdio: 'inherit'
1203
+ stdio: "inherit",
1057
1204
  });
1058
1205
  } catch (e) {
1059
1206
  // Hook may output and exit, this is normal
@@ -1061,85 +1208,91 @@ const commands = {
1061
1208
 
1062
1209
  // Show hint file if exists
1063
1210
  if (fs.existsSync(hintFile)) {
1064
- const hint = fs.readFileSync(hintFile, 'utf-8');
1211
+ const hint = fs.readFileSync(hintFile, "utf-8");
1065
1212
  console.log(hint);
1066
1213
  }
1067
1214
  } else {
1068
- console.log('⚠️ 启动 Hook 不存在');
1069
- console.log(' 请先运行: sumulige-claude template');
1070
- console.log(' 或: sumulige-claude sync');
1215
+ console.log("⚠️ 启动 Hook 不存在");
1216
+ console.log(" 请先运行: sumulige-claude template");
1217
+ console.log(" 或: sumulige-claude sync");
1071
1218
  }
1072
1219
  },
1073
1220
 
1074
1221
  // -------------------------------------------------------------------------
1075
1222
  ultrathink: () => {
1076
1223
  const COLORS = {
1077
- reset: '\x1b[0m',
1078
- green: '\x1b[32m',
1079
- blue: '\x1b[34m',
1080
- yellow: '\x1b[33m',
1081
- gray: '\x1b[90m'
1224
+ reset: "\x1b[0m",
1225
+ green: "\x1b[32m",
1226
+ blue: "\x1b[34m",
1227
+ yellow: "\x1b[33m",
1228
+ gray: "\x1b[90m",
1082
1229
  };
1083
1230
 
1084
- const log = (msg, color = 'reset') => {
1231
+ const log = (msg, color = "reset") => {
1085
1232
  console.log(`${COLORS[color]}${msg}${COLORS.reset}`);
1086
1233
  };
1087
1234
 
1088
- log('', 'gray');
1089
- log('🧠 UltraThink Mode', 'blue');
1090
- log('=====================================', 'gray');
1091
- log('', 'gray');
1092
- log('✅ Deep thinking enabled', 'green');
1093
- log('', 'gray');
1094
- log('Usage:', 'gray');
1095
- log(' Mention "ultrathink" or "深度思考" in conversation', 'gray');
1096
- log('', 'gray');
1097
- log('=====================================', 'gray');
1098
- log('', 'gray');
1235
+ log("", "gray");
1236
+ log("🧠 UltraThink Mode", "blue");
1237
+ log("=====================================", "gray");
1238
+ log("", "gray");
1239
+ log("✅ Deep thinking enabled", "green");
1240
+ log("", "gray");
1241
+ log("Usage:", "gray");
1242
+ log(' Mention "ultrathink" or "深度思考" in conversation', "gray");
1243
+ log("", "gray");
1244
+ log("=====================================", "gray");
1245
+ log("", "gray");
1099
1246
  },
1100
1247
 
1101
1248
  // -------------------------------------------------------------------------
1102
- 'skills:official': () => {
1103
- const fs = require('fs');
1104
- const path = require('path');
1249
+ "skills:official": () => {
1250
+ const fs = require("fs");
1251
+ const path = require("path");
1105
1252
  const COLORS = {
1106
- reset: '\x1b[0m',
1107
- green: '\x1b[32m',
1108
- blue: '\x1b[34m',
1109
- yellow: '\x1b[33m',
1110
- gray: '\x1b[90m',
1111
- cyan: '\x1b[36m',
1112
- magenta: '\x1b[35m'
1253
+ reset: "\x1b[0m",
1254
+ green: "\x1b[32m",
1255
+ blue: "\x1b[34m",
1256
+ yellow: "\x1b[33m",
1257
+ gray: "\x1b[90m",
1258
+ cyan: "\x1b[36m",
1259
+ magenta: "\x1b[35m",
1113
1260
  };
1114
1261
 
1115
- const log = (msg, color = 'reset') => {
1262
+ const log = (msg, color = "reset") => {
1116
1263
  console.log(`${COLORS[color]}${msg}${COLORS.reset}`);
1117
1264
  };
1118
1265
 
1119
- const officialSkillsFile = path.join(__dirname, '../config/official-skills.json');
1266
+ const officialSkillsFile = path.join(
1267
+ __dirname,
1268
+ "../config/official-skills.json",
1269
+ );
1120
1270
 
1121
1271
  if (!fs.existsSync(officialSkillsFile)) {
1122
- log('⚠ Official skills registry not found', 'yellow');
1272
+ log("⚠ Official skills registry not found", "yellow");
1123
1273
  return;
1124
1274
  }
1125
1275
 
1126
- const registry = JSON.parse(fs.readFileSync(officialSkillsFile, 'utf-8'));
1276
+ const registry = JSON.parse(fs.readFileSync(officialSkillsFile, "utf-8"));
1127
1277
 
1128
- log('', 'gray');
1129
- log('📚 Official Skills (anthropics/skills)', 'blue');
1130
- log('=====================================', 'gray');
1131
- log('', 'gray');
1132
- log(`Source: ${registry.source}`, 'gray');
1133
- log(`Updated: ${registry.last_updated}`, 'gray');
1134
- log('', 'gray');
1278
+ log("", "gray");
1279
+ log("📚 Official Skills (anthropics/skills)", "blue");
1280
+ log("=====================================", "gray");
1281
+ log("", "gray");
1282
+ log(`Source: ${registry.source}`, "gray");
1283
+ log(`Updated: ${registry.last_updated}`, "gray");
1284
+ log("", "gray");
1135
1285
 
1136
1286
  // Check which skills are already installed
1137
- const skillsDir = path.join(process.env.HOME || process.env.USERPROFILE, '.claude/skills');
1287
+ const skillsDir = path.join(
1288
+ process.env.HOME || process.env.USERPROFILE,
1289
+ ".claude/skills",
1290
+ );
1138
1291
  const installedSkills = fs.existsSync(skillsDir)
1139
- ? fs.readdirSync(skillsDir).filter(f => {
1140
- const dir = path.join(skillsDir, f);
1141
- return fs.statSync(dir).isDirectory();
1142
- })
1292
+ ? fs.readdirSync(skillsDir).filter((f) => {
1293
+ const dir = path.join(skillsDir, f);
1294
+ return fs.statSync(dir).isDirectory();
1295
+ })
1143
1296
  : [];
1144
1297
 
1145
1298
  // Group by category
@@ -1158,192 +1311,203 @@ const commands = {
1158
1311
  for (const [catName, cat] of Object.entries(byCategory)) {
1159
1312
  if (cat.skills.length === 0) continue;
1160
1313
 
1161
- log(`${cat.icon} ${catName}`, 'cyan');
1162
- log(` ${cat.description}`, 'gray');
1163
- log('', 'gray');
1314
+ log(`${cat.icon} ${catName}`, "cyan");
1315
+ log(` ${cat.description}`, "gray");
1316
+ log("", "gray");
1164
1317
 
1165
1318
  for (const skill of cat.skills) {
1166
- const status = skill.isInstalled ? '' : ' ';
1167
- const rec = skill.recommended ? ' [推荐]' : '';
1168
- const color = skill.isInstalled ? 'green' : 'reset';
1319
+ const status = skill.isInstalled ? "" : " ";
1320
+ const rec = skill.recommended ? " [推荐]" : "";
1321
+ const color = skill.isInstalled ? "green" : "reset";
1169
1322
  log(` [${status}] ${skill.name}${rec}`, color);
1170
- log(` ${skill.description}`, 'gray');
1323
+ log(` ${skill.description}`, "gray");
1171
1324
  }
1172
- log('', 'gray');
1325
+ log("", "gray");
1173
1326
  }
1174
1327
 
1175
- log('=====================================', 'gray');
1176
- log('', 'gray');
1177
- log('Commands:', 'gray');
1178
- log(' smc skills:install-official <name> Install a skill', 'gray');
1179
- log(' smc skills:install-all Install all recommended', 'gray');
1180
- log('', 'gray');
1328
+ log("=====================================", "gray");
1329
+ log("", "gray");
1330
+ log("Commands:", "gray");
1331
+ log(" smc skills:install-official <name> Install a skill", "gray");
1332
+ log(
1333
+ " smc skills:install-all Install all recommended",
1334
+ "gray",
1335
+ );
1336
+ log("", "gray");
1181
1337
  },
1182
1338
 
1183
1339
  // -------------------------------------------------------------------------
1184
- 'skills:install-official': (skillName) => {
1185
- const fs = require('fs');
1186
- const path = require('path');
1187
- const { execSync } = require('child_process');
1340
+ "skills:install-official": (skillName) => {
1341
+ const fs = require("fs");
1342
+ const path = require("path");
1343
+ const { execSync } = require("child_process");
1188
1344
  const COLORS = {
1189
- reset: '\x1b[0m',
1190
- green: '\x1b[32m',
1191
- blue: '\x1b[34m',
1192
- yellow: '\x1b[33m',
1193
- gray: '\x1b[90m',
1194
- red: '\x1b[31m'
1345
+ reset: "\x1b[0m",
1346
+ green: "\x1b[32m",
1347
+ blue: "\x1b[34m",
1348
+ yellow: "\x1b[33m",
1349
+ gray: "\x1b[90m",
1350
+ red: "\x1b[31m",
1195
1351
  };
1196
1352
 
1197
- const log = (msg, color = 'reset') => {
1353
+ const log = (msg, color = "reset") => {
1198
1354
  console.log(`${COLORS[color]}${msg}${COLORS.reset}`);
1199
1355
  };
1200
1356
 
1201
- const officialSkillsFile = path.join(__dirname, '../config/official-skills.json');
1357
+ const officialSkillsFile = path.join(
1358
+ __dirname,
1359
+ "../config/official-skills.json",
1360
+ );
1202
1361
 
1203
1362
  if (!fs.existsSync(officialSkillsFile)) {
1204
- log('⚠ Official skills registry not found', 'yellow');
1363
+ log("⚠ Official skills registry not found", "yellow");
1205
1364
  return;
1206
1365
  }
1207
1366
 
1208
- const registry = JSON.parse(fs.readFileSync(officialSkillsFile, 'utf-8'));
1367
+ const registry = JSON.parse(fs.readFileSync(officialSkillsFile, "utf-8"));
1209
1368
 
1210
1369
  // Check if openskills is installed
1211
1370
  try {
1212
- execSync('openskills --version', { stdio: 'ignore' });
1371
+ execSync("openskills --version", { stdio: "ignore" });
1213
1372
  } catch {
1214
- log('⚠ OpenSkills not installed', 'yellow');
1215
- log('', 'gray');
1216
- log('Installing OpenSkills...', 'gray');
1373
+ log("⚠ OpenSkills not installed", "yellow");
1374
+ log("", "gray");
1375
+ log("Installing OpenSkills...", "gray");
1217
1376
  try {
1218
- execSync('npm i -g openskills', { stdio: 'inherit' });
1219
- log('✅ OpenSkills installed', 'green');
1377
+ execSync("npm i -g openskills", { stdio: "inherit" });
1378
+ log("✅ OpenSkills installed", "green");
1220
1379
  } catch (e) {
1221
- log('❌ Failed to install OpenSkills', 'red');
1222
- log(' Run: npm i -g openskills', 'gray');
1380
+ log("❌ Failed to install OpenSkills", "red");
1381
+ log(" Run: npm i -g openskills", "gray");
1223
1382
  return;
1224
1383
  }
1225
1384
  }
1226
1385
 
1227
1386
  // Find the skill
1228
- const skill = registry.skills.find(s => s.name === skillName);
1387
+ const skill = registry.skills.find((s) => s.name === skillName);
1229
1388
 
1230
1389
  if (!skill) {
1231
- log(`❌ Skill "${skillName}" not found in official registry`, 'red');
1232
- log('', 'gray');
1233
- log('Run: smc skills:official');
1234
- log('to see available skills.', 'gray');
1390
+ log(`❌ Skill "${skillName}" not found in official registry`, "red");
1391
+ log("", "gray");
1392
+ log("Run: smc skills:official");
1393
+ log("to see available skills.", "gray");
1235
1394
  return;
1236
1395
  }
1237
1396
 
1238
- log(`📦 Installing: ${skillName}`, 'blue');
1239
- log('', 'gray');
1240
- log(`Source: ${skill.source}`, 'gray');
1241
- log(`License: ${skill.license}`, 'gray');
1242
- log('', 'gray');
1397
+ log(`📦 Installing: ${skillName}`, "blue");
1398
+ log("", "gray");
1399
+ log(`Source: ${skill.source}`, "gray");
1400
+ log(`License: ${skill.license}`, "gray");
1401
+ log("", "gray");
1243
1402
 
1244
1403
  try {
1245
- execSync(`openskills install ${skill.source} -y`, { stdio: 'inherit' });
1246
- execSync('openskills sync -y', { stdio: 'pipe' });
1247
- log('', 'gray');
1248
- log('✅ Skill installed successfully', 'green');
1249
- log('', 'gray');
1250
- log('The skill is now available in your conversations.', 'gray');
1404
+ execSync(`openskills install ${skill.source} -y`, { stdio: "inherit" });
1405
+ execSync("openskills sync -y", { stdio: "pipe" });
1406
+ log("", "gray");
1407
+ log("✅ Skill installed successfully", "green");
1408
+ log("", "gray");
1409
+ log("The skill is now available in your conversations.", "gray");
1251
1410
  } catch (e) {
1252
- log('❌ Installation failed', 'red');
1411
+ log("❌ Installation failed", "red");
1253
1412
  }
1254
1413
  },
1255
1414
 
1256
1415
  // -------------------------------------------------------------------------
1257
- 'skills:install-all': () => {
1258
- const fs = require('fs');
1259
- const path = require('path');
1260
- const { execSync } = require('child_process');
1416
+ "skills:install-all": () => {
1417
+ const fs = require("fs");
1418
+ const path = require("path");
1419
+ const { execSync } = require("child_process");
1261
1420
  const COLORS = {
1262
- reset: '\x1b[0m',
1263
- green: '\x1b[32m',
1264
- blue: '\x1b[34m',
1265
- yellow: '\x1b[33m',
1266
- gray: '\x1b[90m',
1267
- red: '\x1b[31m',
1268
- cyan: '\x1b[36m'
1421
+ reset: "\x1b[0m",
1422
+ green: "\x1b[32m",
1423
+ blue: "\x1b[34m",
1424
+ yellow: "\x1b[33m",
1425
+ gray: "\x1b[90m",
1426
+ red: "\x1b[31m",
1427
+ cyan: "\x1b[36m",
1269
1428
  };
1270
1429
 
1271
- const log = (msg, color = 'reset') => {
1430
+ const log = (msg, color = "reset") => {
1272
1431
  console.log(`${COLORS[color]}${msg}${COLORS.reset}`);
1273
1432
  };
1274
1433
 
1275
- const officialSkillsFile = path.join(__dirname, '../config/official-skills.json');
1434
+ const officialSkillsFile = path.join(
1435
+ __dirname,
1436
+ "../config/official-skills.json",
1437
+ );
1276
1438
 
1277
1439
  if (!fs.existsSync(officialSkillsFile)) {
1278
- log('⚠ Official skills registry not found', 'yellow');
1440
+ log("⚠ Official skills registry not found", "yellow");
1279
1441
  return;
1280
1442
  }
1281
1443
 
1282
- const registry = JSON.parse(fs.readFileSync(officialSkillsFile, 'utf-8'));
1283
- const recommended = registry.skills.filter(s => s.recommended);
1444
+ const registry = JSON.parse(fs.readFileSync(officialSkillsFile, "utf-8"));
1445
+ const recommended = registry.skills.filter((s) => s.recommended);
1284
1446
 
1285
- log('', 'gray');
1286
- log('📦 Installing All Recommended Skills', 'blue');
1287
- log('=====================================', 'gray');
1288
- log('', 'gray');
1289
- log(`Installing ${recommended.length} skills...`, 'gray');
1290
- log('', 'gray');
1447
+ log("", "gray");
1448
+ log("📦 Installing All Recommended Skills", "blue");
1449
+ log("=====================================", "gray");
1450
+ log("", "gray");
1451
+ log(`Installing ${recommended.length} skills...`, "gray");
1452
+ log("", "gray");
1291
1453
 
1292
1454
  // Check if openskills is installed
1293
1455
  try {
1294
- execSync('openskills --version', { stdio: 'ignore' });
1456
+ execSync("openskills --version", { stdio: "ignore" });
1295
1457
  } catch {
1296
- log('⚠ OpenSkills not installed. Installing...', 'yellow');
1458
+ log("⚠ OpenSkills not installed. Installing...", "yellow");
1297
1459
  try {
1298
- execSync('npm i -g openskills', { stdio: 'inherit' });
1299
- log('✅ OpenSkills installed', 'green');
1300
- log('', 'gray');
1460
+ execSync("npm i -g openskills", { stdio: "inherit" });
1461
+ log("✅ OpenSkills installed", "green");
1462
+ log("", "gray");
1301
1463
  } catch (e) {
1302
- log('❌ Failed to install OpenSkills', 'red');
1464
+ log("❌ Failed to install OpenSkills", "red");
1303
1465
  return;
1304
1466
  }
1305
1467
  }
1306
1468
 
1307
1469
  // Install anthropics/skills (includes all skills)
1308
1470
  try {
1309
- log(`Installing ${registry.source}...`, 'cyan');
1310
- execSync(`openskills install ${registry.source} -y`, { stdio: 'inherit' });
1311
- execSync('openskills sync -y', { stdio: 'pipe' });
1312
- log('', 'gray');
1313
- log('✅ All skills installed successfully', 'green');
1314
- log('', 'gray');
1315
- log('Installed skills:', 'gray');
1316
- recommended.forEach(s => log(` • ${s.name}`, 'gray'));
1317
- log('', 'gray');
1318
- log('These skills are now available in your conversations.', 'gray');
1471
+ log(`Installing ${registry.source}...`, "cyan");
1472
+ execSync(`openskills install ${registry.source} -y`, {
1473
+ stdio: "inherit",
1474
+ });
1475
+ execSync("openskills sync -y", { stdio: "pipe" });
1476
+ log("", "gray");
1477
+ log("✅ All skills installed successfully", "green");
1478
+ log("", "gray");
1479
+ log("Installed skills:", "gray");
1480
+ recommended.forEach((s) => log(` • ${s.name}`, "gray"));
1481
+ log("", "gray");
1482
+ log("These skills are now available in your conversations.", "gray");
1319
1483
  } catch (e) {
1320
- log('❌ Installation failed', 'red');
1484
+ log("❌ Installation failed", "red");
1321
1485
  }
1322
1486
  },
1323
1487
 
1324
1488
  // -------------------------------------------------------------------------
1325
1489
  doctor: () => {
1326
- const fs = require('fs');
1327
- const path = require('path');
1328
- const { execSync } = require('child_process');
1490
+ const fs = require("fs");
1491
+ const path = require("path");
1492
+ const { execSync } = require("child_process");
1329
1493
  const COLORS = {
1330
- reset: '\x1b[0m',
1331
- green: '\x1b[32m',
1332
- blue: '\x1b[34m',
1333
- yellow: '\x1b[33m',
1334
- gray: '\x1b[90m',
1335
- red: '\x1b[31m',
1336
- cyan: '\x1b[36m'
1494
+ reset: "\x1b[0m",
1495
+ green: "\x1b[32m",
1496
+ blue: "\x1b[34m",
1497
+ yellow: "\x1b[33m",
1498
+ gray: "\x1b[90m",
1499
+ red: "\x1b[31m",
1500
+ cyan: "\x1b[36m",
1337
1501
  };
1338
1502
 
1339
- const log = (msg, color = 'reset') => {
1503
+ const log = (msg, color = "reset") => {
1340
1504
  console.log(`${COLORS[color]}${msg}${COLORS.reset}`);
1341
1505
  };
1342
1506
 
1343
- log('', 'gray');
1344
- log('🏥 SMC Health Check', 'blue');
1345
- log('=====================================', 'gray');
1346
- log('', 'gray');
1507
+ log("", "gray");
1508
+ log("🏥 SMC Health Check", "blue");
1509
+ log("=====================================", "gray");
1510
+ log("", "gray");
1347
1511
 
1348
1512
  const checks = [];
1349
1513
  let passCount = 0;
@@ -1351,197 +1515,275 @@ const commands = {
1351
1515
  let failCount = 0;
1352
1516
 
1353
1517
  // Check 1: Global config
1354
- const globalConfigDir = path.join(process.env.HOME || process.env.USERPROFILE, '.claude');
1355
- const globalConfigFile = path.join(globalConfigDir, 'config.json');
1518
+ const globalConfigDir = path.join(
1519
+ process.env.HOME || process.env.USERPROFILE,
1520
+ ".claude",
1521
+ );
1522
+ const globalConfigFile = path.join(globalConfigDir, "config.json");
1356
1523
 
1357
1524
  if (fs.existsSync(globalConfigFile)) {
1358
- checks.push({ name: 'Global config', status: 'pass', msg: globalConfigFile });
1525
+ checks.push({
1526
+ name: "Global config",
1527
+ status: "pass",
1528
+ msg: globalConfigFile,
1529
+ });
1359
1530
  passCount++;
1360
1531
  } else {
1361
- checks.push({ name: 'Global config', status: 'fail', msg: 'Run: smc init' });
1532
+ checks.push({
1533
+ name: "Global config",
1534
+ status: "fail",
1535
+ msg: "Run: smc init",
1536
+ });
1362
1537
  failCount++;
1363
1538
  }
1364
1539
 
1365
1540
  // Check 2: Project .claude directory
1366
1541
  const projectDir = process.cwd();
1367
- const projectClaudeDir = path.join(projectDir, '.claude');
1542
+ const projectClaudeDir = path.join(projectDir, ".claude");
1368
1543
 
1369
1544
  if (fs.existsSync(projectClaudeDir)) {
1370
- checks.push({ name: 'Project .claude/', status: 'pass', msg: projectClaudeDir });
1545
+ checks.push({
1546
+ name: "Project .claude/",
1547
+ status: "pass",
1548
+ msg: projectClaudeDir,
1549
+ });
1371
1550
  passCount++;
1372
1551
 
1373
1552
  // Check for key files
1374
- const agentsFile = path.join(projectClaudeDir, 'AGENTS.md');
1553
+ const agentsFile = path.join(projectClaudeDir, "AGENTS.md");
1375
1554
  if (fs.existsSync(agentsFile)) {
1376
- checks.push({ name: 'AGENTS.md', status: 'pass', msg: 'Generated' });
1555
+ checks.push({ name: "AGENTS.md", status: "pass", msg: "Generated" });
1377
1556
  passCount++;
1378
1557
  } else {
1379
- checks.push({ name: 'AGENTS.md', status: 'warn', msg: 'Run: smc sync' });
1558
+ checks.push({
1559
+ name: "AGENTS.md",
1560
+ status: "warn",
1561
+ msg: "Run: smc sync",
1562
+ });
1380
1563
  warnCount++;
1381
1564
  }
1382
1565
 
1383
1566
  // Check MEMORY.md age
1384
- const memoryFile = path.join(projectClaudeDir, 'MEMORY.md');
1567
+ const memoryFile = path.join(projectClaudeDir, "MEMORY.md");
1385
1568
  if (fs.existsSync(memoryFile)) {
1386
1569
  const stats = fs.statSync(memoryFile);
1387
- const daysSinceUpdate = (Date.now() - stats.mtime.getTime()) / (1000 * 60 * 60 * 24);
1570
+ const daysSinceUpdate =
1571
+ (Date.now() - stats.mtime.getTime()) / (1000 * 60 * 60 * 24);
1388
1572
  if (daysSinceUpdate > 30) {
1389
- checks.push({ name: 'MEMORY.md', status: 'warn', msg: `Updated ${Math.floor(daysSinceUpdate)} days ago` });
1573
+ checks.push({
1574
+ name: "MEMORY.md",
1575
+ status: "warn",
1576
+ msg: `Updated ${Math.floor(daysSinceUpdate)} days ago`,
1577
+ });
1390
1578
  warnCount++;
1391
1579
  } else {
1392
- checks.push({ name: 'MEMORY.md', status: 'pass', msg: `Updated ${Math.floor(daysSinceUpdate)} days ago` });
1580
+ checks.push({
1581
+ name: "MEMORY.md",
1582
+ status: "pass",
1583
+ msg: `Updated ${Math.floor(daysSinceUpdate)} days ago`,
1584
+ });
1393
1585
  passCount++;
1394
1586
  }
1395
1587
  } else {
1396
- checks.push({ name: 'MEMORY.md', status: 'warn', msg: 'Not found' });
1588
+ checks.push({ name: "MEMORY.md", status: "warn", msg: "Not found" });
1397
1589
  warnCount++;
1398
1590
  }
1399
1591
 
1400
1592
  // Check hooks
1401
- const hooksDir = path.join(projectClaudeDir, 'hooks');
1593
+ const hooksDir = path.join(projectClaudeDir, "hooks");
1402
1594
  if (fs.existsSync(hooksDir)) {
1403
- const hookFiles = fs.readdirSync(hooksDir).filter(f => !f.startsWith('.'));
1404
- checks.push({ name: 'Hooks', status: 'pass', msg: `${hookFiles.length} hooks` });
1595
+ const hookFiles = fs
1596
+ .readdirSync(hooksDir)
1597
+ .filter((f) => !f.startsWith("."));
1598
+ checks.push({
1599
+ name: "Hooks",
1600
+ status: "pass",
1601
+ msg: `${hookFiles.length} hooks`,
1602
+ });
1405
1603
  passCount++;
1406
1604
  } else {
1407
- checks.push({ name: 'Hooks', status: 'warn', msg: 'No hooks directory' });
1605
+ checks.push({
1606
+ name: "Hooks",
1607
+ status: "warn",
1608
+ msg: "No hooks directory",
1609
+ });
1408
1610
  warnCount++;
1409
1611
  }
1410
1612
 
1411
1613
  // Check skills
1412
- const skillsDir = path.join(projectClaudeDir, 'skills');
1614
+ const skillsDir = path.join(projectClaudeDir, "skills");
1413
1615
  if (fs.existsSync(skillsDir)) {
1414
- const skillDirs = fs.readdirSync(skillsDir).filter(f => {
1616
+ const skillDirs = fs.readdirSync(skillsDir).filter((f) => {
1415
1617
  const dir = path.join(skillsDir, f);
1416
- return fs.statSync(dir).isDirectory() && f !== 'template' && f !== 'examples';
1618
+ return (
1619
+ fs.statSync(dir).isDirectory() &&
1620
+ f !== "template" &&
1621
+ f !== "examples"
1622
+ );
1623
+ });
1624
+ checks.push({
1625
+ name: "Project Skills",
1626
+ status: "pass",
1627
+ msg: `${skillDirs.length} skills`,
1417
1628
  });
1418
- checks.push({ name: 'Project Skills', status: 'pass', msg: `${skillDirs.length} skills` });
1419
1629
  passCount++;
1420
1630
  } else {
1421
- checks.push({ name: 'Project Skills', status: 'warn', msg: 'No skills directory' });
1631
+ checks.push({
1632
+ name: "Project Skills",
1633
+ status: "warn",
1634
+ msg: "No skills directory",
1635
+ });
1422
1636
  warnCount++;
1423
1637
  }
1424
1638
  } else {
1425
- checks.push({ name: 'Project .claude/', status: 'warn', msg: 'Run: smc template or smc sync' });
1639
+ checks.push({
1640
+ name: "Project .claude/",
1641
+ status: "warn",
1642
+ msg: "Run: smc template or smc sync",
1643
+ });
1426
1644
  warnCount++;
1427
1645
  }
1428
1646
 
1429
1647
  // Check 3: OpenSkills
1430
1648
  try {
1431
- execSync('openskills --version', { stdio: 'ignore' });
1432
- const globalSkillsDir = path.join(globalConfigDir, 'skills');
1649
+ execSync("openskills --version", { stdio: "ignore" });
1650
+ const globalSkillsDir = path.join(globalConfigDir, "skills");
1433
1651
  if (fs.existsSync(globalSkillsDir)) {
1434
- const skillCount = fs.readdirSync(globalSkillsDir).filter(f => {
1652
+ const skillCount = fs.readdirSync(globalSkillsDir).filter((f) => {
1435
1653
  const dir = path.join(globalSkillsDir, f);
1436
- return fs.statSync(dir).isDirectory() && !f.startsWith('.');
1654
+ return fs.statSync(dir).isDirectory() && !f.startsWith(".");
1437
1655
  }).length;
1438
- checks.push({ name: 'OpenSkills', status: 'pass', msg: `${skillCount} global skills` });
1656
+ checks.push({
1657
+ name: "OpenSkills",
1658
+ status: "pass",
1659
+ msg: `${skillCount} global skills`,
1660
+ });
1439
1661
  passCount++;
1440
1662
  } else {
1441
- checks.push({ name: 'OpenSkills', status: 'pass', msg: 'Installed' });
1663
+ checks.push({ name: "OpenSkills", status: "pass", msg: "Installed" });
1442
1664
  passCount++;
1443
1665
  }
1444
1666
  } catch {
1445
- checks.push({ name: 'OpenSkills', status: 'warn', msg: 'Not installed (run: npm i -g openskills)' });
1667
+ checks.push({
1668
+ name: "OpenSkills",
1669
+ status: "warn",
1670
+ msg: "Not installed (run: npm i -g openskills)",
1671
+ });
1446
1672
  warnCount++;
1447
1673
  }
1448
1674
 
1449
1675
  // Check 4: Git
1450
1676
  try {
1451
- execSync('git rev-parse --git-dir', { stdio: 'ignore', cwd: projectDir });
1452
- checks.push({ name: 'Git', status: 'pass', msg: 'Repository detected' });
1677
+ execSync("git rev-parse --git-dir", { stdio: "ignore", cwd: projectDir });
1678
+ checks.push({ name: "Git", status: "pass", msg: "Repository detected" });
1453
1679
  passCount++;
1454
1680
  } catch {
1455
- checks.push({ name: 'Git', status: 'warn', msg: 'Not a git repository' });
1681
+ checks.push({ name: "Git", status: "warn", msg: "Not a git repository" });
1456
1682
  warnCount++;
1457
1683
  }
1458
1684
 
1459
1685
  // Display results
1460
1686
  for (const check of checks) {
1461
- const icon = check.status === 'pass' ? '✅' : check.status === 'warn' ? '⚠️' : '❌';
1462
- const color = check.status === 'pass' ? 'green' : check.status === 'warn' ? 'yellow' : 'red';
1687
+ const icon =
1688
+ check.status === "pass" ? "✅" : check.status === "warn" ? "⚠️" : "❌";
1689
+ const color =
1690
+ check.status === "pass"
1691
+ ? "green"
1692
+ : check.status === "warn"
1693
+ ? "yellow"
1694
+ : "red";
1463
1695
  log(`${icon} ${check.name}`, color);
1464
- log(` ${check.msg}`, 'gray');
1465
- log('', 'gray');
1696
+ log(` ${check.msg}`, "gray");
1697
+ log("", "gray");
1466
1698
  }
1467
1699
 
1468
- log('=====================================', 'gray');
1469
- log(`Summary: ${passCount} passed, ${warnCount} warnings${failCount > 0 ? `, ${failCount} failed` : ''}`, 'gray');
1470
- log('', 'gray');
1700
+ log("=====================================", "gray");
1701
+ log(
1702
+ `Summary: ${passCount} passed, ${warnCount} warnings${failCount > 0 ? `, ${failCount} failed` : ""}`,
1703
+ "gray",
1704
+ );
1705
+ log("", "gray");
1471
1706
 
1472
1707
  if (failCount > 0) {
1473
- log('Fix failed checks to continue.', 'red');
1708
+ log("Fix failed checks to continue.", "red");
1474
1709
  }
1475
1710
  },
1476
1711
 
1477
1712
  // -------------------------------------------------------------------------
1478
- 'skills:search': (keyword) => {
1479
- const fs = require('fs');
1480
- const path = require('path');
1713
+ "skills:search": (keyword) => {
1714
+ const fs = require("fs");
1715
+ const path = require("path");
1481
1716
  const COLORS = {
1482
- reset: '\x1b[0m',
1483
- green: '\x1b[32m',
1484
- blue: '\x1b[34m',
1485
- yellow: '\x1b[33m',
1486
- gray: '\x1b[90m',
1487
- cyan: '\x1b[36m'
1717
+ reset: "\x1b[0m",
1718
+ green: "\x1b[32m",
1719
+ blue: "\x1b[34m",
1720
+ yellow: "\x1b[33m",
1721
+ gray: "\x1b[90m",
1722
+ cyan: "\x1b[36m",
1488
1723
  };
1489
1724
 
1490
- const log = (msg, color = 'reset') => {
1725
+ const log = (msg, color = "reset") => {
1491
1726
  console.log(`${COLORS[color]}${msg}${COLORS.reset}`);
1492
1727
  };
1493
1728
 
1494
1729
  if (!keyword) {
1495
- log('Usage: smc skills:search <keyword>', 'yellow');
1496
- log('', 'gray');
1497
- log('Examples:', 'gray');
1498
- log(' smc skills:search pdf', 'gray');
1499
- log(' smc skills:search "前端设计"', 'gray');
1730
+ log("Usage: smc skills:search <keyword>", "yellow");
1731
+ log("", "gray");
1732
+ log("Examples:", "gray");
1733
+ log(" smc skills:search pdf", "gray");
1734
+ log(' smc skills:search "前端设计"', "gray");
1500
1735
  return;
1501
1736
  }
1502
1737
 
1503
- log('', 'gray');
1504
- log(`🔍 Searching for: "${keyword}"`, 'blue');
1505
- log('=====================================', 'gray');
1506
- log('', 'gray');
1738
+ log("", "gray");
1739
+ log(`🔍 Searching for: "${keyword}"`, "blue");
1740
+ log("=====================================", "gray");
1741
+ log("", "gray");
1507
1742
 
1508
1743
  const results = [];
1509
1744
  const lowerKeyword = keyword.toLowerCase();
1510
1745
 
1511
1746
  // Search in official skills registry
1512
- const officialSkillsFile = path.join(__dirname, '../config/official-skills.json');
1747
+ const officialSkillsFile = path.join(
1748
+ __dirname,
1749
+ "../config/official-skills.json",
1750
+ );
1513
1751
  if (fs.existsSync(officialSkillsFile)) {
1514
- const registry = JSON.parse(fs.readFileSync(officialSkillsFile, 'utf-8'));
1752
+ const registry = JSON.parse(fs.readFileSync(officialSkillsFile, "utf-8"));
1515
1753
 
1516
1754
  for (const skill of registry.skills) {
1517
1755
  const matchName = skill.name.toLowerCase().includes(lowerKeyword);
1518
- const matchDesc = skill.description.toLowerCase().includes(lowerKeyword);
1519
- const matchCat = registry.categories[skill.category]?.name.toLowerCase().includes(lowerKeyword);
1756
+ const matchDesc = skill.description
1757
+ .toLowerCase()
1758
+ .includes(lowerKeyword);
1759
+ const matchCat = registry.categories[skill.category]?.name
1760
+ .toLowerCase()
1761
+ .includes(lowerKeyword);
1520
1762
 
1521
1763
  if (matchName || matchDesc || matchCat) {
1522
1764
  results.push({
1523
1765
  name: skill.name,
1524
1766
  description: skill.description,
1525
1767
  category: registry.categories[skill.category]?.name,
1526
- source: 'official',
1527
- recommended: skill.recommended
1768
+ source: "official",
1769
+ recommended: skill.recommended,
1528
1770
  });
1529
1771
  }
1530
1772
  }
1531
1773
  }
1532
1774
 
1533
1775
  // Search in sources.yaml
1534
- const sourcesFile = path.join(__dirname, '../sources.yaml');
1776
+ const sourcesFile = path.join(__dirname, "../sources.yaml");
1535
1777
  if (fs.existsSync(sourcesFile)) {
1536
- const content = fs.readFileSync(sourcesFile, 'utf-8');
1778
+ const content = fs.readFileSync(sourcesFile, "utf-8");
1537
1779
  // Simple YAML parsing for skills
1538
- const lines = content.split('\n');
1780
+ const lines = content.split("\n");
1539
1781
  let currentSkill = null;
1540
1782
 
1541
1783
  for (const line of lines) {
1542
1784
  const nameMatch = line.match(/^\s*-\s*name:\s*(.+)$/);
1543
1785
  if (nameMatch) {
1544
- currentSkill = { name: nameMatch[1].trim(), source: 'marketplace' };
1786
+ currentSkill = { name: nameMatch[1].trim(), source: "marketplace" };
1545
1787
  if (currentSkill.name.toLowerCase().includes(lowerKeyword)) {
1546
1788
  results.push(currentSkill);
1547
1789
  }
@@ -1557,28 +1799,31 @@ const commands = {
1557
1799
  }
1558
1800
 
1559
1801
  // Search in global skills
1560
- const globalSkillsDir = path.join(process.env.HOME || process.env.USERPROFILE, '.claude/skills');
1802
+ const globalSkillsDir = path.join(
1803
+ process.env.HOME || process.env.USERPROFILE,
1804
+ ".claude/skills",
1805
+ );
1561
1806
  if (fs.existsSync(globalSkillsDir)) {
1562
- const skillDirs = fs.readdirSync(globalSkillsDir).filter(f => {
1807
+ const skillDirs = fs.readdirSync(globalSkillsDir).filter((f) => {
1563
1808
  const dir = path.join(globalSkillsDir, f);
1564
- return fs.statSync(dir).isDirectory() && !f.startsWith('.');
1809
+ return fs.statSync(dir).isDirectory() && !f.startsWith(".");
1565
1810
  });
1566
1811
 
1567
1812
  for (const skillName of skillDirs) {
1568
1813
  if (skillName.toLowerCase().includes(lowerKeyword)) {
1569
1814
  // Check if already in results
1570
- if (!results.some(r => r.name === skillName)) {
1571
- const skillFile = path.join(globalSkillsDir, skillName, 'SKILL.md');
1572
- let description = '';
1815
+ if (!results.some((r) => r.name === skillName)) {
1816
+ const skillFile = path.join(globalSkillsDir, skillName, "SKILL.md");
1817
+ let description = "";
1573
1818
  if (fs.existsSync(skillFile)) {
1574
- const content = fs.readFileSync(skillFile, 'utf-8');
1819
+ const content = fs.readFileSync(skillFile, "utf-8");
1575
1820
  const descMatch = content.match(/description:\s*(.+)/);
1576
1821
  if (descMatch) description = descMatch[1];
1577
1822
  }
1578
1823
  results.push({
1579
1824
  name: skillName,
1580
- description: description || 'Local skill',
1581
- source: 'installed'
1825
+ description: description || "Local skill",
1826
+ source: "installed",
1582
1827
  });
1583
1828
  }
1584
1829
  }
@@ -1587,56 +1832,61 @@ const commands = {
1587
1832
 
1588
1833
  // Display results
1589
1834
  if (results.length === 0) {
1590
- log('No skills found matching your search.', 'yellow');
1835
+ log("No skills found matching your search.", "yellow");
1591
1836
  } else {
1592
1837
  for (const result of results) {
1593
- const sourceIcon = result.source === 'official' ? '🔷' : result.source === 'marketplace' ? '📦' : '✓';
1594
- const rec = result.recommended ? ' [推荐]' : '';
1595
- log(`${sourceIcon} ${result.name}${rec}`, 'cyan');
1838
+ const sourceIcon =
1839
+ result.source === "official"
1840
+ ? "🔷"
1841
+ : result.source === "marketplace"
1842
+ ? "📦"
1843
+ : "✓";
1844
+ const rec = result.recommended ? " [推荐]" : "";
1845
+ log(`${sourceIcon} ${result.name}${rec}`, "cyan");
1596
1846
  if (result.description) {
1597
- log(` ${result.description}`, 'gray');
1847
+ log(` ${result.description}`, "gray");
1598
1848
  }
1599
1849
  if (result.category) {
1600
- log(` 分类: ${result.category}`, 'gray');
1850
+ log(` 分类: ${result.category}`, "gray");
1601
1851
  }
1602
- log('', 'gray');
1852
+ log("", "gray");
1603
1853
  }
1604
1854
  }
1605
1855
 
1606
- log('=====================================', 'gray');
1607
- log(`Found ${results.length} result(s)`, 'gray');
1608
- log('', 'gray');
1856
+ log("=====================================", "gray");
1857
+ log(`Found ${results.length} result(s)`, "gray");
1858
+ log("", "gray");
1609
1859
  },
1610
1860
 
1611
1861
  // -------------------------------------------------------------------------
1612
- 'skills:validate': (skillPath) => {
1613
- const fs = require('fs');
1614
- const path = require('path');
1862
+ "skills:validate": (skillPath) => {
1863
+ const fs = require("fs");
1864
+ const path = require("path");
1615
1865
  const COLORS = {
1616
- reset: '\x1b[0m',
1617
- green: '\x1b[32m',
1618
- blue: '\x1b[34m',
1619
- yellow: '\x1b[33m',
1620
- gray: '\x1b[90m',
1621
- red: '\x1b[31m'
1866
+ reset: "\x1b[0m",
1867
+ green: "\x1b[32m",
1868
+ blue: "\x1b[34m",
1869
+ yellow: "\x1b[33m",
1870
+ gray: "\x1b[90m",
1871
+ red: "\x1b[31m",
1622
1872
  };
1623
1873
 
1624
- const log = (msg, color = 'reset') => {
1874
+ const log = (msg, color = "reset") => {
1625
1875
  console.log(`${COLORS[color]}${msg}${COLORS.reset}`);
1626
1876
  };
1627
1877
 
1628
1878
  // Default to current directory if not specified
1629
- const targetPath = skillPath || path.join(process.cwd(), '.claude/skills');
1879
+ const targetPath = skillPath || path.join(process.cwd(), ".claude/skills");
1630
1880
 
1631
1881
  if (!fs.existsSync(targetPath)) {
1632
- log(`❌ Path not found: ${targetPath}`, 'red');
1882
+ log(`❌ Path not found: ${targetPath}`, "red");
1633
1883
  return;
1634
1884
  }
1635
1885
 
1636
- log('', 'gray');
1637
- log('🔍 Validating Skills', 'blue');
1638
- log('=====================================', 'gray');
1639
- log('', 'gray');
1886
+ log("", "gray");
1887
+ log("🔍 Validating Skills", "blue");
1888
+ log("=====================================", "gray");
1889
+ log("", "gray");
1640
1890
 
1641
1891
  const checks = [];
1642
1892
  let passCount = 0;
@@ -1647,22 +1897,22 @@ const commands = {
1647
1897
 
1648
1898
  const validateSkill = (skillDir) => {
1649
1899
  const skillName = path.basename(skillDir);
1650
- const skillFile = path.join(skillDir, 'SKILL.md');
1900
+ const skillFile = path.join(skillDir, "SKILL.md");
1651
1901
  const errors = [];
1652
1902
  const warnings = [];
1653
1903
 
1654
1904
  // Check SKILL.md exists
1655
1905
  if (!fs.existsSync(skillFile)) {
1656
- errors.push('SKILL.md not found');
1906
+ errors.push("SKILL.md not found");
1657
1907
  return { name: skillName, errors, warnings };
1658
1908
  }
1659
1909
 
1660
1910
  // Parse SKILL.md
1661
- const content = fs.readFileSync(skillFile, 'utf-8');
1911
+ const content = fs.readFileSync(skillFile, "utf-8");
1662
1912
  const frontmatterMatch = content.match(/^---\n(.*?)\n---/s);
1663
1913
 
1664
1914
  if (!frontmatterMatch) {
1665
- errors.push('No frontmatter found (--- delimited YAML required)');
1915
+ errors.push("No frontmatter found (--- delimited YAML required)");
1666
1916
  } else {
1667
1917
  const frontmatter = frontmatterMatch[1];
1668
1918
 
@@ -1676,8 +1926,13 @@ const commands = {
1676
1926
  }
1677
1927
 
1678
1928
  // Check for references directory if referenced
1679
- if (content.includes('references/') && !fs.existsSync(path.join(skillDir, 'references'))) {
1680
- warnings.push('Content references "references/" but directory not found');
1929
+ if (
1930
+ content.includes("references/") &&
1931
+ !fs.existsSync(path.join(skillDir, "references"))
1932
+ ) {
1933
+ warnings.push(
1934
+ 'Content references "references/" but directory not found',
1935
+ );
1681
1936
  }
1682
1937
 
1683
1938
  return { name: skillName, errors, warnings };
@@ -1685,7 +1940,7 @@ const commands = {
1685
1940
 
1686
1941
  if (stats.isDirectory()) {
1687
1942
  // Check if it's a skills directory or a single skill
1688
- const skillFile = path.join(targetPath, 'SKILL.md');
1943
+ const skillFile = path.join(targetPath, "SKILL.md");
1689
1944
  if (fs.existsSync(skillFile)) {
1690
1945
  // Single skill
1691
1946
  const result = validateSkill(targetPath);
@@ -1696,7 +1951,7 @@ const commands = {
1696
1951
  for (const entry of entries) {
1697
1952
  const entryPath = path.join(targetPath, entry);
1698
1953
  const entryStats = fs.statSync(entryPath);
1699
- if (entryStats.isDirectory() && !entry.startsWith('.')) {
1954
+ if (entryStats.isDirectory() && !entry.startsWith(".")) {
1700
1955
  const result = validateSkill(entryPath);
1701
1956
  checks.push(result);
1702
1957
  }
@@ -1707,56 +1962,59 @@ const commands = {
1707
1962
  // Display results
1708
1963
  for (const check of checks) {
1709
1964
  if (check.errors.length === 0 && check.warnings.length === 0) {
1710
- log(`✅ ${check.name}`, 'green');
1965
+ log(`✅ ${check.name}`, "green");
1711
1966
  passCount++;
1712
1967
  } else if (check.errors.length === 0) {
1713
- log(`⚠️ ${check.name}`, 'yellow');
1968
+ log(`⚠️ ${check.name}`, "yellow");
1714
1969
  passCount++;
1715
1970
  } else {
1716
- log(`❌ ${check.name}`, 'red');
1971
+ log(`❌ ${check.name}`, "red");
1717
1972
  failCount++;
1718
1973
  }
1719
1974
 
1720
1975
  for (const error of check.errors) {
1721
- log(` ❌ ${error}`, 'red');
1976
+ log(` ❌ ${error}`, "red");
1722
1977
  }
1723
1978
  for (const warning of check.warnings) {
1724
- log(` ⚠️ ${warning}`, 'yellow');
1979
+ log(` ⚠️ ${warning}`, "yellow");
1725
1980
  }
1726
- log('', 'gray');
1981
+ log("", "gray");
1727
1982
  }
1728
1983
 
1729
- log('=====================================', 'gray');
1730
- log(`Validated ${checks.length} skill(s): ${passCount} passed${failCount > 0 ? `, ${failCount} failed` : ''}`, 'gray');
1731
- log('', 'gray');
1984
+ log("=====================================", "gray");
1985
+ log(
1986
+ `Validated ${checks.length} skill(s): ${passCount} passed${failCount > 0 ? `, ${failCount} failed` : ""}`,
1987
+ "gray",
1988
+ );
1989
+ log("", "gray");
1732
1990
  },
1733
1991
 
1734
1992
  // -------------------------------------------------------------------------
1735
- 'skills:update': () => {
1736
- const fs = require('fs');
1737
- const path = require('path');
1738
- const { execSync } = require('child_process');
1993
+ "skills:update": () => {
1994
+ const fs = require("fs");
1995
+ const path = require("path");
1996
+ const { execSync } = require("child_process");
1739
1997
  const COLORS = {
1740
- reset: '\x1b[0m',
1741
- green: '\x1b[32m',
1742
- blue: '\x1b[34m',
1743
- yellow: '\x1b[33m',
1744
- gray: '\x1b[90m',
1745
- red: '\x1b[31m'
1998
+ reset: "\x1b[0m",
1999
+ green: "\x1b[32m",
2000
+ blue: "\x1b[34m",
2001
+ yellow: "\x1b[33m",
2002
+ gray: "\x1b[90m",
2003
+ red: "\x1b[31m",
1746
2004
  };
1747
2005
 
1748
- const log = (msg, color = 'reset') => {
2006
+ const log = (msg, color = "reset") => {
1749
2007
  console.log(`${COLORS[color]}${msg}${COLORS.reset}`);
1750
2008
  };
1751
2009
 
1752
- log('', 'gray');
1753
- log('🔄 Updating Official Skills List', 'blue');
1754
- log('=====================================', 'gray');
1755
- log('', 'gray');
2010
+ log("", "gray");
2011
+ log("🔄 Updating Official Skills List", "blue");
2012
+ log("=====================================", "gray");
2013
+ log("", "gray");
1756
2014
 
1757
2015
  // Fetch latest skills from anthropics/skills
1758
- const tempDir = path.join(__dirname, '../.tmp');
1759
- const repoUrl = 'https://github.com/anthropics/skills.git';
2016
+ const tempDir = path.join(__dirname, "../.tmp");
2017
+ const repoUrl = "https://github.com/anthropics/skills.git";
1760
2018
 
1761
2019
  try {
1762
2020
  // Create temp dir
@@ -1764,7 +2022,7 @@ const commands = {
1764
2022
  fs.mkdirSync(tempDir, { recursive: true });
1765
2023
  }
1766
2024
 
1767
- const cloneDir = path.join(tempDir, 'anthropics-skills');
2025
+ const cloneDir = path.join(tempDir, "anthropics-skills");
1768
2026
 
1769
2027
  // Remove existing clone if present
1770
2028
  const rimraf = (dir) => {
@@ -1775,106 +2033,115 @@ const commands = {
1775
2033
 
1776
2034
  rimraf(cloneDir);
1777
2035
 
1778
- log('Cloning anthropics/skills...', 'gray');
1779
- execSync(`git clone --depth 1 ${repoUrl} ${cloneDir}`, { stdio: 'pipe' });
2036
+ log("Cloning anthropics/skills...", "gray");
2037
+ execSync(`git clone --depth 1 ${repoUrl} ${cloneDir}`, { stdio: "pipe" });
1780
2038
 
1781
2039
  // Read skills directory to get available skills
1782
- const skillsDir = path.join(cloneDir, 'skills');
1783
- const skillCategories = fs.readdirSync(skillsDir).filter(f => {
2040
+ const skillsDir = path.join(cloneDir, "skills");
2041
+ const skillCategories = fs.readdirSync(skillsDir).filter((f) => {
1784
2042
  const dir = path.join(skillsDir, f);
1785
2043
  return fs.statSync(dir).isDirectory();
1786
2044
  });
1787
2045
 
1788
- log(`Found ${skillCategories.length} skills in repository`, 'gray');
1789
- log('', 'gray');
2046
+ log(`Found ${skillCategories.length} skills in repository`, "gray");
2047
+ log("", "gray");
1790
2048
 
1791
2049
  // Update the registry file
1792
- const registryFile = path.join(__dirname, '../config/official-skills.json');
1793
- let registry = { version: '1.0.0', last_updated: new Date().toISOString().split('T')[0], source: 'anthropics/skills', categories: {}, skills: [] };
2050
+ const registryFile = path.join(
2051
+ __dirname,
2052
+ "../config/official-skills.json",
2053
+ );
2054
+ let registry = {
2055
+ version: "1.0.0",
2056
+ last_updated: new Date().toISOString().split("T")[0],
2057
+ source: "anthropics/skills",
2058
+ categories: {},
2059
+ skills: [],
2060
+ };
1794
2061
 
1795
2062
  if (fs.existsSync(registryFile)) {
1796
- registry = JSON.parse(fs.readFileSync(registryFile, 'utf-8'));
2063
+ registry = JSON.parse(fs.readFileSync(registryFile, "utf-8"));
1797
2064
  }
1798
2065
 
1799
2066
  // Update timestamp
1800
- registry.last_updated = new Date().toISOString().split('T')[0];
2067
+ registry.last_updated = new Date().toISOString().split("T")[0];
1801
2068
 
1802
2069
  fs.writeFileSync(registryFile, JSON.stringify(registry, null, 2));
1803
2070
 
1804
2071
  // Cleanup
1805
2072
  rimraf(cloneDir);
1806
2073
 
1807
- log('✅ Official skills list updated', 'green');
1808
- log(` Updated: ${registry.last_updated}`, 'gray');
1809
- log('', 'gray');
1810
- log('Run: smc skills:official', 'gray');
2074
+ log("✅ Official skills list updated", "green");
2075
+ log(` Updated: ${registry.last_updated}`, "gray");
2076
+ log("", "gray");
2077
+ log("Run: smc skills:official", "gray");
1811
2078
  } catch (e) {
1812
- log('❌ Update failed', 'red');
1813
- log(` ${e.message}`, 'gray');
2079
+ log("❌ Update failed", "red");
2080
+ log(` ${e.message}`, "gray");
1814
2081
  }
1815
2082
  },
1816
2083
 
1817
2084
  // -------------------------------------------------------------------------
1818
2085
  config: (action, key, value) => {
1819
- const fs = require('fs');
1820
- const path = require('path');
1821
- const { loadConfig, saveConfig, CONFIG_FILE } = require('./config');
2086
+ const fs = require("fs");
2087
+ const path = require("path");
2088
+ const { loadConfig, saveConfig, CONFIG_FILE } = require("./config");
1822
2089
  const COLORS = {
1823
- reset: '\x1b[0m',
1824
- green: '\x1b[32m',
1825
- blue: '\x1b[34m',
1826
- yellow: '\x1b[33m',
1827
- gray: '\x1b[90m',
1828
- red: '\x1b[31m'
2090
+ reset: "\x1b[0m",
2091
+ green: "\x1b[32m",
2092
+ blue: "\x1b[34m",
2093
+ yellow: "\x1b[33m",
2094
+ gray: "\x1b[90m",
2095
+ red: "\x1b[31m",
1829
2096
  };
1830
2097
 
1831
- const log = (msg, color = 'reset') => {
2098
+ const log = (msg, color = "reset") => {
1832
2099
  console.log(`${COLORS[color]}${msg}${COLORS.reset}`);
1833
2100
  };
1834
2101
 
1835
2102
  if (!action) {
1836
2103
  // Show current config
1837
2104
  const config = loadConfig();
1838
- log('', 'gray');
1839
- log('⚙️ SMC Configuration', 'blue');
1840
- log('=====================================', 'gray');
1841
- log('', 'gray');
1842
- log(`File: ${CONFIG_FILE}`, 'gray');
1843
- log('', 'gray');
2105
+ log("", "gray");
2106
+ log("⚙️ SMC Configuration", "blue");
2107
+ log("=====================================", "gray");
2108
+ log("", "gray");
2109
+ log(`File: ${CONFIG_FILE}`, "gray");
2110
+ log("", "gray");
1844
2111
  log(JSON.stringify(config, null, 2));
1845
- log('', 'gray');
1846
- log('=====================================', 'gray');
1847
- log('', 'gray');
1848
- log('Commands:', 'gray');
1849
- log(' smc config get <key> Get a config value', 'gray');
1850
- log(' smc config set <key> <value> Set a config value', 'gray');
1851
- log('', 'gray');
2112
+ log("", "gray");
2113
+ log("=====================================", "gray");
2114
+ log("", "gray");
2115
+ log("Commands:", "gray");
2116
+ log(" smc config get <key> Get a config value", "gray");
2117
+ log(" smc config set <key> <value> Set a config value", "gray");
2118
+ log("", "gray");
1852
2119
  return;
1853
2120
  }
1854
2121
 
1855
- if (action === 'get') {
2122
+ if (action === "get") {
1856
2123
  if (!key) {
1857
- log('Usage: smc config get <key>', 'yellow');
2124
+ log("Usage: smc config get <key>", "yellow");
1858
2125
  return;
1859
2126
  }
1860
2127
  const config = loadConfig();
1861
- const keys = key.split('.');
2128
+ const keys = key.split(".");
1862
2129
  let value = config;
1863
2130
  for (const k of keys) {
1864
2131
  value = value?.[k];
1865
2132
  }
1866
2133
  if (value !== undefined) {
1867
- log(`${key}: ${JSON.stringify(value, null, 2)}`, 'green');
2134
+ log(`${key}: ${JSON.stringify(value, null, 2)}`, "green");
1868
2135
  } else {
1869
- log(`Key not found: ${key}`, 'yellow');
2136
+ log(`Key not found: ${key}`, "yellow");
1870
2137
  }
1871
- } else if (action === 'set') {
2138
+ } else if (action === "set") {
1872
2139
  if (!key || value === undefined) {
1873
- log('Usage: smc config set <key> <value>', 'yellow');
2140
+ log("Usage: smc config set <key> <value>", "yellow");
1874
2141
  return;
1875
2142
  }
1876
2143
  const config = loadConfig();
1877
- const keys = key.split('.');
2144
+ const keys = key.split(".");
1878
2145
  let target = config;
1879
2146
  for (let i = 0; i < keys.length - 1; i++) {
1880
2147
  if (!target[keys[i]]) target[keys[i]] = {};
@@ -1887,56 +2154,56 @@ const commands = {
1887
2154
  target[keys[keys.length - 1]] = value;
1888
2155
  }
1889
2156
  saveConfig(config);
1890
- log(`✅ Set ${key} = ${target[keys[keys.length - 1]]}`, 'green');
2157
+ log(`✅ Set ${key} = ${target[keys[keys.length - 1]]}`, "green");
1891
2158
  } else {
1892
- log(`Unknown action: ${action}`, 'red');
1893
- log('Valid actions: get, set', 'gray');
2159
+ log(`Unknown action: ${action}`, "red");
2160
+ log("Valid actions: get, set", "gray");
1894
2161
  }
1895
2162
  },
1896
2163
 
1897
2164
  // -------------------------------------------------------------------------
1898
- 'skills:publish': (skillPath) => {
1899
- const fs = require('fs');
1900
- const path = require('path');
1901
- const { execSync } = require('child_process');
2165
+ "skills:publish": (skillPath) => {
2166
+ const fs = require("fs");
2167
+ const path = require("path");
2168
+ const { execSync } = require("child_process");
1902
2169
  const COLORS = {
1903
- reset: '\x1b[0m',
1904
- green: '\x1b[32m',
1905
- blue: '\x1b[34m',
1906
- yellow: '\x1b[33m',
1907
- gray: '\x1b[90m',
1908
- red: '\x1b[31m',
1909
- cyan: '\x1b[36m'
2170
+ reset: "\x1b[0m",
2171
+ green: "\x1b[32m",
2172
+ blue: "\x1b[34m",
2173
+ yellow: "\x1b[33m",
2174
+ gray: "\x1b[90m",
2175
+ red: "\x1b[31m",
2176
+ cyan: "\x1b[36m",
1910
2177
  };
1911
2178
 
1912
- const log = (msg, color = 'reset') => {
2179
+ const log = (msg, color = "reset") => {
1913
2180
  console.log(`${COLORS[color]}${msg}${COLORS.reset}`);
1914
2181
  };
1915
2182
 
1916
2183
  // Default to current directory's skills folder
1917
- const targetPath = skillPath || path.join(process.cwd(), '.claude/skills');
2184
+ const targetPath = skillPath || path.join(process.cwd(), ".claude/skills");
1918
2185
 
1919
2186
  if (!fs.existsSync(targetPath)) {
1920
- log(`❌ Path not found: ${targetPath}`, 'red');
1921
- log('', 'gray');
1922
- log('Usage: smc skills:publish [skill-path]', 'yellow');
1923
- log(' Creates a GitHub repo with your skill', 'gray');
2187
+ log(`❌ Path not found: ${targetPath}`, "red");
2188
+ log("", "gray");
2189
+ log("Usage: smc skills:publish [skill-path]", "yellow");
2190
+ log(" Creates a GitHub repo with your skill", "gray");
1924
2191
  return;
1925
2192
  }
1926
2193
 
1927
- log('', 'gray');
1928
- log('📦 Publish Skill to GitHub', 'blue');
1929
- log('=====================================', 'gray');
1930
- log('', 'gray');
2194
+ log("", "gray");
2195
+ log("📦 Publish Skill to GitHub", "blue");
2196
+ log("=====================================", "gray");
2197
+ log("", "gray");
1931
2198
 
1932
- const readline = require('readline');
2199
+ const readline = require("readline");
1933
2200
  const rl = readline.createInterface({
1934
2201
  input: process.stdin,
1935
- output: process.stdout
2202
+ output: process.stdout,
1936
2203
  });
1937
2204
 
1938
2205
  const question = (prompt) => {
1939
- return new Promise(resolve => {
2206
+ return new Promise((resolve) => {
1940
2207
  rl.question(prompt, resolve);
1941
2208
  });
1942
2209
  };
@@ -1947,234 +2214,258 @@ const commands = {
1947
2214
  let skillName, skillDir;
1948
2215
 
1949
2216
  if (stat.isDirectory()) {
1950
- const skillFile = path.join(targetPath, 'SKILL.md');
2217
+ const skillFile = path.join(targetPath, "SKILL.md");
1951
2218
  if (fs.existsSync(skillFile)) {
1952
2219
  // Single skill directory
1953
2220
  skillDir = targetPath;
1954
2221
  skillName = path.basename(targetPath);
1955
2222
  } else {
1956
2223
  // Skills directory - ask which skill
1957
- const entries = fs.readdirSync(targetPath).filter(f => {
2224
+ const entries = fs.readdirSync(targetPath).filter((f) => {
1958
2225
  const dir = path.join(targetPath, f);
1959
- return fs.statSync(dir).isDirectory() && !f.startsWith('.') && f !== 'template' && f !== 'examples';
2226
+ return (
2227
+ fs.statSync(dir).isDirectory() &&
2228
+ !f.startsWith(".") &&
2229
+ f !== "template" &&
2230
+ f !== "examples"
2231
+ );
1960
2232
  });
1961
2233
 
1962
2234
  if (entries.length === 0) {
1963
- log('❌ No skills found in directory', 'red');
2235
+ log("❌ No skills found in directory", "red");
1964
2236
  rl.close();
1965
2237
  return;
1966
2238
  }
1967
2239
 
1968
- log('Found skills:', 'gray');
1969
- entries.forEach((e, i) => log(` ${i + 1}. ${e}`, 'gray'));
1970
- log('', 'gray');
2240
+ log("Found skills:", "gray");
2241
+ entries.forEach((e, i) => log(` ${i + 1}. ${e}`, "gray"));
2242
+ log("", "gray");
1971
2243
 
1972
- const choice = await question('Select skill [1]: ');
1973
- const index = parseInt(choice || '1') - 1;
2244
+ const choice = await question("Select skill [1]: ");
2245
+ const index = parseInt(choice || "1") - 1;
1974
2246
  skillName = entries[index] || entries[0];
1975
2247
  skillDir = path.join(targetPath, skillName);
1976
2248
  }
1977
2249
  } else {
1978
- log('❌ Path must be a directory', 'red');
2250
+ log("❌ Path must be a directory", "red");
1979
2251
  rl.close();
1980
2252
  return;
1981
2253
  }
1982
2254
 
1983
2255
  // Read SKILL.md to get info
1984
- const skillFile = path.join(skillDir, 'SKILL.md');
2256
+ const skillFile = path.join(skillDir, "SKILL.md");
1985
2257
  if (!fs.existsSync(skillFile)) {
1986
- log('❌ SKILL.md not found. A skill must have SKILL.md', 'red');
2258
+ log("❌ SKILL.md not found. A skill must have SKILL.md", "red");
1987
2259
  rl.close();
1988
2260
  return;
1989
2261
  }
1990
2262
 
1991
- const skillContent = fs.readFileSync(skillFile, 'utf-8');
2263
+ const skillContent = fs.readFileSync(skillFile, "utf-8");
1992
2264
  const nameMatch = skillContent.match(/name:\s*(.+)/);
1993
2265
  const descMatch = skillContent.match(/description:\s*(.+)/);
1994
2266
  const displayName = nameMatch ? nameMatch[1].trim() : skillName;
1995
- const description = descMatch ? descMatch[1].trim() : '';
2267
+ const description = descMatch ? descMatch[1].trim() : "";
1996
2268
 
1997
- log(`Skill: ${displayName}`, 'cyan');
2269
+ log(`Skill: ${displayName}`, "cyan");
1998
2270
  if (description) {
1999
- log(`Description: ${description}`, 'gray');
2271
+ log(`Description: ${description}`, "gray");
2000
2272
  }
2001
- log(`Path: ${skillDir}`, 'gray');
2002
- log('', 'gray');
2273
+ log(`Path: ${skillDir}`, "gray");
2274
+ log("", "gray");
2003
2275
 
2004
2276
  // Get GitHub info
2005
- const githubUser = await question('GitHub username: ');
2277
+ const githubUser = await question("GitHub username: ");
2006
2278
  if (!githubUser) {
2007
- log('❌ GitHub username required', 'red');
2279
+ log("❌ GitHub username required", "red");
2008
2280
  rl.close();
2009
2281
  return;
2010
2282
  }
2011
2283
 
2012
- const repoName = await question(`Repository name [${skillName}]: `) || skillName;
2013
- const isPrivate = await question('Private repo? [y/N]: ');
2284
+ const repoName =
2285
+ (await question(`Repository name [${skillName}]: `)) || skillName;
2286
+ const isPrivate = await question("Private repo? [y/N]: ");
2014
2287
 
2015
2288
  rl.close();
2016
2289
 
2017
- log('', 'gray');
2018
- log('📝 Instructions:', 'yellow');
2019
- log('', 'gray');
2020
- log(`1. Create GitHub repo:`, 'gray');
2021
- log(` https://github.com/new`, 'gray');
2022
- log(` Name: ${repoName}`, 'gray');
2023
- log(` ${isPrivate.toLowerCase() === 'y' ? 'Private' : 'Public'}`, 'gray');
2024
- log('', 'gray');
2025
- log(`2. Initialize git and push:`, 'gray');
2026
- log(` cd ${skillDir}`, 'gray');
2027
- log(` git init`, 'gray');
2028
- log(` git add .`, 'gray');
2029
- log(` git commit -m "Initial commit"`, 'gray');
2030
- log(` git branch -M main`, 'gray');
2031
- log(` git remote add origin https://github.com/${githubUser}/${repoName}.git`, 'gray');
2032
- log(` git push -u origin main`, 'gray');
2033
- log('', 'gray');
2034
- log(`3. Add to sources.yaml:`, 'gray');
2035
- log(` - name: ${skillName}`, 'gray');
2036
- log(` source:`, 'gray');
2037
- log(` repo: ${githubUser}/${repoName}`, 'gray');
2038
- log(` path: .`, 'gray');
2039
- log(` target:`, 'gray');
2040
- log(` category: tools`, 'gray');
2041
- log(` path: template/.claude/skills/tools/${skillName}`, 'gray');
2042
- log('', 'gray');
2290
+ log("", "gray");
2291
+ log("📝 Instructions:", "yellow");
2292
+ log("", "gray");
2293
+ log(`1. Create GitHub repo:`, "gray");
2294
+ log(` https://github.com/new`, "gray");
2295
+ log(` Name: ${repoName}`, "gray");
2296
+ log(
2297
+ ` ${isPrivate.toLowerCase() === "y" ? "Private" : "Public"}`,
2298
+ "gray",
2299
+ );
2300
+ log("", "gray");
2301
+ log(`2. Initialize git and push:`, "gray");
2302
+ log(` cd ${skillDir}`, "gray");
2303
+ log(` git init`, "gray");
2304
+ log(` git add .`, "gray");
2305
+ log(` git commit -m "Initial commit"`, "gray");
2306
+ log(` git branch -M main`, "gray");
2307
+ log(
2308
+ ` git remote add origin https://github.com/${githubUser}/${repoName}.git`,
2309
+ "gray",
2310
+ );
2311
+ log(` git push -u origin main`, "gray");
2312
+ log("", "gray");
2313
+ log(`3. Add to sources.yaml:`, "gray");
2314
+ log(` - name: ${skillName}`, "gray");
2315
+ log(` source:`, "gray");
2316
+ log(` repo: ${githubUser}/${repoName}`, "gray");
2317
+ log(` path: .`, "gray");
2318
+ log(` target:`, "gray");
2319
+ log(` category: tools`, "gray");
2320
+ log(` path: template/.claude/skills/tools/${skillName}`, "gray");
2321
+ log("", "gray");
2043
2322
 
2044
2323
  // Ask if user wants to auto-execute
2045
- const autoExecute = await question('Auto-execute git commands? [y/N]: ');
2046
- if (autoExecute.toLowerCase() === 'y') {
2324
+ const autoExecute = await question("Auto-execute git commands? [y/N]: ");
2325
+ if (autoExecute.toLowerCase() === "y") {
2047
2326
  try {
2048
- log('', 'gray');
2049
- log('Initializing git...', 'gray');
2050
- execSync('git init', { cwd: skillDir, stdio: 'pipe' });
2051
- execSync('git add .', { cwd: skillDir, stdio: 'pipe' });
2052
- execSync('git commit -m "Initial commit"', { cwd: skillDir, stdio: 'pipe' });
2053
- execSync('git branch -M main', { cwd: skillDir, stdio: 'pipe' });
2054
- log('✅ Git initialized', 'green');
2055
-
2056
- log('Adding remote...', 'gray');
2057
- execSync(`git remote add origin https://github.com/${githubUser}/${repoName}.git`, { cwd: skillDir, stdio: 'pipe' });
2058
- log('✅ Remote added', 'green');
2059
-
2060
- log('', 'gray');
2061
- log('⚠️ Please create the GitHub repo first, then run:', 'yellow');
2062
- log(` cd ${skillDir} && git push -u origin main`, 'gray');
2327
+ log("", "gray");
2328
+ log("Initializing git...", "gray");
2329
+ execSync("git init", { cwd: skillDir, stdio: "pipe" });
2330
+ execSync("git add .", { cwd: skillDir, stdio: "pipe" });
2331
+ execSync('git commit -m "Initial commit"', {
2332
+ cwd: skillDir,
2333
+ stdio: "pipe",
2334
+ });
2335
+ execSync("git branch -M main", { cwd: skillDir, stdio: "pipe" });
2336
+ log("✅ Git initialized", "green");
2337
+
2338
+ log("Adding remote...", "gray");
2339
+ execSync(
2340
+ `git remote add origin https://github.com/${githubUser}/${repoName}.git`,
2341
+ { cwd: skillDir, stdio: "pipe" },
2342
+ );
2343
+ log("✅ Remote added", "green");
2344
+
2345
+ log("", "gray");
2346
+ log("⚠️ Please create the GitHub repo first, then run:", "yellow");
2347
+ log(` cd ${skillDir} && git push -u origin main`, "gray");
2063
2348
  } catch (e) {
2064
- log('❌ Failed to initialize git', 'red');
2065
- log(` ${e.message}`, 'gray');
2349
+ log("❌ Failed to initialize git", "red");
2350
+ log(` ${e.message}`, "gray");
2066
2351
  }
2067
2352
  }
2068
2353
 
2069
- log('', 'gray');
2070
- log('=====================================', 'gray');
2071
- log('✅ Skill publishing guide complete', 'green');
2072
- log('', 'gray');
2354
+ log("", "gray");
2355
+ log("=====================================", "gray");
2356
+ log("✅ Skill publishing guide complete", "green");
2357
+ log("", "gray");
2073
2358
  })();
2074
2359
  },
2075
2360
 
2076
2361
  // -------------------------------------------------------------------------
2077
2362
  changelog: (...args) => {
2078
- const fs = require('fs');
2079
- const path = require('path');
2080
- const { execSync } = require('child_process');
2363
+ const fs = require("fs");
2364
+ const path = require("path");
2365
+ const { execSync } = require("child_process");
2081
2366
  const COLORS = {
2082
- reset: '\x1b[0m',
2083
- green: '\x1b[32m',
2084
- blue: '\x1b[34m',
2085
- yellow: '\x1b[33m',
2086
- gray: '\x1b[90m',
2087
- red: '\x1b[31m',
2088
- cyan: '\x1b[36m'
2367
+ reset: "\x1b[0m",
2368
+ green: "\x1b[32m",
2369
+ blue: "\x1b[34m",
2370
+ yellow: "\x1b[33m",
2371
+ gray: "\x1b[90m",
2372
+ red: "\x1b[31m",
2373
+ cyan: "\x1b[36m",
2089
2374
  };
2090
2375
 
2091
- const log = (msg, color = 'reset') => {
2376
+ const log = (msg, color = "reset") => {
2092
2377
  console.log(`${COLORS[color]}${msg}${COLORS.reset}`);
2093
2378
  };
2094
2379
 
2095
2380
  // Parse options
2096
2381
  const options = { from: null, to: null, json: false, help: false };
2097
2382
  for (let i = 0; i < args.length; i++) {
2098
- if (args[i] === '--from' && args[i + 1]) options.from = args[++i];
2099
- if (args[i] === '--to' && args[i + 1]) options.to = args[++i];
2100
- if (args[i] === '--json') options.json = true;
2101
- if (args[i] === '--help' || args[i] === '-h') options.help = true;
2383
+ if (args[i] === "--from" && args[i + 1]) options.from = args[++i];
2384
+ if (args[i] === "--to" && args[i + 1]) options.to = args[++i];
2385
+ if (args[i] === "--json") options.json = true;
2386
+ if (args[i] === "--help" || args[i] === "-h") options.help = true;
2102
2387
  }
2103
2388
 
2104
2389
  if (options.help) {
2105
- log('', 'gray');
2106
- log('📝 Changelog Generator', 'blue');
2107
- log('=====================================', 'gray');
2108
- log('', 'gray');
2109
- log('Generate changelog from git commits.', 'gray');
2110
- log('', 'gray');
2111
- log('Usage:', 'gray');
2112
- log(' smc changelog [options]', 'gray');
2113
- log('', 'gray');
2114
- log('Options:', 'gray');
2115
- log(' --from <tag> Start from this tag (default: last tag)', 'gray');
2116
- log(' --to <tag> End at this tag (default: HEAD)', 'gray');
2117
- log(' --json Output as JSON', 'gray');
2118
- log(' --help, -h Show this help', 'gray');
2119
- log('', 'gray');
2120
- log('Examples:', 'gray');
2121
- log(' smc changelog # Changelog since last tag', 'gray');
2122
- log(' smc changelog --from v1.0.0 # Since v1.0.0', 'gray');
2123
- log(' smc changelog --from v1.0 --to v1.1 # Range between tags', 'gray');
2124
- log(' smc changelog --json # JSON output', 'gray');
2125
- log('', 'gray');
2390
+ log("", "gray");
2391
+ log("📝 Changelog Generator", "blue");
2392
+ log("=====================================", "gray");
2393
+ log("", "gray");
2394
+ log("Generate changelog from git commits.", "gray");
2395
+ log("", "gray");
2396
+ log("Usage:", "gray");
2397
+ log(" smc changelog [options]", "gray");
2398
+ log("", "gray");
2399
+ log("Options:", "gray");
2400
+ log(" --from <tag> Start from this tag (default: last tag)", "gray");
2401
+ log(" --to <tag> End at this tag (default: HEAD)", "gray");
2402
+ log(" --json Output as JSON", "gray");
2403
+ log(" --help, -h Show this help", "gray");
2404
+ log("", "gray");
2405
+ log("Examples:", "gray");
2406
+ log(
2407
+ " smc changelog # Changelog since last tag",
2408
+ "gray",
2409
+ );
2410
+ log(" smc changelog --from v1.0.0 # Since v1.0.0", "gray");
2411
+ log(
2412
+ " smc changelog --from v1.0 --to v1.1 # Range between tags",
2413
+ "gray",
2414
+ );
2415
+ log(" smc changelog --json # JSON output", "gray");
2416
+ log("", "gray");
2126
2417
  return;
2127
2418
  }
2128
2419
 
2129
2420
  // Check if we're in a git repo
2130
2421
  const projectDir = process.cwd();
2131
2422
  try {
2132
- execSync('git rev-parse --git-dir', { stdio: 'ignore', cwd: projectDir });
2423
+ execSync("git rev-parse --git-dir", { stdio: "ignore", cwd: projectDir });
2133
2424
  } catch {
2134
- log('❌ Not a git repository', 'red');
2425
+ log("❌ Not a git repository", "red");
2135
2426
  return;
2136
2427
  }
2137
2428
 
2138
- log('', 'gray');
2139
- log('📝 Generating Changelog', 'blue');
2140
- log('=====================================', 'gray');
2141
- log('', 'gray');
2429
+ log("", "gray");
2430
+ log("📝 Generating Changelog", "blue");
2431
+ log("=====================================", "gray");
2432
+ log("", "gray");
2142
2433
 
2143
2434
  // Get version range
2144
2435
  let fromRef = options.from;
2145
- let toRef = options.to || 'HEAD';
2436
+ let toRef = options.to || "HEAD";
2146
2437
 
2147
2438
  if (!fromRef) {
2148
2439
  // Try to get the last tag
2149
2440
  try {
2150
- const lastTag = execSync('git describe --tags --abbrev=0', {
2441
+ const lastTag = execSync("git describe --tags --abbrev=0", {
2151
2442
  cwd: projectDir,
2152
- stdio: 'pipe',
2153
- encoding: 'utf-8'
2443
+ stdio: "pipe",
2444
+ encoding: "utf-8",
2154
2445
  }).trim();
2155
2446
  fromRef = lastTag;
2156
- log(`From: ${lastTag} (last tag)`, 'gray');
2447
+ log(`From: ${lastTag} (last tag)`, "gray");
2157
2448
  } catch {
2158
2449
  // No tags found, use first commit
2159
2450
  try {
2160
- const firstCommit = execSync('git rev-list --max-parents=0 HEAD', {
2451
+ const firstCommit = execSync("git rev-list --max-parents=0 HEAD", {
2161
2452
  cwd: projectDir,
2162
- stdio: 'pipe',
2163
- encoding: 'utf-8'
2453
+ stdio: "pipe",
2454
+ encoding: "utf-8",
2164
2455
  }).trim();
2165
2456
  fromRef = firstCommit;
2166
- log(`From: ${firstCommit.substring(0, 8)} (first commit)`, 'gray');
2457
+ log(`From: ${firstCommit.substring(0, 8)} (first commit)`, "gray");
2167
2458
  } catch {
2168
- fromRef = 'HEAD~10'; // Fallback to last 10 commits
2169
- log(`From: HEAD~10 (default)`, 'gray');
2459
+ fromRef = "HEAD~10"; // Fallback to last 10 commits
2460
+ log(`From: HEAD~10 (default)`, "gray");
2170
2461
  }
2171
2462
  }
2172
2463
  } else {
2173
- log(`From: ${fromRef}`, 'gray');
2464
+ log(`From: ${fromRef}`, "gray");
2174
2465
  }
2175
2466
 
2176
- log(`To: ${toRef}`, 'gray');
2177
- log('', 'gray');
2467
+ log(`To: ${toRef}`, "gray");
2468
+ log("", "gray");
2178
2469
 
2179
2470
  // Get commit log
2180
2471
  const range = `${fromRef}..${toRef}`;
@@ -2182,44 +2473,48 @@ const commands = {
2182
2473
  try {
2183
2474
  const logOutput = execSync(
2184
2475
  `git log ${range} --pretty=format:"%H%x1F%s%x1F%an%x1F%ad" --date=short`,
2185
- { cwd: projectDir, stdio: 'pipe', encoding: 'utf-8' }
2476
+ { cwd: projectDir, stdio: "pipe", encoding: "utf-8" },
2186
2477
  );
2187
- commits = logOutput.trim().split('\n').filter(Boolean).map(line => {
2188
- const [hash, subject, author, date] = line.split('\x1F');
2189
- return { hash, subject, author, date };
2190
- });
2478
+ commits = logOutput
2479
+ .trim()
2480
+ .split("\n")
2481
+ .filter(Boolean)
2482
+ .map((line) => {
2483
+ const [hash, subject, author, date] = line.split("\x1F");
2484
+ return { hash, subject, author, date };
2485
+ });
2191
2486
  } catch (e) {
2192
2487
  // Empty range or invalid refs
2193
2488
  commits = [];
2194
2489
  }
2195
2490
 
2196
2491
  if (commits.length === 0) {
2197
- log('⚠️ No commits found in range', 'yellow');
2198
- log('', 'gray');
2492
+ log("⚠️ No commits found in range", "yellow");
2493
+ log("", "gray");
2199
2494
  return;
2200
2495
  }
2201
2496
 
2202
- log(`Found ${commits.length} commit(s)`, 'gray');
2203
- log('', 'gray');
2497
+ log(`Found ${commits.length} commit(s)`, "gray");
2498
+ log("", "gray");
2204
2499
 
2205
2500
  // Parse conventional commits
2206
2501
  const categories = {
2207
- feat: { name: 'Features', icon: '', commits: [] },
2208
- fix: { name: 'Bug Fixes', icon: '🐛', commits: [] },
2209
- docs: { name: 'Documentation', icon: '📝', commits: [] },
2210
- style: { name: 'Styles', icon: '💄', commits: [] },
2211
- refactor: { name: 'Refactor', icon: '♻️', commits: [] },
2212
- perf: { name: 'Performance', icon: '', commits: [] },
2213
- test: { name: 'Tests', icon: '🧪', commits: [] },
2214
- build: { name: 'Build', icon: '📦', commits: [] },
2215
- ci: { name: 'CI', icon: '🤖', commits: [] },
2216
- chore: { name: 'Chores', icon: '🧹', commits: [] },
2217
- other: { name: 'Other', icon: '📌', commits: [] }
2502
+ feat: { name: "Features", icon: "", commits: [] },
2503
+ fix: { name: "Bug Fixes", icon: "🐛", commits: [] },
2504
+ docs: { name: "Documentation", icon: "📝", commits: [] },
2505
+ style: { name: "Styles", icon: "💄", commits: [] },
2506
+ refactor: { name: "Refactor", icon: "♻️", commits: [] },
2507
+ perf: { name: "Performance", icon: "", commits: [] },
2508
+ test: { name: "Tests", icon: "🧪", commits: [] },
2509
+ build: { name: "Build", icon: "📦", commits: [] },
2510
+ ci: { name: "CI", icon: "🤖", commits: [] },
2511
+ chore: { name: "Chores", icon: "🧹", commits: [] },
2512
+ other: { name: "Other", icon: "📌", commits: [] },
2218
2513
  };
2219
2514
 
2220
2515
  const conventionalCommitRegex = /^(\w+)(?:\(([^)]+)\))?:?\s*(.+)$/;
2221
2516
 
2222
- commits.forEach(commit => {
2517
+ commits.forEach((commit) => {
2223
2518
  const match = commit.subject.match(conventionalCommitRegex);
2224
2519
  if (match) {
2225
2520
  const [, type, scope, description] = match;
@@ -2229,7 +2524,7 @@ const commands = {
2229
2524
  description: description.trim(),
2230
2525
  scope: scope || null,
2231
2526
  author: commit.author,
2232
- date: commit.date
2527
+ date: commit.date,
2233
2528
  });
2234
2529
  } else {
2235
2530
  categories.other.commits.push({
@@ -2237,7 +2532,7 @@ const commands = {
2237
2532
  description: commit.subject,
2238
2533
  scope: null,
2239
2534
  author: commit.author,
2240
- date: commit.date
2535
+ date: commit.date,
2241
2536
  });
2242
2537
  }
2243
2538
  });
@@ -2250,7 +2545,7 @@ const commands = {
2250
2545
  jsonOutput[key] = {
2251
2546
  name: category.name,
2252
2547
  icon: category.icon,
2253
- commits: category.commits
2548
+ commits: category.commits,
2254
2549
  };
2255
2550
  }
2256
2551
  }
@@ -2259,14 +2554,14 @@ const commands = {
2259
2554
  }
2260
2555
 
2261
2556
  // Markdown output
2262
- const today = new Date().toISOString().split('T')[0];
2557
+ const today = new Date().toISOString().split("T")[0];
2263
2558
 
2264
2559
  // Check if CHANGELOG.md exists and append
2265
- const changelogFile = path.join(projectDir, 'CHANGELOG.md');
2560
+ const changelogFile = path.join(projectDir, "CHANGELOG.md");
2266
2561
 
2267
- let existingContent = '';
2562
+ let existingContent = "";
2268
2563
  if (fs.existsSync(changelogFile)) {
2269
- existingContent = fs.readFileSync(changelogFile, 'utf-8');
2564
+ existingContent = fs.readFileSync(changelogFile, "utf-8");
2270
2565
  }
2271
2566
 
2272
2567
  // Generate new entry
@@ -2275,11 +2570,11 @@ const commands = {
2275
2570
  for (const [key, category] of Object.entries(categories)) {
2276
2571
  if (category.commits.length > 0) {
2277
2572
  newEntry += `### ${category.icon} ${category.name}\n\n`;
2278
- category.commits.forEach(commit => {
2279
- const scopeStr = commit.scope ? `**${commit.scope}**: ` : '';
2573
+ category.commits.forEach((commit) => {
2574
+ const scopeStr = commit.scope ? `**${commit.scope}**: ` : "";
2280
2575
  newEntry += `- ${scopeStr}${commit.description} (${commit.hash})\n`;
2281
2576
  });
2282
- newEntry += '\n';
2577
+ newEntry += "\n";
2283
2578
  }
2284
2579
  }
2285
2580
 
@@ -2293,15 +2588,15 @@ const commands = {
2293
2588
  // Replace existing unreleased section
2294
2589
  const updatedContent = existingContent.replace(
2295
2590
  unreleasedRegex,
2296
- newEntry.trimEnd() + '\n\n'
2591
+ newEntry.trimEnd() + "\n\n",
2297
2592
  );
2298
2593
  fs.writeFileSync(changelogFile, updatedContent);
2299
- log('✅ Updated [Unreleased] section in CHANGELOG.md', 'green');
2594
+ log("✅ Updated [Unreleased] section in CHANGELOG.md", "green");
2300
2595
  } else {
2301
2596
  // Prepend to existing content
2302
2597
  const newContent = newEntry + existingContent;
2303
2598
  fs.writeFileSync(changelogFile, newContent);
2304
- log('✅ Added to CHANGELOG.md', 'green');
2599
+ log("✅ Added to CHANGELOG.md", "green");
2305
2600
  }
2306
2601
  } else {
2307
2602
  // Create new CHANGELOG.md
@@ -2311,37 +2606,37 @@ All notable changes to this project will be documented in this file.
2311
2606
 
2312
2607
  `;
2313
2608
  fs.writeFileSync(changelogFile, header + newEntry);
2314
- log('✅ Created CHANGELOG.md', 'green');
2609
+ log("✅ Created CHANGELOG.md", "green");
2315
2610
  }
2316
2611
 
2317
- log('', 'gray');
2318
- log('📄 Preview:', 'gray');
2319
- log('', 'gray');
2612
+ log("", "gray");
2613
+ log("📄 Preview:", "gray");
2614
+ log("", "gray");
2320
2615
  console.log(newEntry);
2321
2616
 
2322
- log('=====================================', 'gray');
2323
- log('', 'gray');
2617
+ log("=====================================", "gray");
2618
+ log("", "gray");
2324
2619
  },
2325
2620
 
2326
2621
  // ==========================================================================
2327
2622
  // Quality Gate Commands
2328
2623
  // ==========================================================================
2329
2624
 
2330
- 'qg:check': async (severity = 'warn') => {
2331
- const { QualityGate } = require('./quality-gate');
2625
+ "qg:check": async (severity = "warn") => {
2626
+ const { QualityGate } = require("./quality-gate");
2332
2627
  const gate = new QualityGate({ projectDir: process.cwd() });
2333
2628
  const result = await gate.check({ severity });
2334
2629
  process.exit(result.passed ? 0 : 1);
2335
2630
  },
2336
2631
 
2337
- 'qg:rules': () => {
2338
- const registry = require('./quality-rules').registry;
2632
+ "qg:rules": () => {
2633
+ const registry = require("./quality-rules").registry;
2339
2634
  const rules = registry.getAll();
2340
2635
 
2341
- console.log('📋 Available Quality Rules');
2342
- console.log('');
2343
- console.log('Rules are checked when running quality gate:');
2344
- console.log('');
2636
+ console.log("📋 Available Quality Rules");
2637
+ console.log("");
2638
+ console.log("Rules are checked when running quality gate:");
2639
+ console.log("");
2345
2640
 
2346
2641
  const byCategory = {};
2347
2642
  for (const rule of rules) {
@@ -2352,159 +2647,176 @@ All notable changes to this project will be documented in this file.
2352
2647
  for (const [category, rules] of Object.entries(byCategory)) {
2353
2648
  console.log(`${category.toUpperCase()}:`);
2354
2649
  for (const rule of rules) {
2355
- const status = rule.enabled ? '' : '';
2356
- const sev = { info: 'I', warn: 'W', error: 'E', critical: 'X' }[rule.severity];
2650
+ const status = rule.enabled ? "" : "";
2651
+ const sev = { info: "I", warn: "W", error: "E", critical: "X" }[
2652
+ rule.severity
2653
+ ];
2357
2654
  console.log(` ${status} ${rule.id} [${sev}] - ${rule.name}`);
2358
2655
  }
2359
- console.log('');
2656
+ console.log("");
2360
2657
  }
2361
2658
  },
2362
2659
 
2363
- 'qg:init': () => {
2660
+ "qg:init": () => {
2364
2661
  const projectDir = process.cwd();
2365
- const configDir = path.join(projectDir, '.claude');
2366
- const targetPath = path.join(configDir, 'quality-gate.json');
2367
- const sourcePath = path.join(__dirname, '../config/quality-gate.json');
2662
+ const configDir = path.join(projectDir, ".claude");
2663
+ const targetPath = path.join(configDir, "quality-gate.json");
2664
+ const sourcePath = path.join(__dirname, "../config/quality-gate.json");
2368
2665
 
2369
2666
  if (fs.existsSync(targetPath)) {
2370
- console.log('⚠️ quality-gate.json already exists');
2667
+ console.log("⚠️ quality-gate.json already exists");
2371
2668
  return;
2372
2669
  }
2373
2670
 
2374
2671
  ensureDir(configDir);
2375
2672
  fs.copyFileSync(sourcePath, targetPath);
2376
- console.log('✅ Created .claude/quality-gate.json');
2377
- console.log('');
2378
- console.log('To enable Git hooks:');
2379
- console.log(' ln -s .claude/hooks/pre-commit.cjs .git/hooks/pre-commit');
2380
- console.log(' ln -s .claude/hooks/pre-push.cjs .git/hooks/pre-push');
2673
+ console.log("✅ Created .claude/quality-gate.json");
2674
+ console.log("");
2675
+ console.log("To enable Git hooks:");
2676
+ console.log(" ln -s .claude/hooks/pre-commit.cjs .git/hooks/pre-commit");
2677
+ console.log(" ln -s .claude/hooks/pre-push.cjs .git/hooks/pre-push");
2381
2678
  },
2382
2679
 
2383
2680
  // ==========================================================================
2384
2681
  // Config Commands
2385
2682
  // ==========================================================================
2386
2683
 
2387
- 'config:validate': () => {
2388
- const { ConfigValidator } = require('./config-validator');
2684
+ "config:validate": () => {
2685
+ const { ConfigValidator } = require("./config-validator");
2389
2686
  const validator = new ConfigValidator();
2390
2687
 
2391
- console.log('🔍 Validating configuration...');
2392
- console.log('');
2688
+ console.log("🔍 Validating configuration...");
2689
+ console.log("");
2393
2690
 
2394
2691
  let hasErrors = false;
2395
2692
  let hasWarnings = false;
2396
2693
 
2397
2694
  // Check global config
2398
- const globalConfigPath = path.join(process.env.HOME, '.claude', 'config.json');
2695
+ const globalConfigPath = path.join(
2696
+ process.env.HOME,
2697
+ ".claude",
2698
+ "config.json",
2699
+ );
2399
2700
  console.log(`Global: ${globalConfigPath}`);
2400
2701
  const globalResult = validator.validateFile(globalConfigPath);
2401
2702
 
2402
2703
  if (globalResult.valid) {
2403
- console.log(' ✅ Valid');
2704
+ console.log(" ✅ Valid");
2404
2705
  } else {
2405
2706
  if (globalResult.errors.length > 0) {
2406
2707
  hasErrors = true;
2407
2708
  console.log(` ❌ ${globalResult.errors.length} error(s)`);
2408
- globalResult.errors.forEach(e => {
2709
+ globalResult.errors.forEach((e) => {
2409
2710
  console.log(` [${e.severity}] ${e.path}: ${e.message}`);
2410
2711
  });
2411
2712
  }
2412
2713
  if (globalResult.warnings.length > 0) {
2413
2714
  hasWarnings = true;
2414
2715
  console.log(` ⚠️ ${globalResult.warnings.length} warning(s)`);
2415
- globalResult.warnings.forEach(e => {
2716
+ globalResult.warnings.forEach((e) => {
2416
2717
  console.log(` [${e.severity}] ${e.path}: ${e.message}`);
2417
2718
  });
2418
2719
  }
2419
- if (globalResult.errors.length === 0 && globalResult.warnings.length === 0) {
2420
- console.log(' ❌ Validation failed');
2720
+ if (
2721
+ globalResult.errors.length === 0 &&
2722
+ globalResult.warnings.length === 0
2723
+ ) {
2724
+ console.log(" ❌ Validation failed");
2421
2725
  }
2422
2726
  }
2423
- console.log('');
2727
+ console.log("");
2424
2728
 
2425
2729
  // Check project config if in project
2426
2730
  const projectDir = process.cwd();
2427
- const projectConfigPath = path.join(projectDir, '.claude', 'settings.json');
2731
+ const projectConfigPath = path.join(projectDir, ".claude", "settings.json");
2428
2732
  if (fs.existsSync(projectConfigPath)) {
2429
2733
  console.log(`Project: ${projectConfigPath}`);
2430
- const projectResult = validator.validateFile(projectConfigPath, 'settings');
2734
+ const projectResult = validator.validateFile(
2735
+ projectConfigPath,
2736
+ "settings",
2737
+ );
2431
2738
  if (projectResult.valid) {
2432
- console.log(' ✅ Valid');
2739
+ console.log(" ✅ Valid");
2433
2740
  } else {
2434
2741
  if (projectResult.errors.length > 0) {
2435
2742
  hasErrors = true;
2436
2743
  console.log(` ❌ ${projectResult.errors.length} error(s)`);
2437
- projectResult.errors.forEach(e => {
2744
+ projectResult.errors.forEach((e) => {
2438
2745
  console.log(` [${e.severity}] ${e.path}: ${e.message}`);
2439
2746
  });
2440
2747
  }
2441
2748
  if (projectResult.warnings.length > 0) {
2442
2749
  hasWarnings = true;
2443
2750
  console.log(` ⚠️ ${projectResult.warnings.length} warning(s)`);
2444
- projectResult.warnings.forEach(e => {
2751
+ projectResult.warnings.forEach((e) => {
2445
2752
  console.log(` [${e.severity}] ${e.path}: ${e.message}`);
2446
2753
  });
2447
2754
  }
2448
- if (projectResult.errors.length === 0 && projectResult.warnings.length === 0) {
2449
- console.log(' ❌ Validation failed');
2755
+ if (
2756
+ projectResult.errors.length === 0 &&
2757
+ projectResult.warnings.length === 0
2758
+ ) {
2759
+ console.log(" ❌ Validation failed");
2450
2760
  }
2451
2761
  }
2452
2762
  }
2453
- console.log('');
2763
+ console.log("");
2454
2764
 
2455
2765
  if (hasErrors) {
2456
- console.log('❌ Configuration validation failed');
2766
+ console.log("❌ Configuration validation failed");
2457
2767
  process.exit(1);
2458
2768
  } else if (hasWarnings) {
2459
- console.log('⚠️ Configuration has warnings (but is valid)');
2769
+ console.log("⚠️ Configuration has warnings (but is valid)");
2460
2770
  } else {
2461
- console.log('✅ All configurations are valid');
2771
+ console.log("✅ All configurations are valid");
2462
2772
  }
2463
2773
  },
2464
2774
 
2465
- 'config:backup': () => {
2466
- const { ConfigManager } = require('./config-manager');
2775
+ "config:backup": () => {
2776
+ const { ConfigManager } = require("./config-manager");
2467
2777
  const manager = new ConfigManager();
2468
2778
  const backupPath = manager._createBackup();
2469
- console.log('✅ Config backed up to:', backupPath);
2779
+ console.log("✅ Config backed up to:", backupPath);
2470
2780
  },
2471
2781
 
2472
- 'config:rollback': (version) => {
2473
- const { ConfigManager } = require('./config-manager');
2782
+ "config:rollback": (version) => {
2783
+ const { ConfigManager } = require("./config-manager");
2474
2784
  const manager = new ConfigManager();
2475
2785
 
2476
2786
  const backups = manager.listBackups();
2477
2787
  if (backups.length === 0) {
2478
- console.log('❌ No backups available');
2788
+ console.log("❌ No backups available");
2479
2789
  return;
2480
2790
  }
2481
2791
 
2482
2792
  if (!version) {
2483
- console.log('Available backups:');
2793
+ console.log("Available backups:");
2484
2794
  backups.forEach((b, i) => {
2485
- console.log(` ${i + 1}. ${b.version} (${new Date(b.timestamp).toLocaleString()})`);
2795
+ console.log(
2796
+ ` ${i + 1}. ${b.version} (${new Date(b.timestamp).toLocaleString()})`,
2797
+ );
2486
2798
  });
2487
- console.log('');
2488
- console.log('Usage: smc config:rollback <version>');
2799
+ console.log("");
2800
+ console.log("Usage: smc config:rollback <version>");
2489
2801
  return;
2490
2802
  }
2491
2803
 
2492
2804
  try {
2493
2805
  const result = manager.rollback(version);
2494
- console.log('✅ Rolled back to:', result.restoredFrom);
2806
+ console.log("✅ Rolled back to:", result.restoredFrom);
2495
2807
  } catch (e) {
2496
- console.log('', e.message);
2808
+ console.log("", e.message);
2497
2809
  }
2498
2810
  },
2499
2811
 
2500
- 'config:diff': (file1, file2) => {
2501
- const { ConfigManager } = require('./config-manager');
2812
+ "config:diff": (file1, file2) => {
2813
+ const { ConfigManager } = require("./config-manager");
2502
2814
  const manager = new ConfigManager();
2503
2815
 
2504
2816
  if (!file1) {
2505
2817
  const backups = manager.listBackups();
2506
2818
  if (backups.length === 0) {
2507
- console.log('❌ No backups available');
2819
+ console.log("❌ No backups available");
2508
2820
  return;
2509
2821
  }
2510
2822
  file1 = path.join(manager.backupDir, backups[0].file);
@@ -2513,19 +2825,19 @@ All notable changes to this project will be documented in this file.
2513
2825
 
2514
2826
  const changes = manager.diff(file1, file2);
2515
2827
  if (changes.length === 0) {
2516
- console.log('✅ No differences found');
2828
+ console.log("✅ No differences found");
2517
2829
  return;
2518
2830
  }
2519
2831
 
2520
- console.log('📊 Config Diff:');
2521
- console.log('');
2832
+ console.log("📊 Config Diff:");
2833
+ console.log("");
2522
2834
  for (const change of changes) {
2523
- const icon = { added: '+', removed: '-', changed: '~' }[change.type];
2835
+ const icon = { added: "+", removed: "-", changed: "~" }[change.type];
2524
2836
  console.log(` ${icon} ${change.path}`);
2525
- if (change.type !== 'removed') {
2837
+ if (change.type !== "removed") {
2526
2838
  console.log(` from: ${JSON.stringify(change.from)}`);
2527
2839
  }
2528
- if (change.type !== 'added') {
2840
+ if (change.type !== "added") {
2529
2841
  console.log(` to: ${JSON.stringify(change.to)}`);
2530
2842
  }
2531
2843
  }
@@ -2539,180 +2851,226 @@ All notable changes to this project will be documented in this file.
2539
2851
  const [action, ...rest] = args;
2540
2852
 
2541
2853
  const COLORS = {
2542
- reset: '\x1b[0m',
2543
- green: '\x1b[32m',
2544
- blue: '\x1b[34m',
2545
- yellow: '\x1b[33m',
2546
- gray: '\x1b[90m',
2547
- red: '\x1b[31m',
2548
- cyan: '\x1b[36m'
2854
+ reset: "\x1b[0m",
2855
+ green: "\x1b[32m",
2856
+ blue: "\x1b[34m",
2857
+ yellow: "\x1b[33m",
2858
+ gray: "\x1b[90m",
2859
+ red: "\x1b[31m",
2860
+ cyan: "\x1b[36m",
2549
2861
  };
2550
2862
 
2551
- const log = (msg, color = 'reset') => {
2863
+ const log = (msg, color = "reset") => {
2552
2864
  console.log(`${COLORS[color]}${msg}${COLORS.reset}`);
2553
2865
  };
2554
2866
 
2555
2867
  switch (action) {
2556
- case 'start': {
2557
- const idea = rest.join(' ');
2868
+ case "start": {
2869
+ const idea = rest.join(" ");
2558
2870
  if (!idea) {
2559
- log('Usage: smc workflow start "<your idea>" [context...]', 'gray');
2560
- log('', 'gray');
2561
- log('Example: smc workflow start "Build a REST API for task management"', 'gray');
2871
+ log('Usage: smc workflow start "<your idea>" [context...]', "gray");
2872
+ log("", "gray");
2873
+ log(
2874
+ 'Example: smc workflow start "Build a REST API for task management"',
2875
+ "gray",
2876
+ );
2562
2877
  return;
2563
2878
  }
2564
2879
 
2565
2880
  // Import workflow modules
2566
- const { createProject, generateProjectId } = require('../.claude/workflow/phases/phase1-research');
2567
-
2568
- log('', 'gray');
2569
- log('🚀 Starting Phase 1: Research', 'blue');
2570
- log('=====================================', 'gray');
2571
- log('', 'gray');
2572
- log(`Idea: ${idea}`, 'cyan');
2573
- log('', 'gray');
2574
-
2575
- createProject(idea).then(projectId => {
2576
- log('', 'gray');
2577
- log('✅ Project initialized!', 'green');
2578
- log(` Project ID: ${projectId}`, 'gray');
2579
- log(` Report: development/projects/${projectId}/phase1/feasibility-report.md`, 'gray');
2580
- log('', 'gray');
2581
- log('Next steps:', 'gray');
2582
- log(' 1. Complete the feasibility report', 'gray');
2583
- log(' 2. Validate: smc workflow validate', 'gray');
2584
- log(' 3. Proceed to Phase 2: Claude approval', 'gray');
2585
- log('', 'gray');
2586
- }).catch(err => {
2587
- log('', 'gray');
2588
- log(`❌ Error: ${err.message}`, 'red');
2589
- process.exit(1);
2590
- });
2881
+ const {
2882
+ createProject,
2883
+ generateProjectId,
2884
+ } = require("../.claude/workflow/phases/phase1-research");
2885
+
2886
+ log("", "gray");
2887
+ log("🚀 Starting Phase 1: Research", "blue");
2888
+ log("=====================================", "gray");
2889
+ log("", "gray");
2890
+ log(`Idea: ${idea}`, "cyan");
2891
+ log("", "gray");
2892
+
2893
+ createProject(idea)
2894
+ .then((projectId) => {
2895
+ log("", "gray");
2896
+ log("✅ Project initialized!", "green");
2897
+ log(` Project ID: ${projectId}`, "gray");
2898
+ log(
2899
+ ` Report: development/projects/${projectId}/phase1/feasibility-report.md`,
2900
+ "gray",
2901
+ );
2902
+ log("", "gray");
2903
+ log("Next steps:", "gray");
2904
+ log(" 1. Complete the feasibility report", "gray");
2905
+ log(" 2. Validate: smc workflow validate", "gray");
2906
+ log(" 3. Proceed to Phase 2: Claude approval", "gray");
2907
+ log("", "gray");
2908
+ })
2909
+ .catch((err) => {
2910
+ log("", "gray");
2911
+ log(`❌ Error: ${err.message}`, "red");
2912
+ process.exit(1);
2913
+ });
2591
2914
  break;
2592
2915
  }
2593
2916
 
2594
- case 'status': {
2595
- const { getAllProjectsWithPhases } = require('../.claude/workflow/phases/phase4-develop');
2917
+ case "status": {
2918
+ const {
2919
+ getAllProjectsWithPhases,
2920
+ } = require("../.claude/workflow/phases/phase4-develop");
2596
2921
  const projects = getAllProjectsWithPhases();
2597
2922
 
2598
- log('', 'gray');
2599
- log('📋 Workflow Projects', 'blue');
2600
- log('=====================================', 'gray');
2601
- log('', 'gray');
2923
+ log("", "gray");
2924
+ log("📋 Workflow Projects", "blue");
2925
+ log("=====================================", "gray");
2926
+ log("", "gray");
2602
2927
 
2603
2928
  if (projects.length === 0) {
2604
- log('No projects yet.', 'gray');
2605
- log('Start one with: smc workflow start "<your idea>"', 'gray');
2929
+ log("No projects yet.", "gray");
2930
+ log('Start one with: smc workflow start "<your idea>"', "gray");
2606
2931
  } else {
2607
- projects.forEach(p => {
2608
- const phaseNames = ['', 'Research', 'Approval', 'Planning', 'Development', 'Deployment'];
2609
- const phaseIcons = ['', '🔍', '🤝', '📐', '💻', '🚀'];
2610
- const phaseIcon = phaseIcons[p.currentPhase] || '📋';
2611
- log(`${phaseIcon} ${p.id}`, 'gray');
2612
- log(` Phase: ${p.currentPhase} - ${phaseNames[p.currentPhase] || 'Unknown'}`, 'gray');
2932
+ projects.forEach((p) => {
2933
+ const phaseNames = [
2934
+ "",
2935
+ "Research",
2936
+ "Approval",
2937
+ "Planning",
2938
+ "Development",
2939
+ "Deployment",
2940
+ ];
2941
+ const phaseIcons = ["", "🔍", "🤝", "📐", "💻", "🚀"];
2942
+ const phaseIcon = phaseIcons[p.currentPhase] || "📋";
2943
+ log(`${phaseIcon} ${p.id}`, "gray");
2944
+ log(
2945
+ ` Phase: ${p.currentPhase} - ${phaseNames[p.currentPhase] || "Unknown"}`,
2946
+ "gray",
2947
+ );
2613
2948
  if (p.hasPhase1) {
2614
- log(` ✅ Phase 1: feasibility-report.md`, 'gray');
2949
+ log(` ✅ Phase 1: feasibility-report.md`, "gray");
2615
2950
  }
2616
2951
  if (p.hasPhase2) {
2617
- log(` ✅ Phase 2: requirements.md`, 'gray');
2952
+ log(` ✅ Phase 2: requirements.md`, "gray");
2618
2953
  }
2619
2954
  if (p.hasPhase3) {
2620
- log(` ✅ Phase 3: PRD.md`, 'gray');
2955
+ log(` ✅ Phase 3: PRD.md`, "gray");
2621
2956
  }
2622
2957
  if (p.hasPhase4) {
2623
- log(` ✅ Phase 4: source/`, 'gray');
2958
+ log(` ✅ Phase 4: source/`, "gray");
2624
2959
  }
2625
2960
  });
2626
2961
  }
2627
- log('', 'gray');
2962
+ log("", "gray");
2628
2963
  break;
2629
2964
  }
2630
2965
 
2631
- case 'validate': {
2966
+ case "validate": {
2632
2967
  const [reportPath] = rest;
2633
2968
 
2634
2969
  if (!reportPath) {
2635
- log('Usage: smc workflow validate <file-path|project-id>', 'gray');
2636
- log('', 'gray');
2637
- log('Validates:', 'gray');
2638
- log(' - Phase 1: feasibility-report.md', 'gray');
2639
- log(' - Phase 2: requirements.md', 'gray');
2640
- log(' - Phase 3: PRD.md or TASK_PLAN.md', 'gray');
2641
- log(' - Phase 4: Pass project-id to validate development', 'gray');
2970
+ log("Usage: smc workflow validate <file-path|project-id>", "gray");
2971
+ log("", "gray");
2972
+ log("Validates:", "gray");
2973
+ log(" - Phase 1: feasibility-report.md", "gray");
2974
+ log(" - Phase 2: requirements.md", "gray");
2975
+ log(" - Phase 3: PRD.md or TASK_PLAN.md", "gray");
2976
+ log(" - Phase 4: Pass project-id to validate development", "gray");
2642
2977
  return;
2643
2978
  }
2644
2979
 
2645
2980
  // Check if it's a project ID (for Phase 4 validation)
2646
- if (reportPath.startsWith('proj_')) {
2647
- const { DevelopmentValidator } = require('../.claude/workflow/phases/phase4-develop');
2981
+ if (reportPath.startsWith("proj_")) {
2982
+ const {
2983
+ DevelopmentValidator,
2984
+ } = require("../.claude/workflow/phases/phase4-develop");
2648
2985
  const result = DevelopmentValidator.validateProjectDir(reportPath);
2649
2986
  log(DevelopmentValidator.generateReport(result));
2650
2987
  process.exit(result.passed ? 0 : 1);
2651
2988
  }
2652
2989
 
2653
2990
  // Determine which validator to use based on file name
2654
- const isPhase3 = reportPath.includes('PRD') || reportPath.includes('TASK_PLAN') || reportPath.includes('phase3');
2655
- const isPhase2 = reportPath.includes('requirements') || reportPath.includes('phase2');
2991
+ const isPhase3 =
2992
+ reportPath.includes("PRD") ||
2993
+ reportPath.includes("TASK_PLAN") ||
2994
+ reportPath.includes("phase3");
2995
+ const isPhase2 =
2996
+ reportPath.includes("requirements") || reportPath.includes("phase2");
2656
2997
 
2657
2998
  if (isPhase3) {
2658
- const { PlanningValidator } = require('../.claude/workflow/phases/phase3-plan');
2999
+ const {
3000
+ PlanningValidator,
3001
+ } = require("../.claude/workflow/phases/phase3-plan");
2659
3002
  const result = PlanningValidator.validateFile(reportPath);
2660
3003
  log(PlanningValidator.generateReport(result));
2661
3004
  process.exit(result.passed ? 0 : 1);
2662
3005
  } else if (isPhase2) {
2663
- const { ApprovalValidator } = require('../.claude/workflow/phases/phase2-approve');
3006
+ const {
3007
+ ApprovalValidator,
3008
+ } = require("../.claude/workflow/phases/phase2-approve");
2664
3009
  const result = ApprovalValidator.validateFile(reportPath);
2665
3010
  log(ApprovalValidator.generateReport(result));
2666
3011
  process.exit(result.passed ? 0 : 1);
2667
3012
  } else {
2668
- const { FeasibilityValidator } = require('../.claude/workflow/phases/phase1-research');
3013
+ const {
3014
+ FeasibilityValidator,
3015
+ } = require("../.claude/workflow/phases/phase1-research");
2669
3016
  const result = FeasibilityValidator.validateFile(reportPath);
2670
3017
  log(FeasibilityValidator.generateReport(result));
2671
3018
  process.exit(result.passed ? 0 : 1);
2672
3019
  }
2673
3020
  }
2674
3021
 
2675
- case 'phase': {
3022
+ case "phase": {
2676
3023
  const [phaseNum] = rest;
2677
3024
  const phases = [
2678
- '1 - Research (NotebookLM)',
2679
- '2 - Approval (Claude)',
2680
- '3 - Planning (Claude)',
2681
- '4 - Development (Claude)',
2682
- '5 - Deployment'
3025
+ "1 - Research (NotebookLM)",
3026
+ "2 - Approval (Claude)",
3027
+ "3 - Planning (Claude)",
3028
+ "4 - Development (Claude)",
3029
+ "5 - Deployment",
2683
3030
  ];
2684
3031
 
2685
3032
  if (phaseNum) {
2686
- log(`Phase ${phaseNum}: ${phases[parseInt(phaseNum) - 1] || 'Unknown'}`, 'cyan');
3033
+ log(
3034
+ `Phase ${phaseNum}: ${phases[parseInt(phaseNum) - 1] || "Unknown"}`,
3035
+ "cyan",
3036
+ );
2687
3037
  } else {
2688
- log('', 'gray');
2689
- log('🔄 Workflow Phases', 'blue');
2690
- log('=====================================', 'gray');
2691
- log('', 'gray');
3038
+ log("", "gray");
3039
+ log("🔄 Workflow Phases", "blue");
3040
+ log("=====================================", "gray");
3041
+ log("", "gray");
2692
3042
  phases.forEach((p, i) => {
2693
- log(` Phase ${i + 1}: ${p}`, 'gray');
3043
+ log(` Phase ${i + 1}: ${p}`, "gray");
2694
3044
  });
2695
- log('', 'gray');
3045
+ log("", "gray");
2696
3046
  }
2697
3047
  break;
2698
3048
  }
2699
3049
 
2700
- case 'approve':
2701
- case 'next': {
3050
+ case "approve":
3051
+ case "next": {
2702
3052
  // Determine project ID
2703
3053
  let projectId;
2704
3054
 
2705
- if (action === 'approve') {
3055
+ if (action === "approve") {
2706
3056
  projectId = rest[0];
2707
3057
  } else {
2708
3058
  // 'next' - find the latest project that needs the next phase
2709
- const { getAllProjectsWithPhases } = require('../.claude/workflow/phases/phase4-develop');
3059
+ const {
3060
+ getAllProjectsWithPhases,
3061
+ } = require("../.claude/workflow/phases/phase4-develop");
2710
3062
  const projects = getAllProjectsWithPhases();
2711
3063
 
2712
3064
  // Find project ready for next phase
2713
- const readyForPhase4 = projects.find(p => p.hasPhase3 && !p.hasPhase4);
2714
- const readyForPhase3 = projects.find(p => p.hasPhase2 && !p.hasPhase3);
2715
- const readyForPhase2 = projects.find(p => p.hasPhase1 && !p.hasPhase2);
3065
+ const readyForPhase4 = projects.find(
3066
+ (p) => p.hasPhase3 && !p.hasPhase4,
3067
+ );
3068
+ const readyForPhase3 = projects.find(
3069
+ (p) => p.hasPhase2 && !p.hasPhase3,
3070
+ );
3071
+ const readyForPhase2 = projects.find(
3072
+ (p) => p.hasPhase1 && !p.hasPhase2,
3073
+ );
2716
3074
 
2717
3075
  if (readyForPhase4) {
2718
3076
  projectId = readyForPhase4.id;
@@ -2721,183 +3079,235 @@ All notable changes to this project will be documented in this file.
2721
3079
  } else if (readyForPhase2) {
2722
3080
  projectId = readyForPhase2.id;
2723
3081
  } else if (projects.length === 0) {
2724
- log('No projects found. Start one with: smc workflow start "<your idea>"', 'gray');
3082
+ log(
3083
+ 'No projects found. Start one with: smc workflow start "<your idea>"',
3084
+ "gray",
3085
+ );
2725
3086
  return;
2726
3087
  } else {
2727
- log('All projects are at the latest phase. Start a new project with: smc workflow start "<your idea>"', 'yellow');
3088
+ log(
3089
+ 'All projects are at the latest phase. Start a new project with: smc workflow start "<your idea>"',
3090
+ "yellow",
3091
+ );
2728
3092
  return;
2729
3093
  }
2730
3094
  }
2731
3095
 
2732
3096
  if (!projectId) {
2733
- log('Usage: smc workflow approve <project-id>', 'gray');
2734
- log('Or use: smc workflow next (auto-selects and advances latest project)', 'gray');
3097
+ log("Usage: smc workflow approve <project-id>", "gray");
3098
+ log(
3099
+ "Or use: smc workflow next (auto-selects and advances latest project)",
3100
+ "gray",
3101
+ );
2735
3102
  return;
2736
3103
  }
2737
3104
 
2738
3105
  // Determine which phase to execute
2739
- const { getAllProjectsWithPhases } = require('../.claude/workflow/phases/phase4-develop');
3106
+ const {
3107
+ getAllProjectsWithPhases,
3108
+ } = require("../.claude/workflow/phases/phase4-develop");
2740
3109
  const projects = getAllProjectsWithPhases();
2741
- const project = projects.find(p => p.id === projectId);
3110
+ const project = projects.find((p) => p.id === projectId);
2742
3111
 
2743
3112
  if (!project) {
2744
- log(`Project not found: ${projectId}`, 'red');
3113
+ log(`Project not found: ${projectId}`, "red");
2745
3114
  return;
2746
3115
  }
2747
3116
 
2748
3117
  // Execute the appropriate phase
2749
3118
  if (project.hasPhase3 && !project.hasPhase4) {
2750
3119
  // Execute Phase 4
2751
- const { Phase4DevelopmentExecutor } = require('../.claude/workflow/phases/phase4-develop');
3120
+ const {
3121
+ Phase4DevelopmentExecutor,
3122
+ } = require("../.claude/workflow/phases/phase4-develop");
2752
3123
 
2753
- log('', 'gray');
2754
- log('💻 Starting Phase 4: Development', 'blue');
2755
- log('=====================================', 'gray');
2756
- log('', 'gray');
2757
- log(`Project: ${projectId}`, 'cyan');
2758
- log('', 'gray');
3124
+ log("", "gray");
3125
+ log("💻 Starting Phase 4: Development", "blue");
3126
+ log("=====================================", "gray");
3127
+ log("", "gray");
3128
+ log(`Project: ${projectId}`, "cyan");
3129
+ log("", "gray");
2759
3130
 
2760
3131
  const executor = new Phase4DevelopmentExecutor(projectId);
2761
3132
 
2762
3133
  // Check if Phase 3 task plan exists
2763
3134
  if (!fs.existsSync(executor.taskPlanPath)) {
2764
- log(`❌ Phase 3 task plan not found: ${executor.taskPlanPath}`, 'red');
2765
- log('Complete Phase 3 first.', 'yellow');
3135
+ log(
3136
+ `❌ Phase 3 task plan not found: ${executor.taskPlanPath}`,
3137
+ "red",
3138
+ );
3139
+ log("Complete Phase 3 first.", "yellow");
2766
3140
  process.exit(1);
2767
3141
  }
2768
3142
 
2769
- executor.execute((msg, current, total) => {
2770
- const progress = Math.round((current / total) * 100);
2771
- log(`[${progress}%] ${msg}`, 'gray');
2772
- }).then(result => {
2773
- log('', 'gray');
2774
- log('✅ Phase 4 initialized!', 'green');
2775
- log(` Source: ${result.sourceDir}`, 'gray');
2776
- log(` Tasks: ${result.tasksPath}`, 'gray');
2777
- log(` Dev Log: ${result.devLogPath}`, 'gray');
2778
- log('', 'gray');
2779
- log('Next steps:', 'gray');
2780
- log(' 1. Review the generated scaffold', 'gray');
2781
- log(' 2. Implement tasks according to TASK_PLAN.md', 'gray');
2782
- log(' 3. Write tests for each feature', 'gray');
2783
- log(' 4. Update task progress in TASKS.md', 'gray');
2784
- log(' 5. Validate: smc workflow validate ' + projectId, 'gray');
2785
- log('', 'gray');
2786
- }).catch(err => {
2787
- log('', 'gray');
2788
- log(`❌ Error: ${err.message}`, 'red');
2789
- process.exit(1);
2790
- });
2791
-
3143
+ executor
3144
+ .execute((msg, current, total) => {
3145
+ const progress = Math.round((current / total) * 100);
3146
+ log(`[${progress}%] ${msg}`, "gray");
3147
+ })
3148
+ .then((result) => {
3149
+ log("", "gray");
3150
+ log("✅ Phase 4 initialized!", "green");
3151
+ log(` Source: ${result.sourceDir}`, "gray");
3152
+ log(` Tasks: ${result.tasksPath}`, "gray");
3153
+ log(` Dev Log: ${result.devLogPath}`, "gray");
3154
+ log("", "gray");
3155
+ log("Next steps:", "gray");
3156
+ log(" 1. Review the generated scaffold", "gray");
3157
+ log(" 2. Implement tasks according to TASK_PLAN.md", "gray");
3158
+ log(" 3. Write tests for each feature", "gray");
3159
+ log(" 4. Update task progress in TASKS.md", "gray");
3160
+ log(" 5. Validate: smc workflow validate " + projectId, "gray");
3161
+ log("", "gray");
3162
+ })
3163
+ .catch((err) => {
3164
+ log("", "gray");
3165
+ log(`❌ Error: ${err.message}`, "red");
3166
+ process.exit(1);
3167
+ });
2792
3168
  } else if (project.hasPhase2 && !project.hasPhase3) {
2793
3169
  // Execute Phase 3
2794
- const { Phase3PlanningExecutor } = require('../.claude/workflow/phases/phase3-plan');
3170
+ const {
3171
+ Phase3PlanningExecutor,
3172
+ } = require("../.claude/workflow/phases/phase3-plan");
2795
3173
 
2796
- log('', 'gray');
2797
- log('📐 Starting Phase 3: Planning', 'blue');
2798
- log('=====================================', 'gray');
2799
- log('', 'gray');
2800
- log(`Project: ${projectId}`, 'cyan');
2801
- log('', 'gray');
3174
+ log("", "gray");
3175
+ log("📐 Starting Phase 3: Planning", "blue");
3176
+ log("=====================================", "gray");
3177
+ log("", "gray");
3178
+ log(`Project: ${projectId}`, "cyan");
3179
+ log("", "gray");
2802
3180
 
2803
3181
  const executor = new Phase3PlanningExecutor(projectId);
2804
3182
 
2805
3183
  // Check if Phase 2 requirements exist
2806
3184
  if (!fs.existsSync(executor.phase2RequirementsPath)) {
2807
- log(`❌ Phase 2 requirements not found: ${executor.phase2RequirementsPath}`, 'red');
2808
- log('Complete Phase 2 first.', 'yellow');
3185
+ log(
3186
+ `❌ Phase 2 requirements not found: ${executor.phase2RequirementsPath}`,
3187
+ "red",
3188
+ );
3189
+ log("Complete Phase 2 first.", "yellow");
2809
3190
  process.exit(1);
2810
3191
  }
2811
3192
 
2812
- executor.execute((msg, current, total) => {
2813
- const progress = Math.round((current / total) * 100);
2814
- log(`[${progress}%] ${msg}`, 'gray');
2815
- }).then(result => {
2816
- log('', 'gray');
2817
- log('✅ Phase 3 initialized!', 'green');
2818
- log(` PRD: ${result.prdPath}`, 'gray');
2819
- log(` Task Plan: ${result.taskPlanPath}`, 'gray');
2820
- log(` Prototype: ${result.prototypeDir}`, 'gray');
2821
- log('', 'gray');
2822
- log('Next steps:', 'gray');
2823
- log(' 1. Review and complete the PRD', 'gray');
2824
- log(' 2. Review and adjust the task plan', 'gray');
2825
- log(' 3. Create prototypes/proofs-of-concept', 'gray');
2826
- log(' 4. Validate: smc workflow validate ' + result.prdPath, 'gray');
2827
- log(' 5. Proceed to Phase 4', 'gray');
2828
- log('', 'gray');
2829
- }).catch(err => {
2830
- log('', 'gray');
2831
- log(`❌ Error: ${err.message}`, 'red');
2832
- process.exit(1);
2833
- });
2834
-
3193
+ executor
3194
+ .execute((msg, current, total) => {
3195
+ const progress = Math.round((current / total) * 100);
3196
+ log(`[${progress}%] ${msg}`, "gray");
3197
+ })
3198
+ .then((result) => {
3199
+ log("", "gray");
3200
+ log("✅ Phase 3 initialized!", "green");
3201
+ log(` PRD: ${result.prdPath}`, "gray");
3202
+ log(` Task Plan: ${result.taskPlanPath}`, "gray");
3203
+ log(` Prototype: ${result.prototypeDir}`, "gray");
3204
+ log("", "gray");
3205
+ log("Next steps:", "gray");
3206
+ log(" 1. Review and complete the PRD", "gray");
3207
+ log(" 2. Review and adjust the task plan", "gray");
3208
+ log(" 3. Create prototypes/proofs-of-concept", "gray");
3209
+ log(
3210
+ " 4. Validate: smc workflow validate " + result.prdPath,
3211
+ "gray",
3212
+ );
3213
+ log(" 5. Proceed to Phase 4", "gray");
3214
+ log("", "gray");
3215
+ })
3216
+ .catch((err) => {
3217
+ log("", "gray");
3218
+ log(`❌ Error: ${err.message}`, "red");
3219
+ process.exit(1);
3220
+ });
2835
3221
  } else {
2836
3222
  // Execute Phase 2 (original logic)
2837
- const { Phase2ApprovalExecutor } = require('../.claude/workflow/phases/phase2-approve');
3223
+ const {
3224
+ Phase2ApprovalExecutor,
3225
+ } = require("../.claude/workflow/phases/phase2-approve");
2838
3226
 
2839
- log('', 'gray');
2840
- log('🤝 Starting Phase 2: Approval', 'blue');
2841
- log('=====================================', 'gray');
2842
- log('', 'gray');
2843
- log(`Project: ${projectId}`, 'cyan');
2844
- log('', 'gray');
3227
+ log("", "gray");
3228
+ log("🤝 Starting Phase 2: Approval", "blue");
3229
+ log("=====================================", "gray");
3230
+ log("", "gray");
3231
+ log(`Project: ${projectId}`, "cyan");
3232
+ log("", "gray");
2845
3233
 
2846
3234
  const executor = new Phase2ApprovalExecutor(projectId);
2847
3235
 
2848
3236
  // Check if Phase 1 report exists
2849
3237
  if (!fs.existsSync(executor.phase1ReportPath)) {
2850
- log(`❌ Phase 1 report not found: ${executor.phase1ReportPath}`, 'red');
2851
- log('Complete Phase 1 first.', 'yellow');
3238
+ log(
3239
+ `❌ Phase 1 report not found: ${executor.phase1ReportPath}`,
3240
+ "red",
3241
+ );
3242
+ log("Complete Phase 1 first.", "yellow");
2852
3243
  process.exit(1);
2853
3244
  }
2854
3245
 
2855
- executor.execute((msg, current, total) => {
2856
- const progress = Math.round((current / total) * 100);
2857
- log(`[${progress}%] ${msg}`, 'gray');
2858
- }).then(result => {
2859
- log('', 'gray');
2860
- log('✅ Phase 2 initialized!', 'green');
2861
- log(` Requirements: ${result.requirementsPath}`, 'gray');
2862
- log('', 'gray');
2863
- log('Next steps:', 'gray');
2864
- log(' 1. Review and answer clarification questions', 'gray');
2865
- log(' 2. Define functional requirements with acceptance criteria', 'gray');
2866
- log(' 3. Validate: smc workflow validate ' + result.requirementsPath, 'gray');
2867
- log(' 4. Proceed to Phase 3', 'gray');
2868
- log('', 'gray');
2869
- }).catch(err => {
2870
- log('', 'gray');
2871
- log(`❌ Error: ${err.message}`, 'red');
2872
- process.exit(1);
2873
- });
3246
+ executor
3247
+ .execute((msg, current, total) => {
3248
+ const progress = Math.round((current / total) * 100);
3249
+ log(`[${progress}%] ${msg}`, "gray");
3250
+ })
3251
+ .then((result) => {
3252
+ log("", "gray");
3253
+ log("✅ Phase 2 initialized!", "green");
3254
+ log(` Requirements: ${result.requirementsPath}`, "gray");
3255
+ log("", "gray");
3256
+ log("Next steps:", "gray");
3257
+ log(" 1. Review and answer clarification questions", "gray");
3258
+ log(
3259
+ " 2. Define functional requirements with acceptance criteria",
3260
+ "gray",
3261
+ );
3262
+ log(
3263
+ " 3. Validate: smc workflow validate " +
3264
+ result.requirementsPath,
3265
+ "gray",
3266
+ );
3267
+ log(" 4. Proceed to Phase 3", "gray");
3268
+ log("", "gray");
3269
+ })
3270
+ .catch((err) => {
3271
+ log("", "gray");
3272
+ log(`❌ Error: ${err.message}`, "red");
3273
+ process.exit(1);
3274
+ });
2874
3275
  }
2875
3276
  break;
2876
3277
  }
2877
3278
 
2878
3279
  default:
2879
- log('', 'gray');
2880
- log('🔄 Workflow Commands', 'blue');
2881
- log('=====================================', 'gray');
2882
- log('', 'gray');
2883
- log('Usage: smc workflow <action> [args...]', 'gray');
2884
- log('', 'gray');
2885
- log('Actions:', 'gray');
2886
- log(' start <idea> Start a new project workflow (Phase 1)', 'gray');
2887
- log(' approve <id> Start Phase 2 approval for a project', 'gray');
2888
- log(' next Auto-advance to next phase', 'gray');
2889
- log(' status Show all projects and their phases', 'gray');
2890
- log(' validate <file> Validate a report (feasibility or requirements)', 'gray');
2891
- log(' phase [n] Show phase information', 'gray');
2892
- log('', 'gray');
2893
- log('Examples:', 'gray');
2894
- log(' smc workflow start "Build a REST API"', 'gray');
2895
- log(' smc workflow approve proj_abc123', 'gray');
2896
- log(' smc workflow next', 'gray');
2897
- log(' smc workflow status', 'gray');
2898
- log(' smc workflow validate development/projects/xxx/phase1/feasibility-report.md', 'gray');
2899
- log(' smc workflow phase 1', 'gray');
2900
- log('', 'gray');
3280
+ log("", "gray");
3281
+ log("🔄 Workflow Commands", "blue");
3282
+ log("=====================================", "gray");
3283
+ log("", "gray");
3284
+ log("Usage: smc workflow <action> [args...]", "gray");
3285
+ log("", "gray");
3286
+ log("Actions:", "gray");
3287
+ log(
3288
+ " start <idea> Start a new project workflow (Phase 1)",
3289
+ "gray",
3290
+ );
3291
+ log(" approve <id> Start Phase 2 approval for a project", "gray");
3292
+ log(" next Auto-advance to next phase", "gray");
3293
+ log(" status Show all projects and their phases", "gray");
3294
+ log(
3295
+ " validate <file> Validate a report (feasibility or requirements)",
3296
+ "gray",
3297
+ );
3298
+ log(" phase [n] Show phase information", "gray");
3299
+ log("", "gray");
3300
+ log("Examples:", "gray");
3301
+ log(' smc workflow start "Build a REST API"', "gray");
3302
+ log(" smc workflow approve proj_abc123", "gray");
3303
+ log(" smc workflow next", "gray");
3304
+ log(" smc workflow status", "gray");
3305
+ log(
3306
+ " smc workflow validate development/projects/xxx/phase1/feasibility-report.md",
3307
+ "gray",
3308
+ );
3309
+ log(" smc workflow phase 1", "gray");
3310
+ log("", "gray");
2901
3311
  }
2902
3312
  },
2903
3313
 
@@ -2906,7 +3316,9 @@ All notable changes to this project will be documented in this file.
2906
3316
  // ==========================================================================
2907
3317
 
2908
3318
  knowledge: async (...args) => {
2909
- const { handleKnowledgeCommand } = require('../.claude/workflow/knowledge-engine');
3319
+ const {
3320
+ handleKnowledgeCommand,
3321
+ } = require("../.claude/workflow/knowledge-engine");
2910
3322
  await handleKnowledgeCommand(args);
2911
3323
  },
2912
3324
 
@@ -2915,9 +3327,11 @@ All notable changes to this project will be documented in this file.
2915
3327
  // ==========================================================================
2916
3328
 
2917
3329
  notebooklm: async (...args) => {
2918
- const { handleNotebookLMCommand } = require('../.claude/workflow/notebooklm/browser');
3330
+ const {
3331
+ handleNotebookLMCommand,
3332
+ } = require("../.claude/workflow/notebooklm/browser");
2919
3333
  await handleNotebookLMCommand(args);
2920
- }
3334
+ },
2921
3335
  };
2922
3336
 
2923
3337
  // ============================================================================
@@ -2930,7 +3344,7 @@ function generateAgentsMd(config) {
2930
3344
  const model = agent.model || config.model;
2931
3345
  return `### ${name}\n- **Model**: ${model}\n- **Role**: ${agent.role}`;
2932
3346
  })
2933
- .join('\n\n');
3347
+ .join("\n\n");
2934
3348
 
2935
3349
  return `# AGENTS
2936
3350
 
@@ -2971,9 +3385,14 @@ sumulige-claude skill:list
2971
3385
  async function runCommand(cmd, args) {
2972
3386
  const command = commands[cmd];
2973
3387
  if (command) {
2974
- await command(...args);
3388
+ await command(...(args || []));
2975
3389
  }
2976
3390
  }
2977
3391
 
2978
3392
  exports.runCommand = runCommand;
2979
3393
  exports.commands = commands;
3394
+ // Export helper functions for testing
3395
+ exports.countFiles = countFiles;
3396
+ exports.copySingleFile = copySingleFile;
3397
+ exports.setExecutablePermission = setExecutablePermission;
3398
+ exports.generateAgentsMd = generateAgentsMd;