antikit 1.15.0 ā 1.16.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/README.md +36 -0
- package/package.json +2 -1
- package/src/commands/stats.js +196 -0
- package/src/index.js +6 -0
package/README.md
CHANGED
|
@@ -204,6 +204,42 @@ antikit config set-token <new_token>
|
|
|
204
204
|
antikit config remove-token
|
|
205
205
|
```
|
|
206
206
|
|
|
207
|
+
### š Statistics & Analytics
|
|
208
|
+
|
|
209
|
+
View insights about your installed skills.
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
# Show comprehensive statistics
|
|
213
|
+
antikit stats
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**What you'll see:**
|
|
217
|
+
- š **Overview** - Total skills, sources, metadata coverage
|
|
218
|
+
- š¦ **Source Distribution** - Skills grouped by source with percentages
|
|
219
|
+
- š¢ **Version Stats** - Version tracking information
|
|
220
|
+
- š **Top Skills** - Recently installed or most used skills
|
|
221
|
+
|
|
222
|
+
**Example Output:**
|
|
223
|
+
```
|
|
224
|
+
š Antikit Statistics
|
|
225
|
+
|
|
226
|
+
Metric Value
|
|
227
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
228
|
+
Total Skills Installed 12
|
|
229
|
+
Total Sources Configured 3
|
|
230
|
+
Skills with Metadata 10
|
|
231
|
+
|
|
232
|
+
š¦ Skills by Source:
|
|
233
|
+
|
|
234
|
+
Source Skills Percentage
|
|
235
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
236
|
+
antiskills 8 66.7% āāāāāāāāāāāāāāāā
|
|
237
|
+
claudekit 3 25.0% āāāāā
|
|
238
|
+
local 1 8.3% āā
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
207
243
|
### š Tool Maintenance
|
|
208
244
|
|
|
209
245
|
**Update CLI**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "antikit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.0",
|
|
4
4
|
"description": "CLI tool to manage AI agent skills from Anti Gravity skills repository",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"test:watch": "vitest",
|
|
13
13
|
"test:coverage": "vitest run --coverage",
|
|
14
14
|
"release": "commit-and-tag-version",
|
|
15
|
+
"release:push": "./scripts/release.sh",
|
|
15
16
|
"prepare": "husky",
|
|
16
17
|
"format": "prettier --write ."
|
|
17
18
|
},
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import Table from 'cli-table3';
|
|
3
|
+
import { existsSync, readFileSync } from 'fs';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import { getLocalSkills, findLocalSkillsDir } from '../utils/local.js';
|
|
6
|
+
import { getSources } from '../utils/configManager.js';
|
|
7
|
+
import { METADATA_FILE } from '../utils/constants.js';
|
|
8
|
+
|
|
9
|
+
export async function showStats() {
|
|
10
|
+
const skillsDir = findLocalSkillsDir();
|
|
11
|
+
|
|
12
|
+
if (!skillsDir) {
|
|
13
|
+
console.log(chalk.yellow('No .agent/skills directory found in current path.'));
|
|
14
|
+
console.log(chalk.dim('Run this command from a project with .agent/skills folder.'));
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const skills = getLocalSkills();
|
|
19
|
+
const sources = getSources();
|
|
20
|
+
|
|
21
|
+
console.log(chalk.bold.cyan('\nš Antikit Statistics\n'));
|
|
22
|
+
console.log(chalk.dim(`Skills directory: ${skillsDir}\n`));
|
|
23
|
+
|
|
24
|
+
// 1. Overview Stats
|
|
25
|
+
displayOverview(skills, sources);
|
|
26
|
+
|
|
27
|
+
if (skills.length > 0) {
|
|
28
|
+
// 2. Source Distribution
|
|
29
|
+
displaySourceDistribution(skills);
|
|
30
|
+
|
|
31
|
+
// 3. Version Stats
|
|
32
|
+
displayVersionStats(skills);
|
|
33
|
+
|
|
34
|
+
// 4. Top Skills (by size or complexity)
|
|
35
|
+
displayTopSkills(skills);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
console.log();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function displayOverview(skills, sources) {
|
|
42
|
+
const overview = new Table({
|
|
43
|
+
head: [chalk.cyan('Metric'), chalk.cyan('Value')],
|
|
44
|
+
colWidths: [30, 20],
|
|
45
|
+
style: { head: [], border: [] }
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
overview.push(
|
|
49
|
+
[chalk.bold('Total Skills Installed'), chalk.green.bold(skills.length.toString())],
|
|
50
|
+
[chalk.bold('Total Sources Configured'), chalk.blue(sources.length.toString())],
|
|
51
|
+
[
|
|
52
|
+
chalk.bold('Skills with Metadata'),
|
|
53
|
+
chalk.yellow(
|
|
54
|
+
skills.filter(s => {
|
|
55
|
+
const metaPath = join(s.path, METADATA_FILE);
|
|
56
|
+
return existsSync(metaPath);
|
|
57
|
+
}).length.toString()
|
|
58
|
+
)
|
|
59
|
+
]
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
console.log(overview.toString());
|
|
63
|
+
console.log();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function displaySourceDistribution(skills) {
|
|
67
|
+
const sourceMap = new Map();
|
|
68
|
+
|
|
69
|
+
skills.forEach(skill => {
|
|
70
|
+
const metaPath = join(skill.path, METADATA_FILE);
|
|
71
|
+
let sourceName = 'local';
|
|
72
|
+
|
|
73
|
+
if (existsSync(metaPath)) {
|
|
74
|
+
try {
|
|
75
|
+
const meta = JSON.parse(readFileSync(metaPath, 'utf-8'));
|
|
76
|
+
if (meta.source && meta.source.owner && meta.source.repo) {
|
|
77
|
+
// Use source name if available, otherwise owner/repo
|
|
78
|
+
sourceName = meta.sourceName || `${meta.source.owner}/${meta.source.repo}`;
|
|
79
|
+
}
|
|
80
|
+
} catch { }
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
sourceMap.set(sourceName, (sourceMap.get(sourceName) || 0) + 1);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Sort by count descending
|
|
87
|
+
const sortedSources = Array.from(sourceMap.entries()).sort((a, b) => b[1] - a[1]);
|
|
88
|
+
|
|
89
|
+
console.log(chalk.bold.cyan('š¦ Skills by Source:\n'));
|
|
90
|
+
|
|
91
|
+
const sourceTable = new Table({
|
|
92
|
+
head: [chalk.cyan('Source'), chalk.cyan('Skills'), chalk.cyan('Percentage')],
|
|
93
|
+
colWidths: [35, 12, 15],
|
|
94
|
+
style: { head: [], border: [] }
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const total = skills.length;
|
|
98
|
+
sortedSources.forEach(([source, count]) => {
|
|
99
|
+
const percentage = ((count / total) * 100).toFixed(1);
|
|
100
|
+
const bar = 'ā'.repeat(Math.ceil((count / total) * 20));
|
|
101
|
+
|
|
102
|
+
sourceTable.push([
|
|
103
|
+
chalk.magenta(source),
|
|
104
|
+
chalk.green(count.toString()),
|
|
105
|
+
chalk.yellow(`${percentage}%`) + ' ' + chalk.dim(bar)
|
|
106
|
+
]);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
console.log(sourceTable.toString());
|
|
110
|
+
console.log();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function displayVersionStats(skills) {
|
|
114
|
+
let withVersion = 0;
|
|
115
|
+
let withoutVersion = 0;
|
|
116
|
+
const versions = new Map();
|
|
117
|
+
|
|
118
|
+
skills.forEach(skill => {
|
|
119
|
+
const metaPath = join(skill.path, METADATA_FILE);
|
|
120
|
+
|
|
121
|
+
if (existsSync(metaPath)) {
|
|
122
|
+
try {
|
|
123
|
+
const meta = JSON.parse(readFileSync(metaPath, 'utf-8'));
|
|
124
|
+
if (meta.version) {
|
|
125
|
+
withVersion++;
|
|
126
|
+
// Track version patterns (major.minor.patch)
|
|
127
|
+
const major = meta.version.split('.')[0];
|
|
128
|
+
versions.set(major, (versions.get(major) || 0) + 1);
|
|
129
|
+
} else {
|
|
130
|
+
withoutVersion++;
|
|
131
|
+
}
|
|
132
|
+
} catch {
|
|
133
|
+
withoutVersion++;
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
withoutVersion++;
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
console.log(chalk.bold.cyan('š¢ Version Information:\n'));
|
|
141
|
+
|
|
142
|
+
const versionTable = new Table({
|
|
143
|
+
head: [chalk.cyan('Status'), chalk.cyan('Count')],
|
|
144
|
+
colWidths: [35, 15],
|
|
145
|
+
style: { head: [], border: [] }
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
versionTable.push(
|
|
149
|
+
['Skills with version info', chalk.green(withVersion.toString())],
|
|
150
|
+
['Skills without version info', chalk.dim(withoutVersion.toString())]
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
console.log(versionTable.toString());
|
|
154
|
+
console.log();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function displayTopSkills(skills) {
|
|
158
|
+
// Show skills sorted by name with their basic info
|
|
159
|
+
const topCount = Math.min(5, skills.length);
|
|
160
|
+
|
|
161
|
+
console.log(chalk.bold.cyan(`š Installed Skills (showing ${topCount} of ${skills.length}):\n`));
|
|
162
|
+
|
|
163
|
+
const topTable = new Table({
|
|
164
|
+
head: [chalk.cyan('Skill Name'), chalk.cyan('Version'), chalk.cyan('Source')],
|
|
165
|
+
colWidths: [30, 15, 25],
|
|
166
|
+
wordWrap: true,
|
|
167
|
+
style: { head: [], border: [] }
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Sort alphabetically and take top N
|
|
171
|
+
const sortedSkills = [...skills].sort((a, b) => a.name.localeCompare(b.name)).slice(0, topCount);
|
|
172
|
+
|
|
173
|
+
sortedSkills.forEach(skill => {
|
|
174
|
+
const metaPath = join(skill.path, METADATA_FILE);
|
|
175
|
+
let version = chalk.dim('local');
|
|
176
|
+
let source = chalk.dim('local');
|
|
177
|
+
|
|
178
|
+
if (existsSync(metaPath)) {
|
|
179
|
+
try {
|
|
180
|
+
const meta = JSON.parse(readFileSync(metaPath, 'utf-8'));
|
|
181
|
+
if (meta.version) version = chalk.yellow(meta.version);
|
|
182
|
+
if (meta.source && meta.source.owner && meta.source.repo) {
|
|
183
|
+
source = chalk.magenta(meta.sourceName || `${meta.source.owner}/${meta.source.repo}`);
|
|
184
|
+
}
|
|
185
|
+
} catch { }
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
topTable.push([chalk.bold.cyan(skill.name), version, source]);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
console.log(topTable.toString());
|
|
192
|
+
|
|
193
|
+
if (skills.length > topCount) {
|
|
194
|
+
console.log(chalk.dim(`\n... and ${skills.length - topCount} more. Use 'antikit local' to see all.`));
|
|
195
|
+
}
|
|
196
|
+
}
|
package/src/index.js
CHANGED
|
@@ -11,6 +11,7 @@ import { showSkillInfo } from './commands/info.js';
|
|
|
11
11
|
import { validateSkill } from './commands/validate.js';
|
|
12
12
|
import { updateCli } from './commands/update.js';
|
|
13
13
|
import { upgradeSkills } from './commands/upgrade.js';
|
|
14
|
+
import { showStats } from './commands/stats.js';
|
|
14
15
|
import { listSources, addNewSource, removeExistingSource, setDefault } from './commands/source.js';
|
|
15
16
|
import { listConfig, setGitHubToken, removeGitHubToken } from './commands/config.js';
|
|
16
17
|
import { checkForUpdates } from './utils/updateNotifier.js';
|
|
@@ -89,6 +90,11 @@ program
|
|
|
89
90
|
.option('-y, --yes', 'Skip confirmation')
|
|
90
91
|
.action(upgradeSkills);
|
|
91
92
|
|
|
93
|
+
program
|
|
94
|
+
.command('stats')
|
|
95
|
+
.description('Show statistics about installed skills')
|
|
96
|
+
.action(showStats);
|
|
97
|
+
|
|
92
98
|
program
|
|
93
99
|
.command('completion')
|
|
94
100
|
.description('Setup autocomplete for your shell (zsh/bash)')
|