@petersobhy/ai-toolkit 1.4.0 → 1.6.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 +51 -15
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -9,6 +9,7 @@ const REPO = 'Petersobhy/ai-toolkit';
|
|
|
9
9
|
const BRANCH = 'main';
|
|
10
10
|
const SKILLS_PATH = 'skills';
|
|
11
11
|
const INSTALL_DIR = path.join(os.homedir(), '.claude', 'agents');
|
|
12
|
+
const SCRIPTS_DIR = path.join(INSTALL_DIR, 'scripts');
|
|
12
13
|
|
|
13
14
|
const RAW_BASE = `https://raw.githubusercontent.com/${REPO}/${BRANCH}`;
|
|
14
15
|
const API_BASE = `https://api.github.com/repos/${REPO}/contents`;
|
|
@@ -30,15 +31,20 @@ function get(url) {
|
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
function parseVersion(content) {
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
// metadata.version: 1.0.0 (nested under metadata:)
|
|
35
|
+
const nested = content.match(/^metadata:\s*\n(?:[ \t]+\S[^\n]*\n)*?[ \t]+version:\s*(.+)$/m);
|
|
36
|
+
if (nested) return nested[1].trim();
|
|
37
|
+
// fallback: top-level version: (legacy)
|
|
38
|
+
const top = content.match(/^version:\s*(.+?)$/m);
|
|
39
|
+
return top ? top[1].trim() : null;
|
|
35
40
|
}
|
|
36
41
|
|
|
42
|
+
// List skill folders from GitHub API (directories only, skip README)
|
|
37
43
|
async function listAvailable() {
|
|
38
|
-
const
|
|
39
|
-
return
|
|
40
|
-
.filter(
|
|
41
|
-
.map(
|
|
44
|
+
const entries = JSON.parse(await get(`${API_BASE}/${SKILLS_PATH}`));
|
|
45
|
+
return entries
|
|
46
|
+
.filter(e => e.type === 'dir')
|
|
47
|
+
.map(e => e.name);
|
|
42
48
|
}
|
|
43
49
|
|
|
44
50
|
function listInstalled() {
|
|
@@ -48,18 +54,45 @@ function listInstalled() {
|
|
|
48
54
|
.map(f => f.replace(/\.md$/, ''));
|
|
49
55
|
}
|
|
50
56
|
|
|
57
|
+
// Fetch skill folder contents from GitHub API
|
|
58
|
+
async function getSkillContents(name) {
|
|
59
|
+
const entries = JSON.parse(await get(`${API_BASE}/${SKILLS_PATH}/${name}`));
|
|
60
|
+
return entries; // array of { name, type, download_url, ... }
|
|
61
|
+
}
|
|
62
|
+
|
|
51
63
|
async function installSkill(name) {
|
|
52
|
-
|
|
53
|
-
let content;
|
|
64
|
+
let entries;
|
|
54
65
|
try {
|
|
55
|
-
|
|
66
|
+
entries = await getSkillContents(name);
|
|
56
67
|
} catch {
|
|
57
|
-
console.error(` ✗ ${name} — not found in repo`);
|
|
68
|
+
console.error(` ✗ ${name} — skill folder not found in repo`);
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const skillFile = entries.find(e => e.name === 'SKILL.md');
|
|
73
|
+
if (!skillFile) {
|
|
74
|
+
console.error(` ✗ ${name} — missing SKILL.md in skill folder`);
|
|
58
75
|
return false;
|
|
59
76
|
}
|
|
77
|
+
|
|
78
|
+
// Install SKILL.md → ~/.claude/agents/<name>.md
|
|
79
|
+
const skillContent = await get(`${RAW_BASE}/${SKILLS_PATH}/${name}/SKILL.md`);
|
|
60
80
|
fs.mkdirSync(INSTALL_DIR, { recursive: true });
|
|
61
|
-
fs.writeFileSync(path.join(INSTALL_DIR, `${name}.md`),
|
|
62
|
-
console.log(` ✓ ${name} → ${INSTALL_DIR}
|
|
81
|
+
fs.writeFileSync(path.join(INSTALL_DIR, `${name}.md`), skillContent);
|
|
82
|
+
console.log(` ✓ ${name}.md → ${INSTALL_DIR}`);
|
|
83
|
+
|
|
84
|
+
// Install companion scripts → ~/.claude/agents/scripts/<name>/
|
|
85
|
+
const scripts = entries.filter(e => e.type === 'file' && e.name !== 'SKILL.md' && e.name !== 'README.md');
|
|
86
|
+
if (scripts.length > 0) {
|
|
87
|
+
const scriptDir = path.join(SCRIPTS_DIR, name);
|
|
88
|
+
fs.mkdirSync(scriptDir, { recursive: true });
|
|
89
|
+
for (const script of scripts) {
|
|
90
|
+
const content = await get(`${RAW_BASE}/${SKILLS_PATH}/${name}/${script.name}`);
|
|
91
|
+
fs.writeFileSync(path.join(scriptDir, script.name), content);
|
|
92
|
+
console.log(` ✓ ${script.name} → ${scriptDir}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
63
96
|
return true;
|
|
64
97
|
}
|
|
65
98
|
|
|
@@ -94,9 +127,12 @@ async function cmdList() {
|
|
|
94
127
|
const installed = listInstalled();
|
|
95
128
|
console.log('Available skills:\n');
|
|
96
129
|
for (const name of available) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
130
|
+
let version = null;
|
|
131
|
+
try {
|
|
132
|
+
const content = await get(`${RAW_BASE}/${SKILLS_PATH}/${name}/SKILL.md`);
|
|
133
|
+
version = parseVersion(content);
|
|
134
|
+
} catch { /* skip if fetch fails */ }
|
|
135
|
+
const versionTag = version ? ` v${version}` : '';
|
|
100
136
|
const installedTag = installed.includes(name) ? ' (installed)' : '';
|
|
101
137
|
console.log(` ${name}${versionTag}${installedTag}`);
|
|
102
138
|
}
|