antikit 1.10.0 → 1.10.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/package.json +1 -1
- package/src/commands/list.js +16 -4
- package/src/utils/github.js +141 -13
package/package.json
CHANGED
package/src/commands/list.js
CHANGED
|
@@ -47,10 +47,22 @@ export async function listRemoteSkills(options) {
|
|
|
47
47
|
const infoSpinner = ora('Fetching skill info...').start();
|
|
48
48
|
const skillsWithInfo = await Promise.all(
|
|
49
49
|
skills.map(async skill => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
let description = skill.description;
|
|
51
|
+
let remoteVersion = skill.version || '0.0.0';
|
|
52
|
+
|
|
53
|
+
// Only fetch info if not already fetched (REST fallback)
|
|
54
|
+
if (description === undefined || description === null) {
|
|
55
|
+
// Pass basePath and branch to fetch correct SKILL.md location optimized
|
|
56
|
+
const info = await fetchSkillInfo(
|
|
57
|
+
skill.name,
|
|
58
|
+
skill.owner,
|
|
59
|
+
skill.repo,
|
|
60
|
+
skill.basePath,
|
|
61
|
+
skill.branch
|
|
62
|
+
);
|
|
63
|
+
description = info ? info.description : null;
|
|
64
|
+
remoteVersion = info ? info.version : '0.0.0';
|
|
65
|
+
}
|
|
54
66
|
|
|
55
67
|
const installed = skillExists(skill.name);
|
|
56
68
|
let updateAvailable = false;
|
package/src/utils/github.js
CHANGED
|
@@ -14,14 +14,119 @@ function getHeaders() {
|
|
|
14
14
|
return headers;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Fetch skills using GraphQL (Optimized: 1 request per source)
|
|
19
|
+
*/
|
|
20
|
+
async function fetchSkillsViaGraphQL(source, token) {
|
|
21
|
+
const query = `
|
|
22
|
+
query ($owner: String!, $repo: String!, $expression: String!) {
|
|
23
|
+
repository(owner: $owner, name: $repo) {
|
|
24
|
+
object(expression: $expression) {
|
|
25
|
+
... on Tree {
|
|
26
|
+
entries {
|
|
27
|
+
name
|
|
28
|
+
type
|
|
29
|
+
object {
|
|
30
|
+
... on Tree {
|
|
31
|
+
file: entries(name: "SKILL.md") {
|
|
32
|
+
object {
|
|
33
|
+
... on Blob {
|
|
34
|
+
text
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
const branch = source.branch || 'main'; // This logic might need verifying branch exists, but usually main/master
|
|
48
|
+
// Correct expression for path. If path is provided, it's "branch:path", else just "branch:"
|
|
49
|
+
const expression = source.path ? `${branch}:${source.path}` : `${branch}:`;
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
const response = await fetch('https://api.github.com/graphql', {
|
|
53
|
+
method: 'POST',
|
|
54
|
+
headers: {
|
|
55
|
+
Authorization: `token ${token}`,
|
|
56
|
+
'User-Agent': 'antikit-cli'
|
|
57
|
+
},
|
|
58
|
+
body: JSON.stringify({
|
|
59
|
+
query,
|
|
60
|
+
variables: {
|
|
61
|
+
owner: source.owner,
|
|
62
|
+
repo: source.repo,
|
|
63
|
+
expression
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const { data, errors } = await response.json();
|
|
69
|
+
|
|
70
|
+
if (errors || !data || !data.repository || !data.repository.object) {
|
|
71
|
+
return null; // Fallback to REST
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const entries = data.repository.object.entries || [];
|
|
75
|
+
|
|
76
|
+
return entries
|
|
77
|
+
.filter(item => item.type === 'tree' && !item.name.startsWith('.'))
|
|
78
|
+
.map(item => {
|
|
79
|
+
let description = null;
|
|
80
|
+
let version = '0.0.0';
|
|
81
|
+
|
|
82
|
+
// Attempt to parse SKILL.md content if it exists
|
|
83
|
+
const skillFile = item.object.file && item.object.file[0];
|
|
84
|
+
if (skillFile && skillFile.object && skillFile.object.text) {
|
|
85
|
+
const content = skillFile.object.text;
|
|
86
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
87
|
+
if (match) {
|
|
88
|
+
const frontmatter = match[1];
|
|
89
|
+
const descMatch = frontmatter.match(/description:\s*(.+)/);
|
|
90
|
+
const verMatch = frontmatter.match(/version:\s*(.+)/);
|
|
91
|
+
if (descMatch) description = descMatch[1].trim();
|
|
92
|
+
if (verMatch) version = verMatch[1].trim();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
name: item.name,
|
|
98
|
+
url: `https://github.com/${source.owner}/${source.repo}/tree/${branch}/${source.path ? source.path + '/' : ''}${item.name}`,
|
|
99
|
+
path: source.path ? `${source.path}/${item.name}` : item.name,
|
|
100
|
+
source: source.name,
|
|
101
|
+
owner: source.owner,
|
|
102
|
+
repo: source.repo,
|
|
103
|
+
basePath: source.path,
|
|
104
|
+
description, // Pre-fetched!
|
|
105
|
+
version // Pre-fetched!
|
|
106
|
+
};
|
|
107
|
+
});
|
|
108
|
+
} catch (e) {
|
|
109
|
+
return null; // Fallback
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
17
113
|
/**
|
|
18
114
|
* Fetch list of skills from a specific source
|
|
19
115
|
*/
|
|
20
116
|
async function fetchSkillsFromSource(source) {
|
|
117
|
+
// Try GraphQL first if token exists (Much faster)
|
|
118
|
+
const token = getToken() || process.env.ANTIKIT_GITHUB_TOKEN || process.env.GITHUB_TOKEN;
|
|
119
|
+
if (token) {
|
|
120
|
+
const gqlResult = await fetchSkillsViaGraphQL(source, token);
|
|
121
|
+
if (gqlResult) return gqlResult;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Fallback to REST API
|
|
21
125
|
let url = `${GITHUB_API}/repos/${source.owner}/${source.repo}/contents`;
|
|
22
126
|
if (source.path) {
|
|
23
127
|
url += `/${source.path}`;
|
|
24
128
|
}
|
|
129
|
+
// ... rest of function
|
|
25
130
|
|
|
26
131
|
const response = await fetch(url, {
|
|
27
132
|
headers: getHeaders()
|
|
@@ -61,6 +166,7 @@ async function fetchSkillsFromSource(source) {
|
|
|
61
166
|
source: source.name,
|
|
62
167
|
owner: source.owner,
|
|
63
168
|
repo: source.repo,
|
|
169
|
+
branch: source.branch || 'main',
|
|
64
170
|
basePath: source.path // Keep track of base path
|
|
65
171
|
}));
|
|
66
172
|
|
|
@@ -90,7 +196,7 @@ export async function fetchRemoteSkills(sourceName = null) {
|
|
|
90
196
|
/**
|
|
91
197
|
* Fetch SKILL.md content for a specific skill
|
|
92
198
|
*/
|
|
93
|
-
export async function fetchSkillInfo(skillName, owner, repo, path = null) {
|
|
199
|
+
export async function fetchSkillInfo(skillName, owner, repo, path = null, branch = null) {
|
|
94
200
|
// If owner/repo not provided, search in all sources
|
|
95
201
|
if (!owner || !repo) {
|
|
96
202
|
const skills = await fetchRemoteSkills();
|
|
@@ -99,24 +205,46 @@ export async function fetchSkillInfo(skillName, owner, repo, path = null) {
|
|
|
99
205
|
owner = skill.owner;
|
|
100
206
|
repo = skill.repo;
|
|
101
207
|
path = skill.basePath;
|
|
208
|
+
branch = skill.branch;
|
|
102
209
|
}
|
|
103
210
|
|
|
104
|
-
let
|
|
105
|
-
if (path) {
|
|
106
|
-
url += `/${path}`;
|
|
107
|
-
}
|
|
108
|
-
url += `/${skillName}/SKILL.md`;
|
|
211
|
+
let content = null;
|
|
109
212
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
213
|
+
// Optimized: Use Raw URL if branch is known (avoids API rate limit)
|
|
214
|
+
if (branch) {
|
|
215
|
+
let rawUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}`;
|
|
216
|
+
if (path) rawUrl += `/${path}`;
|
|
217
|
+
rawUrl += `/${skillName}/SKILL.md`;
|
|
113
218
|
|
|
114
|
-
|
|
115
|
-
|
|
219
|
+
try {
|
|
220
|
+
const res = await fetch(rawUrl);
|
|
221
|
+
if (res.ok) {
|
|
222
|
+
content = await res.text();
|
|
223
|
+
}
|
|
224
|
+
} catch (e) {
|
|
225
|
+
// Ignore fetch error, fallback to API
|
|
226
|
+
}
|
|
116
227
|
}
|
|
117
228
|
|
|
118
|
-
|
|
119
|
-
|
|
229
|
+
// Fallback: Use API (Counts against rate limit, but works if branch is wrong/private repo needs Auth)
|
|
230
|
+
if (!content) {
|
|
231
|
+
let url = `${GITHUB_API}/repos/${owner}/${repo}/contents`;
|
|
232
|
+
if (path) {
|
|
233
|
+
url += `/${path}`;
|
|
234
|
+
}
|
|
235
|
+
url += `/${skillName}/SKILL.md`;
|
|
236
|
+
|
|
237
|
+
const response = await fetch(url, {
|
|
238
|
+
headers: getHeaders()
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
if (!response.ok) {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const data = await response.json();
|
|
246
|
+
content = Buffer.from(data.content, 'base64').toString('utf-8');
|
|
247
|
+
}
|
|
120
248
|
|
|
121
249
|
// Extract info from YAML frontmatter
|
|
122
250
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|