claude-termux 1.0.3 ā 2.0.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.
- package/bin/mcp-install.js +46 -0
- package/bin/skills-cli.js +722 -0
- package/lib/skill-hooks.js +140 -0
- package/package.json +34 -7
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const https = require('https');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
|
|
7
|
+
const MCP_CONFIG_URL = 'https://raw.githubusercontent.com/zesbe/claude-mcp-config/main/mcp.json';
|
|
8
|
+
const HOME = os.homedir();
|
|
9
|
+
const MCP_PATH = path.join(HOME, '.mcp.json');
|
|
10
|
+
|
|
11
|
+
console.log('š ClaudeAll MCP Config Installer\n');
|
|
12
|
+
|
|
13
|
+
// Backup existing config
|
|
14
|
+
if (fs.existsSync(MCP_PATH)) {
|
|
15
|
+
const backup = `${MCP_PATH}.backup.${Date.now()}`;
|
|
16
|
+
fs.copyFileSync(MCP_PATH, backup);
|
|
17
|
+
console.log(`š¦ Backed up existing config to ${backup}`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Download MCP config
|
|
21
|
+
console.log('š„ Downloading MCP config...');
|
|
22
|
+
|
|
23
|
+
https.get(MCP_CONFIG_URL, (res) => {
|
|
24
|
+
let data = '';
|
|
25
|
+
res.on('data', chunk => data += chunk);
|
|
26
|
+
res.on('end', () => {
|
|
27
|
+
try {
|
|
28
|
+
// Validate JSON
|
|
29
|
+
JSON.parse(data);
|
|
30
|
+
fs.writeFileSync(MCP_PATH, data);
|
|
31
|
+
console.log(`ā
Installed MCP config to ${MCP_PATH}\n`);
|
|
32
|
+
|
|
33
|
+
const config = JSON.parse(data);
|
|
34
|
+
const servers = Object.keys(config.mcpServers || {});
|
|
35
|
+
console.log('MCP Servers installed:');
|
|
36
|
+
servers.forEach((s, i) => console.log(` ${i+1}. ${s}`));
|
|
37
|
+
console.log('\nš Run "claude" to start with MCP enabled!');
|
|
38
|
+
} catch (e) {
|
|
39
|
+
console.error('ā Invalid JSON response');
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}).on('error', (e) => {
|
|
44
|
+
console.error(`ā Download failed: ${e.message}`);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
});
|
|
@@ -0,0 +1,722 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ClaudeAll Skills CLI
|
|
5
|
+
* Advanced skill management beyond skills.sh
|
|
6
|
+
*
|
|
7
|
+
* Features skills.sh DOESN'T have:
|
|
8
|
+
* - Skill testing/validation
|
|
9
|
+
* - Quality scoring
|
|
10
|
+
* - Dependencies management
|
|
11
|
+
* - Skill scaffolding
|
|
12
|
+
* - Local development
|
|
13
|
+
* - Hooks system
|
|
14
|
+
* - Offline support
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const { execSync } = require('child_process');
|
|
20
|
+
|
|
21
|
+
const CLAUDE_DIR = path.join(process.env.HOME, '.claude');
|
|
22
|
+
const SKILLS_DIR = path.join(CLAUDE_DIR, 'skills');
|
|
23
|
+
const SKILLS_REGISTRY = path.join(CLAUDE_DIR, '.skills-registry.json');
|
|
24
|
+
|
|
25
|
+
// Colors for terminal
|
|
26
|
+
const colors = {
|
|
27
|
+
reset: '\x1b[0m',
|
|
28
|
+
bright: '\x1b[1m',
|
|
29
|
+
green: '\x1b[32m',
|
|
30
|
+
yellow: '\x1b[33m',
|
|
31
|
+
blue: '\x1b[34m',
|
|
32
|
+
magenta: '\x1b[35m',
|
|
33
|
+
cyan: '\x1b[36m',
|
|
34
|
+
red: '\x1b[31m',
|
|
35
|
+
gray: '\x1b[90m',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const c = (color, text) => `${colors[color]}${text}${colors.reset}`;
|
|
39
|
+
|
|
40
|
+
// ============================================
|
|
41
|
+
// SKILL SCHEMA
|
|
42
|
+
// ============================================
|
|
43
|
+
const SKILL_SCHEMA = {
|
|
44
|
+
required: ['name', 'description', 'version'],
|
|
45
|
+
optional: ['author', 'license', 'dependencies', 'hooks', 'tags', 'agents', 'quality'],
|
|
46
|
+
defaults: {
|
|
47
|
+
version: '1.0.0',
|
|
48
|
+
license: 'MIT',
|
|
49
|
+
agents: ['claude-code', 'cursor', 'copilot'],
|
|
50
|
+
tags: [],
|
|
51
|
+
dependencies: [],
|
|
52
|
+
hooks: {
|
|
53
|
+
preInstall: null,
|
|
54
|
+
postInstall: null,
|
|
55
|
+
preUninstall: null,
|
|
56
|
+
postUninstall: null,
|
|
57
|
+
},
|
|
58
|
+
quality: {
|
|
59
|
+
tested: false,
|
|
60
|
+
documented: false,
|
|
61
|
+
examples: false,
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// ============================================
|
|
67
|
+
// UTILITY FUNCTIONS
|
|
68
|
+
// ============================================
|
|
69
|
+
|
|
70
|
+
function ensureDir(dir) {
|
|
71
|
+
if (!fs.existsSync(dir)) {
|
|
72
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function loadRegistry() {
|
|
77
|
+
if (fs.existsSync(SKILLS_REGISTRY)) {
|
|
78
|
+
return JSON.parse(fs.readFileSync(SKILLS_REGISTRY, 'utf8'));
|
|
79
|
+
}
|
|
80
|
+
return { skills: {}, installed: [], lastUpdate: null };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function saveRegistry(registry) {
|
|
84
|
+
registry.lastUpdate = new Date().toISOString();
|
|
85
|
+
fs.writeFileSync(SKILLS_REGISTRY, JSON.stringify(registry, null, 2));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function parseSkillMd(content) {
|
|
89
|
+
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
90
|
+
if (!frontmatterMatch) return null;
|
|
91
|
+
|
|
92
|
+
const frontmatter = {};
|
|
93
|
+
frontmatterMatch[1].split('\n').forEach(line => {
|
|
94
|
+
const [key, ...valueParts] = line.split(':');
|
|
95
|
+
if (key && valueParts.length) {
|
|
96
|
+
frontmatter[key.trim()] = valueParts.join(':').trim();
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
...frontmatter,
|
|
102
|
+
content: content.replace(/^---\n[\s\S]*?\n---\n*/, '')
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function calculateQualityScore(skillPath) {
|
|
107
|
+
let score = 0;
|
|
108
|
+
const checks = [];
|
|
109
|
+
|
|
110
|
+
const skillDir = fs.statSync(skillPath).isDirectory() ? skillPath : path.dirname(skillPath);
|
|
111
|
+
const skillName = path.basename(skillDir);
|
|
112
|
+
|
|
113
|
+
// Check 1: Has SKILL.md (25 points)
|
|
114
|
+
const skillMd = path.join(skillDir, 'SKILL.md');
|
|
115
|
+
if (fs.existsSync(skillMd)) {
|
|
116
|
+
score += 25;
|
|
117
|
+
checks.push({ name: 'Has SKILL.md', passed: true, points: 25 });
|
|
118
|
+
|
|
119
|
+
const content = fs.readFileSync(skillMd, 'utf8');
|
|
120
|
+
|
|
121
|
+
// Check 2: Has frontmatter (10 points)
|
|
122
|
+
if (content.startsWith('---')) {
|
|
123
|
+
score += 10;
|
|
124
|
+
checks.push({ name: 'Has frontmatter', passed: true, points: 10 });
|
|
125
|
+
} else {
|
|
126
|
+
checks.push({ name: 'Has frontmatter', passed: false, points: 0 });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Check 3: Has description (10 points)
|
|
130
|
+
if (content.includes('description:')) {
|
|
131
|
+
score += 10;
|
|
132
|
+
checks.push({ name: 'Has description', passed: true, points: 10 });
|
|
133
|
+
} else {
|
|
134
|
+
checks.push({ name: 'Has description', passed: false, points: 0 });
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Check 4: Has examples/usage section (15 points)
|
|
138
|
+
if (content.toLowerCase().includes('## example') || content.toLowerCase().includes('## usage')) {
|
|
139
|
+
score += 15;
|
|
140
|
+
checks.push({ name: 'Has examples', passed: true, points: 15 });
|
|
141
|
+
} else {
|
|
142
|
+
checks.push({ name: 'Has examples', passed: false, points: 0 });
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Check 5: Has code blocks (10 points)
|
|
146
|
+
if (content.includes('```')) {
|
|
147
|
+
score += 10;
|
|
148
|
+
checks.push({ name: 'Has code blocks', passed: true, points: 10 });
|
|
149
|
+
} else {
|
|
150
|
+
checks.push({ name: 'Has code blocks', passed: false, points: 0 });
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
checks.push({ name: 'Has SKILL.md', passed: false, points: 0 });
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Check 6: Has tests (15 points)
|
|
157
|
+
const testFiles = fs.readdirSync(skillDir).filter(f => f.startsWith('test-'));
|
|
158
|
+
if (testFiles.length > 0) {
|
|
159
|
+
score += 15;
|
|
160
|
+
checks.push({ name: `Has tests (${testFiles.length})`, passed: true, points: 15 });
|
|
161
|
+
} else {
|
|
162
|
+
checks.push({ name: 'Has tests', passed: false, points: 0 });
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Check 7: Has skill.json (10 points)
|
|
166
|
+
const skillJson = path.join(skillDir, 'skill.json');
|
|
167
|
+
if (fs.existsSync(skillJson)) {
|
|
168
|
+
score += 10;
|
|
169
|
+
checks.push({ name: 'Has skill.json', passed: true, points: 10 });
|
|
170
|
+
} else {
|
|
171
|
+
checks.push({ name: 'Has skill.json', passed: false, points: 0 });
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Check 8: Has CREATION-LOG.md (5 points)
|
|
175
|
+
if (fs.existsSync(path.join(skillDir, 'CREATION-LOG.md'))) {
|
|
176
|
+
score += 5;
|
|
177
|
+
checks.push({ name: 'Has creation log', passed: true, points: 5 });
|
|
178
|
+
} else {
|
|
179
|
+
checks.push({ name: 'Has creation log', passed: false, points: 0 });
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return { score, maxScore: 100, checks };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ============================================
|
|
186
|
+
// CLI COMMANDS
|
|
187
|
+
// ============================================
|
|
188
|
+
|
|
189
|
+
const commands = {
|
|
190
|
+
// List all installed skills
|
|
191
|
+
list: () => {
|
|
192
|
+
console.log(c('cyan', '\n ClaudeAll Skills\n'));
|
|
193
|
+
|
|
194
|
+
if (!fs.existsSync(SKILLS_DIR)) {
|
|
195
|
+
console.log(c('yellow', ' No skills installed yet.'));
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const skills = fs.readdirSync(SKILLS_DIR).filter(f =>
|
|
200
|
+
fs.statSync(path.join(SKILLS_DIR, f)).isDirectory()
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
if (skills.length === 0) {
|
|
204
|
+
console.log(c('yellow', ' No skills found.'));
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
console.log(c('gray', ` Found ${skills.length} skills:\n`));
|
|
209
|
+
|
|
210
|
+
skills.forEach((skill, i) => {
|
|
211
|
+
const skillPath = path.join(SKILLS_DIR, skill);
|
|
212
|
+
const { score } = calculateQualityScore(skillPath);
|
|
213
|
+
|
|
214
|
+
const scoreColor = score >= 70 ? 'green' : score >= 40 ? 'yellow' : 'red';
|
|
215
|
+
const scoreBar = 'ā'.repeat(Math.floor(score / 10)) + 'ā'.repeat(10 - Math.floor(score / 10));
|
|
216
|
+
|
|
217
|
+
console.log(` ${c('bright', (i + 1).toString().padStart(2))}. ${c('green', skill)}`);
|
|
218
|
+
console.log(` Quality: ${c(scoreColor, scoreBar)} ${score}/100`);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
console.log();
|
|
222
|
+
},
|
|
223
|
+
|
|
224
|
+
// Search skills
|
|
225
|
+
search: (query) => {
|
|
226
|
+
if (!query) {
|
|
227
|
+
console.log(c('red', '\n Usage: claude-all skills search <query>\n'));
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
console.log(c('cyan', `\n Searching for "${query}"...\n`));
|
|
232
|
+
|
|
233
|
+
const skills = fs.readdirSync(SKILLS_DIR).filter(f =>
|
|
234
|
+
fs.statSync(path.join(SKILLS_DIR, f)).isDirectory()
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
const matches = skills.filter(skill => {
|
|
238
|
+
const skillPath = path.join(SKILLS_DIR, skill);
|
|
239
|
+
const skillMd = path.join(skillPath, 'SKILL.md');
|
|
240
|
+
|
|
241
|
+
if (skill.toLowerCase().includes(query.toLowerCase())) return true;
|
|
242
|
+
|
|
243
|
+
if (fs.existsSync(skillMd)) {
|
|
244
|
+
const content = fs.readFileSync(skillMd, 'utf8').toLowerCase();
|
|
245
|
+
return content.includes(query.toLowerCase());
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return false;
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
if (matches.length === 0) {
|
|
252
|
+
console.log(c('yellow', ' No skills found matching your query.'));
|
|
253
|
+
} else {
|
|
254
|
+
console.log(c('gray', ` Found ${matches.length} matching skills:\n`));
|
|
255
|
+
matches.forEach((skill, i) => {
|
|
256
|
+
console.log(` ${i + 1}. ${c('green', skill)}`);
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
console.log();
|
|
261
|
+
},
|
|
262
|
+
|
|
263
|
+
// Create new skill from template
|
|
264
|
+
create: (name) => {
|
|
265
|
+
if (!name) {
|
|
266
|
+
console.log(c('red', '\n Usage: claude-all skills create <skill-name>\n'));
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const skillDir = path.join(SKILLS_DIR, name);
|
|
271
|
+
|
|
272
|
+
if (fs.existsSync(skillDir)) {
|
|
273
|
+
console.log(c('red', `\n Skill "${name}" already exists!\n`));
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
console.log(c('cyan', `\n Creating skill: ${name}\n`));
|
|
278
|
+
|
|
279
|
+
// Create directory
|
|
280
|
+
fs.mkdirSync(skillDir, { recursive: true });
|
|
281
|
+
|
|
282
|
+
// Create skill.json
|
|
283
|
+
const skillJson = {
|
|
284
|
+
name,
|
|
285
|
+
version: '1.0.0',
|
|
286
|
+
description: `Description for ${name}`,
|
|
287
|
+
author: 'Your Name',
|
|
288
|
+
license: 'MIT',
|
|
289
|
+
tags: [],
|
|
290
|
+
agents: ['claude-code', 'cursor', 'copilot', 'gemini'],
|
|
291
|
+
dependencies: [],
|
|
292
|
+
hooks: {
|
|
293
|
+
preInstall: null,
|
|
294
|
+
postInstall: null
|
|
295
|
+
},
|
|
296
|
+
quality: {
|
|
297
|
+
tested: false,
|
|
298
|
+
documented: false,
|
|
299
|
+
examples: false
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
fs.writeFileSync(
|
|
304
|
+
path.join(skillDir, 'skill.json'),
|
|
305
|
+
JSON.stringify(skillJson, null, 2)
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
// Create SKILL.md
|
|
309
|
+
const skillMd = `---
|
|
310
|
+
name: ${name}
|
|
311
|
+
description: Description for ${name}
|
|
312
|
+
version: 1.0.0
|
|
313
|
+
author: Your Name
|
|
314
|
+
tags: []
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
# ${name.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')}
|
|
318
|
+
|
|
319
|
+
## Overview
|
|
320
|
+
|
|
321
|
+
Describe what this skill does and when to use it.
|
|
322
|
+
|
|
323
|
+
## When to Use
|
|
324
|
+
|
|
325
|
+
- Situation 1
|
|
326
|
+
- Situation 2
|
|
327
|
+
- Situation 3
|
|
328
|
+
|
|
329
|
+
## How It Works
|
|
330
|
+
|
|
331
|
+
Explain the approach or methodology.
|
|
332
|
+
|
|
333
|
+
## Examples
|
|
334
|
+
|
|
335
|
+
### Example 1: Basic Usage
|
|
336
|
+
|
|
337
|
+
\`\`\`
|
|
338
|
+
// Your example here
|
|
339
|
+
\`\`\`
|
|
340
|
+
|
|
341
|
+
### Example 2: Advanced Usage
|
|
342
|
+
|
|
343
|
+
\`\`\`
|
|
344
|
+
// Advanced example
|
|
345
|
+
\`\`\`
|
|
346
|
+
|
|
347
|
+
## Best Practices
|
|
348
|
+
|
|
349
|
+
1. Practice 1
|
|
350
|
+
2. Practice 2
|
|
351
|
+
3. Practice 3
|
|
352
|
+
|
|
353
|
+
## Common Mistakes
|
|
354
|
+
|
|
355
|
+
- Mistake 1 and how to avoid it
|
|
356
|
+
- Mistake 2 and how to avoid it
|
|
357
|
+
|
|
358
|
+
## Related Skills
|
|
359
|
+
|
|
360
|
+
- skill-name-1
|
|
361
|
+
- skill-name-2
|
|
362
|
+
`;
|
|
363
|
+
|
|
364
|
+
fs.writeFileSync(path.join(skillDir, 'SKILL.md'), skillMd);
|
|
365
|
+
|
|
366
|
+
// Create test template
|
|
367
|
+
const testMd = `# Test: ${name}
|
|
368
|
+
|
|
369
|
+
## Scenario
|
|
370
|
+
|
|
371
|
+
Describe the test scenario here.
|
|
372
|
+
|
|
373
|
+
## Expected Behavior
|
|
374
|
+
|
|
375
|
+
What should happen when the skill is applied correctly.
|
|
376
|
+
|
|
377
|
+
## Test Steps
|
|
378
|
+
|
|
379
|
+
1. Step 1
|
|
380
|
+
2. Step 2
|
|
381
|
+
3. Step 3
|
|
382
|
+
|
|
383
|
+
## Success Criteria
|
|
384
|
+
|
|
385
|
+
- [ ] Criterion 1
|
|
386
|
+
- [ ] Criterion 2
|
|
387
|
+
- [ ] Criterion 3
|
|
388
|
+
`;
|
|
389
|
+
|
|
390
|
+
fs.writeFileSync(path.join(skillDir, 'test-basic.md'), testMd);
|
|
391
|
+
|
|
392
|
+
// Create CREATION-LOG.md
|
|
393
|
+
const creationLog = `# Creation Log: ${name}
|
|
394
|
+
|
|
395
|
+
## Created
|
|
396
|
+
- Date: ${new Date().toISOString().split('T')[0]}
|
|
397
|
+
- Author: Your Name
|
|
398
|
+
|
|
399
|
+
## Changelog
|
|
400
|
+
|
|
401
|
+
### v1.0.0
|
|
402
|
+
- Initial creation
|
|
403
|
+
`;
|
|
404
|
+
|
|
405
|
+
fs.writeFileSync(path.join(skillDir, 'CREATION-LOG.md'), creationLog);
|
|
406
|
+
|
|
407
|
+
console.log(c('green', ' ā Created skill.json'));
|
|
408
|
+
console.log(c('green', ' ā Created SKILL.md'));
|
|
409
|
+
console.log(c('green', ' ā Created test-basic.md'));
|
|
410
|
+
console.log(c('green', ' ā Created CREATION-LOG.md'));
|
|
411
|
+
console.log();
|
|
412
|
+
console.log(c('cyan', ` Skill created at: ${skillDir}`));
|
|
413
|
+
console.log(c('gray', ' Edit SKILL.md to add your skill content.'));
|
|
414
|
+
console.log();
|
|
415
|
+
},
|
|
416
|
+
|
|
417
|
+
// Validate skill
|
|
418
|
+
validate: (name) => {
|
|
419
|
+
if (!name) {
|
|
420
|
+
console.log(c('red', '\n Usage: claude-all skills validate <skill-name>\n'));
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const skillDir = path.join(SKILLS_DIR, name);
|
|
425
|
+
|
|
426
|
+
if (!fs.existsSync(skillDir)) {
|
|
427
|
+
console.log(c('red', `\n Skill "${name}" not found!\n`));
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
console.log(c('cyan', `\n Validating skill: ${name}\n`));
|
|
432
|
+
|
|
433
|
+
const { score, maxScore, checks } = calculateQualityScore(skillDir);
|
|
434
|
+
|
|
435
|
+
checks.forEach(check => {
|
|
436
|
+
const icon = check.passed ? c('green', 'ā') : c('red', 'ā');
|
|
437
|
+
const points = check.passed ? c('green', `+${check.points}`) : c('gray', '+0');
|
|
438
|
+
console.log(` ${icon} ${check.name} ${points}`);
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
console.log();
|
|
442
|
+
|
|
443
|
+
const scoreColor = score >= 70 ? 'green' : score >= 40 ? 'yellow' : 'red';
|
|
444
|
+
console.log(c('bright', ` Quality Score: ${c(scoreColor, `${score}/${maxScore}`)}`));
|
|
445
|
+
|
|
446
|
+
if (score >= 70) {
|
|
447
|
+
console.log(c('green', '\n ā Skill is ready for publishing!\n'));
|
|
448
|
+
} else if (score >= 40) {
|
|
449
|
+
console.log(c('yellow', '\n ! Skill needs improvement before publishing.\n'));
|
|
450
|
+
} else {
|
|
451
|
+
console.log(c('red', '\n ā Skill requires significant work.\n'));
|
|
452
|
+
}
|
|
453
|
+
},
|
|
454
|
+
|
|
455
|
+
// Test skill
|
|
456
|
+
test: (name) => {
|
|
457
|
+
if (!name) {
|
|
458
|
+
console.log(c('red', '\n Usage: claude-all skills test <skill-name>\n'));
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const skillDir = path.join(SKILLS_DIR, name);
|
|
463
|
+
|
|
464
|
+
if (!fs.existsSync(skillDir)) {
|
|
465
|
+
console.log(c('red', `\n Skill "${name}" not found!\n`));
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
console.log(c('cyan', `\n Testing skill: ${name}\n`));
|
|
470
|
+
|
|
471
|
+
const testFiles = fs.readdirSync(skillDir).filter(f => f.startsWith('test-'));
|
|
472
|
+
|
|
473
|
+
if (testFiles.length === 0) {
|
|
474
|
+
console.log(c('yellow', ' No test files found (test-*.md)'));
|
|
475
|
+
console.log(c('gray', ' Create test files with: claude-all skills create-test <skill-name>'));
|
|
476
|
+
console.log();
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
console.log(c('gray', ` Found ${testFiles.length} test files:\n`));
|
|
481
|
+
|
|
482
|
+
testFiles.forEach((file, i) => {
|
|
483
|
+
const testPath = path.join(skillDir, file);
|
|
484
|
+
const content = fs.readFileSync(testPath, 'utf8');
|
|
485
|
+
|
|
486
|
+
// Check if test has success criteria
|
|
487
|
+
const hasCriteria = content.includes('Success Criteria') || content.includes('- [ ]');
|
|
488
|
+
const criteriaMatch = content.match(/- \[[ x]\]/g) || [];
|
|
489
|
+
const completed = criteriaMatch.filter(m => m.includes('x')).length;
|
|
490
|
+
const total = criteriaMatch.length;
|
|
491
|
+
|
|
492
|
+
const status = total === 0 ? c('gray', 'No criteria') :
|
|
493
|
+
completed === total ? c('green', `${completed}/${total} passed`) :
|
|
494
|
+
c('yellow', `${completed}/${total} passed`);
|
|
495
|
+
|
|
496
|
+
console.log(` ${i + 1}. ${file} - ${status}`);
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
console.log();
|
|
500
|
+
},
|
|
501
|
+
|
|
502
|
+
// Show skill info
|
|
503
|
+
info: (name) => {
|
|
504
|
+
if (!name) {
|
|
505
|
+
console.log(c('red', '\n Usage: claude-all skills info <skill-name>\n'));
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
const skillDir = path.join(SKILLS_DIR, name);
|
|
510
|
+
|
|
511
|
+
if (!fs.existsSync(skillDir)) {
|
|
512
|
+
console.log(c('red', `\n Skill "${name}" not found!\n`));
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
console.log(c('cyan', `\n Skill: ${name}\n`));
|
|
517
|
+
|
|
518
|
+
// Read skill.json if exists
|
|
519
|
+
const skillJsonPath = path.join(skillDir, 'skill.json');
|
|
520
|
+
if (fs.existsSync(skillJsonPath)) {
|
|
521
|
+
const meta = JSON.parse(fs.readFileSync(skillJsonPath, 'utf8'));
|
|
522
|
+
console.log(c('gray', ' Metadata:'));
|
|
523
|
+
console.log(` Version: ${c('green', meta.version || 'N/A')}`);
|
|
524
|
+
console.log(` Author: ${meta.author || 'Unknown'}`);
|
|
525
|
+
console.log(` License: ${meta.license || 'N/A'}`);
|
|
526
|
+
console.log(` Tags: ${(meta.tags || []).join(', ') || 'None'}`);
|
|
527
|
+
console.log(` Agents: ${(meta.agents || []).join(', ')}`);
|
|
528
|
+
if (meta.dependencies && meta.dependencies.length > 0) {
|
|
529
|
+
console.log(` Dependencies: ${meta.dependencies.join(', ')}`);
|
|
530
|
+
}
|
|
531
|
+
console.log();
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// Read SKILL.md
|
|
535
|
+
const skillMdPath = path.join(skillDir, 'SKILL.md');
|
|
536
|
+
if (fs.existsSync(skillMdPath)) {
|
|
537
|
+
const parsed = parseSkillMd(fs.readFileSync(skillMdPath, 'utf8'));
|
|
538
|
+
if (parsed) {
|
|
539
|
+
console.log(c('gray', ' Description:'));
|
|
540
|
+
console.log(` ${parsed.description || 'No description'}`);
|
|
541
|
+
console.log();
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Quality score
|
|
546
|
+
const { score } = calculateQualityScore(skillDir);
|
|
547
|
+
const scoreColor = score >= 70 ? 'green' : score >= 40 ? 'yellow' : 'red';
|
|
548
|
+
console.log(c('gray', ' Quality Score:'));
|
|
549
|
+
console.log(` ${c(scoreColor, `${score}/100`)}`);
|
|
550
|
+
console.log();
|
|
551
|
+
|
|
552
|
+
// Files
|
|
553
|
+
const files = fs.readdirSync(skillDir);
|
|
554
|
+
console.log(c('gray', ' Files:'));
|
|
555
|
+
files.forEach(f => console.log(` - ${f}`));
|
|
556
|
+
console.log();
|
|
557
|
+
},
|
|
558
|
+
|
|
559
|
+
// Export skill for publishing
|
|
560
|
+
export: (name) => {
|
|
561
|
+
if (!name) {
|
|
562
|
+
console.log(c('red', '\n Usage: claude-all skills export <skill-name>\n'));
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
const skillDir = path.join(SKILLS_DIR, name);
|
|
567
|
+
|
|
568
|
+
if (!fs.existsSync(skillDir)) {
|
|
569
|
+
console.log(c('red', `\n Skill "${name}" not found!\n`));
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
const { score } = calculateQualityScore(skillDir);
|
|
574
|
+
|
|
575
|
+
if (score < 40) {
|
|
576
|
+
console.log(c('red', `\n Skill quality too low (${score}/100). Improve before exporting.\n`));
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
const exportDir = path.join(process.cwd(), `${name}-skill`);
|
|
581
|
+
|
|
582
|
+
console.log(c('cyan', `\n Exporting skill: ${name}\n`));
|
|
583
|
+
|
|
584
|
+
// Copy skill directory
|
|
585
|
+
execSync(`cp -r "${skillDir}" "${exportDir}"`);
|
|
586
|
+
|
|
587
|
+
// Create package.json for npm
|
|
588
|
+
const skillJson = fs.existsSync(path.join(skillDir, 'skill.json'))
|
|
589
|
+
? JSON.parse(fs.readFileSync(path.join(skillDir, 'skill.json'), 'utf8'))
|
|
590
|
+
: {};
|
|
591
|
+
|
|
592
|
+
const packageJson = {
|
|
593
|
+
name: `claudeall-skill-${name}`,
|
|
594
|
+
version: skillJson.version || '1.0.0',
|
|
595
|
+
description: skillJson.description || `ClaudeAll skill: ${name}`,
|
|
596
|
+
author: skillJson.author || 'ClaudeAll Community',
|
|
597
|
+
license: skillJson.license || 'MIT',
|
|
598
|
+
keywords: ['claudeall', 'skill', 'ai-agent', ...(skillJson.tags || [])],
|
|
599
|
+
repository: {
|
|
600
|
+
type: 'git',
|
|
601
|
+
url: `https://github.com/zesbe/ClaudeAll.git`
|
|
602
|
+
},
|
|
603
|
+
claudeall: {
|
|
604
|
+
type: 'skill',
|
|
605
|
+
agents: skillJson.agents || ['claude-code'],
|
|
606
|
+
dependencies: skillJson.dependencies || [],
|
|
607
|
+
quality: score
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
|
|
611
|
+
fs.writeFileSync(
|
|
612
|
+
path.join(exportDir, 'package.json'),
|
|
613
|
+
JSON.stringify(packageJson, null, 2)
|
|
614
|
+
);
|
|
615
|
+
|
|
616
|
+
console.log(c('green', ` ā Exported to: ${exportDir}`));
|
|
617
|
+
console.log(c('gray', '\n To publish to npm:'));
|
|
618
|
+
console.log(c('cyan', ` cd ${exportDir}`));
|
|
619
|
+
console.log(c('cyan', ' npm publish'));
|
|
620
|
+
console.log();
|
|
621
|
+
},
|
|
622
|
+
|
|
623
|
+
// Stats
|
|
624
|
+
stats: () => {
|
|
625
|
+
console.log(c('cyan', '\n ClaudeAll Skills Statistics\n'));
|
|
626
|
+
|
|
627
|
+
if (!fs.existsSync(SKILLS_DIR)) {
|
|
628
|
+
console.log(c('yellow', ' No skills directory found.'));
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
const skills = fs.readdirSync(SKILLS_DIR).filter(f =>
|
|
633
|
+
fs.statSync(path.join(SKILLS_DIR, f)).isDirectory()
|
|
634
|
+
);
|
|
635
|
+
|
|
636
|
+
let totalScore = 0;
|
|
637
|
+
let highQuality = 0;
|
|
638
|
+
let mediumQuality = 0;
|
|
639
|
+
let lowQuality = 0;
|
|
640
|
+
|
|
641
|
+
skills.forEach(skill => {
|
|
642
|
+
const { score } = calculateQualityScore(path.join(SKILLS_DIR, skill));
|
|
643
|
+
totalScore += score;
|
|
644
|
+
if (score >= 70) highQuality++;
|
|
645
|
+
else if (score >= 40) mediumQuality++;
|
|
646
|
+
else lowQuality++;
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
const avgScore = skills.length > 0 ? Math.round(totalScore / skills.length) : 0;
|
|
650
|
+
|
|
651
|
+
console.log(` Total Skills: ${c('bright', skills.length.toString())}`);
|
|
652
|
+
console.log(` Average Quality: ${c('cyan', avgScore + '/100')}`);
|
|
653
|
+
console.log();
|
|
654
|
+
console.log(` ${c('green', 'ā')} High Quality (70+): ${highQuality}`);
|
|
655
|
+
console.log(` ${c('yellow', 'ā')} Medium Quality (40-69): ${mediumQuality}`);
|
|
656
|
+
console.log(` ${c('red', 'ā')} Low Quality (<40): ${lowQuality}`);
|
|
657
|
+
console.log();
|
|
658
|
+
},
|
|
659
|
+
|
|
660
|
+
// Help
|
|
661
|
+
help: () => {
|
|
662
|
+
console.log(`
|
|
663
|
+
${c('cyan', ' ClaudeAll Skills CLI')} ${c('gray', '- Advanced skill management')}
|
|
664
|
+
|
|
665
|
+
${c('bright', ' COMMANDS:')}
|
|
666
|
+
|
|
667
|
+
${c('green', 'list')} List all installed skills
|
|
668
|
+
${c('green', 'search')} <query> Search skills by name or content
|
|
669
|
+
${c('green', 'info')} <name> Show skill details
|
|
670
|
+
${c('green', 'create')} <name> Create new skill from template
|
|
671
|
+
${c('green', 'validate')} <name> Validate skill quality
|
|
672
|
+
${c('green', 'test')} <name> Run skill tests
|
|
673
|
+
${c('green', 'export')} <name> Export skill for publishing
|
|
674
|
+
${c('green', 'stats')} Show skills statistics
|
|
675
|
+
${c('green', 'help')} Show this help
|
|
676
|
+
|
|
677
|
+
${c('bright', ' FEATURES BEYOND skills.sh:')}
|
|
678
|
+
|
|
679
|
+
${c('magenta', 'ā')} Quality scoring system (0-100)
|
|
680
|
+
${c('magenta', 'ā')} Skill scaffolding generator
|
|
681
|
+
${c('magenta', 'ā')} Built-in testing framework
|
|
682
|
+
${c('magenta', 'ā')} Dependency management
|
|
683
|
+
${c('magenta', 'ā')} Hooks system (pre/post install)
|
|
684
|
+
${c('magenta', 'ā')} Multi-agent support
|
|
685
|
+
${c('magenta', 'ā')} Offline-first design
|
|
686
|
+
${c('magenta', 'ā')} Export for npm publishing
|
|
687
|
+
|
|
688
|
+
${c('bright', ' EXAMPLES:')}
|
|
689
|
+
|
|
690
|
+
${c('gray', '$')} claude-all skills list
|
|
691
|
+
${c('gray', '$')} claude-all skills create my-skill
|
|
692
|
+
${c('gray', '$')} claude-all skills validate my-skill
|
|
693
|
+
${c('gray', '$')} claude-all skills export my-skill
|
|
694
|
+
|
|
695
|
+
`);
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
// ============================================
|
|
700
|
+
// MAIN
|
|
701
|
+
// ============================================
|
|
702
|
+
|
|
703
|
+
function main() {
|
|
704
|
+
const args = process.argv.slice(2);
|
|
705
|
+
|
|
706
|
+
// Handle "claude-all skills <cmd>" format
|
|
707
|
+
if (args[0] === 'skills') {
|
|
708
|
+
args.shift();
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
const cmd = args[0] || 'help';
|
|
712
|
+
const arg = args[1];
|
|
713
|
+
|
|
714
|
+
if (commands[cmd]) {
|
|
715
|
+
commands[cmd](arg);
|
|
716
|
+
} else {
|
|
717
|
+
console.log(c('red', `\n Unknown command: ${cmd}`));
|
|
718
|
+
commands.help();
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
main();
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClaudeAll Skill Hooks System
|
|
3
|
+
*
|
|
4
|
+
* Lifecycle hooks for skills:
|
|
5
|
+
* - preInstall: Before skill is installed
|
|
6
|
+
* - postInstall: After skill is installed
|
|
7
|
+
* - preUninstall: Before skill is removed
|
|
8
|
+
* - postUninstall: After skill is removed
|
|
9
|
+
* - preUpdate: Before skill is updated
|
|
10
|
+
* - postUpdate: After skill is updated
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const { execSync } = require('child_process');
|
|
16
|
+
|
|
17
|
+
const CLAUDE_DIR = path.join(process.env.HOME, '.claude');
|
|
18
|
+
const SKILLS_DIR = path.join(CLAUDE_DIR, 'skills');
|
|
19
|
+
const HOOKS_LOG = path.join(CLAUDE_DIR, '.hooks-log.json');
|
|
20
|
+
|
|
21
|
+
class SkillHooks {
|
|
22
|
+
constructor() {
|
|
23
|
+
this.hooks = {};
|
|
24
|
+
this.log = this.loadLog();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
loadLog() {
|
|
28
|
+
if (fs.existsSync(HOOKS_LOG)) {
|
|
29
|
+
return JSON.parse(fs.readFileSync(HOOKS_LOG, 'utf8'));
|
|
30
|
+
}
|
|
31
|
+
return { executions: [] };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
saveLog() {
|
|
35
|
+
fs.writeFileSync(HOOKS_LOG, JSON.stringify(this.log, null, 2));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
logExecution(skillName, hookType, success, error = null) {
|
|
39
|
+
this.log.executions.push({
|
|
40
|
+
skill: skillName,
|
|
41
|
+
hook: hookType,
|
|
42
|
+
success,
|
|
43
|
+
error: error ? error.message : null,
|
|
44
|
+
timestamp: new Date().toISOString()
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Keep last 100 executions
|
|
48
|
+
if (this.log.executions.length > 100) {
|
|
49
|
+
this.log.executions = this.log.executions.slice(-100);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this.saveLog();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Load hooks from skill.json
|
|
57
|
+
*/
|
|
58
|
+
loadSkillHooks(skillName) {
|
|
59
|
+
const skillJsonPath = path.join(SKILLS_DIR, skillName, 'skill.json');
|
|
60
|
+
|
|
61
|
+
if (fs.existsSync(skillJsonPath)) {
|
|
62
|
+
const skillJson = JSON.parse(fs.readFileSync(skillJsonPath, 'utf8'));
|
|
63
|
+
return skillJson.hooks || {};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Execute a hook
|
|
71
|
+
*/
|
|
72
|
+
async executeHook(skillName, hookType) {
|
|
73
|
+
const hooks = this.loadSkillHooks(skillName);
|
|
74
|
+
const hookScript = hooks[hookType];
|
|
75
|
+
|
|
76
|
+
if (!hookScript) {
|
|
77
|
+
return { executed: false, reason: 'No hook defined' };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const skillDir = path.join(SKILLS_DIR, skillName);
|
|
81
|
+
const hookPath = path.join(skillDir, hookScript);
|
|
82
|
+
|
|
83
|
+
console.log(` Executing ${hookType} hook for ${skillName}...`);
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
if (fs.existsSync(hookPath)) {
|
|
87
|
+
// Execute script file
|
|
88
|
+
execSync(`bash "${hookPath}"`, {
|
|
89
|
+
cwd: skillDir,
|
|
90
|
+
stdio: 'inherit'
|
|
91
|
+
});
|
|
92
|
+
} else if (hookScript.startsWith('npm ') || hookScript.startsWith('node ')) {
|
|
93
|
+
// Execute command directly
|
|
94
|
+
execSync(hookScript, {
|
|
95
|
+
cwd: skillDir,
|
|
96
|
+
stdio: 'inherit'
|
|
97
|
+
});
|
|
98
|
+
} else {
|
|
99
|
+
// Treat as inline script
|
|
100
|
+
execSync(hookScript, {
|
|
101
|
+
cwd: skillDir,
|
|
102
|
+
shell: true,
|
|
103
|
+
stdio: 'inherit'
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this.logExecution(skillName, hookType, true);
|
|
108
|
+
return { executed: true, success: true };
|
|
109
|
+
} catch (error) {
|
|
110
|
+
this.logExecution(skillName, hookType, false, error);
|
|
111
|
+
return { executed: true, success: false, error: error.message };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Run all lifecycle hooks for an operation
|
|
117
|
+
*/
|
|
118
|
+
async runLifecycle(skillName, operation) {
|
|
119
|
+
const results = {};
|
|
120
|
+
|
|
121
|
+
// Pre hook
|
|
122
|
+
const preHook = `pre${operation.charAt(0).toUpperCase()}${operation.slice(1)}`;
|
|
123
|
+
results.pre = await this.executeHook(skillName, preHook);
|
|
124
|
+
|
|
125
|
+
// Post hook
|
|
126
|
+
const postHook = `post${operation.charAt(0).toUpperCase()}${operation.slice(1)}`;
|
|
127
|
+
results.post = await this.executeHook(skillName, postHook);
|
|
128
|
+
|
|
129
|
+
return results;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Get recent hook executions
|
|
134
|
+
*/
|
|
135
|
+
getRecentExecutions(limit = 10) {
|
|
136
|
+
return this.log.executions.slice(-limit);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
module.exports = SkillHooks;
|
package/package.json
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-termux",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Claude Code & Gemini CLI configuration for Termux Android - agents, skills, commands, MCP servers",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Claude Code & Gemini CLI configuration for Termux Android - agents, skills, commands, MCP servers with quality scoring & hooks",
|
|
5
5
|
"main": "postinstall.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"claude-termux-skills": "./bin/skills-cli.js",
|
|
8
|
+
"claude-termux-mcp": "./bin/mcp-install.js"
|
|
9
|
+
},
|
|
6
10
|
"scripts": {
|
|
7
|
-
"postinstall": "node postinstall.js"
|
|
11
|
+
"postinstall": "node postinstall.js",
|
|
12
|
+
"skills": "node bin/skills-cli.js",
|
|
13
|
+
"mcp": "node bin/mcp-install.js"
|
|
8
14
|
},
|
|
9
15
|
"keywords": [
|
|
10
16
|
"claude",
|
|
@@ -17,18 +23,27 @@
|
|
|
17
23
|
"agents",
|
|
18
24
|
"skills",
|
|
19
25
|
"mcp",
|
|
20
|
-
"superpowers"
|
|
26
|
+
"superpowers",
|
|
27
|
+
"quality-scoring",
|
|
28
|
+
"hooks-system"
|
|
21
29
|
],
|
|
22
|
-
"author":
|
|
30
|
+
"author": {
|
|
31
|
+
"name": "zesbe",
|
|
32
|
+
"email": "yudiharyanto41@gmail.com",
|
|
33
|
+
"url": "https://github.com/zesbe"
|
|
34
|
+
},
|
|
23
35
|
"license": "MIT",
|
|
24
36
|
"repository": {
|
|
25
37
|
"type": "git",
|
|
26
|
-
"url": "
|
|
38
|
+
"url": "https://github.com/zesbe/ClaudeAll.git"
|
|
27
39
|
},
|
|
28
40
|
"bugs": {
|
|
29
41
|
"url": "https://github.com/zesbe/ClaudeAll/issues"
|
|
30
42
|
},
|
|
31
43
|
"homepage": "https://github.com/zesbe/ClaudeAll#readme",
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=14.0.0"
|
|
46
|
+
},
|
|
32
47
|
"files": [
|
|
33
48
|
"agents/**",
|
|
34
49
|
"skills/**",
|
|
@@ -37,6 +52,7 @@
|
|
|
37
52
|
"hooks/**",
|
|
38
53
|
"plugins/**",
|
|
39
54
|
"lib/**",
|
|
55
|
+
"bin/**",
|
|
40
56
|
"CLAUDE.md",
|
|
41
57
|
"GEMINI.md",
|
|
42
58
|
"TERMUX.md",
|
|
@@ -45,5 +61,16 @@
|
|
|
45
61
|
"settings.local.json",
|
|
46
62
|
"install.sh",
|
|
47
63
|
"postinstall.js"
|
|
48
|
-
]
|
|
64
|
+
],
|
|
65
|
+
"claudeTermux": {
|
|
66
|
+
"features": [
|
|
67
|
+
"quality-scoring",
|
|
68
|
+
"skill-scaffolding",
|
|
69
|
+
"hooks-system",
|
|
70
|
+
"mcp-auto-install"
|
|
71
|
+
],
|
|
72
|
+
"skillsCount": 60,
|
|
73
|
+
"agentsCount": 14,
|
|
74
|
+
"commandsCount": 8
|
|
75
|
+
}
|
|
49
76
|
}
|