sumulige-claude 1.0.6 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/.claude/.kickoff-hint.txt +51 -0
  2. package/.claude/ANCHORS.md +40 -0
  3. package/.claude/MEMORY.md +34 -0
  4. package/.claude/PROJECT_LOG.md +101 -0
  5. package/.claude/THINKING_CHAIN_GUIDE.md +287 -0
  6. package/.claude/commands/commit-push-pr.md +59 -0
  7. package/.claude/commands/commit.md +53 -0
  8. package/.claude/commands/pr.md +76 -0
  9. package/.claude/commands/review.md +61 -0
  10. package/.claude/commands/sessions.md +62 -0
  11. package/.claude/commands/skill-create.md +131 -0
  12. package/.claude/commands/test.md +56 -0
  13. package/.claude/commands/todos.md +99 -0
  14. package/.claude/commands/verify-work.md +63 -0
  15. package/.claude/hooks/code-formatter.cjs +187 -0
  16. package/.claude/hooks/code-tracer.cjs +331 -0
  17. package/.claude/hooks/conversation-recorder.cjs +340 -0
  18. package/.claude/hooks/decision-tracker.cjs +398 -0
  19. package/.claude/hooks/export.cjs +329 -0
  20. package/.claude/hooks/multi-session.cjs +181 -0
  21. package/.claude/hooks/privacy-filter.js +224 -0
  22. package/.claude/hooks/project-kickoff.cjs +114 -0
  23. package/.claude/hooks/rag-skill-loader.cjs +159 -0
  24. package/.claude/hooks/session-end.sh +61 -0
  25. package/.claude/hooks/sync-to-log.sh +83 -0
  26. package/.claude/hooks/thinking-silent.cjs +145 -0
  27. package/.claude/hooks/tl-summary.sh +54 -0
  28. package/.claude/hooks/todo-manager.cjs +248 -0
  29. package/.claude/hooks/verify-work.cjs +134 -0
  30. package/.claude/sessions/active-sessions.json +359 -0
  31. package/.claude/settings.local.json +43 -2
  32. package/.claude/thinking-routes/.last-sync +1 -0
  33. package/.claude/thinking-routes/QUICKREF.md +98 -0
  34. package/.claude-plugin/marketplace.json +71 -0
  35. package/.github/workflows/sync-skills.yml +74 -0
  36. package/AGENTS.md +81 -22
  37. package/DEV_TOOLS_GUIDE.md +190 -0
  38. package/PROJECT_STRUCTURE.md +10 -1
  39. package/README.md +142 -708
  40. package/cli.js +116 -822
  41. package/config/defaults.json +34 -0
  42. package/config/skill-categories.json +40 -0
  43. package/development/todos/INDEX.md +14 -58
  44. package/docs/DEVELOPMENT.md +423 -0
  45. package/docs/MARKETPLACE.md +352 -0
  46. package/lib/commands.js +698 -0
  47. package/lib/config.js +71 -0
  48. package/lib/marketplace.js +486 -0
  49. package/lib/utils.js +62 -0
  50. package/package.json +11 -5
  51. package/scripts/sync-external.mjs +298 -0
  52. package/scripts/update-registry.mjs +325 -0
  53. package/sources.yaml +83 -0
package/cli.js CHANGED
@@ -8,855 +8,149 @@
8
8
  * - Skills management via OpenSkills
9
9
  * - Built-in Claude Code project template
10
10
  * - ThinkingLens conversation tracking
11
+ *
12
+ * @version 1.0.7
11
13
  */
12
14
 
13
- const fs = require('fs');
14
- const path = require('path');
15
- const { execSync } = require('child_process');
15
+ const { runCommand } = require('./lib/commands');
16
+ const { marketplaceCommands } = require('./lib/marketplace');
16
17
 
17
- const CONFIG_DIR = path.join(process.env.HOME, '.claude');
18
- const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
19
- const SKILLS_DIR = path.join(CONFIG_DIR, 'skills');
20
- const TEMPLATE_DIR = path.join(__dirname, 'template');
18
+ // ============================================================================
19
+ // Command Registry (data-driven, no if-else chains)
20
+ // ============================================================================
21
21
 
22
- // 默认配置 - 所有 Agent 使用 Opus 4.5
23
- const DEFAULT_CONFIG = {
24
- version: '1.0.0',
25
- agents: {
26
- conductor: { model: 'claude-opus-4.5', role: 'Task coordination and decomposition' },
27
- architect: { model: 'claude-opus-4.5', role: 'Architecture design and decisions' },
28
- builder: { model: 'claude-opus-4.5', role: 'Code implementation and testing' },
29
- reviewer: { model: 'claude-opus-4.5', role: 'Code review and quality check' },
30
- librarian: { model: 'claude-opus-4.5', role: 'Documentation and knowledge' }
22
+ const COMMANDS = {
23
+ init: {
24
+ help: 'Initialize configuration',
25
+ args: ''
31
26
  },
32
- skills: [
33
- 'anthropics/skills',
34
- 'numman-ali/n-skills'
35
- ],
36
- hooks: {
37
- preTask: [],
38
- postTask: []
27
+ sync: {
28
+ help: 'Sync to current project',
29
+ args: ''
39
30
  },
40
- thinkingLens: {
41
- enabled: true,
42
- autoSync: true,
43
- syncInterval: 20
44
- }
45
- };
46
-
47
- // 命令处理
48
- const commands = {
49
- init: () => {
50
- console.log('🚀 Initializing Sumulige Claude...');
51
-
52
- // 创建配置目录
53
- if (!fs.existsSync(CONFIG_DIR)) {
54
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
55
- }
56
-
57
- // 创建配置文件
58
- if (!fs.existsSync(CONFIG_FILE)) {
59
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(DEFAULT_CONFIG, null, 2));
60
- console.log('✅ Created config:', CONFIG_FILE);
61
- } else {
62
- console.log('ℹ️ Config already exists:', CONFIG_FILE);
63
- }
64
-
65
- // 创建技能目录
66
- if (!fs.existsSync(SKILLS_DIR)) {
67
- fs.mkdirSync(SKILLS_DIR, { recursive: true });
68
- console.log('✅ Created skills directory:', SKILLS_DIR);
69
- }
70
-
71
- // 安装 openskills(如果未安装)
72
- try {
73
- execSync('openskills --version', { stdio: 'ignore' });
74
- console.log('✅ OpenSkills already installed');
75
- } catch {
76
- console.log('📦 Installing OpenSkills...');
77
- try {
78
- execSync('npm i -g openskills', { stdio: 'inherit' });
79
- console.log('✅ OpenSkills installed');
80
- } catch (e) {
81
- console.log('⚠️ Failed to install OpenSkills. Run: npm i -g openskills');
82
- }
83
- }
84
-
85
- console.log('');
86
- console.log('🎉 Sumulige Claude initialized!');
87
- console.log('');
88
- console.log('Next steps:');
89
- console.log(' sumulige-claude sync # Sync to current project');
90
- console.log(' sumulige-claude agent # Run agent orchestration');
91
- console.log(' sumulige-claude status # Show configuration');
31
+ template: {
32
+ help: 'Deploy Claude Code project template',
33
+ args: '[path]'
92
34
  },
93
-
94
- sync: () => {
95
- console.log('🔄 Syncing Sumulige Claude to current project...');
96
-
97
- const projectDir = process.cwd();
98
- const projectConfigDir = path.join(projectDir, '.claude');
99
- const agentsFile = path.join(projectConfigDir, 'AGENTS.md');
100
- const readmeFile = path.join(projectConfigDir, 'README.md');
101
- const templateReadme = path.join(TEMPLATE_DIR, '.claude', 'README.md');
102
-
103
- // 创建 .claude 目录
104
- if (!fs.existsSync(projectConfigDir)) {
105
- fs.mkdirSync(projectConfigDir, { recursive: true });
106
- console.log('✅ Created .claude directory');
107
- }
108
-
109
- // 同步配置
110
- const config = loadConfig();
111
-
112
- // 生成 AGENTS.md
113
- const agentsMd = generateAgentsMd(config);
114
- fs.writeFileSync(agentsFile, agentsMd);
115
- console.log('✅ Created AGENTS.md');
116
-
117
- // 静默同步 README.md(如果 template 更新了)
118
- if (fs.existsSync(templateReadme)) {
119
- const templateContent = fs.readFileSync(templateReadme, 'utf-8');
120
- let needsUpdate = true;
121
-
122
- // 检查是否需要更新(比较文件内容)
123
- if (fs.existsSync(readmeFile)) {
124
- const existingContent = fs.readFileSync(readmeFile, 'utf-8');
125
- // 提取版本标记(如果有)
126
- const templateVersion = templateContent.match(/@version:\s*(\d+\.\d+\.\d+)/)?.[1] || '0.0.0';
127
- const existingVersion = existingContent.match(/@version:\s*(\d+\.\d+\.\d+)/)?.[1] || '0.0.0';
128
- needsUpdate = templateVersion !== existingVersion;
129
- }
130
-
131
- if (needsUpdate) {
132
- fs.writeFileSync(readmeFile, templateContent);
133
- // 静默更新,不输出
134
- }
135
- }
136
-
137
- // 同步 todos 目录结构
138
- const todosTemplateDir = path.join(TEMPLATE_DIR, 'development', 'todos');
139
- const todosProjectDir = path.join(projectDir, 'development', 'todos');
140
-
141
- if (fs.existsSync(todosTemplateDir)) {
142
- // 复制 todos 模板文件(如果不存在)
143
- const copyRecursive = (src, dest) => {
144
- if (!fs.existsSync(dest)) {
145
- fs.mkdirSync(dest, { recursive: true });
146
- }
147
- const entries = fs.readdirSync(src, { withFileTypes: true });
148
- for (const entry of entries) {
149
- const srcPath = path.join(src, entry.name);
150
- const destPath = path.join(dest, entry.name);
151
- if (entry.isDirectory()) {
152
- copyRecursive(srcPath, destPath);
153
- } else if (!fs.existsSync(destPath)) {
154
- fs.copyFileSync(srcPath, destPath);
155
- }
156
- }
157
- };
158
- copyRecursive(todosTemplateDir, todosProjectDir);
159
- // 静默同步,不输出
160
- }
161
-
162
- // 同步技能
163
- try {
164
- execSync('openskills sync -y', { stdio: 'pipe' });
165
- console.log('✅ Synced skills');
166
- } catch (e) {
167
- console.log('⚠️ Failed to sync skills');
168
- }
169
-
170
- console.log('');
171
- console.log('✅ Sync complete!');
35
+ kickoff: {
36
+ help: 'Start project planning workflow (Manus-style)',
37
+ args: ''
172
38
  },
173
-
174
- agent: (task) => {
175
- if (!task) {
176
- console.log('Usage: sumulige-claude agent <task>');
177
- console.log('');
178
- console.log('Example: sumulige-claude agent "Build a React dashboard"');
179
- return;
180
- }
181
-
182
- const config = loadConfig();
183
- console.log('🤖 Starting Agent Orchestration...');
184
- console.log('');
185
- console.log('Task:', task);
186
- console.log('');
187
- console.log('Available Agents:');
188
- Object.entries(config.agents).forEach(([name, agent]) => {
189
- console.log(` - ${name}: ${agent.model} (${agent.role})`);
190
- });
191
- console.log('');
192
- console.log('💡 In Claude Code, use /skill <name> to invoke specific agent capabilities');
39
+ agent: {
40
+ help: 'Run agent orchestration',
41
+ args: '<task>'
193
42
  },
194
-
195
- status: () => {
196
- const config = loadConfig();
197
- console.log('📊 Sumulige Claude Status');
198
- console.log('');
199
- console.log('Config:', CONFIG_FILE);
200
- console.log('');
201
- console.log('Agents:');
202
- Object.entries(config.agents).forEach(([name, agent]) => {
203
- console.log(` ${name.padEnd(12)} ${agent.model.padEnd(20)} (${agent.role})`);
204
- });
205
- console.log('');
206
- console.log('Skills:', config.skills.join(', '));
207
- console.log('');
208
- console.log('ThinkingLens:', config.thinkingLens.enabled ? '✅ Enabled' : '❌ Disabled');
209
- console.log('');
210
-
211
- // 显示项目 todos 状态
212
- const projectDir = process.cwd();
213
- const todosIndex = path.join(projectDir, 'development', 'todos', 'INDEX.md');
214
-
215
- if (fs.existsSync(todosIndex)) {
216
- const content = fs.readFileSync(todosIndex, 'utf-8');
217
-
218
- // 提取进度信息
219
- const totalMatch = content.match(/Total:\s+`([^`]+)`\s+(\d+)%/);
220
- const p0Match = content.match(/P0[^`]*`([^`]+)`\s+(\d+)%\s+\((\d+)\/(\d+)\)/);
221
- const p1Match = content.match(/P1[^`]*`([^`]+)`\s+(\d+)%\s+\((\d+)\/(\d+)\)/);
222
- const p2Match = content.match(/P2[^`]*`([^`]+)`\s+(\d+)%\s+\((\d+)\/(\d+)\)/);
223
-
224
- const activeMatch = content.match(/\|\s+🚧 进行中[^|]*\|\s+`active\/`\s+\|\s+(\d+)/);
225
- const completedMatch = content.match(/\|\s+✅ 已完成[^|]*\|\s+`completed\/`\s+\|\s+(\d+)/);
226
- const backlogMatch = content.match(/\|\s+📋 待办[^|]*\|\s+`backlog\/`\s+\|\s+(\d+)/);
227
-
228
- console.log('📋 Project Tasks:');
229
- console.log('');
230
- if (totalMatch) {
231
- console.log(` Total: ${totalMatch[1]} ${totalMatch[2]}%`);
232
- }
233
- if (p0Match) {
234
- console.log(` P0: ${p0Match[1]} ${p0Match[2]}% (${p0Match[3]}/${p0Match[4]})`);
235
- }
236
- if (p1Match) {
237
- console.log(` P1: ${p1Match[1]} ${p1Match[2]}% (${p1Match[3]}/${p1Match[4]})`);
238
- }
239
- if (p2Match) {
240
- console.log(` P2: ${p2Match[1]} ${p2Match[2]}% (${p2Match[3]}/${p2Match[4]})`);
241
- }
242
- console.log('');
243
- console.log(` 🚧 Active: ${activeMatch ? activeMatch[1] : 0}`);
244
- console.log(` ✅ Completed: ${completedMatch ? completedMatch[1] : 0}`);
245
- console.log(` 📋 Backlog: ${backlogMatch ? backlogMatch[1] : 0}`);
246
- console.log('');
247
- console.log(` View: cat development/todos/INDEX.md`);
248
- } else {
249
- console.log('📋 Project Tasks: (not initialized)');
250
- console.log(' Run: node .claude/hooks/todo-manager.cjs --force');
251
- }
43
+ status: {
44
+ help: 'Show configuration status',
45
+ args: ''
252
46
  },
253
-
254
- 'skill:list': () => {
255
- try {
256
- const result = execSync('openskills list', { encoding: 'utf-8' });
257
- console.log(result);
258
- } catch (e) {
259
- console.log('⚠️ OpenSkills not installed. Run: npm i -g openskills');
260
- }
47
+ 'skill:list': {
48
+ help: 'List installed skills',
49
+ args: ''
261
50
  },
262
-
263
- 'skill:create': (skillName) => {
264
- if (!skillName) {
265
- console.log('Usage: sumulige-claude skill:create <skill-name>');
266
- console.log('');
267
- console.log('Example: sumulige-claude skill:create api-tester');
268
- console.log('');
269
- console.log('The skill will be created at:');
270
- console.log(' .claude/skills/<skill-name>/');
271
- return;
272
- }
273
-
274
- // 验证 skill 名称 (kebab-case)
275
- if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(skillName)) {
276
- console.log('❌ Invalid skill name. Use kebab-case (e.g., api-tester, code-reviewer)');
277
- return;
278
- }
279
-
280
- const projectDir = process.cwd();
281
- const skillsDir = path.join(projectDir, '.claude', 'skills');
282
- const skillDir = path.join(skillsDir, skillName);
283
- const templateDir = path.join(TEMPLATE_DIR, '.claude', 'skills', 'template');
284
-
285
- // 检查技能是否已存在
286
- if (fs.existsSync(skillDir)) {
287
- console.log(`⚠️ Skill "${skillName}" already exists at ${skillDir}`);
288
- return;
289
- }
290
-
291
- console.log(`📝 Creating skill: ${skillName}`);
292
- console.log('');
293
-
294
- // 创建技能目录结构
295
- fs.mkdirSync(path.join(skillDir, 'templates'), { recursive: true });
296
- fs.mkdirSync(path.join(skillDir, 'examples'), { recursive: true });
297
- console.log('✅ Created directory structure');
298
-
299
- // 复制模板文件
300
- if (fs.existsSync(templateDir)) {
301
- const skillTemplate = fs.readFileSync(path.join(templateDir, 'SKILL.md'), 'utf-8');
302
- const metadataTemplate = fs.readFileSync(path.join(templateDir, 'metadata.yaml'), 'utf-8');
303
-
304
- // 替换占位符
305
- const date = new Date().toISOString().split('T')[0];
306
- let skillContent = skillTemplate
307
- .replace(/Skill Name/g, toTitleCase(skillName.replace(/-/g, ' ')))
308
- .replace(/{current-date}/g, date)
309
- .replace(/skill-name/g, skillName);
310
-
311
- let metadataContent = metadataTemplate
312
- .replace(/skill-name/g, skillName)
313
- .replace(/dependencies: \[\]/g, 'dependencies: []') // 保持依赖为空,用户手动添加
314
- .replace(/difficulty: beginner/g, 'difficulty: beginner'); // 默认难度
315
-
316
- fs.writeFileSync(path.join(skillDir, 'SKILL.md'), skillContent);
317
- fs.writeFileSync(path.join(skillDir, 'metadata.yaml'), metadataContent);
318
- console.log('✅ Created SKILL.md and metadata.yaml');
319
- }
320
-
321
- // 创建示例模板
322
- fs.writeFileSync(
323
- path.join(skillDir, 'templates', 'default.md'),
324
- `# Default Template for ${skillName}\n\nReplace this with your actual template.\n`
325
- );
326
- fs.writeFileSync(
327
- path.join(skillDir, 'examples', 'basic.md'),
328
- `# Basic Example for ${skillName}\n\nReplace this with your actual example.\n`
329
- );
330
- console.log('✅ Created templates and examples');
331
-
332
- // 更新 RAG 索引
333
- const ragDir = path.join(projectDir, '.claude', 'rag');
334
- const ragIndexFile = path.join(ragDir, 'skill-index.json');
335
- let ragIndex = { skills: [], auto_load: { enabled: true } };
336
-
337
- // 确保 rag 目录存在
338
- if (!fs.existsSync(ragDir)) {
339
- fs.mkdirSync(ragDir, { recursive: true });
340
- }
341
-
342
- if (fs.existsSync(ragIndexFile)) {
343
- try {
344
- ragIndex = JSON.parse(fs.readFileSync(ragIndexFile, 'utf-8'));
345
- } catch (e) { }
346
- }
347
-
348
- // 添加新技能到索引
349
- const newSkill = {
350
- name: skillName,
351
- description: `TODO: Add description for ${skillName}`,
352
- keywords: [skillName.replace(/-/g, ' ')],
353
- path: `.claude/skills/${skillName}/SKILL.md`
354
- };
355
-
356
- // 避免重复
357
- if (!ragIndex.skills.some(s => s.name === skillName)) {
358
- ragIndex.skills.push(newSkill);
359
- fs.writeFileSync(ragIndexFile, JSON.stringify(ragIndex, null, 2));
360
- console.log('✅ Updated RAG skill index');
361
- }
362
-
363
- console.log('');
364
- console.log('✅ Skill created successfully!');
365
- console.log('');
366
- console.log(`Next steps:`);
367
- console.log(` 1. Edit .claude/skills/${skillName}/SKILL.md`);
368
- console.log(` 2. Add your templates and examples`);
369
- console.log(` 3. Use in Claude Code: /skill ${skillName}`);
51
+ 'skill:create': {
52
+ help: 'Create a new skill',
53
+ args: '<name>'
370
54
  },
371
-
372
- 'skill:check': (skillName) => {
373
- const projectDir = process.cwd();
374
- const skillsDir = path.join(projectDir, '.claude', 'skills');
375
-
376
- console.log('🔍 Checking skill dependencies...');
377
- console.log('');
378
-
379
- const checkSkill = (name, visited = new Set()) => {
380
- if (visited.has(name)) {
381
- console.log(`⚠️ Circular dependency detected: ${name}`);
382
- return;
383
- }
384
- visited.add(name);
385
-
386
- const skillDir = path.join(skillsDir, name);
387
- const metadataFile = path.join(skillDir, 'metadata.yaml');
388
-
389
- if (!fs.existsSync(skillDir)) {
390
- console.log(`❌ Skill "${name}" not found`);
391
- return;
392
- }
393
-
394
- if (!fs.existsSync(metadataFile)) {
395
- console.log(`ℹ️ ${name}: No metadata.yaml`);
396
- return;
397
- }
398
-
399
- // 简单解析 YAML(只支持基本的 key: value 格式)
400
- const parseSimpleYaml = (content) => {
401
- const result = {};
402
- content.split('\n').forEach(line => {
403
- const match = line.match(/^(\w+):\s*(.*)$/);
404
- if (match) {
405
- const value = match[2].trim();
406
- if (value === '[]') {
407
- result[match[1]] = [];
408
- } else if (value.startsWith('[')) {
409
- try {
410
- result[match[1]] = JSON.parse(value.replace(/'/g, '"'));
411
- } catch (e) {
412
- result[match[1]] = [];
413
- }
414
- } else {
415
- result[match[1]] = value;
416
- }
417
- }
418
- });
419
- return result;
420
- };
421
-
422
- const metadata = parseSimpleYaml(fs.readFileSync(metadataFile, 'utf-8'));
423
- const deps = metadata.dependencies || [];
424
-
425
- if (deps.length === 0) {
426
- console.log(`✅ ${name}: No dependencies`);
427
- return;
428
- }
429
-
430
- console.log(`📦 ${name} depends on:`);
431
- deps.forEach(dep => {
432
- const depDir = path.join(skillsDir, dep);
433
- if (fs.existsSync(depDir)) {
434
- console.log(` ✅ ${dep}`);
435
- checkSkill(dep, new Set(visited));
436
- } else {
437
- console.log(` ❌ ${dep} (missing)`);
438
- }
439
- });
440
- };
441
-
442
- if (skillName) {
443
- checkSkill(skillName);
444
- } else {
445
- // 检查所有技能
446
- const allSkills = fs.existsSync(skillsDir)
447
- ? fs.readdirSync(skillsDir).filter(f => {
448
- const dir = path.join(skillsDir, f);
449
- return fs.statSync(dir).isDirectory() && f !== 'template' && f !== 'examples';
450
- })
451
- : [];
452
-
453
- console.log(`Found ${allSkills.length} skills\n`);
454
- allSkills.forEach(skill => checkSkill(skill));
455
- }
55
+ 'skill:check': {
56
+ help: 'Check skill dependencies',
57
+ args: '[name]'
456
58
  },
457
-
458
- 'skill:install': (source) => {
459
- if (!source) {
460
- console.log('Usage: sumulige-claude skill:install <source>');
461
- console.log('Example: sumulige-claude skill:install anthropics/skills');
462
- return;
463
- }
464
- try {
465
- execSync(`openskills install ${source} -y`, { stdio: 'inherit' });
466
- execSync('openskills sync -y', { stdio: 'pipe' });
467
- console.log('✅ Skill installed and synced');
468
- } catch (e) {
469
- console.log('❌ Failed to install skill');
470
- }
59
+ 'skill:install': {
60
+ help: 'Install a skill',
61
+ args: '<source>'
471
62
  },
472
-
473
- template: (targetPath) => {
474
- const targetDir = targetPath ? path.resolve(targetPath) : process.cwd();
475
-
476
- console.log('🚀 Initializing Claude Code project template...');
477
- console.log(' Target:', targetDir);
478
- console.log('');
479
-
480
- // 检查模板目录是否存在
481
- if (!fs.existsSync(TEMPLATE_DIR)) {
482
- console.log('❌ Template not found at:', TEMPLATE_DIR);
483
- console.log(' Please reinstall sumulige-claude');
484
- process.exit(1);
485
- }
486
-
487
- // 递归复制目录(含子目录和文件)
488
- const copyRecursive = (src, dest, overwrite = false) => {
489
- if (!fs.existsSync(src)) return 0;
490
-
491
- if (!fs.existsSync(dest)) {
492
- fs.mkdirSync(dest, { recursive: true });
493
- }
494
-
495
- let count = 0;
496
- const entries = fs.readdirSync(src, { withFileTypes: true });
497
-
498
- for (const entry of entries) {
499
- const srcPath = path.join(src, entry.name);
500
- const destPath = path.join(dest, entry.name);
501
-
502
- if (entry.isDirectory()) {
503
- count += copyRecursive(srcPath, destPath, overwrite);
504
- } else {
505
- if (overwrite || !fs.existsSync(destPath)) {
506
- fs.copyFileSync(srcPath, destPath);
507
- // 添加执行权限
508
- if (entry.name.endsWith('.sh') || entry.name.endsWith('.cjs')) {
509
- fs.chmodSync(destPath, 0o755);
510
- }
511
- count++;
512
- }
513
- }
514
- }
515
- return count;
516
- };
517
-
518
- // 创建目录结构
519
- console.log('📁 Creating directory structure...');
520
- const dirs = [
521
- path.join(targetDir, '.claude'),
522
- path.join(targetDir, 'prompts'),
523
- path.join(targetDir, 'development/todos/active'),
524
- path.join(targetDir, 'development/todos/completed'),
525
- path.join(targetDir, 'development/todos/backlog'),
526
- path.join(targetDir, 'development/todos/archived')
527
- ];
528
-
529
- dirs.forEach(dir => {
530
- if (!fs.existsSync(dir)) {
531
- fs.mkdirSync(dir, { recursive: true });
532
- }
533
- });
534
- console.log(' ✅ Directories created');
535
-
536
- // 复制文件
537
- console.log('📋 Copying template files...');
538
-
539
- const claudeTemplateDir = path.join(TEMPLATE_DIR, '.claude');
540
- const targetClaudeDir = path.join(targetDir, '.claude');
541
-
542
- // 1. CLAUDE.md (从 CLAUDE-template.md)
543
- const claudeTemplate = path.join(claudeTemplateDir, 'CLAUDE-template.md');
544
- if (fs.existsSync(claudeTemplate)) {
545
- fs.copyFileSync(claudeTemplate, path.join(targetClaudeDir, 'CLAUDE.md'));
546
- console.log(' ✅ .claude/CLAUDE.md');
547
- }
548
-
549
- // 2. README.md
550
- const readmeFile = path.join(claudeTemplateDir, 'README.md');
551
- if (fs.existsSync(readmeFile)) {
552
- fs.copyFileSync(readmeFile, path.join(targetClaudeDir, 'README.md'));
553
- console.log(' ✅ .claude/README.md');
554
- }
555
-
556
- // 3. settings.json
557
- const settingsFile = path.join(claudeTemplateDir, 'settings.json');
558
- if (fs.existsSync(settingsFile)) {
559
- fs.copyFileSync(settingsFile, path.join(targetClaudeDir, 'settings.json'));
560
- console.log(' ✅ .claude/settings.json');
561
- }
562
-
563
- // 4. boris-optimizations.md
564
- const borisFile = path.join(claudeTemplateDir, 'boris-optimizations.md');
565
- if (fs.existsSync(borisFile)) {
566
- fs.copyFileSync(borisFile, path.join(targetClaudeDir, 'boris-optimizations.md'));
567
- console.log(' ✅ .claude/boris-optimizations.md');
568
- }
569
-
570
- // 5. hooks/ (递归复制)
571
- const hooksDir = path.join(claudeTemplateDir, 'hooks');
572
- if (fs.existsSync(hooksDir)) {
573
- const count = copyRecursive(hooksDir, path.join(targetClaudeDir, 'hooks'), true);
574
- console.log(` ✅ .claude/hooks/ (${count} files)`);
575
- }
576
-
577
- // 6. commands/ (递归复制) ⭐ 新增
578
- const commandsDir = path.join(claudeTemplateDir, 'commands');
579
- if (fs.existsSync(commandsDir)) {
580
- const count = copyRecursive(commandsDir, path.join(targetClaudeDir, 'commands'), true);
581
- console.log(` ✅ .claude/commands/ (${count} files)`);
582
- }
583
-
584
- // 7. skills/ (递归复制) ⭐ 新增
585
- const skillsDir = path.join(claudeTemplateDir, 'skills');
586
- if (fs.existsSync(skillsDir)) {
587
- const count = copyRecursive(skillsDir, path.join(targetClaudeDir, 'skills'), false);
588
- console.log(` ✅ .claude/skills/ (${count} files)`);
589
- }
590
-
591
- // 8. templates/ (递归复制) ⭐ 新增
592
- const templatesDir = path.join(claudeTemplateDir, 'templates');
593
- if (fs.existsSync(templatesDir)) {
594
- const count = copyRecursive(templatesDir, path.join(targetClaudeDir, 'templates'), false);
595
- console.log(` ✅ .claude/templates/ (${count} files)`);
596
- }
597
-
598
- // 9. thinking-routes/
599
- const routesDir = path.join(claudeTemplateDir, 'thinking-routes');
600
- if (fs.existsSync(routesDir)) {
601
- const count = copyRecursive(routesDir, path.join(targetClaudeDir, 'thinking-routes'), false);
602
- console.log(` ✅ .claude/thinking-routes/ (${count} files)`);
603
- }
604
-
605
- // 10. rag/
606
- const ragDir = path.join(claudeTemplateDir, 'rag');
607
- if (fs.existsSync(ragDir)) {
608
- const count = copyRecursive(ragDir, path.join(targetClaudeDir, 'rag'), true);
609
- console.log(` ✅ .claude/rag/ (${count} files)`);
610
- }
611
-
612
- // 11. prompts/
613
- const promptsDir = path.join(TEMPLATE_DIR, 'prompts');
614
- if (fs.existsSync(promptsDir)) {
615
- const count = copyRecursive(promptsDir, path.join(targetDir, 'prompts'), false);
616
- console.log(` ✅ prompts/ (${count} files)`);
617
- }
618
-
619
- // 12. development/todos/
620
- const todosDir = path.join(TEMPLATE_DIR, 'development', 'todos');
621
- if (fs.existsSync(todosDir)) {
622
- const count = copyRecursive(todosDir, path.join(targetDir, 'development', 'todos'), false);
623
- console.log(` ✅ development/todos/ (${count} files)`);
624
- }
625
-
626
- // 13. 根目录文件
627
- const rootFiles = ['project-paradigm.md', 'thinkinglens-silent.md', 'CLAUDE-template.md'];
628
- rootFiles.forEach(file => {
629
- const src = path.join(TEMPLATE_DIR, file);
630
- if (fs.existsSync(src)) {
631
- fs.copyFileSync(src, path.join(targetDir, file));
632
- console.log(' ✅ ' + file);
633
- }
634
- });
635
-
636
- // 创建记忆文件
637
- console.log('📝 Creating memory files...');
638
- if (!fs.existsSync(path.join(targetClaudeDir, 'MEMORY.md'))) {
639
- fs.writeFileSync(path.join(targetClaudeDir, 'MEMORY.md'), '# Memory\n\n<!-- Project memory updated by AI -->\n');
640
- }
641
- if (!fs.existsSync(path.join(targetClaudeDir, 'PROJECT_LOG.md'))) {
642
- fs.writeFileSync(path.join(targetClaudeDir, 'PROJECT_LOG.md'), '# Project Log\n\n<!-- Build history and decisions -->\n');
643
- }
644
- console.log(' ✅ Memory files created');
645
-
646
- // 创建 ANCHORS.md
647
- const anchorsContent = `# [Project Name] - Skill Anchors Index
648
-
649
- > This file is auto-maintained by AI as a quick index for the skill system
650
- > Last updated: ${new Date().toISOString().split('T')[0]}
651
-
652
- ---
653
-
654
- ## 🚀 AI Startup: Memory Loading Order
655
-
656
- \`\`\`
657
- 1. ANCHORS.md (this file) → Quick locate modules
658
- 2. PROJECT_LOG.md → Understand build history
659
- 3. MEMORY.md → View latest changes
660
- 4. CLAUDE.md → Load core knowledge
661
- 5. prompts/ → View tutorials
662
- 6. .claude/rag/skills.md → RAG skill index ⭐
663
- 7. Specific files → Deep dive into implementation
664
- \`\`\`
665
-
666
- ---
667
-
668
- ## Current Anchor Mapping
669
-
670
- ### Teaching Resources
671
- | Anchor | File Path | Purpose |
672
- |--------|-----------|---------|
673
- | \`[doc:paradigm]\` | \`prompts/project-paradigm.md\` | General development paradigm ⭐ |
674
- | \`[doc:claude-template]\` | \`.claude/CLAUDE.md\` | CLAUDE.md template for new projects |
675
-
676
- ### RAG System
677
- | Anchor | File Path | Purpose |
678
- |--------|-----------|---------|
679
- | \`[system:rag-index]\` | \`.claude/rag/skill-index.json\` | Dynamic skill index ⭐ |
680
-
681
- ---
682
-
683
- ## Add Your Anchors Here...
684
-
685
- `;
686
- fs.writeFileSync(path.join(targetClaudeDir, 'ANCHORS.md'), anchorsContent);
687
- console.log(' ✅ .claude/ANCHORS.md');
688
-
689
- // 初始化 Sumulige Claude(如果已安装)
690
- console.log('');
691
- console.log('🤖 Initializing Sumulige Claude...');
692
- try {
693
- execSync('sumulige-claude sync', { cwd: targetDir, stdio: 'pipe' });
694
- console.log(' ✅ Sumulige Claude synced');
695
- } catch (e) {
696
- console.log(' ⚠️ Sumulige Claude not available (run: npm i -g sumulige-claude)');
697
- }
698
-
699
- console.log('');
700
- console.log('✅ Template initialization complete!');
701
- console.log('');
702
- console.log('📦 What was included:');
703
- console.log(' • AI autonomous memory system (ThinkingLens)');
704
- console.log(' • Slash commands (/commit, /test, /review, etc.)');
705
- console.log(' • Skills system with templates');
706
- console.log(' • RAG dynamic skill index');
707
- console.log(' • Hooks for automation');
708
- console.log(' • TODO management system');
709
- console.log('');
710
- console.log('Next steps:');
711
- console.log(' 1. Edit .claude/CLAUDE.md with your project info');
712
- console.log(' 2. Run: claude # Start Claude Code');
713
- console.log(' 3. Try: /commit, /test, /review');
714
- console.log('');
63
+ 'marketplace:list': {
64
+ help: 'List all available skills',
65
+ args: ''
715
66
  },
716
-
717
- kickoff: () => {
718
- const projectDir = process.cwd();
719
- const kickoffFile = path.join(projectDir, 'PROJECT_KICKOFF.md');
720
- const hintFile = path.join(projectDir, '.claude/.kickoff-hint.txt');
721
-
722
- console.log('🚀 Project Kickoff - Manus 风格项目启动');
723
- console.log('');
724
-
725
- if (fs.existsSync(kickoffFile)) {
726
- console.log('ℹ️ 项目已经完成启动流程');
727
- console.log(' 文件:', kickoffFile);
728
- console.log('');
729
- console.log('如需重新规划,请先删除以下文件:');
730
- console.log(' - PROJECT_KICKOFF.md');
731
- console.log(' - TASK_PLAN.md');
732
- console.log(' - PROJECT_PROPOSAL.md');
733
- return;
734
- }
735
-
736
- // 运行启动 Hook
737
- const kickoffHook = path.join(projectDir, '.claude/hooks/project-kickoff.cjs');
738
- if (fs.existsSync(kickoffHook)) {
739
- try {
740
- execSync(`node "${kickoffHook}"`, {
741
- cwd: projectDir,
742
- env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir },
743
- stdio: 'inherit'
744
- });
745
- } catch (e) {
746
- // Hook 可能会输出内容然后退出,这是正常的
747
- }
748
-
749
- // 显示提示文件内容(如果存在)
750
- if (fs.existsSync(hintFile)) {
751
- const hint = fs.readFileSync(hintFile, 'utf-8');
752
- console.log(hint);
753
- }
754
- } else {
755
- console.log('⚠️ 启动 Hook 不存在');
756
- console.log(' 请先运行: sumulige-claude template');
757
- console.log(' 或: sumulige-claude sync');
758
- }
67
+ 'marketplace:install': {
68
+ help: 'Install a skill from marketplace',
69
+ args: '<name>'
70
+ },
71
+ 'marketplace:sync': {
72
+ help: 'Sync external skills',
73
+ args: ''
74
+ },
75
+ 'marketplace:add': {
76
+ help: 'Add external skill source',
77
+ args: '<owner/repo>'
78
+ },
79
+ 'marketplace:remove': {
80
+ help: 'Remove skill from sources',
81
+ args: '<name>'
82
+ },
83
+ 'marketplace:status': {
84
+ help: 'Show marketplace status',
85
+ args: ''
759
86
  }
760
87
  };
761
88
 
762
- function loadConfig() {
763
- if (fs.existsSync(CONFIG_FILE)) {
764
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'));
765
- }
766
- return DEFAULT_CONFIG;
767
- }
768
-
769
- function toTitleCase(str) {
770
- return str.replace(/\b\w/g, char => char.toUpperCase());
89
+ // ============================================================================
90
+ // Help Display
91
+ // ============================================================================
92
+
93
+ function showHelp() {
94
+ console.log('Sumulige Claude (smc) - Agent Harness for Claude Code');
95
+ console.log('');
96
+ console.log('Usage: smc <command> [args]');
97
+ console.log(' (or: sumulige-claude <command> [args])');
98
+ console.log('');
99
+ console.log('Commands:');
100
+
101
+ const maxCmdLen = Math.max(...Object.keys(COMMANDS).map(k => k.length));
102
+
103
+ Object.entries(COMMANDS).forEach(([cmd, info]) => {
104
+ const cmdPad = cmd.padEnd(maxCmdLen);
105
+ const args = info.args ? ' ' + info.args : '';
106
+ const argsPad = args.padEnd(10);
107
+ console.log(` ${cmdPad}${argsPad} ${info.help}`);
108
+ });
109
+
110
+ console.log('');
111
+ console.log('Examples:');
112
+ console.log(' smc init');
113
+ console.log(' smc sync');
114
+ console.log(' smc template');
115
+ console.log(' smc template /path/to/project');
116
+ console.log(' smc kickoff # Start project planning');
117
+ console.log(' smc agent "Build a REST API"');
118
+ console.log(' smc skill:create api-tester');
119
+ console.log(' smc skill:check manus-kickoff');
120
+ console.log(' smc skill:install anthropics/skills');
121
+ console.log(' smc marketplace:list');
122
+ console.log(' smc marketplace:install dev-browser');
123
+ console.log(' smc marketplace:sync');
771
124
  }
772
125
 
773
- function generateAgentsMd(config) {
774
- const agentsList = Object.entries(config.agents)
775
- .map(([name, agent]) => `### ${name}\n- **Model**: ${agent.model}\n- **Role**: ${agent.role}`)
776
- .join('\n\n');
777
-
778
- return `# AGENTS
779
-
780
- <skills_system priority="1">
781
-
782
- ## Agent Orchestration
783
-
784
- This project uses **Sumulige Claude** for multi-agent collaboration.
126
+ // ============================================================================
127
+ // Main Entry
128
+ // ============================================================================
785
129
 
786
- ${agentsList}
787
-
788
- ## Usage
789
-
790
- \`\`\`bash
791
- # View agent status
792
- sumulige-claude status
793
-
794
- # Run agent task
795
- sumulige-claude agent <task>
796
-
797
- # List skills
798
- sumulige-claude skill:list
799
- \`\`\`
130
+ function main() {
131
+ const [cmd, ...args] = process.argv.slice(2);
800
132
 
801
- </skills_system>
802
- `;
803
- }
133
+ if (!cmd) {
134
+ showHelp();
135
+ return;
136
+ }
804
137
 
805
- // CLI 入口
806
- function main() {
807
- const args = process.argv.slice(2);
808
- const cmd = args[0];
809
- const arg = args[1];
138
+ const handler = COMMANDS[cmd];
810
139
 
811
- if (cmd === 'init') {
812
- commands.init();
813
- } else if (cmd === 'sync') {
814
- commands.sync();
815
- } else if (cmd === 'agent') {
816
- commands.agent(arg);
817
- } else if (cmd === 'status') {
818
- commands.status();
819
- } else if (cmd === 'skill:list') {
820
- commands['skill:list']();
821
- } else if (cmd === 'skill:create') {
822
- commands['skill:create'](arg);
823
- } else if (cmd === 'skill:check') {
824
- commands['skill:check'](arg);
825
- } else if (cmd === 'skill:install') {
826
- commands['skill:install'](arg);
827
- } else if (cmd === 'template') {
828
- commands.template(arg);
829
- } else if (cmd === 'kickoff') {
830
- commands.kickoff();
140
+ if (handler) {
141
+ // Check if it's a marketplace command
142
+ if (cmd.startsWith('marketplace:')) {
143
+ marketplaceCommands[cmd](...args);
144
+ } else {
145
+ runCommand(cmd, args);
146
+ }
831
147
  } else {
832
- console.log('Sumulige Claude (smc) - Agent Harness for Claude Code');
833
- console.log('');
834
- console.log('Usage: smc <command> [args]');
835
- console.log(' (or: sumulige-claude <command> [args])');
836
- console.log('');
837
- console.log('Commands:');
838
- console.log(' init Initialize configuration');
839
- console.log(' sync Sync to current project');
840
- console.log(' template [path] Deploy Claude Code project template');
841
- console.log(' kickoff Start project planning workflow (Manus-style)');
842
- console.log(' agent <task> Run agent orchestration');
843
- console.log(' status Show configuration status');
844
- console.log(' skill:list List installed skills');
845
- console.log(' skill:create <n> Create a new skill');
846
- console.log(' skill:check [n] Check skill dependencies');
847
- console.log(' skill:install <s> Install a skill');
148
+ console.log(`Unknown command: ${cmd}`);
848
149
  console.log('');
849
- console.log('Examples:');
850
- console.log(' smc init');
851
- console.log(' smc sync');
852
- console.log(' smc template');
853
- console.log(' smc template /path/to/project');
854
- console.log(' smc kickoff # Start project planning');
855
- console.log(' smc agent "Build a REST API"');
856
- console.log(' smc skill:create api-tester');
857
- console.log(' smc skill:check manus-kickoff');
858
- console.log(' smc skill:install anthropics/skills');
150
+ showHelp();
151
+ process.exit(1);
859
152
  }
860
153
  }
861
154
 
155
+ // Run
862
156
  main();