superskill 0.2.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 (301) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/LICENSE +21 -0
  3. package/README.md +235 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +1158 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/commands/brainstorm.d.ts +9 -0
  8. package/dist/commands/brainstorm.js +37 -0
  9. package/dist/commands/brainstorm.js.map +1 -0
  10. package/dist/commands/brainstorm.test.d.ts +1 -0
  11. package/dist/commands/brainstorm.test.js +110 -0
  12. package/dist/commands/brainstorm.test.js.map +1 -0
  13. package/dist/commands/context.d.ts +18 -0
  14. package/dist/commands/context.js +88 -0
  15. package/dist/commands/context.js.map +1 -0
  16. package/dist/commands/context.test.d.ts +1 -0
  17. package/dist/commands/context.test.js +230 -0
  18. package/dist/commands/context.test.js.map +1 -0
  19. package/dist/commands/decide.d.ts +12 -0
  20. package/dist/commands/decide.js +40 -0
  21. package/dist/commands/decide.js.map +1 -0
  22. package/dist/commands/decide.test.d.ts +1 -0
  23. package/dist/commands/decide.test.js +109 -0
  24. package/dist/commands/decide.test.js.map +1 -0
  25. package/dist/commands/graph.d.ts +15 -0
  26. package/dist/commands/graph.js +89 -0
  27. package/dist/commands/graph.js.map +1 -0
  28. package/dist/commands/graph.test.d.ts +1 -0
  29. package/dist/commands/graph.test.js +215 -0
  30. package/dist/commands/graph.test.js.map +1 -0
  31. package/dist/commands/init.d.ts +11 -0
  32. package/dist/commands/init.js +257 -0
  33. package/dist/commands/init.js.map +1 -0
  34. package/dist/commands/learn.d.ts +25 -0
  35. package/dist/commands/learn.js +92 -0
  36. package/dist/commands/learn.js.map +1 -0
  37. package/dist/commands/learn.test.d.ts +1 -0
  38. package/dist/commands/learn.test.js +241 -0
  39. package/dist/commands/learn.test.js.map +1 -0
  40. package/dist/commands/prune.d.ts +58 -0
  41. package/dist/commands/prune.js +246 -0
  42. package/dist/commands/prune.js.map +1 -0
  43. package/dist/commands/read.d.ts +8 -0
  44. package/dist/commands/read.js +7 -0
  45. package/dist/commands/read.js.map +1 -0
  46. package/dist/commands/read.test.d.ts +1 -0
  47. package/dist/commands/read.test.js +48 -0
  48. package/dist/commands/read.test.js.map +1 -0
  49. package/dist/commands/resume.d.ts +20 -0
  50. package/dist/commands/resume.js +141 -0
  51. package/dist/commands/resume.js.map +1 -0
  52. package/dist/commands/resume.test.d.ts +1 -0
  53. package/dist/commands/resume.test.js +243 -0
  54. package/dist/commands/resume.test.js.map +1 -0
  55. package/dist/commands/search.d.ts +8 -0
  56. package/dist/commands/search.js +25 -0
  57. package/dist/commands/search.js.map +1 -0
  58. package/dist/commands/search.test.d.ts +1 -0
  59. package/dist/commands/search.test.js +61 -0
  60. package/dist/commands/search.test.js.map +1 -0
  61. package/dist/commands/session.d.ts +22 -0
  62. package/dist/commands/session.js +79 -0
  63. package/dist/commands/session.js.map +1 -0
  64. package/dist/commands/session.test.d.ts +1 -0
  65. package/dist/commands/session.test.js +231 -0
  66. package/dist/commands/session.test.js.map +1 -0
  67. package/dist/commands/skill/catalog.d.ts +39 -0
  68. package/dist/commands/skill/catalog.js +260 -0
  69. package/dist/commands/skill/catalog.js.map +1 -0
  70. package/dist/commands/skill/index.d.ts +55 -0
  71. package/dist/commands/skill/index.js +82 -0
  72. package/dist/commands/skill/index.js.map +1 -0
  73. package/dist/commands/skill/index.test.d.ts +1 -0
  74. package/dist/commands/skill/index.test.js +137 -0
  75. package/dist/commands/skill/index.test.js.map +1 -0
  76. package/dist/commands/skill/install.d.ts +14 -0
  77. package/dist/commands/skill/install.js +108 -0
  78. package/dist/commands/skill/install.js.map +1 -0
  79. package/dist/commands/skill/install.test.d.ts +1 -0
  80. package/dist/commands/skill/install.test.js +225 -0
  81. package/dist/commands/skill/install.test.js.map +1 -0
  82. package/dist/commands/skill/list.d.ts +6 -0
  83. package/dist/commands/skill/list.js +5 -0
  84. package/dist/commands/skill/list.js.map +1 -0
  85. package/dist/commands/skill/list.test.d.ts +1 -0
  86. package/dist/commands/skill/list.test.js +101 -0
  87. package/dist/commands/skill/list.test.js.map +1 -0
  88. package/dist/commands/skill/marketplace.d.ts +121 -0
  89. package/dist/commands/skill/marketplace.js +548 -0
  90. package/dist/commands/skill/marketplace.js.map +1 -0
  91. package/dist/commands/skill/schema.d.ts +27 -0
  92. package/dist/commands/skill/schema.js +55 -0
  93. package/dist/commands/skill/schema.js.map +1 -0
  94. package/dist/commands/skill/schema.test.d.ts +1 -0
  95. package/dist/commands/skill/schema.test.js +142 -0
  96. package/dist/commands/skill/schema.test.js.map +1 -0
  97. package/dist/commands/skill/validate.d.ts +10 -0
  98. package/dist/commands/skill/validate.js +40 -0
  99. package/dist/commands/skill/validate.js.map +1 -0
  100. package/dist/commands/skill/validate.test.d.ts +1 -0
  101. package/dist/commands/skill/validate.test.js +171 -0
  102. package/dist/commands/skill/validate.test.js.map +1 -0
  103. package/dist/commands/task.d.ts +34 -0
  104. package/dist/commands/task.js +160 -0
  105. package/dist/commands/task.js.map +1 -0
  106. package/dist/commands/task.test.d.ts +1 -0
  107. package/dist/commands/task.test.js +395 -0
  108. package/dist/commands/task.test.js.map +1 -0
  109. package/dist/commands/todo.d.ts +15 -0
  110. package/dist/commands/todo.js +99 -0
  111. package/dist/commands/todo.js.map +1 -0
  112. package/dist/commands/todo.test.d.ts +1 -0
  113. package/dist/commands/todo.test.js +324 -0
  114. package/dist/commands/todo.test.js.map +1 -0
  115. package/dist/commands/write.d.ts +12 -0
  116. package/dist/commands/write.js +40 -0
  117. package/dist/commands/write.js.map +1 -0
  118. package/dist/commands/write.test.d.ts +1 -0
  119. package/dist/commands/write.test.js +79 -0
  120. package/dist/commands/write.test.js.map +1 -0
  121. package/dist/config.d.ts +15 -0
  122. package/dist/config.js +49 -0
  123. package/dist/config.js.map +1 -0
  124. package/dist/config.test.d.ts +1 -0
  125. package/dist/config.test.js +147 -0
  126. package/dist/config.test.js.map +1 -0
  127. package/dist/core/executor.d.ts +11 -0
  128. package/dist/core/executor.js +42 -0
  129. package/dist/core/executor.js.map +1 -0
  130. package/dist/core/executor.test.d.ts +1 -0
  131. package/dist/core/executor.test.js +206 -0
  132. package/dist/core/executor.test.js.map +1 -0
  133. package/dist/core/middleware/error-handler.d.ts +2 -0
  134. package/dist/core/middleware/error-handler.js +29 -0
  135. package/dist/core/middleware/error-handler.js.map +1 -0
  136. package/dist/core/middleware/index.d.ts +2 -0
  137. package/dist/core/middleware/index.js +3 -0
  138. package/dist/core/middleware/index.js.map +1 -0
  139. package/dist/core/middleware/logging.d.ts +2 -0
  140. package/dist/core/middleware/logging.js +18 -0
  141. package/dist/core/middleware/logging.js.map +1 -0
  142. package/dist/core/registry.d.ts +12 -0
  143. package/dist/core/registry.js +552 -0
  144. package/dist/core/registry.js.map +1 -0
  145. package/dist/core/registry.test.d.ts +1 -0
  146. package/dist/core/registry.test.js +213 -0
  147. package/dist/core/registry.test.js.map +1 -0
  148. package/dist/core/types.d.ts +38 -0
  149. package/dist/core/types.js +2 -0
  150. package/dist/core/types.js.map +1 -0
  151. package/dist/integration/coordination.test.d.ts +1 -0
  152. package/dist/integration/coordination.test.js +286 -0
  153. package/dist/integration/coordination.test.js.map +1 -0
  154. package/dist/integration/project-artifacts.test.d.ts +1 -0
  155. package/dist/integration/project-artifacts.test.js +275 -0
  156. package/dist/integration/project-artifacts.test.js.map +1 -0
  157. package/dist/integration/registry-graph.test.d.ts +1 -0
  158. package/dist/integration/registry-graph.test.js +157 -0
  159. package/dist/integration/registry-graph.test.js.map +1 -0
  160. package/dist/integration/vault-lifecycle.test.d.ts +1 -0
  161. package/dist/integration/vault-lifecycle.test.js +183 -0
  162. package/dist/integration/vault-lifecycle.test.js.map +1 -0
  163. package/dist/lib/auto-number.d.ts +10 -0
  164. package/dist/lib/auto-number.js +33 -0
  165. package/dist/lib/auto-number.js.map +1 -0
  166. package/dist/lib/auto-number.test.d.ts +1 -0
  167. package/dist/lib/auto-number.test.js +88 -0
  168. package/dist/lib/auto-number.test.js.map +1 -0
  169. package/dist/lib/auto-profile.d.ts +11 -0
  170. package/dist/lib/auto-profile.js +123 -0
  171. package/dist/lib/auto-profile.js.map +1 -0
  172. package/dist/lib/auto-profile.test.d.ts +1 -0
  173. package/dist/lib/auto-profile.test.js +227 -0
  174. package/dist/lib/auto-profile.test.js.map +1 -0
  175. package/dist/lib/escape-regex.d.ts +4 -0
  176. package/dist/lib/escape-regex.js +8 -0
  177. package/dist/lib/escape-regex.js.map +1 -0
  178. package/dist/lib/escape-regex.test.d.ts +1 -0
  179. package/dist/lib/escape-regex.test.js +27 -0
  180. package/dist/lib/escape-regex.test.js.map +1 -0
  181. package/dist/lib/frontmatter.d.ts +34 -0
  182. package/dist/lib/frontmatter.js +75 -0
  183. package/dist/lib/frontmatter.js.map +1 -0
  184. package/dist/lib/frontmatter.test.d.ts +1 -0
  185. package/dist/lib/frontmatter.test.js +192 -0
  186. package/dist/lib/frontmatter.test.js.map +1 -0
  187. package/dist/lib/project-detector.d.ts +12 -0
  188. package/dist/lib/project-detector.js +124 -0
  189. package/dist/lib/project-detector.js.map +1 -0
  190. package/dist/lib/project-detector.test.d.ts +1 -0
  191. package/dist/lib/project-detector.test.js +117 -0
  192. package/dist/lib/project-detector.test.js.map +1 -0
  193. package/dist/lib/safe-external-path.d.ts +10 -0
  194. package/dist/lib/safe-external-path.js +47 -0
  195. package/dist/lib/safe-external-path.js.map +1 -0
  196. package/dist/lib/safe-external-path.test.d.ts +1 -0
  197. package/dist/lib/safe-external-path.test.js +99 -0
  198. package/dist/lib/safe-external-path.test.js.map +1 -0
  199. package/dist/lib/search-engine.d.ts +19 -0
  200. package/dist/lib/search-engine.js +164 -0
  201. package/dist/lib/search-engine.js.map +1 -0
  202. package/dist/lib/search-engine.test.d.ts +1 -0
  203. package/dist/lib/search-engine.test.js +120 -0
  204. package/dist/lib/search-engine.test.js.map +1 -0
  205. package/dist/lib/session-registry.d.ts +59 -0
  206. package/dist/lib/session-registry.js +231 -0
  207. package/dist/lib/session-registry.js.map +1 -0
  208. package/dist/lib/session-registry.test.d.ts +1 -0
  209. package/dist/lib/session-registry.test.js +199 -0
  210. package/dist/lib/session-registry.test.js.map +1 -0
  211. package/dist/lib/skill-registry.d.ts +13 -0
  212. package/dist/lib/skill-registry.js +77 -0
  213. package/dist/lib/skill-registry.js.map +1 -0
  214. package/dist/lib/stack-detector.d.ts +7 -0
  215. package/dist/lib/stack-detector.js +184 -0
  216. package/dist/lib/stack-detector.js.map +1 -0
  217. package/dist/lib/stack-detector.test.d.ts +1 -0
  218. package/dist/lib/stack-detector.test.js +110 -0
  219. package/dist/lib/stack-detector.test.js.map +1 -0
  220. package/dist/lib/token-estimator.d.ts +19 -0
  221. package/dist/lib/token-estimator.js +59 -0
  222. package/dist/lib/token-estimator.js.map +1 -0
  223. package/dist/lib/token-estimator.test.d.ts +1 -0
  224. package/dist/lib/token-estimator.test.js +65 -0
  225. package/dist/lib/token-estimator.test.js.map +1 -0
  226. package/dist/lib/tool-detector.d.ts +8 -0
  227. package/dist/lib/tool-detector.js +76 -0
  228. package/dist/lib/tool-detector.js.map +1 -0
  229. package/dist/lib/tool-detector.test.d.ts +1 -0
  230. package/dist/lib/tool-detector.test.js +170 -0
  231. package/dist/lib/tool-detector.test.js.map +1 -0
  232. package/dist/lib/vault-fs.d.ts +39 -0
  233. package/dist/lib/vault-fs.js +184 -0
  234. package/dist/lib/vault-fs.js.map +1 -0
  235. package/dist/lib/vault-fs.test.d.ts +1 -0
  236. package/dist/lib/vault-fs.test.js +210 -0
  237. package/dist/lib/vault-fs.test.js.map +1 -0
  238. package/dist/mcp-server.d.ts +2 -0
  239. package/dist/mcp-server.js +387 -0
  240. package/dist/mcp-server.js.map +1 -0
  241. package/dist/setup/clients.d.ts +2 -0
  242. package/dist/setup/clients.js +109 -0
  243. package/dist/setup/clients.js.map +1 -0
  244. package/dist/setup/configure.d.ts +6 -0
  245. package/dist/setup/configure.js +126 -0
  246. package/dist/setup/configure.js.map +1 -0
  247. package/dist/setup/configure.test.d.ts +1 -0
  248. package/dist/setup/configure.test.js +112 -0
  249. package/dist/setup/configure.test.js.map +1 -0
  250. package/dist/setup/detect.d.ts +3 -0
  251. package/dist/setup/detect.js +24 -0
  252. package/dist/setup/detect.js.map +1 -0
  253. package/dist/setup/detect.test.d.ts +1 -0
  254. package/dist/setup/detect.test.js +44 -0
  255. package/dist/setup/detect.test.js.map +1 -0
  256. package/dist/setup/index.d.ts +2 -0
  257. package/dist/setup/index.js +147 -0
  258. package/dist/setup/index.js.map +1 -0
  259. package/dist/setup/instructions.d.ts +4 -0
  260. package/dist/setup/instructions.js +62 -0
  261. package/dist/setup/instructions.js.map +1 -0
  262. package/dist/setup/instructions.test.d.ts +1 -0
  263. package/dist/setup/instructions.test.js +84 -0
  264. package/dist/setup/instructions.test.js.map +1 -0
  265. package/dist/setup/json-config.d.ts +10 -0
  266. package/dist/setup/json-config.js +43 -0
  267. package/dist/setup/json-config.js.map +1 -0
  268. package/dist/setup/json-config.test.d.ts +1 -0
  269. package/dist/setup/json-config.test.js +92 -0
  270. package/dist/setup/json-config.test.js.map +1 -0
  271. package/dist/setup/postinstall.d.ts +2 -0
  272. package/dist/setup/postinstall.js +22 -0
  273. package/dist/setup/postinstall.js.map +1 -0
  274. package/dist/setup/preuninstall.d.ts +2 -0
  275. package/dist/setup/preuninstall.js +12 -0
  276. package/dist/setup/preuninstall.js.map +1 -0
  277. package/dist/setup/setup-integration.test.d.ts +1 -0
  278. package/dist/setup/setup-integration.test.js +72 -0
  279. package/dist/setup/setup-integration.test.js.map +1 -0
  280. package/dist/setup/teardown.d.ts +5 -0
  281. package/dist/setup/teardown.js +94 -0
  282. package/dist/setup/teardown.js.map +1 -0
  283. package/dist/setup/teardown.test.d.ts +1 -0
  284. package/dist/setup/teardown.test.js +105 -0
  285. package/dist/setup/teardown.test.js.map +1 -0
  286. package/dist/setup/toml-config.d.ts +5 -0
  287. package/dist/setup/toml-config.js +26 -0
  288. package/dist/setup/toml-config.js.map +1 -0
  289. package/dist/setup/toml-config.test.d.ts +1 -0
  290. package/dist/setup/toml-config.test.js +49 -0
  291. package/dist/setup/toml-config.test.js.map +1 -0
  292. package/dist/setup/types.d.ts +52 -0
  293. package/dist/setup/types.js +23 -0
  294. package/dist/setup/types.js.map +1 -0
  295. package/dist/test-helpers.d.ts +20 -0
  296. package/dist/test-helpers.js +47 -0
  297. package/dist/test-helpers.js.map +1 -0
  298. package/dist/test-helpers.test.d.ts +1 -0
  299. package/dist/test-helpers.test.js +90 -0
  300. package/dist/test-helpers.test.js.map +1 -0
  301. package/package.json +74 -0
@@ -0,0 +1,55 @@
1
+ import { VaultFS } from "../../lib/vault-fs.js";
2
+ import { InstallResult } from "./install.js";
3
+ import { ListResult } from "./list.js";
4
+ import { ValidateResult } from "./validate.js";
5
+ import { type CatalogResult, type CollisionResult, type ResolveResult, type GenerateResult } from "./marketplace.js";
6
+ export interface SkillCommandOptions {
7
+ action: 'install' | 'list' | 'validate' | 'delete' | 'catalog' | 'collisions' | 'resolve' | 'generate';
8
+ source?: string;
9
+ skillPath?: string;
10
+ skillName?: string;
11
+ force?: boolean;
12
+ domain?: string;
13
+ repo?: string;
14
+ search?: string;
15
+ profile?: string;
16
+ includeNonColliding?: boolean;
17
+ outputPath?: string;
18
+ pipe?: boolean;
19
+ pipeLayer?: 'core' | 'extended' | 'reference' | 'all';
20
+ relevantDomains?: string[];
21
+ }
22
+ export type SkillCommandResult = {
23
+ action: 'install';
24
+ result: InstallResult;
25
+ } | {
26
+ action: 'list';
27
+ result: ListResult;
28
+ } | {
29
+ action: 'validate';
30
+ result: ValidateResult;
31
+ } | {
32
+ action: 'delete';
33
+ result: InstallResult;
34
+ } | {
35
+ action: 'catalog';
36
+ result: CatalogResult;
37
+ } | {
38
+ action: 'collisions';
39
+ result: CollisionResult;
40
+ } | {
41
+ action: 'resolve';
42
+ result: ResolveResult;
43
+ } | {
44
+ action: 'generate';
45
+ result: GenerateResult;
46
+ };
47
+ export declare function skillCommand(vaultFs: VaultFS, vaultPath: string, options: SkillCommandOptions): Promise<SkillCommandResult>;
48
+ export { installSkill, deleteSkill } from "./install.js";
49
+ export { listSkills } from "./list.js";
50
+ export { validateSkill } from "./validate.js";
51
+ export { SkillRegistryManager } from "../../lib/skill-registry.js";
52
+ export * from "./schema.js";
53
+ export * from "./catalog.js";
54
+ export { catalogCommand, collisionsCommand, resolveCommand, generateCommand } from "./marketplace.js";
55
+ export type { CatalogResult, CollisionResult, ResolveResult, GenerateResult } from "./marketplace.js";
@@ -0,0 +1,82 @@
1
+ import { SkillRegistryManager } from "../../lib/skill-registry.js";
2
+ import { installSkill, deleteSkill } from "./install.js";
3
+ import { listSkills } from "./list.js";
4
+ import { validateSkill } from "./validate.js";
5
+ import { catalogCommand, collisionsCommand, resolveCommand, generateCommand, } from "./marketplace.js";
6
+ export async function skillCommand(vaultFs, vaultPath, options) {
7
+ const registryManager = new SkillRegistryManager(vaultPath);
8
+ switch (options.action) {
9
+ case 'install': {
10
+ if (!options.source) {
11
+ return {
12
+ action: 'install',
13
+ result: { success: false, error: 'Source is required for install action' },
14
+ };
15
+ }
16
+ const result = await installSkill(vaultFs, registryManager, {
17
+ source: options.source,
18
+ force: options.force,
19
+ });
20
+ return { action: 'install', result };
21
+ }
22
+ case 'list': {
23
+ const result = await listSkills(registryManager);
24
+ return { action: 'list', result };
25
+ }
26
+ case 'validate': {
27
+ if (!options.skillPath) {
28
+ return {
29
+ action: 'validate',
30
+ result: { valid: false, errors: ['Skill path is required for validate action'] },
31
+ };
32
+ }
33
+ const result = await validateSkill({ skillPath: options.skillPath });
34
+ return { action: 'validate', result };
35
+ }
36
+ case 'delete': {
37
+ if (!options.skillName) {
38
+ return {
39
+ action: 'delete',
40
+ result: { success: false, error: 'Skill name is required for delete action' },
41
+ };
42
+ }
43
+ const result = await deleteSkill(vaultFs, registryManager, options.skillName);
44
+ return { action: 'delete', result };
45
+ }
46
+ case 'catalog': {
47
+ const result = await catalogCommand({
48
+ domain: options.domain,
49
+ repo: options.repo,
50
+ search: options.search,
51
+ });
52
+ return { action: 'catalog', result };
53
+ }
54
+ case 'collisions': {
55
+ const result = await collisionsCommand();
56
+ return { action: 'collisions', result };
57
+ }
58
+ case 'resolve': {
59
+ const result = await resolveCommand({ profile: options.profile });
60
+ return { action: 'resolve', result };
61
+ }
62
+ case 'generate': {
63
+ const result = await generateCommand(vaultFs, vaultPath, {
64
+ profile: options.profile,
65
+ includeNonColliding: options.includeNonColliding,
66
+ outputPath: options.outputPath,
67
+ pipe: options.pipe,
68
+ pipeLayer: options.pipeLayer,
69
+ relevantDomains: options.relevantDomains,
70
+ });
71
+ return { action: 'generate', result };
72
+ }
73
+ }
74
+ }
75
+ export { installSkill, deleteSkill } from "./install.js";
76
+ export { listSkills } from "./list.js";
77
+ export { validateSkill } from "./validate.js";
78
+ export { SkillRegistryManager } from "../../lib/skill-registry.js";
79
+ export * from "./schema.js";
80
+ export * from "./catalog.js";
81
+ export { catalogCommand, collisionsCommand, resolveCommand, generateCommand } from "./marketplace.js";
82
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/skill/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,137 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { mkdir, writeFile, rm } from "fs/promises";
3
+ import { homedir } from "os";
4
+ import { join } from "path";
5
+ import { skillCommand } from "./index.js";
6
+ import { VaultFS } from "../../lib/vault-fs.js";
7
+ const validSkillContent = `---
8
+ name: test-skill
9
+ description: A test skill
10
+ version: "1.0.0"
11
+ ---
12
+
13
+ # Test Skill
14
+ `;
15
+ describe("skillCommand", () => {
16
+ let vaultRoot;
17
+ let vaultFs;
18
+ beforeEach(async () => {
19
+ vaultRoot = join(homedir(), `.vault-skill-cmd-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
20
+ await mkdir(vaultRoot, { recursive: true });
21
+ vaultFs = new VaultFS(vaultRoot);
22
+ });
23
+ afterEach(async () => {
24
+ await rm(vaultRoot, { recursive: true, force: true });
25
+ });
26
+ describe("install action", () => {
27
+ it("requires source option", async () => {
28
+ const result = await skillCommand(vaultFs, vaultRoot, { action: "install" });
29
+ expect(result.action).toBe("install");
30
+ const r = result.result;
31
+ expect(r.success).toBe(false);
32
+ expect(r.error).toContain("Source is required");
33
+ });
34
+ it("installs from local file path", async () => {
35
+ const skillPath = join(vaultRoot, "src", "skill.md");
36
+ await mkdir(join(vaultRoot, "src"), { recursive: true });
37
+ await writeFile(skillPath, validSkillContent);
38
+ const result = await skillCommand(vaultFs, vaultRoot, {
39
+ action: "install",
40
+ source: skillPath,
41
+ });
42
+ expect(result.action).toBe("install");
43
+ const r = result.result;
44
+ expect(r.success).toBe(true);
45
+ expect(r.skill?.name).toBe("test-skill");
46
+ });
47
+ it("passes force flag to install", async () => {
48
+ const skillPath = join(vaultRoot, "src", "skill.md");
49
+ await mkdir(join(vaultRoot, "src"), { recursive: true });
50
+ await writeFile(skillPath, validSkillContent);
51
+ const result1 = await skillCommand(vaultFs, vaultRoot, { action: "install", source: skillPath });
52
+ expect(result1.result.success).toBe(true);
53
+ const result2 = await skillCommand(vaultFs, vaultRoot, { action: "install", source: skillPath, force: true });
54
+ expect(result2.result.success).toBe(true);
55
+ });
56
+ });
57
+ describe("list action", () => {
58
+ it("returns empty list when no skills installed", async () => {
59
+ const result = await skillCommand(vaultFs, vaultRoot, { action: "list" });
60
+ expect(result.action).toBe("list");
61
+ expect(result.result.skills).toEqual([]);
62
+ });
63
+ it("returns installed skills", async () => {
64
+ const skillPath = join(vaultRoot, "src", "skill.md");
65
+ await mkdir(join(vaultRoot, "src"), { recursive: true });
66
+ await writeFile(skillPath, validSkillContent);
67
+ await skillCommand(vaultFs, vaultRoot, { action: "install", source: skillPath });
68
+ const result = await skillCommand(vaultFs, vaultRoot, { action: "list" });
69
+ expect(result.action).toBe("list");
70
+ const r = result.result;
71
+ expect(r.skills).toHaveLength(1);
72
+ expect(r.skills[0].name).toBe("test-skill");
73
+ });
74
+ });
75
+ describe("validate action", () => {
76
+ it("requires skillPath option", async () => {
77
+ const result = await skillCommand(vaultFs, vaultRoot, { action: "validate" });
78
+ expect(result.action).toBe("validate");
79
+ const r = result.result;
80
+ expect(r.valid).toBe(false);
81
+ expect(r.errors[0]).toContain("Skill path is required");
82
+ });
83
+ it("validates a valid local skill file", async () => {
84
+ const skillPath = join(vaultRoot, "src", "valid.md");
85
+ await mkdir(join(vaultRoot, "src"), { recursive: true });
86
+ await writeFile(skillPath, validSkillContent);
87
+ const result = await skillCommand(vaultFs, vaultRoot, { action: "validate", skillPath });
88
+ expect(result.action).toBe("validate");
89
+ const r = result.result;
90
+ expect(r.valid).toBe(true);
91
+ expect(r.frontmatter?.name).toBe("test-skill");
92
+ });
93
+ it("reports errors for invalid skill file", async () => {
94
+ const skillPath = join(vaultRoot, "src", "invalid.md");
95
+ await mkdir(join(vaultRoot, "src"), { recursive: true });
96
+ await writeFile(skillPath, "---\n---\n\n# No frontmatter");
97
+ const result = await skillCommand(vaultFs, vaultRoot, { action: "validate", skillPath });
98
+ expect(result.action).toBe("validate");
99
+ const r = result.result;
100
+ expect(r.valid).toBe(false);
101
+ expect(r.errors.length).toBeGreaterThan(0);
102
+ });
103
+ it("reports error for nonexistent file", async () => {
104
+ const result = await skillCommand(vaultFs, vaultRoot, { action: "validate", skillPath: "/nonexistent/skill.md" });
105
+ expect(result.action).toBe("validate");
106
+ const r = result.result;
107
+ expect(r.valid).toBe(false);
108
+ expect(r.errors[0]).toContain("Failed to read file");
109
+ });
110
+ });
111
+ describe("delete action", () => {
112
+ it("requires skillName option", async () => {
113
+ const result = await skillCommand(vaultFs, vaultRoot, { action: "delete" });
114
+ expect(result.action).toBe("delete");
115
+ const r = result.result;
116
+ expect(r.success).toBe(false);
117
+ expect(r.error).toContain("Skill name is required");
118
+ });
119
+ it("fails when skill not found", async () => {
120
+ const result = await skillCommand(vaultFs, vaultRoot, { action: "delete", skillName: "nonexistent" });
121
+ expect(result.action).toBe("delete");
122
+ const r = result.result;
123
+ expect(r.success).toBe(false);
124
+ expect(r.error).toContain("not found");
125
+ });
126
+ it("deletes an installed skill", async () => {
127
+ const skillPath = join(vaultRoot, "src", "skill.md");
128
+ await mkdir(join(vaultRoot, "src"), { recursive: true });
129
+ await writeFile(skillPath, validSkillContent);
130
+ await skillCommand(vaultFs, vaultRoot, { action: "install", source: skillPath });
131
+ const result = await skillCommand(vaultFs, vaultRoot, { action: "delete", skillName: "test-skill" });
132
+ expect(result.action).toBe("delete");
133
+ expect(result.result.success).toBe(true);
134
+ });
135
+ });
136
+ });
137
+ //# sourceMappingURL=index.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../../src/commands/skill/index.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { VaultFS } from "../../lib/vault-fs.js";
2
+ import { SkillRegistryManager } from "../../lib/skill-registry.js";
3
+ import { InstalledSkill } from "./schema.js";
4
+ export interface InstallOptions {
5
+ source: string;
6
+ force?: boolean;
7
+ }
8
+ export interface InstallResult {
9
+ success: boolean;
10
+ skill?: InstalledSkill;
11
+ error?: string;
12
+ }
13
+ export declare function installSkill(vaultFs: VaultFS, registryManager: SkillRegistryManager, options: InstallOptions): Promise<InstallResult>;
14
+ export declare function deleteSkill(vaultFs: VaultFS, registryManager: SkillRegistryManager, skillName: string): Promise<InstallResult>;
@@ -0,0 +1,108 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later OR Commercial
2
+ import { readFile, rm } from "fs/promises";
3
+ import { dirname } from "path";
4
+ import { isSkillFrontmatter } from "./schema.js";
5
+ import { parseFrontmatter } from "../../lib/frontmatter.js";
6
+ async function fetchUrl(url) {
7
+ const response = await fetch(url);
8
+ if (!response.ok) {
9
+ throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`);
10
+ }
11
+ return response.text();
12
+ }
13
+ function isUrl(source) {
14
+ return source.startsWith("http://") || source.startsWith("https://");
15
+ }
16
+ async function readSkillContent(source) {
17
+ if (isUrl(source)) {
18
+ const content = await fetchUrl(source);
19
+ return { content, sourceType: 'url' };
20
+ }
21
+ const content = await readFile(source, "utf-8");
22
+ return { content, sourceType: 'file' };
23
+ }
24
+ export async function installSkill(vaultFs, registryManager, options) {
25
+ const { source, force = false } = options;
26
+ let skillContent;
27
+ let sourceType;
28
+ try {
29
+ const result = await readSkillContent(source);
30
+ skillContent = result.content;
31
+ sourceType = result.sourceType;
32
+ }
33
+ catch (e) {
34
+ return {
35
+ success: false,
36
+ error: `Failed to read source: ${e.message}`,
37
+ };
38
+ }
39
+ const { data } = parseFrontmatter(skillContent);
40
+ if (!isSkillFrontmatter(data)) {
41
+ return {
42
+ success: false,
43
+ error: "Invalid skill frontmatter: missing required fields (name, description)",
44
+ };
45
+ }
46
+ const skillData = data;
47
+ const skillName = skillData.name;
48
+ const existing = await registryManager.get(skillName);
49
+ if (existing && !force) {
50
+ return {
51
+ success: false,
52
+ error: `Skill "${skillName}" already installed. Use --force to overwrite.`,
53
+ };
54
+ }
55
+ const installedPath = registryManager.getInstalledPath(skillName);
56
+ const relativePath = `skills/installed/${skillName}/SKILL.md`;
57
+ try {
58
+ await vaultFs.write(relativePath, skillContent);
59
+ }
60
+ catch (e) {
61
+ return {
62
+ success: false,
63
+ error: `Failed to write skill file: ${e.message}`,
64
+ };
65
+ }
66
+ const now = new Date().toISOString();
67
+ const installedSkill = {
68
+ name: skillName,
69
+ source: sourceType === 'url' ? source : 'local',
70
+ source_path: sourceType === 'file' ? source : undefined,
71
+ version: skillData.version ?? '0.0.0',
72
+ installed_at: existing?.installed_at ?? now,
73
+ updated_at: now,
74
+ status: 'active',
75
+ auto_update: sourceType === 'url',
76
+ depends_on: skillData.depends_on,
77
+ };
78
+ await registryManager.add(installedSkill);
79
+ return {
80
+ success: true,
81
+ skill: installedSkill,
82
+ };
83
+ }
84
+ export async function deleteSkill(vaultFs, registryManager, skillName) {
85
+ const existing = await registryManager.get(skillName);
86
+ if (!existing) {
87
+ return {
88
+ success: false,
89
+ error: `Skill "${skillName}" not found in registry.`,
90
+ };
91
+ }
92
+ const skillDir = `skills/installed/${skillName}`;
93
+ try {
94
+ if (await vaultFs.exists(skillDir)) {
95
+ const absolutePath = dirname(registryManager.getInstalledPath(skillName));
96
+ await rm(absolutePath, { recursive: true, force: true });
97
+ }
98
+ }
99
+ catch (e) {
100
+ console.error("[skill] Error removing skill directory:", e.message);
101
+ }
102
+ await registryManager.remove(skillName);
103
+ return {
104
+ success: true,
105
+ skill: existing,
106
+ };
107
+ }
108
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../../src/commands/skill/install.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,225 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { mkdir, writeFile, rm } from "fs/promises";
3
+ import { homedir } from "os";
4
+ import { join } from "path";
5
+ import { VaultFS } from "../../lib/vault-fs.js";
6
+ import { SkillRegistryManager } from "../../lib/skill-registry.js";
7
+ import { installSkill, deleteSkill } from "./install.js";
8
+ describe("installSkill", () => {
9
+ let vaultRoot;
10
+ let vaultFs;
11
+ let registryManager;
12
+ const validSkillContent = `---
13
+ name: test-skill
14
+ description: A test skill for unit tests
15
+ version: "1.0.0"
16
+ author: test-author
17
+ tags:
18
+ - test
19
+ - example
20
+ ---
21
+
22
+ # Test Skill
23
+
24
+ This is the body of the test skill.
25
+ `;
26
+ const missingNameContent = `---
27
+ description: Missing name field
28
+ ---
29
+
30
+ # Skill without name
31
+ `;
32
+ const missingDescContent = `---
33
+ name: no-desc-skill
34
+ ---
35
+
36
+ # Skill without description
37
+ `;
38
+ const emptyFrontmatter = `---
39
+ ---
40
+
41
+ # Empty frontmatter
42
+ `;
43
+ beforeEach(async () => {
44
+ vaultRoot = join(homedir(), `.vault-skill-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
45
+ await mkdir(vaultRoot, { recursive: true });
46
+ vaultFs = new VaultFS(vaultRoot);
47
+ registryManager = new SkillRegistryManager(vaultRoot);
48
+ });
49
+ afterEach(async () => {
50
+ await rm(vaultRoot, { recursive: true, force: true });
51
+ });
52
+ describe("install from local file", () => {
53
+ it("installs a valid skill from local file", async () => {
54
+ const skillPath = join(vaultRoot, "source", "test-skill.md");
55
+ await mkdir(join(vaultRoot, "source"), { recursive: true });
56
+ await writeFile(skillPath, validSkillContent);
57
+ const result = await installSkill(vaultFs, registryManager, {
58
+ source: skillPath,
59
+ });
60
+ expect(result.success).toBe(true);
61
+ expect(result.skill).toBeDefined();
62
+ expect(result.skill?.name).toBe("test-skill");
63
+ expect(result.skill?.source).toBe("local");
64
+ expect(result.skill?.source_path).toBe(skillPath);
65
+ expect(result.skill?.version).toBe("1.0.0");
66
+ expect(result.skill?.status).toBe("active");
67
+ expect(result.skill?.auto_update).toBe(false);
68
+ });
69
+ it("fails when source file does not exist", async () => {
70
+ const result = await installSkill(vaultFs, registryManager, {
71
+ source: "/nonexistent/path/skill.md",
72
+ });
73
+ expect(result.success).toBe(false);
74
+ expect(result.error).toContain("Failed to read source");
75
+ });
76
+ it("fails when frontmatter is missing required name field", async () => {
77
+ const skillPath = join(vaultRoot, "source", "invalid.md");
78
+ await mkdir(join(vaultRoot, "source"), { recursive: true });
79
+ await writeFile(skillPath, missingNameContent);
80
+ const result = await installSkill(vaultFs, registryManager, {
81
+ source: skillPath,
82
+ });
83
+ expect(result.success).toBe(false);
84
+ expect(result.error).toContain("Invalid skill frontmatter");
85
+ });
86
+ it("fails when frontmatter is missing required description field", async () => {
87
+ const skillPath = join(vaultRoot, "source", "no-desc.md");
88
+ await mkdir(join(vaultRoot, "source"), { recursive: true });
89
+ await writeFile(skillPath, missingDescContent);
90
+ const result = await installSkill(vaultFs, registryManager, {
91
+ source: skillPath,
92
+ });
93
+ expect(result.success).toBe(false);
94
+ expect(result.error).toContain("Invalid skill frontmatter");
95
+ });
96
+ it("fails when frontmatter is empty", async () => {
97
+ const skillPath = join(vaultRoot, "source", "empty.md");
98
+ await mkdir(join(vaultRoot, "source"), { recursive: true });
99
+ await writeFile(skillPath, emptyFrontmatter);
100
+ const result = await installSkill(vaultFs, registryManager, {
101
+ source: skillPath,
102
+ });
103
+ expect(result.success).toBe(false);
104
+ expect(result.error).toContain("Invalid skill frontmatter");
105
+ });
106
+ it("fails when skill already installed without force", async () => {
107
+ const skillPath = join(vaultRoot, "source", "test-skill.md");
108
+ await mkdir(join(vaultRoot, "source"), { recursive: true });
109
+ await writeFile(skillPath, validSkillContent);
110
+ const result1 = await installSkill(vaultFs, registryManager, {
111
+ source: skillPath,
112
+ });
113
+ expect(result1.success).toBe(true);
114
+ const result2 = await installSkill(vaultFs, registryManager, {
115
+ source: skillPath,
116
+ });
117
+ expect(result2.success).toBe(false);
118
+ expect(result2.error).toContain("already installed");
119
+ });
120
+ it("overwrites existing skill with force flag", async () => {
121
+ const skillPath = join(vaultRoot, "source", "test-skill.md");
122
+ await mkdir(join(vaultRoot, "source"), { recursive: true });
123
+ await writeFile(skillPath, validSkillContent);
124
+ const result1 = await installSkill(vaultFs, registryManager, {
125
+ source: skillPath,
126
+ });
127
+ expect(result1.success).toBe(true);
128
+ const result2 = await installSkill(vaultFs, registryManager, {
129
+ source: skillPath,
130
+ force: true,
131
+ });
132
+ expect(result2.success).toBe(true);
133
+ expect(result2.skill?.updated_at).not.toBe(result1.skill?.updated_at);
134
+ });
135
+ it("uses default version when not specified", async () => {
136
+ const noVersionContent = `---
137
+ name: no-version-skill
138
+ description: Skill without version
139
+ ---
140
+ # Content
141
+ `;
142
+ const skillPath = join(vaultRoot, "source", "no-version.md");
143
+ await mkdir(join(vaultRoot, "source"), { recursive: true });
144
+ await writeFile(skillPath, noVersionContent);
145
+ const result = await installSkill(vaultFs, registryManager, {
146
+ source: skillPath,
147
+ });
148
+ expect(result.success).toBe(true);
149
+ expect(result.skill?.version).toBe("0.0.0");
150
+ });
151
+ it("preserves depends_on from frontmatter", async () => {
152
+ const withDepsContent = `---
153
+ name: skill-with-deps
154
+ description: Skill with dependencies
155
+ depends_on:
156
+ - base-skill
157
+ - utils-skill
158
+ ---
159
+ # Content
160
+ `;
161
+ const skillPath = join(vaultRoot, "source", "with-deps.md");
162
+ await mkdir(join(vaultRoot, "source"), { recursive: true });
163
+ await writeFile(skillPath, withDepsContent);
164
+ const result = await installSkill(vaultFs, registryManager, {
165
+ source: skillPath,
166
+ });
167
+ expect(result.success).toBe(true);
168
+ expect(result.skill?.depends_on).toEqual(["base-skill", "utils-skill"]);
169
+ });
170
+ });
171
+ describe("deleteSkill", () => {
172
+ it("deletes an installed skill", async () => {
173
+ const skillPath = join(vaultRoot, "source", "test-skill.md");
174
+ await mkdir(join(vaultRoot, "source"), { recursive: true });
175
+ await writeFile(skillPath, validSkillContent);
176
+ const installResult = await installSkill(vaultFs, registryManager, {
177
+ source: skillPath,
178
+ });
179
+ expect(installResult.success).toBe(true);
180
+ const deleteResult = await deleteSkill(vaultFs, registryManager, "test-skill");
181
+ expect(deleteResult.success).toBe(true);
182
+ expect(deleteResult.skill?.name).toBe("test-skill");
183
+ const registry = await registryManager.read();
184
+ expect(registry.skills.find(s => s.name === "test-skill")).toBeUndefined();
185
+ });
186
+ it("fails when skill not found", async () => {
187
+ const result = await deleteSkill(vaultFs, registryManager, "nonexistent-skill");
188
+ expect(result.success).toBe(false);
189
+ expect(result.error).toContain("not found in registry");
190
+ });
191
+ it("returns the deleted skill info", async () => {
192
+ const skillPath = join(vaultRoot, "source", "test-skill.md");
193
+ await mkdir(join(vaultRoot, "source"), { recursive: true });
194
+ await writeFile(skillPath, validSkillContent);
195
+ await installSkill(vaultFs, registryManager, { source: skillPath });
196
+ const result = await deleteSkill(vaultFs, registryManager, "test-skill");
197
+ expect(result.success).toBe(true);
198
+ expect(result.skill?.name).toBe("test-skill");
199
+ expect(result.skill?.version).toBe("1.0.0");
200
+ });
201
+ });
202
+ describe("registry operations", () => {
203
+ it("lists installed skills", async () => {
204
+ const skillPath = join(vaultRoot, "source", "test-skill.md");
205
+ await mkdir(join(vaultRoot, "source"), { recursive: true });
206
+ await writeFile(skillPath, validSkillContent);
207
+ await installSkill(vaultFs, registryManager, { source: skillPath });
208
+ const skills = await registryManager.list();
209
+ expect(skills).toHaveLength(1);
210
+ expect(skills[0].name).toBe("test-skill");
211
+ });
212
+ it("gets specific skill by name", async () => {
213
+ const skillPath = join(vaultRoot, "source", "test-skill.md");
214
+ await mkdir(join(vaultRoot, "source"), { recursive: true });
215
+ await writeFile(skillPath, validSkillContent);
216
+ await installSkill(vaultFs, registryManager, { source: skillPath });
217
+ const skill = await registryManager.get("test-skill");
218
+ expect(skill).toBeDefined();
219
+ expect(skill?.name).toBe("test-skill");
220
+ const missing = await registryManager.get("nonexistent");
221
+ expect(missing).toBeUndefined();
222
+ });
223
+ });
224
+ });
225
+ //# sourceMappingURL=install.test.js.map