overskill 1.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/LICENSE +21 -0
- package/README.md +261 -0
- package/dist/commands/add.d.ts +3 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +121 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/bundle.d.ts +3 -0
- package/dist/commands/bundle.d.ts.map +1 -0
- package/dist/commands/bundle.js +58 -0
- package/dist/commands/bundle.js.map +1 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +109 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/delete.d.ts +3 -0
- package/dist/commands/delete.d.ts.map +1 -0
- package/dist/commands/delete.js +64 -0
- package/dist/commands/delete.js.map +1 -0
- package/dist/commands/diff.d.ts +3 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +93 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/edit.d.ts +3 -0
- package/dist/commands/edit.d.ts.map +1 -0
- package/dist/commands/edit.js +69 -0
- package/dist/commands/edit.js.map +1 -0
- package/dist/commands/import.d.ts +3 -0
- package/dist/commands/import.d.ts.map +1 -0
- package/dist/commands/import.js +514 -0
- package/dist/commands/import.js.map +1 -0
- package/dist/commands/info.d.ts +3 -0
- package/dist/commands/info.d.ts.map +1 -0
- package/dist/commands/info.js +89 -0
- package/dist/commands/info.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +88 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +84 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/login.d.ts +3 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +143 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/new.d.ts +3 -0
- package/dist/commands/new.d.ts.map +1 -0
- package/dist/commands/new.js +262 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/publish.d.ts +3 -0
- package/dist/commands/publish.d.ts.map +1 -0
- package/dist/commands/publish.js +215 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/push.d.ts +3 -0
- package/dist/commands/push.d.ts.map +1 -0
- package/dist/commands/push.js +151 -0
- package/dist/commands/push.js.map +1 -0
- package/dist/commands/registry.d.ts +3 -0
- package/dist/commands/registry.d.ts.map +1 -0
- package/dist/commands/registry.js +169 -0
- package/dist/commands/registry.js.map +1 -0
- package/dist/commands/remove.d.ts +3 -0
- package/dist/commands/remove.d.ts.map +1 -0
- package/dist/commands/remove.js +48 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/search.d.ts +3 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +48 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/sync.d.ts +3 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +160 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/update.d.ts +3 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +130 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/validate.d.ts +3 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +94 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api.d.ts +60 -0
- package/dist/lib/api.d.ts.map +1 -0
- package/dist/lib/api.js +340 -0
- package/dist/lib/api.js.map +1 -0
- package/dist/lib/auth.d.ts +78 -0
- package/dist/lib/auth.d.ts.map +1 -0
- package/dist/lib/auth.js +241 -0
- package/dist/lib/auth.js.map +1 -0
- package/dist/lib/config.d.ts +94 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +294 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/editor.d.ts +6 -0
- package/dist/lib/editor.d.ts.map +1 -0
- package/dist/lib/editor.js +60 -0
- package/dist/lib/editor.js.map +1 -0
- package/dist/lib/fs.d.ts +74 -0
- package/dist/lib/fs.d.ts.map +1 -0
- package/dist/lib/fs.js +235 -0
- package/dist/lib/fs.js.map +1 -0
- package/dist/lib/index-gen.d.ts +18 -0
- package/dist/lib/index-gen.d.ts.map +1 -0
- package/dist/lib/index-gen.js +75 -0
- package/dist/lib/index-gen.js.map +1 -0
- package/dist/lib/local-registry/index.d.ts +15 -0
- package/dist/lib/local-registry/index.d.ts.map +1 -0
- package/dist/lib/local-registry/index.js +18 -0
- package/dist/lib/local-registry/index.js.map +1 -0
- package/dist/lib/local-registry/objects.d.ts +51 -0
- package/dist/lib/local-registry/objects.d.ts.map +1 -0
- package/dist/lib/local-registry/objects.js +148 -0
- package/dist/lib/local-registry/objects.js.map +1 -0
- package/dist/lib/local-registry/paths.d.ts +53 -0
- package/dist/lib/local-registry/paths.d.ts.map +1 -0
- package/dist/lib/local-registry/paths.js +85 -0
- package/dist/lib/local-registry/paths.js.map +1 -0
- package/dist/lib/local-registry/skills.d.ts +83 -0
- package/dist/lib/local-registry/skills.d.ts.map +1 -0
- package/dist/lib/local-registry/skills.js +261 -0
- package/dist/lib/local-registry/skills.js.map +1 -0
- package/dist/lib/local-registry/types.d.ts +79 -0
- package/dist/lib/local-registry/types.d.ts.map +1 -0
- package/dist/lib/local-registry/types.js +5 -0
- package/dist/lib/local-registry/types.js.map +1 -0
- package/dist/lib/local-registry/versions.d.ts +61 -0
- package/dist/lib/local-registry/versions.d.ts.map +1 -0
- package/dist/lib/local-registry/versions.js +163 -0
- package/dist/lib/local-registry/versions.js.map +1 -0
- package/dist/lib/lockfile.d.ts +38 -0
- package/dist/lib/lockfile.d.ts.map +1 -0
- package/dist/lib/lockfile.js +102 -0
- package/dist/lib/lockfile.js.map +1 -0
- package/dist/lib/meta-skill.d.ts +6 -0
- package/dist/lib/meta-skill.d.ts.map +1 -0
- package/dist/lib/meta-skill.js +72 -0
- package/dist/lib/meta-skill.js.map +1 -0
- package/dist/lib/semver.d.ts +63 -0
- package/dist/lib/semver.d.ts.map +1 -0
- package/dist/lib/semver.js +107 -0
- package/dist/lib/semver.js.map +1 -0
- package/dist/types.d.ts +147 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { confirm } from '@inquirer/prompts';
|
|
5
|
+
import * as config from '../lib/config.js';
|
|
6
|
+
import * as auth from '../lib/auth.js';
|
|
7
|
+
import { updateGitignore, ensureDir } from '../lib/fs.js';
|
|
8
|
+
import { ensureRegistryStructure } from '../lib/local-registry/index.js';
|
|
9
|
+
export const initCommand = new Command('init')
|
|
10
|
+
.description('Initialize a new skills configuration in the current directory')
|
|
11
|
+
.option('--cloud', 'Include a cloud registry source')
|
|
12
|
+
.option('-u, --url <url>', 'API URL for the cloud registry (requires --cloud)')
|
|
13
|
+
.option('-r, --registry <slug>', 'Cloud registry slug (requires --cloud)')
|
|
14
|
+
.option('-p, --path <path>', 'Install path for skills', '.skills')
|
|
15
|
+
.action(async (options) => {
|
|
16
|
+
try {
|
|
17
|
+
// Check if already initialized
|
|
18
|
+
if (config.configExists()) {
|
|
19
|
+
console.log(chalk.yellow('Skills configuration already exists in this directory.'));
|
|
20
|
+
console.log('Use `skill sync` to sync skills or edit .skills.yaml manually.');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const installPath = options.path || auth.getDefaultInstallPath();
|
|
24
|
+
// Build sources list
|
|
25
|
+
const sources = [];
|
|
26
|
+
// Always add local source as default
|
|
27
|
+
sources.push(config.createLocalSource('local'));
|
|
28
|
+
// Optionally add cloud source
|
|
29
|
+
if (options.cloud) {
|
|
30
|
+
const apiUrl = options.url || auth.getApiUrl();
|
|
31
|
+
if (!apiUrl) {
|
|
32
|
+
console.log(chalk.red('Error: API URL is required for cloud source.'));
|
|
33
|
+
console.log('Provide it with --url or set it globally with `skills config api_url <url>`');
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
const registry = options.registry;
|
|
37
|
+
if (!registry) {
|
|
38
|
+
console.log(chalk.red('Error: Registry slug is required for cloud source.'));
|
|
39
|
+
console.log('Provide it with --registry <slug>');
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
sources.push(config.createCloudSource('cloud', registry, apiUrl));
|
|
43
|
+
}
|
|
44
|
+
// Create config
|
|
45
|
+
const skillsConfig = {
|
|
46
|
+
sources,
|
|
47
|
+
install_path: installPath,
|
|
48
|
+
skills: [],
|
|
49
|
+
};
|
|
50
|
+
// Write config
|
|
51
|
+
config.writeConfig(skillsConfig);
|
|
52
|
+
// Create install directory
|
|
53
|
+
const fullInstallPath = path.join(process.cwd(), installPath);
|
|
54
|
+
ensureDir(fullInstallPath);
|
|
55
|
+
// Ensure local registry structure exists
|
|
56
|
+
ensureRegistryStructure();
|
|
57
|
+
const trackInGit = await confirm({
|
|
58
|
+
message: 'Track skills in git? Tracking skills in git allows coding agents that clone your repo to see the included skills. If your skills include private information, respond "no".',
|
|
59
|
+
default: false,
|
|
60
|
+
});
|
|
61
|
+
// Update .gitignore if user does not want to track skills in git
|
|
62
|
+
if (!trackInGit) {
|
|
63
|
+
updateGitignore(installPath);
|
|
64
|
+
}
|
|
65
|
+
console.log(chalk.green('Initialized skills configuration!'));
|
|
66
|
+
console.log('');
|
|
67
|
+
console.log('Created files:');
|
|
68
|
+
console.log(` ${chalk.cyan('.skills.yaml')} - Configuration file`);
|
|
69
|
+
console.log(` ${chalk.cyan(installPath + '/')} - Skills install directory`);
|
|
70
|
+
console.log('');
|
|
71
|
+
console.log('Next steps:');
|
|
72
|
+
console.log(` ${chalk.cyan('skill import')} Import skills from Claude, Cursor, etc.`);
|
|
73
|
+
console.log(` ${chalk.cyan('skill new <slug>')} Create a new skill`);
|
|
74
|
+
console.log(` ${chalk.cyan('skill add <slug>')} Add an existing skill from cache`);
|
|
75
|
+
console.log(` ${chalk.cyan('skill sync')} Install skills to ${installPath}/`);
|
|
76
|
+
if (options.cloud) {
|
|
77
|
+
console.log('');
|
|
78
|
+
console.log('Cloud registry configured:');
|
|
79
|
+
console.log(` ${chalk.cyan('skill login')} Authenticate with cloud registry`);
|
|
80
|
+
console.log(` ${chalk.cyan('skill cache pull')} Pull skills from cloud to local cache`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAC3C,OAAO,KAAK,IAAI,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAGzE,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC3C,WAAW,CAAC,gEAAgE,CAAC;KAC7E,MAAM,CAAC,SAAS,EAAE,iCAAiC,CAAC;KACpD,MAAM,CAAC,iBAAiB,EAAE,mDAAmD,CAAC;KAC9E,MAAM,CAAC,uBAAuB,EAAE,wCAAwC,CAAC;KACzE,MAAM,CAAC,mBAAmB,EAAE,yBAAyB,EAAE,SAAS,CAAC;KACjE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,IAAI,CAAC;QACH,+BAA+B;QAC/B,IAAI,MAAM,CAAC,YAAY,EAAE,EAAE,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,wDAAwD,CAAC,CAAC,CAAC;YACpF,OAAO,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;YAC9E,OAAO;QACT,CAAC;QAED,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAEjE,qBAAqB;QACrB,MAAM,OAAO,GAAkB,EAAE,CAAC;QAElC,qCAAqC;QACrC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC;QAEhD,8BAA8B;QAC9B,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAClB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YAC/C,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC,CAAC;gBACvE,OAAO,CAAC,GAAG,CAAC,6EAA6E,CAAC,CAAC;gBAC3F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;YAClC,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC,CAAC;gBAC7E,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;gBACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;QACpE,CAAC;QAED,gBAAgB;QAChB,MAAM,YAAY,GAAiB;YACjC,OAAO;YACP,YAAY,EAAE,WAAW;YACzB,MAAM,EAAE,EAAE;SACX,CAAC;QAEF,eAAe;QACf,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;QAEjC,2BAA2B;QAC3B,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,WAAW,CAAC,CAAC;QAC9D,SAAS,CAAC,eAAe,CAAC,CAAC;QAE3B,yCAAyC;QACzC,uBAAuB,EAAE,CAAC;QAE1B,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC;YAC/B,OAAO,EACL,6KAA6K;YAC/K,OAAO,EAAE,KAAK;SACf,CAAC,CAAC;QAEH,iEAAiE;QACjE,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,eAAe,CAAC,WAAW,CAAC,CAAC;QAC/B,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC,CAAC;QAC9D,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,uBAAuB,CAAC,CAAC;QACpE,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC,6BAA6B,CAAC,CAAC;QAC7E,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,mDAAmD,CAAC,CAAC;QAChG,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,0BAA0B,CAAC,CAAC;QAC3E,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,wCAAwC,CAAC,CAAC;QACzF,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,iCAAiC,WAAW,GAAG,CAAC,CAAC;QAE1F,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,6CAA6C,CAAC,CAAC;YACzF,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,6CAA6C,CAAC,CAAC;QAChG,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACnF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,eAAO,MAAM,WAAW,SAkGpB,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import * as config from '../lib/config.js';
|
|
4
|
+
import * as localRegistry from '../lib/local-registry/index.js';
|
|
5
|
+
import * as lockfile from '../lib/lockfile.js';
|
|
6
|
+
export const listCommand = new Command('list')
|
|
7
|
+
.description('List skills')
|
|
8
|
+
.option('-i, --installed', 'List only installed skills in current project')
|
|
9
|
+
.option('-l, --local', 'List skills from local registry cache')
|
|
10
|
+
.option('-t, --tags <tags>', 'Filter by tags (comma-separated)')
|
|
11
|
+
.option('-c, --compat <compat>', 'Filter by compatibility (comma-separated)')
|
|
12
|
+
.action(async (options) => {
|
|
13
|
+
try {
|
|
14
|
+
if (options.installed) {
|
|
15
|
+
// List installed skills in current project
|
|
16
|
+
if (!config.configExists()) {
|
|
17
|
+
console.log(chalk.red('Error: Not in a skills project.'));
|
|
18
|
+
console.log(`Run ${chalk.cyan('skills init')} first.`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
const skillsConfig = config.readConfig();
|
|
22
|
+
const lock = lockfile.readLockfile();
|
|
23
|
+
if (skillsConfig.skills.length === 0) {
|
|
24
|
+
console.log(chalk.yellow('No skills configured in this project.'));
|
|
25
|
+
console.log(`Run ${chalk.cyan('skills add <slug>')} to add skills.`);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
console.log(chalk.bold('Project Skills:'));
|
|
29
|
+
console.log('');
|
|
30
|
+
for (const skill of skillsConfig.skills) {
|
|
31
|
+
const locked = lock?.skills.find((s) => s.slug === skill.slug);
|
|
32
|
+
const lockedVersion = locked?.version || 'not synced';
|
|
33
|
+
// Check if update available
|
|
34
|
+
const latestCached = localRegistry.getLatestVersion(skill.slug);
|
|
35
|
+
const hasUpdate = latestCached && locked?.version && latestCached !== locked.version;
|
|
36
|
+
const constraint = skill.version ? chalk.gray(` (${skill.version})`) : '';
|
|
37
|
+
const updateNote = hasUpdate ? chalk.yellow(` → ${latestCached} available`) : '';
|
|
38
|
+
console.log(` ${chalk.cyan(skill.slug.padEnd(25))} v${lockedVersion.padEnd(12)}${constraint}${updateNote}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
// List all skills in local registry cache
|
|
43
|
+
let skills = localRegistry.listSkills();
|
|
44
|
+
if (skills.length === 0) {
|
|
45
|
+
console.log(chalk.yellow('No skills in local cache.'));
|
|
46
|
+
console.log('');
|
|
47
|
+
console.log('To add skills:');
|
|
48
|
+
console.log(` ${chalk.cyan('skills new <slug>')} Create a new skill`);
|
|
49
|
+
console.log(` ${chalk.cyan('skills cache import <path>')} Import from a file`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// Filter by tags
|
|
53
|
+
if (options.tags) {
|
|
54
|
+
const filterTags = options.tags.split(',').map((t) => t.trim().toLowerCase());
|
|
55
|
+
skills = skills.filter((skill) => skill.meta.tags.some((tag) => filterTags.includes(tag.toLowerCase())));
|
|
56
|
+
}
|
|
57
|
+
// Filter by compat
|
|
58
|
+
if (options.compat) {
|
|
59
|
+
const filterCompat = options.compat.split(',').map((c) => c.trim().toLowerCase());
|
|
60
|
+
skills = skills.filter((skill) => skill.meta.compat.some((c) => filterCompat.includes(c.toLowerCase())));
|
|
61
|
+
}
|
|
62
|
+
if (skills.length === 0) {
|
|
63
|
+
console.log(chalk.yellow('No skills match the specified filters.'));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
console.log(chalk.bold(`Local Registry (${skills.length} skills):`));
|
|
67
|
+
console.log('');
|
|
68
|
+
for (const skill of skills) {
|
|
69
|
+
const description = skill.meta.description
|
|
70
|
+
? chalk.gray(` - ${skill.meta.description.substring(0, 50)}${skill.meta.description.length > 50 ? '...' : ''}`)
|
|
71
|
+
: '';
|
|
72
|
+
const versionInfo = skill.versionCount > 1
|
|
73
|
+
? chalk.gray(` (${skill.versionCount} versions)`)
|
|
74
|
+
: '';
|
|
75
|
+
console.log(` ${chalk.cyan(skill.slug.padEnd(25))} v${skill.latestVersion.padEnd(10)}${versionInfo}${description}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwBpC,eAAO,MAAM,YAAY,SAqHrB,CAAC"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { createServer } from 'http';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import open from 'open';
|
|
5
|
+
import { ofetch } from 'ofetch';
|
|
6
|
+
import * as auth from '../lib/auth.js';
|
|
7
|
+
const CALLBACK_PORT = 9876;
|
|
8
|
+
/**
|
|
9
|
+
* Get the web app URL for authentication.
|
|
10
|
+
* Falls back to deriving from API URL if not explicitly configured.
|
|
11
|
+
*/
|
|
12
|
+
function getAuthUrl() {
|
|
13
|
+
// Check for explicit web app URL first
|
|
14
|
+
const webAppUrl = auth.getWebAppUrl();
|
|
15
|
+
if (webAppUrl) {
|
|
16
|
+
return webAppUrl;
|
|
17
|
+
}
|
|
18
|
+
// Fall back to default local development URL
|
|
19
|
+
return 'http://localhost:3000';
|
|
20
|
+
}
|
|
21
|
+
export const loginCommand = new Command('login')
|
|
22
|
+
.description('Authenticate with the skills platform')
|
|
23
|
+
.option('--manual', 'Use manual code entry instead of browser redirect')
|
|
24
|
+
.action(async (options) => {
|
|
25
|
+
try {
|
|
26
|
+
const webAppUrl = getAuthUrl();
|
|
27
|
+
if (!webAppUrl) {
|
|
28
|
+
console.log(chalk.red('Error: Web app URL not configured.'));
|
|
29
|
+
console.log(`Run ${chalk.cyan('skills config web_app_url <url>')} first.`);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
// Build login URL for web app
|
|
33
|
+
const redirectUri = `http://localhost:${CALLBACK_PORT}/callback`;
|
|
34
|
+
const state = Math.random().toString(36).substring(7);
|
|
35
|
+
const authorizeUrl = new URL(`${webAppUrl}/login`);
|
|
36
|
+
authorizeUrl.searchParams.set('cli', 'true');
|
|
37
|
+
authorizeUrl.searchParams.set('redirect_uri', redirectUri);
|
|
38
|
+
authorizeUrl.searchParams.set('state', state);
|
|
39
|
+
if (options.manual) {
|
|
40
|
+
// Manual flow - user copies code
|
|
41
|
+
console.log('Open this URL in your browser to log in:');
|
|
42
|
+
console.log('');
|
|
43
|
+
console.log(chalk.cyan(authorizeUrl.toString()));
|
|
44
|
+
console.log('');
|
|
45
|
+
const readline = await import('readline');
|
|
46
|
+
const rl = readline.createInterface({
|
|
47
|
+
input: process.stdin,
|
|
48
|
+
output: process.stdout,
|
|
49
|
+
});
|
|
50
|
+
const code = await new Promise((resolve) => {
|
|
51
|
+
rl.question('Enter the authorization code: ', (answer) => {
|
|
52
|
+
rl.close();
|
|
53
|
+
resolve(answer.trim());
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
await exchangeCodeForTokens(webAppUrl, code);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// Browser flow with local callback server
|
|
60
|
+
console.log('Opening browser for authentication...');
|
|
61
|
+
const code = await new Promise((resolve, reject) => {
|
|
62
|
+
let timeoutId;
|
|
63
|
+
const server = createServer((req, res) => {
|
|
64
|
+
const url = new URL(req.url || '', `http://localhost:${CALLBACK_PORT}`);
|
|
65
|
+
if (url.pathname === '/callback') {
|
|
66
|
+
const authCode = url.searchParams.get('code');
|
|
67
|
+
const returnedState = url.searchParams.get('state');
|
|
68
|
+
if (returnedState !== state) {
|
|
69
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
70
|
+
res.end('<h1>Error: Invalid state</h1>');
|
|
71
|
+
reject(new Error('Invalid state'));
|
|
72
|
+
server.close();
|
|
73
|
+
if (timeoutId)
|
|
74
|
+
clearTimeout(timeoutId);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (!authCode) {
|
|
78
|
+
const error = url.searchParams.get('error') || 'Unknown error';
|
|
79
|
+
res.writeHead(400, { 'Content-Type': 'text/html' });
|
|
80
|
+
res.end(`<h1>Error: ${error}</h1>`);
|
|
81
|
+
reject(new Error(error));
|
|
82
|
+
server.close();
|
|
83
|
+
if (timeoutId)
|
|
84
|
+
clearTimeout(timeoutId);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
88
|
+
res.end(`
|
|
89
|
+
<html>
|
|
90
|
+
<head>
|
|
91
|
+
<style>
|
|
92
|
+
body { font-family: sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }
|
|
93
|
+
.container { background: white; padding: 40px; border-radius: 12px; text-align: center; }
|
|
94
|
+
h1 { color: #333; margin-bottom: 10px; }
|
|
95
|
+
p { color: #666; }
|
|
96
|
+
</style>
|
|
97
|
+
</head>
|
|
98
|
+
<body>
|
|
99
|
+
<div class="container">
|
|
100
|
+
<h1>Authentication Successful!</h1>
|
|
101
|
+
<p>You can close this window and return to the terminal.</p>
|
|
102
|
+
</div>
|
|
103
|
+
</body>
|
|
104
|
+
</html>
|
|
105
|
+
`);
|
|
106
|
+
resolve(authCode);
|
|
107
|
+
server.close();
|
|
108
|
+
if (timeoutId)
|
|
109
|
+
clearTimeout(timeoutId);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
server.listen(CALLBACK_PORT, () => {
|
|
113
|
+
open(authorizeUrl.toString());
|
|
114
|
+
});
|
|
115
|
+
// Timeout after 5 minutes
|
|
116
|
+
timeoutId = setTimeout(() => {
|
|
117
|
+
server.close();
|
|
118
|
+
reject(new Error('Authentication timed out'));
|
|
119
|
+
}, 5 * 60 * 1000);
|
|
120
|
+
});
|
|
121
|
+
await exchangeCodeForTokens(webAppUrl, code);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
async function exchangeCodeForTokens(webAppUrl, code) {
|
|
130
|
+
console.log('Exchanging code for tokens...');
|
|
131
|
+
const response = await ofetch(`${webAppUrl}/api/auth/token`, {
|
|
132
|
+
method: 'POST',
|
|
133
|
+
body: {
|
|
134
|
+
grant_type: 'authorization_code',
|
|
135
|
+
code,
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
auth.setTokens(response.access_token, response.refresh_token, response.expires_in || 3600);
|
|
139
|
+
console.log(chalk.green('Successfully logged in!'));
|
|
140
|
+
// Exit cleanly - the HTTP server's callback connection may still be open
|
|
141
|
+
process.exit(0);
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"new.d.ts","sourceRoot":"","sources":["../../src/commands/new.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqHpC,eAAO,MAAM,UAAU,SAqLnB,CAAC"}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import * as os from 'os';
|
|
5
|
+
import { spawn } from 'child_process';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import ora from 'ora';
|
|
8
|
+
import * as yaml from 'yaml';
|
|
9
|
+
import * as localRegistry from '../lib/local-registry/index.js';
|
|
10
|
+
import * as config from '../lib/config.js';
|
|
11
|
+
import * as auth from '../lib/auth.js';
|
|
12
|
+
import { isValidVersion } from '../lib/semver.js';
|
|
13
|
+
import { parseEditorCommand } from '../lib/editor.js';
|
|
14
|
+
const SKILL_TEMPLATE = `# {{name}}
|
|
15
|
+
|
|
16
|
+
## Instructions
|
|
17
|
+
|
|
18
|
+
<!-- Add your skill instructions here -->
|
|
19
|
+
|
|
20
|
+
## Examples
|
|
21
|
+
|
|
22
|
+
<!-- Add examples of how to use this skill -->
|
|
23
|
+
`;
|
|
24
|
+
function collectMetadata(value, previous) {
|
|
25
|
+
return [...previous, value];
|
|
26
|
+
}
|
|
27
|
+
function parseMetadata(values) {
|
|
28
|
+
const result = {};
|
|
29
|
+
const entries = values ?? [];
|
|
30
|
+
for (const entry of entries) {
|
|
31
|
+
const separatorIndex = entry.indexOf('=');
|
|
32
|
+
if (separatorIndex <= 0 || separatorIndex === entry.length - 1) {
|
|
33
|
+
throw new Error(`Invalid metadata '${entry}'. Use key=value.`);
|
|
34
|
+
}
|
|
35
|
+
const key = entry.slice(0, separatorIndex).trim();
|
|
36
|
+
const value = entry.slice(separatorIndex + 1).trim();
|
|
37
|
+
if (!key || !value) {
|
|
38
|
+
throw new Error(`Invalid metadata '${entry}'. Use non-empty key=value.`);
|
|
39
|
+
}
|
|
40
|
+
result[key] = value;
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
function buildFrontmatter(params) {
|
|
45
|
+
const frontmatter = {
|
|
46
|
+
name: params.name,
|
|
47
|
+
description: params.description,
|
|
48
|
+
};
|
|
49
|
+
if (params.metadata && Object.keys(params.metadata).length > 0) {
|
|
50
|
+
frontmatter.metadata = params.metadata;
|
|
51
|
+
}
|
|
52
|
+
const body = yaml.stringify(frontmatter, { lineWidth: 0 }).trim();
|
|
53
|
+
return `---\n${body}\n---\n\n`;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Open content in the user's preferred editor
|
|
57
|
+
*/
|
|
58
|
+
async function openInEditor(content) {
|
|
59
|
+
const editor = auth.getEditor();
|
|
60
|
+
const tempFile = path.join(os.tmpdir(), `skill-${Date.now()}.md`);
|
|
61
|
+
// Write initial content to temp file
|
|
62
|
+
fs.writeFileSync(tempFile, content, 'utf-8');
|
|
63
|
+
return new Promise((resolve, reject) => {
|
|
64
|
+
let command;
|
|
65
|
+
let args;
|
|
66
|
+
try {
|
|
67
|
+
const parsed = parseEditorCommand(editor);
|
|
68
|
+
command = parsed.command;
|
|
69
|
+
args = parsed.args;
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
fs.unlinkSync(tempFile);
|
|
73
|
+
reject(error);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const child = spawn(command, [...args, tempFile], { stdio: 'inherit' });
|
|
77
|
+
child.on('error', (err) => {
|
|
78
|
+
fs.unlinkSync(tempFile);
|
|
79
|
+
reject(new Error(`Failed to open editor: ${err.message}`));
|
|
80
|
+
});
|
|
81
|
+
child.on('exit', (code) => {
|
|
82
|
+
if (code !== 0) {
|
|
83
|
+
fs.unlinkSync(tempFile);
|
|
84
|
+
reject(new Error(`Editor exited with code ${code}`));
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Read the edited content
|
|
88
|
+
const editedContent = fs.readFileSync(tempFile, 'utf-8');
|
|
89
|
+
fs.unlinkSync(tempFile);
|
|
90
|
+
resolve(editedContent);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
export const newCommand = new Command('new')
|
|
95
|
+
.description('Create a new skill in the local registry')
|
|
96
|
+
.argument('<slug>', 'Skill slug (lowercase, hyphens allowed)')
|
|
97
|
+
.option('-n, --name <name>', 'Skill display name')
|
|
98
|
+
.option('-d, --description <desc>', 'Skill description')
|
|
99
|
+
.option('-t, --tags <tags>', 'Comma-separated tags')
|
|
100
|
+
.option('-c, --compat <compat>', 'Comma-separated compatibility list (e.g., claude,gpt4)')
|
|
101
|
+
.option('-v, --version <version>', 'Initial version', '1.0.0')
|
|
102
|
+
.option('-m, --metadata <key=value>', 'Repeatable metadata to include in SKILL.md frontmatter', collectMetadata, [])
|
|
103
|
+
.option('--content <file>', 'Read content from file instead of opening editor')
|
|
104
|
+
.option('--blank', 'Open editor with blank content (frontmatter only)')
|
|
105
|
+
.option('--no-editor', 'Skip editor and create with template')
|
|
106
|
+
.option('--no-add', 'Skip adding to project after creation')
|
|
107
|
+
.option('--no-sync', 'Skip automatic sync after adding')
|
|
108
|
+
.action(async (slug, options) => {
|
|
109
|
+
try {
|
|
110
|
+
// Validate slug
|
|
111
|
+
if (!/^[a-z0-9-]+$/.test(slug)) {
|
|
112
|
+
console.log(chalk.red('Error: Slug must be lowercase alphanumeric with hyphens only.'));
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
// Check if skill already exists
|
|
116
|
+
if (localRegistry.skillExists(slug)) {
|
|
117
|
+
console.log(chalk.red(`Error: Skill '${slug}' already exists in local registry.`));
|
|
118
|
+
console.log(`Use ${chalk.cyan(`skills publish ${slug}`)} to add a new version.`);
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
// Validate version
|
|
122
|
+
const version = options.version;
|
|
123
|
+
if (!isValidVersion(version)) {
|
|
124
|
+
console.log(chalk.red(`Error: Invalid version '${version}'. Use semver format (e.g., 1.0.0).`));
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
// Parse options
|
|
128
|
+
const name = options.name || slug.split('-').map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
|
|
129
|
+
const description = options.description || '';
|
|
130
|
+
const metadata = parseMetadata(options.metadata);
|
|
131
|
+
const tags = options.tags ? options.tags.split(',').map((t) => t.trim()) : [];
|
|
132
|
+
const compat = options.compat ? options.compat.split(',').map((c) => c.trim()) : [];
|
|
133
|
+
const frontmatterDescription = description || 'A new skill.';
|
|
134
|
+
const frontmatter = buildFrontmatter({
|
|
135
|
+
name: slug,
|
|
136
|
+
description: frontmatterDescription,
|
|
137
|
+
metadata: metadata,
|
|
138
|
+
});
|
|
139
|
+
// Get content
|
|
140
|
+
let content;
|
|
141
|
+
if (options.content) {
|
|
142
|
+
// Read from file
|
|
143
|
+
if (!fs.existsSync(options.content)) {
|
|
144
|
+
console.log(chalk.red(`Error: File not found: ${options.content}`));
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
content = fs.readFileSync(options.content, 'utf-8');
|
|
148
|
+
}
|
|
149
|
+
else if (options.editor === false) {
|
|
150
|
+
// Use template without editor
|
|
151
|
+
content = `${frontmatter}${SKILL_TEMPLATE.replace('{{name}}', name)}`;
|
|
152
|
+
}
|
|
153
|
+
else if (options.blank) {
|
|
154
|
+
// Open editor with blank content (frontmatter only)
|
|
155
|
+
console.log(chalk.gray('Opening editor with blank content...'));
|
|
156
|
+
const blankContent = `${frontmatter}\n`;
|
|
157
|
+
try {
|
|
158
|
+
content = await openInEditor(blankContent);
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
console.log(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
162
|
+
process.exit(1);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
// Open editor with template
|
|
167
|
+
console.log(chalk.gray('Opening editor...'));
|
|
168
|
+
const template = `${frontmatter}${SKILL_TEMPLATE.replace('{{name}}', name)}`;
|
|
169
|
+
try {
|
|
170
|
+
content = await openInEditor(template);
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
console.log(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// Validate content
|
|
178
|
+
if (!content.trim()) {
|
|
179
|
+
console.log(chalk.red('Error: Skill content cannot be empty.'));
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
182
|
+
const spinner = ora('Creating skill...').start();
|
|
183
|
+
try {
|
|
184
|
+
// Save to local registry
|
|
185
|
+
const { sha256 } = localRegistry.putVersion({
|
|
186
|
+
slug,
|
|
187
|
+
version,
|
|
188
|
+
content,
|
|
189
|
+
meta: {
|
|
190
|
+
name,
|
|
191
|
+
description: description || undefined,
|
|
192
|
+
tags,
|
|
193
|
+
compat,
|
|
194
|
+
},
|
|
195
|
+
provenance: {
|
|
196
|
+
kind: 'local',
|
|
197
|
+
source: 'created',
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
spinner.succeed(`Created ${chalk.cyan(slug)}@${version}`);
|
|
201
|
+
console.log('');
|
|
202
|
+
console.log('Skill details:');
|
|
203
|
+
console.log(` ${chalk.bold('Slug:')} ${slug}`);
|
|
204
|
+
console.log(` ${chalk.bold('Name:')} ${name}`);
|
|
205
|
+
console.log(` ${chalk.bold('Version:')} ${version}`);
|
|
206
|
+
console.log(` ${chalk.bold('SHA256:')} ${sha256.substring(0, 16)}...`);
|
|
207
|
+
if (tags.length > 0) {
|
|
208
|
+
console.log(` ${chalk.bold('Tags:')} ${tags.join(', ')}`);
|
|
209
|
+
}
|
|
210
|
+
if (compat.length > 0) {
|
|
211
|
+
console.log(` ${chalk.bold('Compat:')} ${compat.join(', ')}`);
|
|
212
|
+
}
|
|
213
|
+
// Auto-add to project if initialized and not disabled
|
|
214
|
+
const isInProject = config.configExists();
|
|
215
|
+
let addedToProject = false;
|
|
216
|
+
if (isInProject && options.add !== false) {
|
|
217
|
+
const skillsConfig = config.readConfig();
|
|
218
|
+
const existing = skillsConfig.skills.find((s) => s.slug === slug);
|
|
219
|
+
if (!existing) {
|
|
220
|
+
const entry = { slug };
|
|
221
|
+
config.addSkill(entry);
|
|
222
|
+
addedToProject = true;
|
|
223
|
+
console.log('');
|
|
224
|
+
console.log(chalk.green(`Added ${slug} to .skills.yaml`));
|
|
225
|
+
// Run sync if not disabled
|
|
226
|
+
if (options.sync !== false) {
|
|
227
|
+
console.log('');
|
|
228
|
+
console.log('Running sync...');
|
|
229
|
+
const { syncCommand } = await import('./sync.js');
|
|
230
|
+
await syncCommand.parseAsync(['node', 'skills', 'sync']);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
console.log('');
|
|
235
|
+
if (addedToProject) {
|
|
236
|
+
console.log('Next steps:');
|
|
237
|
+
console.log(` ${chalk.cyan(`skills info ${slug}`)} View skill details`);
|
|
238
|
+
console.log(` ${chalk.cyan(`skills publish ${slug}`)} Publish a new version`);
|
|
239
|
+
}
|
|
240
|
+
else if (isInProject) {
|
|
241
|
+
console.log('Next steps:');
|
|
242
|
+
console.log(` ${chalk.cyan(`skills add ${slug}`)} Add to current project`);
|
|
243
|
+
console.log(` ${chalk.cyan(`skills info ${slug}`)} View skill details`);
|
|
244
|
+
console.log(` ${chalk.cyan(`skills publish ${slug}`)} Publish a new version`);
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
console.log('Next steps:');
|
|
248
|
+
console.log(` ${chalk.cyan('skills init')} Initialize a project first`);
|
|
249
|
+
console.log(` ${chalk.cyan(`skills info ${slug}`)} View skill details`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
catch (error) {
|
|
253
|
+
spinner.fail('Failed to create skill');
|
|
254
|
+
throw error;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
|
|
259
|
+
process.exit(1);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
//# sourceMappingURL=new.js.map
|