@maccesar/aiskills 1.19.0 → 1.20.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
CHANGED
|
@@ -540,10 +540,11 @@ How to invoke it — in whatever words you'd use anyway:
|
|
|
540
540
|
|
|
541
541
|
### aiskills list
|
|
542
542
|
|
|
543
|
-
Lists all available skills with their descriptions.
|
|
543
|
+
Lists all available skills with their descriptions, marking each one installed (✓) or not (✗). It works before you have installed anything — descriptions for a skill that is not installed come from the copy bundled in this package — so the list doubles as the catalog of what is on offer.
|
|
544
544
|
|
|
545
545
|
```bash
|
|
546
546
|
aiskills list
|
|
547
|
+
aiskills ls # same thing
|
|
547
548
|
```
|
|
548
549
|
|
|
549
550
|
---
|
package/bin/aiskills.js
CHANGED
package/lib/commands/list.js
CHANGED
|
@@ -111,25 +111,44 @@ export function parseDescription(frontmatter) {
|
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
/**
|
|
114
|
-
* Read a
|
|
115
|
-
* @param {string}
|
|
116
|
-
* @returns {
|
|
114
|
+
* Read a description out of one SKILL.md.
|
|
115
|
+
* @param {string} skillMd - Path to a SKILL.md
|
|
116
|
+
* @returns {string|null} The first sentence, or null when unreadable
|
|
117
117
|
*/
|
|
118
|
-
function
|
|
119
|
-
const skillMd = join(skillDir, 'SKILL.md');
|
|
120
|
-
if (!existsSync(skillMd)) {
|
|
121
|
-
return { description: null, installed: false };
|
|
122
|
-
}
|
|
123
|
-
|
|
118
|
+
function readDescription(skillMd) {
|
|
124
119
|
try {
|
|
125
120
|
const content = readFileSync(skillMd, 'utf8');
|
|
126
121
|
const frontmatter = content.match(/^---\n([\s\S]*?)\n---/);
|
|
127
|
-
if (!frontmatter) return
|
|
128
|
-
|
|
129
|
-
return { description: parseDescription(frontmatter[1]), installed: true };
|
|
122
|
+
if (!frontmatter) return null;
|
|
123
|
+
return parseDescription(frontmatter[1]);
|
|
130
124
|
} catch {
|
|
131
|
-
return
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Read a skill's description, preferring the installed copy and falling back
|
|
131
|
+
* to the one bundled in this package.
|
|
132
|
+
*
|
|
133
|
+
* The fallback is what lets the list describe a skill that is not installed
|
|
134
|
+
* yet — which is exactly when someone runs `aiskills list` and needs to know
|
|
135
|
+
* what they would be installing. `skills/` ships in the npm tarball, so the
|
|
136
|
+
* bundled copy is there for every install channel.
|
|
137
|
+
* @param {string} skillDir - Where the skill would be installed
|
|
138
|
+
* @param {string} name - Skill name, used to find the bundled copy
|
|
139
|
+
* @returns {{description: string|null, installed: boolean}}
|
|
140
|
+
*/
|
|
141
|
+
function readSkillMetadata(skillDir, name) {
|
|
142
|
+
const installedMd = join(skillDir, 'SKILL.md');
|
|
143
|
+
if (existsSync(installedMd)) {
|
|
144
|
+
return { description: readDescription(installedMd), installed: true };
|
|
132
145
|
}
|
|
146
|
+
|
|
147
|
+
const bundledMd = new URL(`../../skills/${name}/SKILL.md`, import.meta.url);
|
|
148
|
+
return {
|
|
149
|
+
description: existsSync(bundledMd) ? readDescription(bundledMd) : null,
|
|
150
|
+
installed: false,
|
|
151
|
+
};
|
|
133
152
|
}
|
|
134
153
|
|
|
135
154
|
export async function listCommand() {
|
|
@@ -139,21 +158,13 @@ export async function listCommand() {
|
|
|
139
158
|
|
|
140
159
|
const skillsDir = getAgentsSkillsDir();
|
|
141
160
|
|
|
142
|
-
if (!existsSync(skillsDir)) {
|
|
143
|
-
console.log(chalk.yellow('No skills installed yet.'));
|
|
144
|
-
console.log('Install with:');
|
|
145
|
-
console.log(chalk.cyan(' aiskills install'));
|
|
146
|
-
console.log('');
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
161
|
const rows = [];
|
|
151
162
|
let installedCount = 0;
|
|
152
163
|
let maxNameLen = 0;
|
|
153
164
|
|
|
154
165
|
for (const name of SKILLS) {
|
|
155
166
|
const skillDir = join(skillsDir, name);
|
|
156
|
-
const { description, installed } = readSkillMetadata(skillDir);
|
|
167
|
+
const { description, installed } = readSkillMetadata(skillDir, name);
|
|
157
168
|
|
|
158
169
|
if (installed) installedCount++;
|
|
159
170
|
if (name.length > maxNameLen) maxNameLen = name.length;
|
|
@@ -179,6 +190,18 @@ export async function listCommand() {
|
|
|
179
190
|
}
|
|
180
191
|
|
|
181
192
|
console.log('');
|
|
193
|
+
|
|
194
|
+
if (installedCount === 0) {
|
|
195
|
+
// Naming the directory would point at somewhere that does not exist yet.
|
|
196
|
+
console.log(chalk.gray(`0/${SKILLS.length} installed`));
|
|
197
|
+
console.log('');
|
|
198
|
+
console.log(chalk.yellow('No skills installed yet.'));
|
|
199
|
+
console.log('Install with:');
|
|
200
|
+
console.log(chalk.cyan(' aiskills install'));
|
|
201
|
+
console.log('');
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
182
205
|
console.log(chalk.gray(`${installedCount}/${SKILLS.length} installed at ${skillsDir}`));
|
|
183
206
|
console.log('');
|
|
184
207
|
console.log(chalk.gray('Run `aiskills status` for installation health.'));
|
package/package.json
CHANGED
|
Binary file
|