@agentskill.sh/cli 1.0.8 → 2.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/dist/agents.d.ts +10 -0
- package/dist/agents.js +347 -0
- package/dist/api.js +1 -1
- package/dist/commands/feedback.js +9 -9
- package/dist/commands/find.d.ts +1 -0
- package/dist/commands/find.js +183 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +82 -0
- package/dist/commands/install.js +118 -81
- package/dist/commands/list.js +105 -50
- package/dist/commands/remove.js +105 -25
- package/dist/commands/search.js +52 -26
- package/dist/commands/setup.d.ts +1 -1
- package/dist/commands/setup.js +99 -31
- package/dist/commands/update.js +75 -105
- package/dist/index.js +91 -59
- package/dist/installer.d.ts +33 -0
- package/dist/installer.js +145 -0
- package/dist/skill-lock.d.ts +19 -0
- package/dist/skill-lock.js +63 -0
- package/dist/types.d.ts +58 -0
- package/dist/types.js +1 -0
- package/dist/ui.d.ts +17 -0
- package/dist/ui.js +84 -0
- package/package.json +5 -1
package/dist/commands/setup.js
CHANGED
|
@@ -1,41 +1,109 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import * as p from '@clack/prompts';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
import { apiFetch } from '../api.js';
|
|
4
|
+
import { showLogo, ORANGE } from '../ui.js';
|
|
5
|
+
import { detectInstalledAgents, getUniversalAgents, getNonUniversalAgents, getAgentDisplayName, } from '../agents.js';
|
|
6
|
+
import { installToAgents } from '../installer.js';
|
|
7
|
+
import { addToLock, saveSelectedAgents } from '../skill-lock.js';
|
|
8
|
+
const OFFICIAL_SKILLS = ['agentskill-sh/learn', 'agentskill-sh/review-skill'];
|
|
9
|
+
export async function setupCommand(_args) {
|
|
10
|
+
showLogo();
|
|
11
|
+
// Detect installed agents
|
|
12
|
+
const s = p.spinner();
|
|
13
|
+
s.start('Detecting installed agents...');
|
|
14
|
+
const installedAgents = await detectInstalledAgents();
|
|
15
|
+
if (!installedAgents.length) {
|
|
16
|
+
s.stop('No agents detected');
|
|
17
|
+
p.log.warn('No AI agents detected on this machine.');
|
|
18
|
+
p.log.info(`We will install to ${pc.bold('Claude Code')} by default. You can change this later.`);
|
|
19
|
+
installedAgents.push('claude-code');
|
|
12
20
|
}
|
|
13
|
-
|
|
14
|
-
|
|
21
|
+
else {
|
|
22
|
+
s.stop(`Found ${installedAgents.length} agent${installedAgents.length !== 1 ? 's' : ''}`);
|
|
23
|
+
}
|
|
24
|
+
// Show agent selection
|
|
25
|
+
const universal = getUniversalAgents().filter((a) => installedAgents.includes(a));
|
|
26
|
+
const nonUniversal = getNonUniversalAgents().filter((a) => installedAgents.includes(a));
|
|
27
|
+
// Build options
|
|
28
|
+
const options = [
|
|
29
|
+
...universal.map((a) => ({
|
|
30
|
+
value: a,
|
|
31
|
+
label: `${getAgentDisplayName(a)} ${pc.dim('(.agents/skills)')}`,
|
|
32
|
+
hint: 'universal',
|
|
33
|
+
})),
|
|
34
|
+
...nonUniversal.map((a) => ({
|
|
35
|
+
value: a,
|
|
36
|
+
label: getAgentDisplayName(a),
|
|
37
|
+
})),
|
|
38
|
+
];
|
|
39
|
+
let selectedAgents;
|
|
40
|
+
if (options.length > 1) {
|
|
41
|
+
const selected = await p.multiselect({
|
|
42
|
+
message: 'Select agents to install skills to:',
|
|
43
|
+
options,
|
|
44
|
+
initialValues: installedAgents,
|
|
45
|
+
required: true,
|
|
46
|
+
});
|
|
47
|
+
if (p.isCancel(selected)) {
|
|
48
|
+
p.cancel('Setup cancelled.');
|
|
49
|
+
process.exit(0);
|
|
50
|
+
}
|
|
51
|
+
selectedAgents = selected;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
selectedAgents = installedAgents;
|
|
55
|
+
p.log.step(`Installing to ${pc.bold(getAgentDisplayName(installedAgents[0]))}`);
|
|
56
|
+
}
|
|
57
|
+
// Save selected agents
|
|
58
|
+
saveSelectedAgents(selectedAgents);
|
|
59
|
+
// Install official skills
|
|
60
|
+
p.log.step(`Installing ${OFFICIAL_SKILLS.length} official skill${OFFICIAL_SKILLS.length !== 1 ? 's' : ''}...`);
|
|
15
61
|
for (const slug of OFFICIAL_SKILLS) {
|
|
62
|
+
const spin = p.spinner();
|
|
63
|
+
spin.start(`Fetching ${slug}...`);
|
|
16
64
|
try {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
65
|
+
const data = await apiFetch(`/agent/skills/${encodeURIComponent(slug)}/install`);
|
|
66
|
+
if (!data.skillMd) {
|
|
67
|
+
spin.error(`${slug} has no SKILL.md`);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
spin.stop(`Fetched ${ORANGE(data.name)}`);
|
|
71
|
+
const results = installToAgents(data, selectedAgents);
|
|
72
|
+
const successful = results.filter((r) => r.success);
|
|
73
|
+
if (successful.length) {
|
|
74
|
+
addToLock(data.slug, data.contentSha || '', selectedAgents);
|
|
75
|
+
p.log.success(`${ORANGE(data.name)} installed to ${successful.length} agent${successful.length !== 1 ? 's' : ''}`);
|
|
76
|
+
}
|
|
77
|
+
const failed = results.filter((r) => !r.success);
|
|
78
|
+
for (const r of failed) {
|
|
79
|
+
p.log.warn(`Failed for ${getAgentDisplayName(r.agent)}: ${r.error}`);
|
|
23
80
|
}
|
|
24
81
|
}
|
|
25
82
|
catch (err) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
results.push({ slug, status: `failed: ${msg}` });
|
|
29
|
-
if (!jsonFlag) {
|
|
30
|
-
console.error(` Failed: ${slug} - ${msg}`);
|
|
31
|
-
}
|
|
83
|
+
spin.error(`Failed to install ${slug}`);
|
|
84
|
+
p.log.error(err instanceof Error ? err.message : String(err));
|
|
32
85
|
}
|
|
33
86
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
87
|
+
// Offer to install globally
|
|
88
|
+
console.log();
|
|
89
|
+
const installGlobal = await p.confirm({
|
|
90
|
+
message: 'Install ags globally? (npm install -g @agentskill.sh/cli)',
|
|
91
|
+
initialValue: false,
|
|
92
|
+
});
|
|
93
|
+
if (!p.isCancel(installGlobal) && installGlobal) {
|
|
94
|
+
const gs = p.spinner();
|
|
95
|
+
gs.start('Installing globally...');
|
|
96
|
+
try {
|
|
97
|
+
const { execSync } = await import('child_process');
|
|
98
|
+
execSync('npm install -g @agentskill.sh/cli', { stdio: 'pipe' });
|
|
99
|
+
gs.stop('Installed globally');
|
|
100
|
+
p.log.success('You can now use `ags` from anywhere.');
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
gs.error('Global install failed');
|
|
104
|
+
p.log.info('You can install manually: npm install -g @agentskill.sh/cli');
|
|
105
|
+
}
|
|
40
106
|
}
|
|
107
|
+
console.log();
|
|
108
|
+
p.outro(pc.green('Setup complete! Restart your agent to use the new skills.'));
|
|
41
109
|
}
|
package/dist/commands/update.js
CHANGED
|
@@ -1,133 +1,103 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import { existsSync } from 'fs';
|
|
1
|
+
import * as p from '@clack/prompts';
|
|
2
|
+
import pc from 'picocolors';
|
|
4
3
|
import { apiFetch } from '../api.js';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const lines = content.split('\n');
|
|
10
|
-
let inHeader = false;
|
|
11
|
-
for (const line of lines) {
|
|
12
|
-
if (line.trim() === '# --- agentskill.sh ---') {
|
|
13
|
-
inHeader = true;
|
|
14
|
-
continue;
|
|
15
|
-
}
|
|
16
|
-
if (line.trim() === '# ---')
|
|
17
|
-
break;
|
|
18
|
-
if (inHeader && line.startsWith('# ')) {
|
|
19
|
-
const match = line.match(/^# (\w+): (.+)$/);
|
|
20
|
-
if (match)
|
|
21
|
-
meta[match[1]] = match[2];
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
return meta;
|
|
25
|
-
}
|
|
26
|
-
async function scanInstalled(baseDir) {
|
|
27
|
-
const skills = [];
|
|
28
|
-
async function scan(dir, depth) {
|
|
29
|
-
if (depth > 2)
|
|
30
|
-
return;
|
|
31
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
32
|
-
for (const entry of entries) {
|
|
33
|
-
if (!entry.isDirectory())
|
|
34
|
-
continue;
|
|
35
|
-
const entryPath = join(dir, entry.name);
|
|
36
|
-
const skillMdPath = join(entryPath, 'SKILL.md');
|
|
37
|
-
if (existsSync(skillMdPath)) {
|
|
38
|
-
try {
|
|
39
|
-
const content = await readFile(skillMdPath, 'utf-8');
|
|
40
|
-
const meta = parseHeader(content);
|
|
41
|
-
if (meta.slug) {
|
|
42
|
-
skills.push({
|
|
43
|
-
slug: meta.slug,
|
|
44
|
-
owner: meta.owner || '',
|
|
45
|
-
contentSha: meta.contentSha || '',
|
|
46
|
-
dir: entryPath,
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
catch {
|
|
51
|
-
// Skip unreadable
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
await scan(entryPath, depth + 1);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
await scan(baseDir, 0);
|
|
60
|
-
return skills;
|
|
61
|
-
}
|
|
4
|
+
import { readLock, addToLock } from '../skill-lock.js';
|
|
5
|
+
import { installToAgents } from '../installer.js';
|
|
6
|
+
import { getAgentDisplayName } from '../agents.js';
|
|
7
|
+
import { ORANGE } from '../ui.js';
|
|
62
8
|
export async function updateCommand(args) {
|
|
63
9
|
const jsonFlag = args.includes('--json');
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
if (jsonFlag) {
|
|
67
|
-
console.log(JSON.stringify({ updated: [], upToDate: 0 }));
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
console.log('No skills installed.');
|
|
71
|
-
}
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
const installed = await scanInstalled(baseDir);
|
|
10
|
+
const lock = readLock();
|
|
11
|
+
const installed = Object.values(lock.skills).filter((sk) => sk.slug && sk.contentSha);
|
|
75
12
|
if (!installed.length) {
|
|
76
13
|
if (jsonFlag) {
|
|
77
14
|
console.log(JSON.stringify({ updated: [], upToDate: 0 }));
|
|
78
15
|
}
|
|
79
16
|
else {
|
|
80
|
-
|
|
17
|
+
p.log.warn('No skills installed.');
|
|
81
18
|
}
|
|
82
19
|
return;
|
|
83
20
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
21
|
+
const s = p.spinner();
|
|
22
|
+
s.start('Checking for updates...');
|
|
23
|
+
let remote;
|
|
24
|
+
try {
|
|
25
|
+
const slugs = installed.map((sk) => sk.slug).join(',');
|
|
26
|
+
remote = await apiFetch(`/agent/skills/version?slugs=${encodeURIComponent(slugs)}`);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
s.error('Failed to check versions');
|
|
30
|
+
throw err;
|
|
31
|
+
}
|
|
87
32
|
const remoteMap = new Map(remote.map((r) => [r.slug, r.contentSha]));
|
|
88
|
-
const outdated = installed.filter((
|
|
33
|
+
const outdated = installed.filter((sk) => remoteMap.has(sk.slug) && remoteMap.get(sk.slug) !== sk.contentSha);
|
|
89
34
|
if (!outdated.length) {
|
|
35
|
+
s.stop(`All ${installed.length} skill${installed.length !== 1 ? 's' : ''} up to date`);
|
|
90
36
|
if (jsonFlag) {
|
|
91
37
|
console.log(JSON.stringify({ updated: [], upToDate: installed.length }));
|
|
92
38
|
}
|
|
93
|
-
else {
|
|
94
|
-
console.log(`All ${installed.length} skill(s) are up to date.`);
|
|
95
|
-
}
|
|
96
39
|
return;
|
|
97
40
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
await installCommand([s.slug, '--json']);
|
|
112
|
-
updated.push(s.slug);
|
|
113
|
-
if (!jsonFlag) {
|
|
114
|
-
console.log(` Updated: ${s.slug}`);
|
|
41
|
+
s.stop(`${outdated.length} update${outdated.length !== 1 ? 's' : ''} available`);
|
|
42
|
+
if (jsonFlag) {
|
|
43
|
+
// In JSON mode, proceed without confirmation
|
|
44
|
+
const updated = [];
|
|
45
|
+
for (const sk of outdated) {
|
|
46
|
+
try {
|
|
47
|
+
const data = await apiFetch(`/agent/skills/${encodeURIComponent(sk.slug)}/install`);
|
|
48
|
+
const results = installToAgents(data, sk.agents);
|
|
49
|
+
const successful = results.filter((r) => r.success);
|
|
50
|
+
if (successful.length) {
|
|
51
|
+
addToLock(data.slug, data.contentSha || '', sk.agents);
|
|
52
|
+
updated.push(sk.slug);
|
|
53
|
+
}
|
|
115
54
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
119
|
-
if (!jsonFlag) {
|
|
120
|
-
console.error(` Failed to update ${s.slug}: ${msg}`);
|
|
55
|
+
catch {
|
|
56
|
+
// Skip failed
|
|
121
57
|
}
|
|
122
58
|
}
|
|
123
|
-
}
|
|
124
|
-
if (jsonFlag) {
|
|
125
59
|
console.log(JSON.stringify({
|
|
126
60
|
updated,
|
|
127
61
|
upToDate: installed.length - outdated.length,
|
|
128
62
|
}, null, 2));
|
|
63
|
+
return;
|
|
129
64
|
}
|
|
130
|
-
|
|
131
|
-
|
|
65
|
+
// Show what will be updated
|
|
66
|
+
for (const sk of outdated) {
|
|
67
|
+
const agentNames = sk.agents.map((a) => getAgentDisplayName(a)).join(', ');
|
|
68
|
+
p.log.info(`${ORANGE(sk.slug)} ${pc.dim(`(${agentNames})`)}`);
|
|
69
|
+
}
|
|
70
|
+
const proceed = await p.confirm({
|
|
71
|
+
message: `Update ${outdated.length} skill${outdated.length !== 1 ? 's' : ''}?`,
|
|
72
|
+
});
|
|
73
|
+
if (p.isCancel(proceed) || !proceed) {
|
|
74
|
+
p.cancel('Update cancelled.');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
// Update each skill
|
|
78
|
+
const updated = [];
|
|
79
|
+
for (const sk of outdated) {
|
|
80
|
+
const spin = p.spinner();
|
|
81
|
+
spin.start(`Updating ${sk.slug}...`);
|
|
82
|
+
try {
|
|
83
|
+
const data = await apiFetch(`/agent/skills/${encodeURIComponent(sk.slug)}/install`);
|
|
84
|
+
// Reinstall to the same agents
|
|
85
|
+
const results = installToAgents(data, sk.agents);
|
|
86
|
+
const successful = results.filter((r) => r.success);
|
|
87
|
+
if (successful.length) {
|
|
88
|
+
addToLock(data.slug, data.contentSha || '', sk.agents);
|
|
89
|
+
updated.push(sk.slug);
|
|
90
|
+
spin.stop(`Updated ${ORANGE(sk.slug)}`);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
spin.error(`Failed to update ${sk.slug}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
spin.error(`Failed to update ${sk.slug}`);
|
|
98
|
+
p.log.error(err instanceof Error ? err.message : String(err));
|
|
99
|
+
}
|
|
132
100
|
}
|
|
101
|
+
console.log();
|
|
102
|
+
p.log.success(`${updated.length} updated, ${installed.length - outdated.length} already current.`);
|
|
133
103
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,98 +1,130 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const VERSION =
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
ags update
|
|
41
|
-
|
|
42
|
-
More info: https://agentskill.sh/install
|
|
43
|
-
`;
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
|
+
import { join, dirname } from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import pc from 'picocolors';
|
|
6
|
+
import { showLogo, ORANGE, DIM } from './ui.js';
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
9
|
+
const VERSION = pkg.version;
|
|
10
|
+
const CMD = 'npx @agentskill.sh/cli';
|
|
11
|
+
function printHelp() {
|
|
12
|
+
showLogo();
|
|
13
|
+
console.log(` ${DIM('The package manager for AI agent skills')} ${DIM('v' + VERSION)}`);
|
|
14
|
+
console.log();
|
|
15
|
+
console.log(` ${pc.bold('Usage:')}`);
|
|
16
|
+
console.log(` ${DIM('$')} ${CMD} ${ORANGE('<command>')} ${DIM('[options]')}`);
|
|
17
|
+
console.log();
|
|
18
|
+
console.log(` ${pc.bold('Commands:')}`);
|
|
19
|
+
console.log(` ${ORANGE('search')} ${DIM('s')} Search for skills on agentskill.sh`);
|
|
20
|
+
console.log(` ${ORANGE('install')} ${DIM('i')} Install a skill to your project`);
|
|
21
|
+
console.log(` ${ORANGE('setup')} Install all official agentskill.sh skills`);
|
|
22
|
+
console.log(` ${ORANGE('find')} ${DIM('f')} Browse and discover skills interactively`);
|
|
23
|
+
console.log(` ${ORANGE('init')} Scaffold a new SKILL.md`);
|
|
24
|
+
console.log(` ${ORANGE('list')} ${DIM('ls')} Show installed skills`);
|
|
25
|
+
console.log(` ${ORANGE('remove')} ${DIM('rm')} Uninstall a skill`);
|
|
26
|
+
console.log(` ${ORANGE('feedback')} ${DIM('rate')} Rate a skill (1-5) with optional comment`);
|
|
27
|
+
console.log(` ${ORANGE('update')} Update installed skills to latest versions`);
|
|
28
|
+
console.log();
|
|
29
|
+
console.log(` ${pc.bold('Examples:')}`);
|
|
30
|
+
console.log(` ${DIM('$')} ${CMD} setup`);
|
|
31
|
+
console.log(` ${DIM('$')} ${CMD} search react`);
|
|
32
|
+
console.log(` ${DIM('$')} ${CMD} install seo-optimizer`);
|
|
33
|
+
console.log(` ${DIM('$')} ${CMD} install @anthropics/react-best-practices`);
|
|
34
|
+
console.log(` ${DIM('$')} ${CMD} list`);
|
|
35
|
+
console.log(` ${DIM('$')} ${CMD} feedback seo-optimizer 5 "Worked perfectly"`);
|
|
36
|
+
console.log();
|
|
37
|
+
console.log(` ${DIM('More info:')} ${pc.underline('https://agentskill.sh/install')}`);
|
|
38
|
+
console.log();
|
|
39
|
+
}
|
|
44
40
|
async function main() {
|
|
45
41
|
const args = process.argv.slice(2);
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
// No args: show full banner with commands
|
|
43
|
+
if (args.length === 0) {
|
|
44
|
+
printHelp();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// Flags that bypass command routing
|
|
48
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
49
|
+
printHelp();
|
|
48
50
|
return;
|
|
49
51
|
}
|
|
50
52
|
if (args.includes('--version') || args.includes('-v')) {
|
|
51
53
|
console.log(VERSION);
|
|
52
54
|
return;
|
|
53
55
|
}
|
|
56
|
+
// Show logo on interactive commands (skip for --json)
|
|
57
|
+
if (!args.includes('--json')) {
|
|
58
|
+
showLogo();
|
|
59
|
+
}
|
|
54
60
|
const command = args[0];
|
|
55
61
|
const commandArgs = args.slice(1);
|
|
56
62
|
try {
|
|
57
63
|
switch (command) {
|
|
58
64
|
case 'search':
|
|
59
|
-
case 's':
|
|
65
|
+
case 's': {
|
|
66
|
+
const { searchCommand } = await import('./commands/search.js');
|
|
60
67
|
await searchCommand(commandArgs);
|
|
61
68
|
break;
|
|
69
|
+
}
|
|
62
70
|
case 'install':
|
|
63
|
-
case 'i':
|
|
71
|
+
case 'i': {
|
|
72
|
+
const { installCommand } = await import('./commands/install.js');
|
|
64
73
|
await installCommand(commandArgs);
|
|
65
74
|
break;
|
|
75
|
+
}
|
|
76
|
+
case 'setup': {
|
|
77
|
+
const { setupCommand } = await import('./commands/setup.js');
|
|
78
|
+
await setupCommand(commandArgs);
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
case 'init': {
|
|
82
|
+
const { initCommand } = await import('./commands/init.js');
|
|
83
|
+
await initCommand(commandArgs);
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
case 'find':
|
|
87
|
+
case 'f': {
|
|
88
|
+
const { findCommand } = await import('./commands/find.js');
|
|
89
|
+
await findCommand(commandArgs);
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
66
92
|
case 'list':
|
|
67
|
-
case 'ls':
|
|
93
|
+
case 'ls': {
|
|
94
|
+
const { listCommand } = await import('./commands/list.js');
|
|
68
95
|
await listCommand(commandArgs);
|
|
69
96
|
break;
|
|
97
|
+
}
|
|
70
98
|
case 'remove':
|
|
71
|
-
case 'rm':
|
|
72
|
-
|
|
99
|
+
case 'rm': {
|
|
100
|
+
const { removeCommand } = await import('./commands/remove.js');
|
|
73
101
|
await removeCommand(commandArgs);
|
|
74
102
|
break;
|
|
103
|
+
}
|
|
75
104
|
case 'feedback':
|
|
76
|
-
case 'rate':
|
|
105
|
+
case 'rate': {
|
|
106
|
+
const { feedbackCommand } = await import('./commands/feedback.js');
|
|
77
107
|
await feedbackCommand(commandArgs);
|
|
78
108
|
break;
|
|
79
|
-
|
|
80
|
-
case '
|
|
109
|
+
}
|
|
110
|
+
case 'update': {
|
|
111
|
+
const { updateCommand } = await import('./commands/update.js');
|
|
81
112
|
await updateCommand(commandArgs);
|
|
82
113
|
break;
|
|
83
|
-
|
|
84
|
-
case 'init':
|
|
85
|
-
await setupCommand(commandArgs);
|
|
86
|
-
break;
|
|
114
|
+
}
|
|
87
115
|
default:
|
|
88
|
-
console.
|
|
89
|
-
console.
|
|
116
|
+
console.log(` ${pc.red('Unknown command:')} ${command}`);
|
|
117
|
+
console.log();
|
|
118
|
+
console.log(` Run ${DIM(`${CMD} --help`)} for usage.`);
|
|
119
|
+
console.log();
|
|
90
120
|
process.exit(1);
|
|
91
121
|
}
|
|
92
122
|
}
|
|
93
123
|
catch (err) {
|
|
94
124
|
const message = err instanceof Error ? err.message : String(err);
|
|
95
|
-
console.
|
|
125
|
+
console.log();
|
|
126
|
+
console.log(` ${pc.red('Error:')} ${message}`);
|
|
127
|
+
console.log();
|
|
96
128
|
process.exit(1);
|
|
97
129
|
}
|
|
98
130
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AgentType, InstallResponse, InstallMode } from './types.js';
|
|
2
|
+
export interface InstallOptions {
|
|
3
|
+
global?: boolean;
|
|
4
|
+
mode?: InstallMode;
|
|
5
|
+
}
|
|
6
|
+
export interface InstallResult {
|
|
7
|
+
agent: string;
|
|
8
|
+
dir: string;
|
|
9
|
+
files: string[];
|
|
10
|
+
success: boolean;
|
|
11
|
+
error?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Sanitize a skill name into a filesystem-safe slug.
|
|
15
|
+
* Strips @owner/ prefix, lowercases, replaces non-alphanumeric with hyphens.
|
|
16
|
+
*/
|
|
17
|
+
export declare function sanitizeName(name: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Install a skill to a single agent directory.
|
|
20
|
+
* Returns the path where the skill was installed.
|
|
21
|
+
*/
|
|
22
|
+
export declare function installSkillToAgent(skillData: InstallResponse, agentType: AgentType, options?: InstallOptions): InstallResult;
|
|
23
|
+
/**
|
|
24
|
+
* Install a skill to multiple agents.
|
|
25
|
+
*
|
|
26
|
+
* Strategy:
|
|
27
|
+
* 1. First agent gets the canonical (full) copy of all files.
|
|
28
|
+
* 2. Remaining agents get a directory symlink pointing to the canonical copy.
|
|
29
|
+
* 3. If symlink creation fails (permissions, cross-device, Windows), falls back to a full copy.
|
|
30
|
+
*
|
|
31
|
+
* Set options.mode = 'copy' to skip symlinks entirely.
|
|
32
|
+
*/
|
|
33
|
+
export declare function installToAgents(skillData: InstallResponse, agentTypes: AgentType[], options?: InstallOptions): InstallResult[];
|