@petersobhy/ai-toolkit 1.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/index.js +118 -0
- package/package.json +19 -0
package/index.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const https = require('https');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
|
|
8
|
+
const REPO = 'peter-at-integrant/ai-toolkit';
|
|
9
|
+
const BRANCH = 'main';
|
|
10
|
+
const SKILLS_PATH = 'skills';
|
|
11
|
+
const INSTALL_DIR = path.join(os.homedir(), '.claude', 'agents');
|
|
12
|
+
|
|
13
|
+
const RAW_BASE = `https://raw.githubusercontent.com/${REPO}/${BRANCH}`;
|
|
14
|
+
const API_BASE = `https://api.github.com/repos/${REPO}/contents`;
|
|
15
|
+
|
|
16
|
+
function get(url) {
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
https.get(url, { headers: { 'User-Agent': 'ai-toolkit-cli' } }, (res) => {
|
|
19
|
+
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
20
|
+
return get(res.headers.location).then(resolve).catch(reject);
|
|
21
|
+
}
|
|
22
|
+
let data = '';
|
|
23
|
+
res.on('data', chunk => data += chunk);
|
|
24
|
+
res.on('end', () => {
|
|
25
|
+
if (res.statusCode !== 200) reject(new Error(`HTTP ${res.statusCode} for ${url}`));
|
|
26
|
+
else resolve(data);
|
|
27
|
+
});
|
|
28
|
+
}).on('error', reject);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function listAvailable() {
|
|
33
|
+
const data = JSON.parse(await get(`${API_BASE}/${SKILLS_PATH}`));
|
|
34
|
+
return data
|
|
35
|
+
.filter(f => f.name.endsWith('.md') && f.name !== 'README.md')
|
|
36
|
+
.map(f => f.name.replace(/\.md$/, ''));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function listInstalled() {
|
|
40
|
+
if (!fs.existsSync(INSTALL_DIR)) return [];
|
|
41
|
+
return fs.readdirSync(INSTALL_DIR)
|
|
42
|
+
.filter(f => f.endsWith('.md'))
|
|
43
|
+
.map(f => f.replace(/\.md$/, ''));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function installSkill(name) {
|
|
47
|
+
const url = `${RAW_BASE}/${SKILLS_PATH}/${name}.md`;
|
|
48
|
+
let content;
|
|
49
|
+
try {
|
|
50
|
+
content = await get(url);
|
|
51
|
+
} catch {
|
|
52
|
+
console.error(` ✗ ${name} — not found in repo`);
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
fs.mkdirSync(INSTALL_DIR, { recursive: true });
|
|
56
|
+
fs.writeFileSync(path.join(INSTALL_DIR, `${name}.md`), content);
|
|
57
|
+
console.log(` ✓ ${name} → ${INSTALL_DIR}/${name}.md`);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function cmdAdd(args) {
|
|
62
|
+
const all = args.includes('--all');
|
|
63
|
+
const names = all ? await listAvailable() : args.filter(a => !a.startsWith('-'));
|
|
64
|
+
|
|
65
|
+
if (names.length === 0) {
|
|
66
|
+
console.log('Usage: ai-toolkit add <skill-name>');
|
|
67
|
+
console.log(' ai-toolkit add --all');
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log(all ? `Installing all ${names.length} skills...\n` : `Installing ${names.length} skill(s)...\n`);
|
|
72
|
+
for (const name of names) await installSkill(name);
|
|
73
|
+
console.log('\nRestart Claude Code to activate installed skills.');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function cmdUpdate() {
|
|
77
|
+
const installed = listInstalled();
|
|
78
|
+
if (installed.length === 0) {
|
|
79
|
+
console.log('No skills installed. Run: ai-toolkit add --all');
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
console.log(`Updating ${installed.length} installed skill(s)...\n`);
|
|
83
|
+
for (const name of installed) await installSkill(name);
|
|
84
|
+
console.log('\nRestart Claude Code to activate updated skills.');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function cmdList() {
|
|
88
|
+
const [available, installed] = await Promise.all([listAvailable(), Promise.resolve(listInstalled())]);
|
|
89
|
+
console.log('Available skills:\n');
|
|
90
|
+
for (const name of available) {
|
|
91
|
+
const tag = installed.includes(name) ? ' (installed)' : '';
|
|
92
|
+
console.log(` ${name}${tag}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function main() {
|
|
97
|
+
const [cmd, ...args] = process.argv.slice(2);
|
|
98
|
+
|
|
99
|
+
const commands = { add: cmdAdd, update: cmdUpdate, list: cmdList };
|
|
100
|
+
|
|
101
|
+
if (!cmd || !commands[cmd]) {
|
|
102
|
+
console.log('Usage:');
|
|
103
|
+
console.log(' ai-toolkit list List available skills');
|
|
104
|
+
console.log(' ai-toolkit add <skill-name> Install a skill');
|
|
105
|
+
console.log(' ai-toolkit add --all Install all skills');
|
|
106
|
+
console.log(' ai-toolkit update Update all installed skills');
|
|
107
|
+
process.exit(cmd ? 1 : 0);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
await commands[cmd](args);
|
|
112
|
+
} catch (err) {
|
|
113
|
+
console.error(`Error: ${err.message}`);
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@petersobhy/ai-toolkit",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Install and manage Integrant squad AI skills for Claude Code",
|
|
5
|
+
"bin": {
|
|
6
|
+
"ai-toolkit": "./index.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"index.js"
|
|
10
|
+
],
|
|
11
|
+
"engines": {
|
|
12
|
+
"node": ">=18"
|
|
13
|
+
},
|
|
14
|
+
"license": "UNLICENSED",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/peter-at-integrant/ai-toolkit.git"
|
|
18
|
+
}
|
|
19
|
+
}
|