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.
Files changed (151) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +261 -0
  3. package/dist/commands/add.d.ts +3 -0
  4. package/dist/commands/add.d.ts.map +1 -0
  5. package/dist/commands/add.js +121 -0
  6. package/dist/commands/add.js.map +1 -0
  7. package/dist/commands/bundle.d.ts +3 -0
  8. package/dist/commands/bundle.d.ts.map +1 -0
  9. package/dist/commands/bundle.js +58 -0
  10. package/dist/commands/bundle.js.map +1 -0
  11. package/dist/commands/config.d.ts +3 -0
  12. package/dist/commands/config.d.ts.map +1 -0
  13. package/dist/commands/config.js +109 -0
  14. package/dist/commands/config.js.map +1 -0
  15. package/dist/commands/delete.d.ts +3 -0
  16. package/dist/commands/delete.d.ts.map +1 -0
  17. package/dist/commands/delete.js +64 -0
  18. package/dist/commands/delete.js.map +1 -0
  19. package/dist/commands/diff.d.ts +3 -0
  20. package/dist/commands/diff.d.ts.map +1 -0
  21. package/dist/commands/diff.js +93 -0
  22. package/dist/commands/diff.js.map +1 -0
  23. package/dist/commands/edit.d.ts +3 -0
  24. package/dist/commands/edit.d.ts.map +1 -0
  25. package/dist/commands/edit.js +69 -0
  26. package/dist/commands/edit.js.map +1 -0
  27. package/dist/commands/import.d.ts +3 -0
  28. package/dist/commands/import.d.ts.map +1 -0
  29. package/dist/commands/import.js +514 -0
  30. package/dist/commands/import.js.map +1 -0
  31. package/dist/commands/info.d.ts +3 -0
  32. package/dist/commands/info.d.ts.map +1 -0
  33. package/dist/commands/info.js +89 -0
  34. package/dist/commands/info.js.map +1 -0
  35. package/dist/commands/init.d.ts +3 -0
  36. package/dist/commands/init.d.ts.map +1 -0
  37. package/dist/commands/init.js +88 -0
  38. package/dist/commands/init.js.map +1 -0
  39. package/dist/commands/list.d.ts +3 -0
  40. package/dist/commands/list.d.ts.map +1 -0
  41. package/dist/commands/list.js +84 -0
  42. package/dist/commands/list.js.map +1 -0
  43. package/dist/commands/login.d.ts +3 -0
  44. package/dist/commands/login.d.ts.map +1 -0
  45. package/dist/commands/login.js +143 -0
  46. package/dist/commands/login.js.map +1 -0
  47. package/dist/commands/new.d.ts +3 -0
  48. package/dist/commands/new.d.ts.map +1 -0
  49. package/dist/commands/new.js +262 -0
  50. package/dist/commands/new.js.map +1 -0
  51. package/dist/commands/publish.d.ts +3 -0
  52. package/dist/commands/publish.d.ts.map +1 -0
  53. package/dist/commands/publish.js +215 -0
  54. package/dist/commands/publish.js.map +1 -0
  55. package/dist/commands/push.d.ts +3 -0
  56. package/dist/commands/push.d.ts.map +1 -0
  57. package/dist/commands/push.js +151 -0
  58. package/dist/commands/push.js.map +1 -0
  59. package/dist/commands/registry.d.ts +3 -0
  60. package/dist/commands/registry.d.ts.map +1 -0
  61. package/dist/commands/registry.js +169 -0
  62. package/dist/commands/registry.js.map +1 -0
  63. package/dist/commands/remove.d.ts +3 -0
  64. package/dist/commands/remove.d.ts.map +1 -0
  65. package/dist/commands/remove.js +48 -0
  66. package/dist/commands/remove.js.map +1 -0
  67. package/dist/commands/search.d.ts +3 -0
  68. package/dist/commands/search.d.ts.map +1 -0
  69. package/dist/commands/search.js +48 -0
  70. package/dist/commands/search.js.map +1 -0
  71. package/dist/commands/sync.d.ts +3 -0
  72. package/dist/commands/sync.d.ts.map +1 -0
  73. package/dist/commands/sync.js +160 -0
  74. package/dist/commands/sync.js.map +1 -0
  75. package/dist/commands/update.d.ts +3 -0
  76. package/dist/commands/update.d.ts.map +1 -0
  77. package/dist/commands/update.js +130 -0
  78. package/dist/commands/update.js.map +1 -0
  79. package/dist/commands/validate.d.ts +3 -0
  80. package/dist/commands/validate.d.ts.map +1 -0
  81. package/dist/commands/validate.js +94 -0
  82. package/dist/commands/validate.js.map +1 -0
  83. package/dist/index.d.ts +3 -0
  84. package/dist/index.d.ts.map +1 -0
  85. package/dist/index.js +56 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/lib/api.d.ts +60 -0
  88. package/dist/lib/api.d.ts.map +1 -0
  89. package/dist/lib/api.js +340 -0
  90. package/dist/lib/api.js.map +1 -0
  91. package/dist/lib/auth.d.ts +78 -0
  92. package/dist/lib/auth.d.ts.map +1 -0
  93. package/dist/lib/auth.js +241 -0
  94. package/dist/lib/auth.js.map +1 -0
  95. package/dist/lib/config.d.ts +94 -0
  96. package/dist/lib/config.d.ts.map +1 -0
  97. package/dist/lib/config.js +294 -0
  98. package/dist/lib/config.js.map +1 -0
  99. package/dist/lib/editor.d.ts +6 -0
  100. package/dist/lib/editor.d.ts.map +1 -0
  101. package/dist/lib/editor.js +60 -0
  102. package/dist/lib/editor.js.map +1 -0
  103. package/dist/lib/fs.d.ts +74 -0
  104. package/dist/lib/fs.d.ts.map +1 -0
  105. package/dist/lib/fs.js +235 -0
  106. package/dist/lib/fs.js.map +1 -0
  107. package/dist/lib/index-gen.d.ts +18 -0
  108. package/dist/lib/index-gen.d.ts.map +1 -0
  109. package/dist/lib/index-gen.js +75 -0
  110. package/dist/lib/index-gen.js.map +1 -0
  111. package/dist/lib/local-registry/index.d.ts +15 -0
  112. package/dist/lib/local-registry/index.d.ts.map +1 -0
  113. package/dist/lib/local-registry/index.js +18 -0
  114. package/dist/lib/local-registry/index.js.map +1 -0
  115. package/dist/lib/local-registry/objects.d.ts +51 -0
  116. package/dist/lib/local-registry/objects.d.ts.map +1 -0
  117. package/dist/lib/local-registry/objects.js +148 -0
  118. package/dist/lib/local-registry/objects.js.map +1 -0
  119. package/dist/lib/local-registry/paths.d.ts +53 -0
  120. package/dist/lib/local-registry/paths.d.ts.map +1 -0
  121. package/dist/lib/local-registry/paths.js +85 -0
  122. package/dist/lib/local-registry/paths.js.map +1 -0
  123. package/dist/lib/local-registry/skills.d.ts +83 -0
  124. package/dist/lib/local-registry/skills.d.ts.map +1 -0
  125. package/dist/lib/local-registry/skills.js +261 -0
  126. package/dist/lib/local-registry/skills.js.map +1 -0
  127. package/dist/lib/local-registry/types.d.ts +79 -0
  128. package/dist/lib/local-registry/types.d.ts.map +1 -0
  129. package/dist/lib/local-registry/types.js +5 -0
  130. package/dist/lib/local-registry/types.js.map +1 -0
  131. package/dist/lib/local-registry/versions.d.ts +61 -0
  132. package/dist/lib/local-registry/versions.d.ts.map +1 -0
  133. package/dist/lib/local-registry/versions.js +163 -0
  134. package/dist/lib/local-registry/versions.js.map +1 -0
  135. package/dist/lib/lockfile.d.ts +38 -0
  136. package/dist/lib/lockfile.d.ts.map +1 -0
  137. package/dist/lib/lockfile.js +102 -0
  138. package/dist/lib/lockfile.js.map +1 -0
  139. package/dist/lib/meta-skill.d.ts +6 -0
  140. package/dist/lib/meta-skill.d.ts.map +1 -0
  141. package/dist/lib/meta-skill.js +72 -0
  142. package/dist/lib/meta-skill.js.map +1 -0
  143. package/dist/lib/semver.d.ts +63 -0
  144. package/dist/lib/semver.d.ts.map +1 -0
  145. package/dist/lib/semver.js +107 -0
  146. package/dist/lib/semver.js.map +1 -0
  147. package/dist/types.d.ts +147 -0
  148. package/dist/types.d.ts.map +1 -0
  149. package/dist/types.js +8 -0
  150. package/dist/types.js.map +1 -0
  151. 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":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const listCommand: Command;
3
+ //# sourceMappingURL=list.d.ts.map
@@ -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":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAC3C,OAAO,KAAK,aAAa,MAAM,gCAAgC,CAAC;AAChE,OAAO,KAAK,QAAQ,MAAM,oBAAoB,CAAC;AAE/C,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC3C,WAAW,CAAC,aAAa,CAAC;KAC1B,MAAM,CAAC,iBAAiB,EAAE,+CAA+C,CAAC;KAC1E,MAAM,CAAC,aAAa,EAAE,uCAAuC,CAAC;KAC9D,MAAM,CAAC,mBAAmB,EAAE,kCAAkC,CAAC;KAC/D,MAAM,CAAC,uBAAuB,EAAE,2CAA2C,CAAC;KAC5E,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,IAAI,CAAC;QACH,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACtB,2CAA2C;YAC3C,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,EAAE,CAAC;gBAC3B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC,CAAC;gBAC1D,OAAO,CAAC,GAAG,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;gBACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,MAAM,YAAY,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;YACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAC;YAErC,IAAI,YAAY,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACrC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,uCAAuC,CAAC,CAAC,CAAC;gBACnE,OAAO,CAAC,GAAG,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,iBAAiB,CAAC,CAAC;gBACrE,OAAO;YACT,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;YAC3C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAEhB,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,MAAM,EAAE,CAAC;gBACxC,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC/D,MAAM,aAAa,GAAG,MAAM,EAAE,OAAO,IAAI,YAAY,CAAC;gBAEtD,4BAA4B;gBAC5B,MAAM,YAAY,GAAG,aAAa,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAChE,MAAM,SAAS,GAAG,YAAY,IAAI,MAAM,EAAE,OAAO,IAAI,YAAY,KAAK,MAAM,CAAC,OAAO,CAAC;gBAErF,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1E,MAAM,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,YAAY,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAEjF,OAAO,CAAC,GAAG,CACT,KAAK,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,KAAK,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,UAAU,GAAG,UAAU,EAAE,CAChG,CAAC;YACJ,CAAC;QACH,CAAC;aAAM,CAAC;YACN,0CAA0C;YAC1C,IAAI,MAAM,GAAG,aAAa,CAAC,UAAU,EAAE,CAAC;YAExC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,2BAA2B,CAAC,CAAC,CAAC;gBACvD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAChB,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,+BAA+B,CAAC,CAAC;gBACjF,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,4BAA4B,CAAC,qBAAqB,CAAC,CAAC;gBAChF,OAAO;YACT,CAAC;YAED,iBAAiB;YACjB,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;gBACjB,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;gBACtF,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAC/B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CACtE,CAAC;YACJ,CAAC;YAED,mBAAmB;YACnB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACnB,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;gBAC1F,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAC/B,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CACtE,CAAC;YACJ,CAAC;YAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACxB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,wCAAwC,CAAC,CAAC,CAAC;gBACpE,OAAO;YACT,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,MAAM,CAAC,MAAM,WAAW,CAAC,CAAC,CAAC;YACrE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAEhB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;gBAC3B,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW;oBACxC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;oBAC/G,CAAC,CAAC,EAAE,CAAC;gBAEP,MAAM,WAAW,GAAG,KAAK,CAAC,YAAY,GAAG,CAAC;oBACxC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,YAAY,YAAY,CAAC;oBACjD,CAAC,CAAC,EAAE,CAAC;gBAEP,OAAO,CAAC,GAAG,CACT,KAAK,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,WAAW,GAAG,WAAW,EAAE,CACxG,CAAC;YACJ,CAAC;QACH,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,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const loginCommand: Command;
3
+ //# sourceMappingURL=login.d.ts.map
@@ -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,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const newCommand: Command;
3
+ //# sourceMappingURL=new.d.ts.map
@@ -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