sumulige-claude 1.5.1 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/hooks/hook-registry.json +0 -15
- package/.claude/rules/coding-style.md +18 -7
- package/.claude/rules/hooks.md +15 -4
- package/.claude/rules/performance.md +15 -5
- package/.claude/rules/security.md +140 -4
- package/.claude/rules/testing.md +138 -9
- package/.claude/rules/web-design-standard.md +16 -5
- package/.claude/skills/algorithmic-art/metadata.yaml +28 -0
- package/.claude/skills/api-tester/SKILL.md +61 -0
- package/.claude/skills/api-tester/examples/basic.md +3 -0
- package/.claude/skills/api-tester/metadata.yaml +30 -0
- package/.claude/skills/api-tester/templates/default.md +3 -0
- package/.claude/skills/brand-guidelines/metadata.yaml +26 -0
- package/.claude/skills/canvas-design/metadata.yaml +27 -0
- package/.claude/skills/code-reviewer-123/SKILL.md +61 -0
- package/.claude/skills/code-reviewer-123/examples/basic.md +3 -0
- package/.claude/skills/code-reviewer-123/metadata.yaml +30 -0
- package/.claude/skills/code-reviewer-123/templates/default.md +3 -0
- package/.claude/skills/doc-coauthoring/metadata.yaml +27 -0
- package/.claude/skills/docx/metadata.yaml +30 -0
- package/.claude/skills/frontend-design/metadata.yaml +28 -0
- package/.claude/skills/internal-comms/metadata.yaml +28 -0
- package/.claude/skills/mcp-builder/metadata.yaml +26 -0
- package/.claude/skills/my-skill/SKILL.md +61 -0
- package/.claude/skills/my-skill/examples/basic.md +3 -0
- package/.claude/skills/my-skill/metadata.yaml +30 -0
- package/.claude/skills/my-skill/templates/default.md +3 -0
- package/.claude/skills/pdf/metadata.yaml +29 -0
- package/.claude/skills/pptx/metadata.yaml +29 -0
- package/.claude/skills/react-best-practices/metadata.yaml +26 -0
- package/.claude/skills/react-node-practices/SKILL.md +409 -0
- package/.claude/skills/react-node-practices/metadata.yaml +56 -0
- package/.claude/skills/skill-creator/metadata.yaml +25 -0
- package/.claude/skills/slack-gif-creator/metadata.yaml +28 -0
- package/.claude/skills/test-skill-name/SKILL.md +61 -0
- package/.claude/skills/test-skill-name/examples/basic.md +3 -0
- package/.claude/skills/test-skill-name/metadata.yaml +30 -0
- package/.claude/skills/test-skill-name/templates/default.md +3 -0
- package/.claude/skills/test-workflow/metadata.yaml +32 -0
- package/.claude/skills/theme-factory/metadata.yaml +26 -0
- package/.claude/skills/threejs-fundamentals/metadata.yaml +27 -0
- package/.claude/skills/web-artifacts-builder/metadata.yaml +30 -0
- package/.claude/skills/web-design-guidelines/metadata.yaml +26 -0
- package/.claude/skills/webapp-testing/metadata.yaml +26 -0
- package/.claude/skills/xlsx/metadata.yaml +29 -0
- package/LICENSE +21 -0
- package/cli.js +1 -1
- package/package.json +25 -3
- package/.claude/.kickoff-hint.txt +0 -52
- package/.claude/.sumulige-claude-version +0 -1
- package/.claude/.version +0 -1
- package/.claude/AGENTS.md +0 -42
- package/.claude/ANCHORS.md +0 -40
- package/.claude/CLAUDE.md +0 -138
- package/.claude/MEMORY.md +0 -69
- package/.claude/PROJECT_LOG.md +0 -101
- package/.claude/THINKING_CHAIN_GUIDE.md +0 -287
- package/.claude/USAGE.md +0 -175
- package/.claude/boris-optimizations.md +0 -167
- package/.claude/handoffs/INDEX.md +0 -21
- package/.claude/handoffs/LATEST.md +0 -76
- package/.claude/handoffs/handoff_2026-01-22T13-07-04-757Z.md +0 -76
- package/.claude/quality-gate.json +0 -82
- package/.claude/rag/skill-index.json +0 -135
- package/.claude/settings.json +0 -99
- package/.claude/settings.local.json +0 -175
- package/.claude/templates/PROJECT_KICKOFF.md +0 -89
- package/.claude/templates/PROJECT_PROPOSAL.md +0 -227
- package/.claude/templates/TASK_PLAN.md +0 -121
- package/.claude/templates/hooks/README.md +0 -302
- package/.claude/templates/hooks/hook.sh.template +0 -94
- package/.claude/templates/hooks/user-prompt-submit.cjs.template +0 -116
- package/.claude/templates/hooks/user-response-submit.cjs.template +0 -94
- package/.claude/templates/hooks/validate.js +0 -173
- package/.claude/templates/tasks/develop.md +0 -69
- package/.claude/templates/tasks/research.md +0 -64
- package/.claude/templates/tasks/test.md +0 -96
- package/.claude/thinking-routes/.last-sync +0 -1
- package/.claude/thinking-routes/QUICKREF.md +0 -98
- package/.claude/workflow/document-scanner.js +0 -426
- package/.claude/workflow/knowledge-engine.js +0 -941
- package/.claude/workflow/notebooklm/browser.js +0 -1028
- package/.claude/workflow/phases/phase1-research.js +0 -578
- package/.claude/workflow/phases/phase1-research.ts +0 -465
- package/.claude/workflow/phases/phase2-approve.js +0 -722
- package/.claude/workflow/phases/phase3-plan.js +0 -1200
- package/.claude/workflow/phases/phase4-develop.js +0 -894
- package/.claude/workflow/search-cache.js +0 -230
- package/.claude/workflow/templates/approval.md +0 -315
- package/.claude/workflow/templates/development.md +0 -377
- package/.claude/workflow/templates/planning.md +0 -328
- package/.claude/workflow/templates/research.md +0 -250
- package/.claude/workflow/types.js +0 -37
- package/.claude/workflow/web-search.js +0 -278
- package/.claude-plugin/marketplace.json +0 -71
- package/.github/workflows/sync-skills.yml +0 -74
- package/.versionrc +0 -25
- package/AGENTS.md +0 -580
- package/CHANGELOG.md +0 -481
- package/CLAUDE-template.md +0 -114
- package/DEV_TOOLS_GUIDE.md +0 -190
- package/PROJECT_STRUCTURE.md +0 -266
- package/Q&A.md +0 -325
- package/config/defaults.json +0 -34
- package/config/official-skills.json +0 -183
- package/config/quality-gate.json +0 -67
- package/config/skill-categories.json +0 -40
- package/config/version-manifest.json +0 -85
- package/demos/power-3d-scatter.html +0 -683
- package/development/cache/web-search/search_1193d605f8eb364651fc2f2041b58a31.json +0 -36
- package/development/cache/web-search/search_3798bf06960edc125f744a1abb5b72c5.json +0 -36
- package/development/cache/web-search/search_37c7d4843a53f0d83f1122a6f908a2a3.json +0 -36
- package/development/cache/web-search/search_44166fa0153709ee168485a22aa0ab40.json +0 -36
- package/development/cache/web-search/search_4deaebb1f77e86a8ca066dc5a49c59fd.json +0 -36
- package/development/cache/web-search/search_94da91789466070a7f545612e73c7372.json +0 -36
- package/development/cache/web-search/search_dd5de8491b8b803a3cb01339cd210fb0.json +0 -36
- package/development/knowledge-base/.index.clean.json +0 -1
- package/development/knowledge-base/.index.json +0 -486
- package/development/knowledge-base/test-best-practices.md +0 -29
- package/development/projects/proj_mkh1pazz_ixmt1/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4jvnb_z7rwf/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4jxkd_ewz5a/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4k84n_ni73k/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4wfyd_u9w88/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4wsbo_iahvf/development/projects/proj_mkh4xbpg_4na5w/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4wsbo_iahvf/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4xulg_1ka8x/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4xwhj_gch8j/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4y2qk_9lm8z/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4y2qk_9lm8z/phase2/requirements.md +0 -226
- package/development/projects/proj_mkh4y2qk_9lm8z/phase3/PRD.md +0 -345
- package/development/projects/proj_mkh4y2qk_9lm8z/phase3/TASK_PLAN.md +0 -284
- package/development/projects/proj_mkh4y2qk_9lm8z/phase3/prototype/README.md +0 -14
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/DEVELOPMENT_LOG.md +0 -35
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/TASKS.md +0 -34
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/.env.example +0 -5
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/README.md +0 -60
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/package.json +0 -25
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/src/index.js +0 -70
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/src/routes/index.js +0 -48
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/tests/health.test.js +0 -20
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/tests/jest.config.js +0 -21
- package/development/projects/proj_mkh7veqg_3lypc/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh7veqg_3lypc/phase2/requirements.md +0 -226
- package/development/projects/proj_mkh7veqg_3lypc/phase3/PRD.md +0 -345
- package/development/projects/proj_mkh7veqg_3lypc/phase3/TASK_PLAN.md +0 -284
- package/development/projects/proj_mkh7veqg_3lypc/phase3/prototype/README.md +0 -14
- package/development/projects/proj_mkh8k8fo_rmqn5/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh8xyhy_1vshq/phase1/feasibility-report.md +0 -178
- package/development/projects/proj_mkh8zddd_dhamf/phase1/feasibility-report.md +0 -377
- package/development/projects/proj_mkh8zddd_dhamf/phase2/requirements.md +0 -442
- package/development/projects/proj_mkh8zddd_dhamf/phase3/api-design.md +0 -800
- package/development/projects/proj_mkh8zddd_dhamf/phase3/architecture.md +0 -625
- package/development/projects/proj_mkh8zddd_dhamf/phase3/data-model.md +0 -830
- package/development/projects/proj_mkh8zddd_dhamf/phase3/risks.md +0 -957
- package/development/projects/proj_mkh8zddd_dhamf/phase3/wbs.md +0 -381
- package/development/todos/.state.json +0 -19
- package/development/todos/INDEX.md +0 -63
- package/development/todos/active/_README.md +0 -49
- package/development/todos/archived/_README.md +0 -11
- package/development/todos/backlog/_README.md +0 -11
- package/development/todos/backlog/mcp-integration.md +0 -35
- package/development/todos/completed/_README.md +0 -11
- package/development/todos/completed/boris-optimizations.md +0 -39
- package/development/todos/completed/develop/local-knowledge-index.md +0 -85
- package/development/todos/completed/develop/todo-system.md +0 -47
- package/development/todos/completed/develop/web-search-integration.md +0 -83
- package/development/todos/completed/test/phase1-e2e-test.md +0 -103
- package/docs/DEVELOPMENT.md +0 -461
- package/docs/MARKETPLACE.md +0 -352
- package/docs/RELEASE.md +0 -93
- package/jest.config.js +0 -63
- package/lib/commands.js +0 -3588
- package/lib/config-manager.js +0 -441
- package/lib/config-schema.js +0 -408
- package/lib/config-validator.js +0 -330
- package/lib/config.js +0 -122
- package/lib/errors.js +0 -305
- package/lib/incremental-sync.js +0 -274
- package/lib/marketplace.js +0 -487
- package/lib/migrations.js +0 -154
- package/lib/permission-audit.js +0 -255
- package/lib/quality-gate.js +0 -431
- package/lib/quality-rules.js +0 -373
- package/lib/utils.js +0 -150
- package/lib/version-check.js +0 -169
- package/lib/version-manifest.js +0 -171
- package/project-paradigm.md +0 -313
- package/prompts/how-to-find.md +0 -163
- package/prompts/linus-architect.md +0 -71
- package/prompts/software-architect.md +0 -173
- package/prompts/web-designer.md +0 -249
- package/scripts/fix-hooks.mjs +0 -97
- package/scripts/sync-external.mjs +0 -298
- package/scripts/sync-to-home.sh +0 -108
- package/scripts/update-registry.mjs +0 -325
- package/sources.yaml +0 -83
- package/tests/README.md +0 -263
- package/tests/commands.test.js +0 -1086
- package/tests/config-manager.test.js +0 -677
- package/tests/config-schema.test.js +0 -425
- package/tests/config-validator.test.js +0 -436
- package/tests/config.test.js +0 -100
- package/tests/errors.test.js +0 -477
- package/tests/manual/phase1-e2e.sh +0 -389
- package/tests/manual/phase2-test-cases.md +0 -311
- package/tests/manual/phase3-test-cases.md +0 -309
- package/tests/manual/phase4-test-cases.md +0 -414
- package/tests/manual/test-cases.md +0 -417
- package/tests/marketplace.test.js +0 -420
- package/tests/migrations.test.js +0 -187
- package/tests/quality-gate.test.js +0 -679
- package/tests/quality-rules.test.js +0 -619
- package/tests/sync-external.test.js +0 -214
- package/tests/update-registry.test.js +0 -251
- package/tests/utils.test.js +0 -171
- package/tests/version-check.test.js +0 -75
- package/tests/web-search.test.js +0 -392
- package/thinkinglens-silent.md +0 -138
package/lib/marketplace.js
DELETED
|
@@ -1,487 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Marketplace Commands
|
|
3
|
-
*
|
|
4
|
-
* Commands for managing the skill marketplace and external skill sources.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
const path = require('path');
|
|
9
|
-
const { execSync } = require('child_process');
|
|
10
|
-
|
|
11
|
-
const ROOT_DIR = path.join(__dirname, '..');
|
|
12
|
-
const SOURCES_FILE = path.join(ROOT_DIR, 'sources.yaml');
|
|
13
|
-
const MARKETPLACE_FILE = path.join(ROOT_DIR, '.claude-plugin', 'marketplace.json');
|
|
14
|
-
const CATEGORIES_FILE = path.join(ROOT_DIR, 'config', 'skill-categories.json');
|
|
15
|
-
const TEMPLATE_SKILLS_DIR = path.join(ROOT_DIR, 'template', '.claude', 'skills');
|
|
16
|
-
|
|
17
|
-
// ============================================================================
|
|
18
|
-
// Logging Utilities
|
|
19
|
-
// ============================================================================
|
|
20
|
-
|
|
21
|
-
const COLORS = {
|
|
22
|
-
reset: '\x1b[0m',
|
|
23
|
-
green: '\x1b[32m',
|
|
24
|
-
blue: '\x1b[34m',
|
|
25
|
-
yellow: '\x1b[33m',
|
|
26
|
-
red: '\x1b[31m',
|
|
27
|
-
cyan: '\x1b[36m',
|
|
28
|
-
gray: '\x1b[90m',
|
|
29
|
-
magenta: '\x1b[35m'
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
function log(message, color = 'reset') {
|
|
33
|
-
console.log(`${COLORS[color]}${message}${COLORS.reset}`);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// ============================================================================
|
|
37
|
-
// YAML Parser (Simple)
|
|
38
|
-
// ============================================================================
|
|
39
|
-
|
|
40
|
-
function parseSimpleYaml(content) {
|
|
41
|
-
const result = { skills: [] };
|
|
42
|
-
let currentSection = null;
|
|
43
|
-
let currentSkill = null;
|
|
44
|
-
let currentKey = null;
|
|
45
|
-
|
|
46
|
-
content.split('\n').forEach(line => {
|
|
47
|
-
const trimmed = line.trim();
|
|
48
|
-
const indent = line.search(/\S/);
|
|
49
|
-
|
|
50
|
-
// Skip empty lines and comments
|
|
51
|
-
if (!trimmed || trimmed.startsWith('#')) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Version
|
|
56
|
-
if (trimmed.startsWith('version:')) {
|
|
57
|
-
result.version = parseInt(trimmed.split(':')[1].trim());
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Skills array starts
|
|
62
|
-
if (trimmed === 'skills:') {
|
|
63
|
-
currentSection = 'skills';
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// New skill entry (starts with -)
|
|
68
|
-
if (trimmed.startsWith('- name:')) {
|
|
69
|
-
if (currentSkill) {
|
|
70
|
-
result.skills.push(currentSkill);
|
|
71
|
-
}
|
|
72
|
-
currentSkill = { name: trimmed.split(':')[1].trim() };
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Skill properties
|
|
77
|
-
if (currentSection === 'skills' && currentSkill) {
|
|
78
|
-
// Determine nesting level by indent
|
|
79
|
-
const isTopLevel = indent === 2;
|
|
80
|
-
|
|
81
|
-
if (isTopLevel) {
|
|
82
|
-
const match = trimmed.match(/^([\w-]+):\s*(.*)$/);
|
|
83
|
-
if (match) {
|
|
84
|
-
currentKey = match[1];
|
|
85
|
-
let value = match[2].trim();
|
|
86
|
-
|
|
87
|
-
// Handle arrays
|
|
88
|
-
if (value === '[]') {
|
|
89
|
-
value = [];
|
|
90
|
-
} else if (value === 'true') {
|
|
91
|
-
value = true;
|
|
92
|
-
} else if (value === 'false') {
|
|
93
|
-
value = false;
|
|
94
|
-
} else if (value.startsWith('"') || value.startsWith("'")) {
|
|
95
|
-
value = value.slice(1, -1);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
currentSkill[currentKey] = value;
|
|
99
|
-
|
|
100
|
-
// Initialize nested objects
|
|
101
|
-
if (['source', 'target', 'author', 'sync'].includes(currentKey)) {
|
|
102
|
-
currentSkill[currentKey] = {};
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
} else if (currentKey) {
|
|
106
|
-
// Nested property
|
|
107
|
-
const match = trimmed.match(/^([\w-]+):\s*(.*)$/);
|
|
108
|
-
if (match) {
|
|
109
|
-
let value = match[2].trim();
|
|
110
|
-
if (value === 'true') value = true;
|
|
111
|
-
if (value === 'false') value = false;
|
|
112
|
-
if (value === '[]') value = [];
|
|
113
|
-
currentSkill[currentKey][match[1]] = value;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// Push last skill
|
|
120
|
-
if (currentSkill) {
|
|
121
|
-
result.skills.push(currentSkill);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return result;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// ============================================================================
|
|
128
|
-
// Marketplace Commands
|
|
129
|
-
// ============================================================================
|
|
130
|
-
|
|
131
|
-
const marketplaceCommands = {
|
|
132
|
-
// -------------------------------------------------------------------------
|
|
133
|
-
'marketplace:list': () => {
|
|
134
|
-
log('📋 SMC Skill Marketplace', 'blue');
|
|
135
|
-
log('=====================================', 'gray');
|
|
136
|
-
log('');
|
|
137
|
-
|
|
138
|
-
// Load marketplace registry
|
|
139
|
-
let registry = { plugins: [], metadata: { skill_count: 0, categories: {} } };
|
|
140
|
-
if (fs.existsSync(MARKETPLACE_FILE)) {
|
|
141
|
-
try {
|
|
142
|
-
registry = JSON.parse(fs.readFileSync(MARKETPLACE_FILE, 'utf-8'));
|
|
143
|
-
} catch (e) {
|
|
144
|
-
log('Warning: Failed to parse marketplace.json', 'yellow');
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Load sources.yaml
|
|
149
|
-
let sources = { skills: [] };
|
|
150
|
-
if (fs.existsSync(SOURCES_FILE)) {
|
|
151
|
-
try {
|
|
152
|
-
const content = fs.readFileSync(SOURCES_FILE, 'utf-8');
|
|
153
|
-
sources = parseSimpleYaml(content);
|
|
154
|
-
} catch (e) {
|
|
155
|
-
log('Warning: Failed to parse sources.yaml', 'yellow');
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Display by category
|
|
160
|
-
const categories = registry.metadata.categories || {
|
|
161
|
-
tools: { name: 'CLI 工具', icon: '🔧' },
|
|
162
|
-
workflow: { name: '工作流编排', icon: '🎼' },
|
|
163
|
-
development: { name: '开发辅助', icon: '💻' },
|
|
164
|
-
productivity: { name: '效率工具', icon: '⚡' },
|
|
165
|
-
automation: { name: '自动化', icon: '🤖' },
|
|
166
|
-
data: { name: '数据处理', icon: '📊' },
|
|
167
|
-
documentation: { name: '文档', icon: '📚' }
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
// Group skills by category
|
|
171
|
-
const byCategory = {};
|
|
172
|
-
for (const [key, cat] of Object.entries(categories)) {
|
|
173
|
-
byCategory[key] = [];
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Add from registry
|
|
177
|
-
for (const plugin of registry.plugins) {
|
|
178
|
-
if (plugin.skill_list) {
|
|
179
|
-
for (const skill of plugin.skill_list) {
|
|
180
|
-
if (byCategory[skill.category]) {
|
|
181
|
-
byCategory[skill.category].push({
|
|
182
|
-
name: skill.name,
|
|
183
|
-
description: skill.description,
|
|
184
|
-
external: skill.external
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// Add from sources.yaml
|
|
192
|
-
for (const skill of sources.skills) {
|
|
193
|
-
const cat = skill.target?.category || 'tools';
|
|
194
|
-
if (!byCategory[cat]) {
|
|
195
|
-
byCategory[cat] = [];
|
|
196
|
-
}
|
|
197
|
-
if (!byCategory[cat].some(s => s.name === skill.name)) {
|
|
198
|
-
byCategory[cat].push({
|
|
199
|
-
name: skill.name,
|
|
200
|
-
description: skill.description,
|
|
201
|
-
native: skill.native
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Display
|
|
207
|
-
for (const [key, skills] of Object.entries(byCategory)) {
|
|
208
|
-
if (skills.length === 0) continue;
|
|
209
|
-
|
|
210
|
-
const cat = categories[key] || { name: key, icon: '📁' };
|
|
211
|
-
log(`${cat.icon} ${cat.name}`, 'cyan');
|
|
212
|
-
log('', 'gray');
|
|
213
|
-
|
|
214
|
-
for (const skill of skills) {
|
|
215
|
-
const badge = skill.native ? ' [native]' : skill.external ? ' [external]' : '';
|
|
216
|
-
log(` ${skill.name}${badge}`, 'green');
|
|
217
|
-
if (skill.description) {
|
|
218
|
-
log(` ${skill.description}`, 'gray');
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
log('', 'gray');
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
log('=====================================', 'gray');
|
|
225
|
-
log(`Total: ${registry.metadata.skill_count || sources.skills.length} skills`, 'gray');
|
|
226
|
-
log('', 'gray');
|
|
227
|
-
log('Commands:', 'gray');
|
|
228
|
-
log(' smc marketplace:install <name> Install a skill', 'gray');
|
|
229
|
-
log(' smc marketplace:sync Sync external skills', 'gray');
|
|
230
|
-
log(' smc marketplace:add <repo> Add external source', 'gray');
|
|
231
|
-
},
|
|
232
|
-
|
|
233
|
-
// -------------------------------------------------------------------------
|
|
234
|
-
'marketplace:install': (skillName) => {
|
|
235
|
-
if (!skillName) {
|
|
236
|
-
log('Usage: smc marketplace:install <skill-name>', 'yellow');
|
|
237
|
-
log('', 'gray');
|
|
238
|
-
log('Examples:', 'gray');
|
|
239
|
-
log(' smc marketplace:install dev-browser', 'gray');
|
|
240
|
-
log(' smc marketplace:install gastown', 'gray');
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
log(`📦 Installing skill: ${skillName}`, 'blue');
|
|
245
|
-
log('', 'gray');
|
|
246
|
-
|
|
247
|
-
// Load sources.yaml to find the skill
|
|
248
|
-
let sources = { skills: [] };
|
|
249
|
-
if (fs.existsSync(SOURCES_FILE)) {
|
|
250
|
-
try {
|
|
251
|
-
const content = fs.readFileSync(SOURCES_FILE, 'utf-8');
|
|
252
|
-
sources = parseSimpleYaml(content);
|
|
253
|
-
} catch (e) {
|
|
254
|
-
log('Warning: Failed to parse sources.yaml', 'yellow');
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const skill = sources.skills.find(s => s.name === skillName);
|
|
259
|
-
if (!skill) {
|
|
260
|
-
log(`Skill "${skillName}" not found in sources.yaml`, 'yellow');
|
|
261
|
-
log('', 'gray');
|
|
262
|
-
log('Available skills:', 'gray');
|
|
263
|
-
log(' smc marketplace:list', 'gray');
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Native skills are already in the repo
|
|
268
|
-
if (skill.native) {
|
|
269
|
-
log(`✅ Skill "${skillName}" is a native skill, already available at:`, 'green');
|
|
270
|
-
log(` ${skill.target.path}`, 'gray');
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// External skills - sync them
|
|
275
|
-
log(`Syncing from external source...`, 'gray');
|
|
276
|
-
|
|
277
|
-
try {
|
|
278
|
-
execSync('npm run sync', { stdio: 'inherit' });
|
|
279
|
-
log(``, 'gray');
|
|
280
|
-
log(`✅ Skill "${skillName}" installed`, 'green');
|
|
281
|
-
} catch (e) {
|
|
282
|
-
log(`❌ Failed to install skill`, 'red');
|
|
283
|
-
}
|
|
284
|
-
},
|
|
285
|
-
|
|
286
|
-
// -------------------------------------------------------------------------
|
|
287
|
-
'marketplace:sync': () => {
|
|
288
|
-
log('🔄 Syncing external skills...', 'blue');
|
|
289
|
-
log('', 'gray');
|
|
290
|
-
|
|
291
|
-
try {
|
|
292
|
-
execSync('npm run sync:all', { stdio: 'inherit' });
|
|
293
|
-
log('', 'gray');
|
|
294
|
-
log('✅ Sync complete', 'green');
|
|
295
|
-
} catch (e) {
|
|
296
|
-
log('❌ Sync failed', 'red');
|
|
297
|
-
}
|
|
298
|
-
},
|
|
299
|
-
|
|
300
|
-
// -------------------------------------------------------------------------
|
|
301
|
-
'marketplace:add': (repo) => {
|
|
302
|
-
if (!repo) {
|
|
303
|
-
log('Usage: smc marketplace:add <owner/repo>', 'yellow');
|
|
304
|
-
log('', 'gray');
|
|
305
|
-
log('This command adds an external skill repository to sources.yaml', 'gray');
|
|
306
|
-
log('', 'gray');
|
|
307
|
-
log('Example:', 'gray');
|
|
308
|
-
log(' smc marketplace:add SawyerHood/dev-browser', 'gray');
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
// Parse repo
|
|
313
|
-
const match = repo.match(/^([^/]+)\/(.+)$/);
|
|
314
|
-
if (!match) {
|
|
315
|
-
log('Invalid repo format. Use: owner/repo', 'red');
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
const [, owner, name] = match;
|
|
320
|
-
const skillName = name.toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
321
|
-
|
|
322
|
-
log(`📝 Adding skill source: ${repo}`, 'blue');
|
|
323
|
-
log('', 'gray');
|
|
324
|
-
|
|
325
|
-
// Check sources.yaml exists
|
|
326
|
-
if (!fs.existsSync(SOURCES_FILE)) {
|
|
327
|
-
log(`sources.yaml not found. Creating...`, 'yellow');
|
|
328
|
-
fs.writeFileSync(SOURCES_FILE, `version: 1\nskills:\n`);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// Read existing sources
|
|
332
|
-
const content = fs.readFileSync(SOURCES_FILE, 'utf-8');
|
|
333
|
-
const lines = content.split('\n');
|
|
334
|
-
|
|
335
|
-
// Check if skill already exists
|
|
336
|
-
if (lines.some(l => l.includes(`name: ${skillName}`))) {
|
|
337
|
-
log(`Skill "${skillName}" already exists in sources.yaml`, 'yellow');
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// Find where to insert (after existing skills or before # Comments)
|
|
342
|
-
let insertIndex = lines.length;
|
|
343
|
-
for (let i = 0; i < lines.length; i++) {
|
|
344
|
-
if (lines[i].trim().startsWith('#') && lines[i].includes('Schema')) {
|
|
345
|
-
insertIndex = i;
|
|
346
|
-
break;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
// Build new skill entry
|
|
351
|
-
const newEntry = `
|
|
352
|
-
# ─────────────────────────────────────────────────────────────────────────────
|
|
353
|
-
# ${skillName} - External skill from ${repo}
|
|
354
|
-
# ─────────────────────────────────────────────────────────────────────────────
|
|
355
|
-
- name: ${skillName}
|
|
356
|
-
description: "TODO: Add description for ${skillName}"
|
|
357
|
-
source:
|
|
358
|
-
repo: ${repo}
|
|
359
|
-
path: skills/${skillName}
|
|
360
|
-
ref: main
|
|
361
|
-
target:
|
|
362
|
-
category: tools
|
|
363
|
-
path: template/.claude/skills/tools/${skillName}
|
|
364
|
-
author:
|
|
365
|
-
name: ${owner}
|
|
366
|
-
github: ${owner}
|
|
367
|
-
license: MIT
|
|
368
|
-
homepage: https://github.com/${repo}
|
|
369
|
-
verified: false
|
|
370
|
-
`;
|
|
371
|
-
|
|
372
|
-
// Insert new entry
|
|
373
|
-
lines.splice(insertIndex, 0, newEntry.trim());
|
|
374
|
-
|
|
375
|
-
// Write back
|
|
376
|
-
fs.writeFileSync(SOURCES_FILE, lines.join('\n'));
|
|
377
|
-
|
|
378
|
-
log(`✅ Added "${skillName}" to sources.yaml`, 'green');
|
|
379
|
-
log('', 'gray');
|
|
380
|
-
log('Next steps:', 'gray');
|
|
381
|
-
log(` 1. Edit sources.yaml to update description and category`, 'gray');
|
|
382
|
-
log(` 2. Run: smc marketplace:sync`, 'gray');
|
|
383
|
-
},
|
|
384
|
-
|
|
385
|
-
// -------------------------------------------------------------------------
|
|
386
|
-
'marketplace:remove': (skillName) => {
|
|
387
|
-
if (!skillName) {
|
|
388
|
-
log('Usage: smc marketplace:remove <skill-name>', 'yellow');
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
log(`🗑️ Removing skill: ${skillName}`, 'blue');
|
|
393
|
-
log('', 'gray');
|
|
394
|
-
|
|
395
|
-
// Read sources.yaml
|
|
396
|
-
if (!fs.existsSync(SOURCES_FILE)) {
|
|
397
|
-
log('sources.yaml not found', 'yellow');
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
const content = fs.readFileSync(SOURCES_FILE, 'utf-8');
|
|
402
|
-
const lines = content.split('\n');
|
|
403
|
-
|
|
404
|
-
// Find and remove the skill entry
|
|
405
|
-
let inSkillEntry = false;
|
|
406
|
-
let removed = false;
|
|
407
|
-
const newLines = [];
|
|
408
|
-
|
|
409
|
-
for (let i = 0; i < lines.length; i++) {
|
|
410
|
-
const line = lines[i];
|
|
411
|
-
|
|
412
|
-
// Check if this is the skill to remove
|
|
413
|
-
if (line.includes(`name: ${skillName}`) && line.trim().startsWith('-')) {
|
|
414
|
-
inSkillEntry = true;
|
|
415
|
-
removed = true;
|
|
416
|
-
continue;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
// Skip lines while in the skill entry
|
|
420
|
-
if (inSkillEntry) {
|
|
421
|
-
// End of skill entry
|
|
422
|
-
if (line.trim().startsWith('- name:') || line.trim().startsWith('#')) {
|
|
423
|
-
inSkillEntry = false;
|
|
424
|
-
newLines.push(line);
|
|
425
|
-
}
|
|
426
|
-
continue;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
newLines.push(line);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
if (!removed) {
|
|
433
|
-
log(`Skill "${skillName}" not found in sources.yaml`, 'yellow');
|
|
434
|
-
return;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
// Write back
|
|
438
|
-
fs.writeFileSync(SOURCES_FILE, newLines.join('\n'));
|
|
439
|
-
|
|
440
|
-
log(`✅ Removed "${skillName}" from sources.yaml`, 'green');
|
|
441
|
-
log('', 'gray');
|
|
442
|
-
log('Note: The skill files remain in the template directory.', 'yellow');
|
|
443
|
-
log(' To remove them, delete:', 'yellow');
|
|
444
|
-
log(` template/.claude/skills/*/${skillName}`, 'gray');
|
|
445
|
-
},
|
|
446
|
-
|
|
447
|
-
// -------------------------------------------------------------------------
|
|
448
|
-
'marketplace:status': () => {
|
|
449
|
-
log('📊 Marketplace Status', 'blue');
|
|
450
|
-
log('=====================================', 'gray');
|
|
451
|
-
log('');
|
|
452
|
-
|
|
453
|
-
// Check marketplace.json
|
|
454
|
-
if (fs.existsSync(MARKETPLACE_FILE)) {
|
|
455
|
-
const registry = JSON.parse(fs.readFileSync(MARKETPLACE_FILE, 'utf-8'));
|
|
456
|
-
log(`Registry: ${MARKETPLACE_FILE}`, 'green');
|
|
457
|
-
log(`Version: ${registry.metadata.version}`, 'gray');
|
|
458
|
-
log(`Skills: ${registry.metadata.skill_count}`, 'gray');
|
|
459
|
-
log(`Updated: ${registry.metadata.generated_at}`, 'gray');
|
|
460
|
-
} else {
|
|
461
|
-
log(`Registry: Not found (run: smc marketplace:sync)`, 'yellow');
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
log('');
|
|
465
|
-
|
|
466
|
-
// Check sources.yaml
|
|
467
|
-
if (fs.existsSync(SOURCES_FILE)) {
|
|
468
|
-
const content = fs.readFileSync(SOURCES_FILE, 'utf-8');
|
|
469
|
-
const sources = parseSimpleYaml(content);
|
|
470
|
-
log(`Sources: ${SOURCES_FILE}`, 'green');
|
|
471
|
-
log(`External sources: ${sources.skills.filter(s => !s.native).length}`, 'gray');
|
|
472
|
-
log(`Native skills: ${sources.skills.filter(s => s.native).length}`, 'gray');
|
|
473
|
-
} else {
|
|
474
|
-
log(`Sources: Not found`, 'yellow');
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
log('');
|
|
478
|
-
log('=====================================', 'gray');
|
|
479
|
-
}
|
|
480
|
-
};
|
|
481
|
-
|
|
482
|
-
// ============================================================================
|
|
483
|
-
// Exports
|
|
484
|
-
// ============================================================================
|
|
485
|
-
|
|
486
|
-
exports.marketplaceCommands = marketplaceCommands;
|
|
487
|
-
exports.parseSimpleYaml = parseSimpleYaml;
|
package/lib/migrations.js
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Migrations - Version control for project templates
|
|
3
|
-
*
|
|
4
|
-
* 每个迁移函数:
|
|
5
|
-
* - from: 起始版本
|
|
6
|
-
* - to: 目标版本
|
|
7
|
-
* - migrate: 实际迁移逻辑
|
|
8
|
-
*
|
|
9
|
-
* 迁移链:v1.0.0 → v1.0.2 → v1.0.10 → ...
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const fs = require('fs');
|
|
13
|
-
const path = require('path');
|
|
14
|
-
|
|
15
|
-
// 当前模板版本
|
|
16
|
-
const TEMPLATE_VERSION = '1.0.10';
|
|
17
|
-
|
|
18
|
-
// 版本文件路径
|
|
19
|
-
const getVersionFile = (projectDir) => path.join(projectDir, '.claude', '.version');
|
|
20
|
-
|
|
21
|
-
// 读取项目版本
|
|
22
|
-
function getProjectVersion(projectDir) {
|
|
23
|
-
const versionFile = getVersionFile(projectDir);
|
|
24
|
-
if (!fs.existsSync(versionFile)) {
|
|
25
|
-
// 没有 version 文件说明是旧版本项目
|
|
26
|
-
return '1.0.0';
|
|
27
|
-
}
|
|
28
|
-
try {
|
|
29
|
-
return fs.readFileSync(versionFile, 'utf-8').trim();
|
|
30
|
-
} catch {
|
|
31
|
-
return '1.0.0';
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// 写入项目版本
|
|
36
|
-
function setProjectVersion(projectDir, version) {
|
|
37
|
-
const versionFile = getVersionFile(projectDir);
|
|
38
|
-
fs.writeFileSync(versionFile, version + '\n');
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// 版本比较
|
|
42
|
-
function compareVersions(v1, v2) {
|
|
43
|
-
const parts1 = v1.split('.').map(Number);
|
|
44
|
-
const parts2 = v2.split('.').map(Number);
|
|
45
|
-
|
|
46
|
-
for (let i = 0; i < 3; i++) {
|
|
47
|
-
if (parts1[i] < parts2[i]) return -1;
|
|
48
|
-
if (parts1[i] > parts2[i]) return 1;
|
|
49
|
-
}
|
|
50
|
-
return 0;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// 迁移列表
|
|
54
|
-
const migrations = [
|
|
55
|
-
{
|
|
56
|
-
from: '1.0.0',
|
|
57
|
-
to: '1.0.10',
|
|
58
|
-
description: 'Migrate hooks format from old to new',
|
|
59
|
-
migrate: (projectDir) => {
|
|
60
|
-
const settingsFile = path.join(projectDir, '.claude', 'settings.json');
|
|
61
|
-
if (!fs.existsSync(settingsFile)) return;
|
|
62
|
-
|
|
63
|
-
let settings;
|
|
64
|
-
try {
|
|
65
|
-
settings = JSON.parse(fs.readFileSync(settingsFile, 'utf-8'));
|
|
66
|
-
} catch {
|
|
67
|
-
return; // 无效 JSON,跳过
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// 检测旧格式
|
|
71
|
-
const isOldFormat = settings.matcher || (settings.hooks && typeof settings.hooks === 'object');
|
|
72
|
-
if (!isOldFormat) return;
|
|
73
|
-
|
|
74
|
-
// 读取新模板
|
|
75
|
-
const templateDir = path.join(__dirname, '../template');
|
|
76
|
-
const templateSettings = path.join(templateDir, '.claude', 'settings.json');
|
|
77
|
-
|
|
78
|
-
if (fs.existsSync(templateSettings)) {
|
|
79
|
-
fs.writeFileSync(settingsFile, fs.readFileSync(templateSettings, 'utf-8'));
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
];
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* 执行迁移
|
|
87
|
-
* @param {string} projectDir - 项目目录
|
|
88
|
-
* @param {boolean} silent - 是否静默模式
|
|
89
|
-
* @returns {object} { success, migrations, currentVersion }
|
|
90
|
-
*/
|
|
91
|
-
function runMigrations(projectDir, silent = false) {
|
|
92
|
-
const currentVersion = getProjectVersion(projectDir);
|
|
93
|
-
|
|
94
|
-
// 已经是最新版本
|
|
95
|
-
if (compareVersions(currentVersion, TEMPLATE_VERSION) >= 0) {
|
|
96
|
-
return {
|
|
97
|
-
success: true,
|
|
98
|
-
migrations: [],
|
|
99
|
-
currentVersion,
|
|
100
|
-
templateVersion: TEMPLATE_VERSION
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// 找到需要执行的迁移
|
|
105
|
-
const pendingMigrations = migrations.filter(m => {
|
|
106
|
-
const cmp = compareVersions(currentVersion, m.to);
|
|
107
|
-
return cmp < 0; // 只执行版本高于当前版本的迁移
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// 按版本顺序执行
|
|
111
|
-
pendingMigrations.sort((a, b) => compareVersions(a.to, b.to));
|
|
112
|
-
|
|
113
|
-
const executed = [];
|
|
114
|
-
|
|
115
|
-
for (const migration of pendingMigrations) {
|
|
116
|
-
try {
|
|
117
|
-
if (!silent) {
|
|
118
|
-
console.log(`⬆️ Migrating: ${currentVersion} → ${migration.to}`);
|
|
119
|
-
console.log(` ${migration.description}`);
|
|
120
|
-
}
|
|
121
|
-
migration.migrate(projectDir);
|
|
122
|
-
executed.push(migration);
|
|
123
|
-
setProjectVersion(projectDir, migration.to);
|
|
124
|
-
if (!silent) {
|
|
125
|
-
console.log(` ✅ Done`);
|
|
126
|
-
}
|
|
127
|
-
} catch (error) {
|
|
128
|
-
if (!silent) {
|
|
129
|
-
console.log(` ❌ Failed: ${error.message}`);
|
|
130
|
-
}
|
|
131
|
-
return {
|
|
132
|
-
success: false,
|
|
133
|
-
error: error.message,
|
|
134
|
-
currentVersion,
|
|
135
|
-
executed
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
return {
|
|
141
|
-
success: true,
|
|
142
|
-
migrations: executed,
|
|
143
|
-
currentVersion: TEMPLATE_VERSION,
|
|
144
|
-
templateVersion: TEMPLATE_VERSION
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
module.exports = {
|
|
149
|
-
TEMPLATE_VERSION,
|
|
150
|
-
getProjectVersion,
|
|
151
|
-
setProjectVersion,
|
|
152
|
-
compareVersions,
|
|
153
|
-
runMigrations
|
|
154
|
-
};
|