atomism 0.1.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 (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +210 -0
  3. package/dist/chunk-34O5KJWR.js +81 -0
  4. package/dist/chunk-34O5KJWR.js.map +1 -0
  5. package/dist/chunk-55AP34JO.js +116 -0
  6. package/dist/chunk-55AP34JO.js.map +1 -0
  7. package/dist/chunk-6MDHM2B4.js +17 -0
  8. package/dist/chunk-6MDHM2B4.js.map +1 -0
  9. package/dist/chunk-GU2R4KLP.js +43 -0
  10. package/dist/chunk-GU2R4KLP.js.map +1 -0
  11. package/dist/chunk-H7WC3NXZ.js +39 -0
  12. package/dist/chunk-H7WC3NXZ.js.map +1 -0
  13. package/dist/chunk-P33CQFMY.js +329 -0
  14. package/dist/chunk-P33CQFMY.js.map +1 -0
  15. package/dist/chunk-P6X7T4KA.js +200 -0
  16. package/dist/chunk-P6X7T4KA.js.map +1 -0
  17. package/dist/chunk-PLQJM2KT.js +9 -0
  18. package/dist/chunk-PLQJM2KT.js.map +1 -0
  19. package/dist/chunk-RS2IEGW3.js +10 -0
  20. package/dist/chunk-RS2IEGW3.js.map +1 -0
  21. package/dist/chunk-S6Z5G5DB.js +84 -0
  22. package/dist/chunk-S6Z5G5DB.js.map +1 -0
  23. package/dist/chunk-UVUDQ4XP.js +259 -0
  24. package/dist/chunk-UVUDQ4XP.js.map +1 -0
  25. package/dist/chunk-UWVZQSP4.js +597 -0
  26. package/dist/chunk-UWVZQSP4.js.map +1 -0
  27. package/dist/chunk-YKJO3ZFY.js +308 -0
  28. package/dist/chunk-YKJO3ZFY.js.map +1 -0
  29. package/dist/cli.d.ts +1 -0
  30. package/dist/cli.js +152 -0
  31. package/dist/cli.js.map +1 -0
  32. package/dist/create-atom-AXPDBYQL.js +153 -0
  33. package/dist/create-atom-AXPDBYQL.js.map +1 -0
  34. package/dist/escalate-BTEJT5NL.js +211 -0
  35. package/dist/escalate-BTEJT5NL.js.map +1 -0
  36. package/dist/extract-RPKCTINT.js +514 -0
  37. package/dist/extract-RPKCTINT.js.map +1 -0
  38. package/dist/graduate-453M7ZRQ.js +222 -0
  39. package/dist/graduate-453M7ZRQ.js.map +1 -0
  40. package/dist/helpers-PJPFPYBQ.js +11 -0
  41. package/dist/helpers-PJPFPYBQ.js.map +1 -0
  42. package/dist/history-OPD7NLZW.js +258 -0
  43. package/dist/history-OPD7NLZW.js.map +1 -0
  44. package/dist/import-generator-4CKRBMTE.js +1864 -0
  45. package/dist/import-generator-4CKRBMTE.js.map +1 -0
  46. package/dist/index.d.ts +230 -0
  47. package/dist/index.js +41 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/init-2FINDMYK.js +741 -0
  50. package/dist/init-2FINDMYK.js.map +1 -0
  51. package/dist/list-NEBVBGG3.js +71 -0
  52. package/dist/list-NEBVBGG3.js.map +1 -0
  53. package/dist/parser-3BILOSOO.js +157 -0
  54. package/dist/parser-3BILOSOO.js.map +1 -0
  55. package/dist/plan-DNVARHWH.js +249 -0
  56. package/dist/plan-DNVARHWH.js.map +1 -0
  57. package/dist/register-XTRMSH7Y.js +91 -0
  58. package/dist/register-XTRMSH7Y.js.map +1 -0
  59. package/dist/revert-J4CRDE2K.js +87 -0
  60. package/dist/revert-J4CRDE2K.js.map +1 -0
  61. package/dist/run-3GI3SBYL.js +188 -0
  62. package/dist/run-3GI3SBYL.js.map +1 -0
  63. package/dist/scan-generators-ST4TBEY7.js +375 -0
  64. package/dist/scan-generators-ST4TBEY7.js.map +1 -0
  65. package/dist/signatures-K5QIL4WG.js +258 -0
  66. package/dist/signatures-K5QIL4WG.js.map +1 -0
  67. package/dist/skills-assign-IHOXX4AI.js +182 -0
  68. package/dist/skills-assign-IHOXX4AI.js.map +1 -0
  69. package/dist/skills-load-JSD5UG2K.js +20 -0
  70. package/dist/skills-load-JSD5UG2K.js.map +1 -0
  71. package/dist/skills-scan-WACJFRJN.js +25 -0
  72. package/dist/skills-scan-WACJFRJN.js.map +1 -0
  73. package/dist/skills-suggest-JFI2NUJI.js +269 -0
  74. package/dist/skills-suggest-JFI2NUJI.js.map +1 -0
  75. package/dist/status-KQVSAZFR.js +111 -0
  76. package/dist/status-KQVSAZFR.js.map +1 -0
  77. package/dist/suggest-IFFJQFIW.js +183 -0
  78. package/dist/suggest-IFFJQFIW.js.map +1 -0
  79. package/dist/test-HP3FG3MO.js +152 -0
  80. package/dist/test-HP3FG3MO.js.map +1 -0
  81. package/dist/test-gen-2ZGPOP35.js +347 -0
  82. package/dist/test-gen-2ZGPOP35.js.map +1 -0
  83. package/dist/trust-4R26DULG.js +248 -0
  84. package/dist/trust-4R26DULG.js.map +1 -0
  85. package/dist/validate-generator-46H2LYYQ.js +410 -0
  86. package/dist/validate-generator-46H2LYYQ.js.map +1 -0
  87. package/dist/workflow-5UVLBS7J.js +655 -0
  88. package/dist/workflow-5UVLBS7J.js.map +1 -0
  89. package/package.json +84 -0
@@ -0,0 +1,10 @@
1
+ // src/utils/paths.ts
2
+ import { isAbsolute, resolve } from "path";
3
+ function resolveAtomPath(path, baseDir) {
4
+ return isAbsolute(path) ? path : resolve(baseDir, path);
5
+ }
6
+
7
+ export {
8
+ resolveAtomPath
9
+ };
10
+ //# sourceMappingURL=chunk-RS2IEGW3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/paths.ts"],"sourcesContent":["import { isAbsolute, resolve } from 'node:path';\n\n/**\n * Resolve a potentially relative path against a base directory.\n *\n * If the path is already absolute it is returned as-is; otherwise it is\n * resolved relative to `baseDir`.\n */\nexport function resolveAtomPath(path: string, baseDir: string): string {\n return isAbsolute(path) ? path : resolve(baseDir, path);\n}\n"],"mappings":";AAAA,SAAS,YAAY,eAAe;AAQ7B,SAAS,gBAAgB,MAAc,SAAyB;AACrE,SAAO,WAAW,IAAI,IAAI,OAAO,QAAQ,SAAS,IAAI;AACxD;","names":[]}
@@ -0,0 +1,84 @@
1
+ // src/cli/format.ts
2
+ var codes = {
3
+ reset: "\x1B[0m",
4
+ bold: "\x1B[1m",
5
+ dim: "\x1B[2m",
6
+ red: "\x1B[31m",
7
+ green: "\x1B[32m",
8
+ yellow: "\x1B[33m",
9
+ blue: "\x1B[34m",
10
+ magenta: "\x1B[35m",
11
+ cyan: "\x1B[36m",
12
+ gray: "\x1B[90m"
13
+ };
14
+ var useColors = process.stdout.isTTY && !process.env["NO_COLOR"] && process.env["TERM"] !== "dumb";
15
+ function colorize(code, text) {
16
+ if (!useColors) return text;
17
+ return `${codes[code]}${text}${codes.reset}`;
18
+ }
19
+ var fmt = {
20
+ // Colors
21
+ red: (text) => colorize("red", text),
22
+ green: (text) => colorize("green", text),
23
+ yellow: (text) => colorize("yellow", text),
24
+ blue: (text) => colorize("blue", text),
25
+ magenta: (text) => colorize("magenta", text),
26
+ cyan: (text) => colorize("cyan", text),
27
+ gray: (text) => colorize("gray", text),
28
+ // Styles
29
+ bold: (text) => colorize("bold", text),
30
+ dim: (text) => colorize("dim", text),
31
+ // Semantic helpers
32
+ success: (text) => colorize("green", text),
33
+ error: (text) => colorize("red", text),
34
+ warning: (text) => colorize("yellow", text),
35
+ info: (text) => colorize("blue", text),
36
+ hint: (text) => colorize("cyan", text),
37
+ // Error type colors
38
+ errorType: (type) => {
39
+ switch (type) {
40
+ case "validation":
41
+ return colorize("yellow", type);
42
+ case "execution":
43
+ return colorize("red", type);
44
+ case "dependency":
45
+ return colorize("magenta", type);
46
+ case "timeout":
47
+ return colorize("cyan", type);
48
+ default:
49
+ return colorize("red", type);
50
+ }
51
+ }
52
+ };
53
+ function formatAtomError(error) {
54
+ const lines = [];
55
+ lines.push(`${fmt.error("Error")} ${fmt.gray("[")}${fmt.errorType(error.type)}${fmt.gray("]")}`);
56
+ lines.push(` ${error.message}`);
57
+ if (error.suggestion) {
58
+ lines.push(` ${fmt.hint("Suggestion:")} ${error.suggestion}`);
59
+ }
60
+ lines.push(
61
+ ` ${fmt.gray("Recoverable:")} ${error.recoverable ? fmt.green("yes") : fmt.red("no")}`
62
+ );
63
+ if (error.context && Object.keys(error.context).length > 0) {
64
+ lines.push(` ${fmt.gray("Context:")}`);
65
+ for (const [key, value] of Object.entries(error.context)) {
66
+ lines.push(` ${fmt.dim(key)}: ${JSON.stringify(value)}`);
67
+ }
68
+ }
69
+ return lines.join("\n");
70
+ }
71
+ function formatSuccess(atomName, duration) {
72
+ return `${fmt.success("\u2713")} ${fmt.bold(atomName)} ${fmt.gray(`completed in ${duration}ms`)}`;
73
+ }
74
+ function formatFailure(atomName) {
75
+ return `${fmt.error("\u2717")} ${fmt.bold(atomName)} ${fmt.gray("failed")}`;
76
+ }
77
+
78
+ export {
79
+ fmt,
80
+ formatAtomError,
81
+ formatSuccess,
82
+ formatFailure
83
+ };
84
+ //# sourceMappingURL=chunk-S6Z5G5DB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/format.ts"],"sourcesContent":["/**\n * Terminal formatting utilities for CLI output\n */\n\n// ANSI escape codes for colors\nconst codes = {\n reset: '\\x1b[0m',\n bold: '\\x1b[1m',\n dim: '\\x1b[2m',\n red: '\\x1b[31m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n blue: '\\x1b[34m',\n magenta: '\\x1b[35m',\n cyan: '\\x1b[36m',\n gray: '\\x1b[90m',\n};\n\n// Check if colors should be used (has TTY, respects NO_COLOR standard, excludes dumb terminals)\nconst useColors =\n process.stdout.isTTY &&\n !process.env['NO_COLOR'] &&\n process.env['TERM'] !== 'dumb';\n\nfunction colorize(code: keyof typeof codes, text: string): string {\n if (!useColors) return text;\n return `${codes[code]}${text}${codes.reset}`;\n}\n\nexport const fmt = {\n // Colors\n red: (text: string) => colorize('red', text),\n green: (text: string) => colorize('green', text),\n yellow: (text: string) => colorize('yellow', text),\n blue: (text: string) => colorize('blue', text),\n magenta: (text: string) => colorize('magenta', text),\n cyan: (text: string) => colorize('cyan', text),\n gray: (text: string) => colorize('gray', text),\n\n // Styles\n bold: (text: string) => colorize('bold', text),\n dim: (text: string) => colorize('dim', text),\n\n // Semantic helpers\n success: (text: string) => colorize('green', text),\n error: (text: string) => colorize('red', text),\n warning: (text: string) => colorize('yellow', text),\n info: (text: string) => colorize('blue', text),\n hint: (text: string) => colorize('cyan', text),\n\n // Error type colors\n errorType: (type: string): string => {\n switch (type) {\n case 'validation':\n return colorize('yellow', type);\n case 'execution':\n return colorize('red', type);\n case 'dependency':\n return colorize('magenta', type);\n case 'timeout':\n return colorize('cyan', type);\n default:\n return colorize('red', type);\n }\n },\n};\n\n/**\n * Format an AtomError for CLI display\n */\nexport function formatAtomError(error: {\n type: string;\n message: string;\n recoverable: boolean;\n suggestion?: string;\n context?: Record<string, unknown>;\n}): string {\n const lines: string[] = [];\n\n lines.push(`${fmt.error('Error')} ${fmt.gray('[')}${fmt.errorType(error.type)}${fmt.gray(']')}`);\n lines.push(` ${error.message}`);\n\n if (error.suggestion) {\n lines.push(` ${fmt.hint('Suggestion:')} ${error.suggestion}`);\n }\n\n lines.push(\n ` ${fmt.gray('Recoverable:')} ${error.recoverable ? fmt.green('yes') : fmt.red('no')}`\n );\n\n if (error.context && Object.keys(error.context).length > 0) {\n lines.push(` ${fmt.gray('Context:')}`);\n for (const [key, value] of Object.entries(error.context)) {\n lines.push(` ${fmt.dim(key)}: ${JSON.stringify(value)}`);\n }\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Format a success message\n */\nexport function formatSuccess(atomName: string, duration: number): string {\n return `${fmt.success('✓')} ${fmt.bold(atomName)} ${fmt.gray(`completed in ${duration}ms`)}`;\n}\n\n/**\n * Format a failure message\n */\nexport function formatFailure(atomName: string): string {\n return `${fmt.error('✗')} ${fmt.bold(atomName)} ${fmt.gray('failed')}`;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,259 @@
1
+ import {
2
+ fmt
3
+ } from "./chunk-S6Z5G5DB.js";
4
+ import {
5
+ toErrorMessage
6
+ } from "./chunk-PLQJM2KT.js";
7
+
8
+ // src/commands/skills-scan.ts
9
+ import { readdir, readFile, stat, realpath } from "fs/promises";
10
+ import { join, basename } from "path";
11
+ import { homedir } from "os";
12
+ import { z } from "zod";
13
+ var MCPSkillSchema = z.object({
14
+ name: z.string().optional(),
15
+ description: z.string().optional()
16
+ });
17
+ var MCPServerSchema = z.object({
18
+ skills: z.array(MCPSkillSchema).optional()
19
+ });
20
+ var MCPConfigSchema = z.object({
21
+ mcpServers: z.record(z.string(), MCPServerSchema).optional()
22
+ });
23
+ function parseFrontmatter(content) {
24
+ const normalized = content.replace(/\r\n/g, "\n");
25
+ const frontmatterMatch = normalized.match(/^---\n([\s\S]*?)\n---/);
26
+ if (!frontmatterMatch || !frontmatterMatch[1]) {
27
+ return {};
28
+ }
29
+ const frontmatter = frontmatterMatch[1];
30
+ const result = {};
31
+ const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
32
+ if (nameMatch && nameMatch[1]) {
33
+ result.name = nameMatch[1].trim();
34
+ }
35
+ const descMatch = frontmatter.match(/^description:\s*(.+)$/m);
36
+ if (descMatch && descMatch[1]) {
37
+ result.description = descMatch[1].trim();
38
+ }
39
+ return result;
40
+ }
41
+ function truncateDescription(description, maxLength = 80) {
42
+ if (description.length <= maxLength) {
43
+ return description;
44
+ }
45
+ return description.substring(0, maxLength - 3) + "...";
46
+ }
47
+ async function scanSkillEntry(entryPath, source) {
48
+ try {
49
+ const stats = await stat(entryPath);
50
+ let skillPath = entryPath;
51
+ let resolvedPath;
52
+ try {
53
+ const realPath = await realpath(entryPath);
54
+ if (realPath !== entryPath) {
55
+ resolvedPath = realPath;
56
+ }
57
+ } catch {
58
+ }
59
+ if (stats.isDirectory()) {
60
+ skillPath = join(entryPath, "SKILL.md");
61
+ try {
62
+ await stat(skillPath);
63
+ } catch {
64
+ return null;
65
+ }
66
+ } else if (!entryPath.endsWith(".md")) {
67
+ return null;
68
+ }
69
+ const content = await readFile(skillPath, "utf-8");
70
+ const { name, description } = parseFrontmatter(content);
71
+ if (!name) {
72
+ const derivedName = basename(entryPath, ".md");
73
+ return {
74
+ name: derivedName,
75
+ description: description || "",
76
+ location: entryPath,
77
+ source,
78
+ resolvedPath
79
+ };
80
+ }
81
+ return {
82
+ name,
83
+ description: description || "",
84
+ location: entryPath,
85
+ source,
86
+ resolvedPath
87
+ };
88
+ } catch {
89
+ return null;
90
+ }
91
+ }
92
+ async function scanSkillsDirectory(dirPath, source) {
93
+ const skills = [];
94
+ const errors = [];
95
+ try {
96
+ const entries = await readdir(dirPath);
97
+ for (const entry of entries) {
98
+ if (entry.startsWith(".")) {
99
+ continue;
100
+ }
101
+ const entryPath = join(dirPath, entry);
102
+ const skill = await scanSkillEntry(entryPath, source);
103
+ if (skill) {
104
+ skills.push(skill);
105
+ }
106
+ }
107
+ } catch (err) {
108
+ const code = err.code;
109
+ if (code !== "ENOENT") {
110
+ errors.push(`Failed to scan ${dirPath}: ${toErrorMessage(err)}`);
111
+ }
112
+ }
113
+ return { skills, errors };
114
+ }
115
+ function getProjectSkillsPath() {
116
+ return join(process.cwd(), ".claude", "skills");
117
+ }
118
+ function getGlobalSkillsPath() {
119
+ return join(homedir(), ".claude", "skills");
120
+ }
121
+ async function detectMCPSkills() {
122
+ const skills = [];
123
+ const errors = [];
124
+ const mcpConfigPaths = [
125
+ join(homedir(), ".claude", "mcp.json"),
126
+ join(homedir(), ".config", "claude", "mcp.json"),
127
+ join(process.cwd(), ".claude", "mcp.json")
128
+ ];
129
+ for (const configPath of mcpConfigPaths) {
130
+ try {
131
+ const content = await readFile(configPath, "utf-8");
132
+ const json = JSON.parse(content);
133
+ const parseResult = MCPConfigSchema.safeParse(json);
134
+ if (!parseResult.success) {
135
+ continue;
136
+ }
137
+ const config = parseResult.data;
138
+ if (config.mcpServers) {
139
+ const servers = config.mcpServers;
140
+ for (const serverName of Object.keys(servers)) {
141
+ const serverConfig = servers[serverName];
142
+ if (serverConfig?.skills) {
143
+ for (const skill of serverConfig.skills) {
144
+ skills.push({
145
+ name: skill.name || serverName,
146
+ description: skill.description || "",
147
+ location: configPath,
148
+ source: "mcp"
149
+ });
150
+ }
151
+ }
152
+ }
153
+ }
154
+ } catch {
155
+ }
156
+ }
157
+ return { skills, errors };
158
+ }
159
+ async function scanSkills() {
160
+ const allSkills = [];
161
+ const allErrors = [];
162
+ const projectResult = await scanSkillsDirectory(getProjectSkillsPath(), "project");
163
+ allSkills.push(...projectResult.skills);
164
+ allErrors.push(...projectResult.errors);
165
+ const globalResult = await scanSkillsDirectory(getGlobalSkillsPath(), "global");
166
+ allSkills.push(...globalResult.skills);
167
+ allErrors.push(...globalResult.errors);
168
+ const mcpResult = await detectMCPSkills();
169
+ allSkills.push(...mcpResult.skills);
170
+ allErrors.push(...mcpResult.errors);
171
+ allSkills.sort((a, b) => {
172
+ const sourceOrder = { project: 0, global: 1, mcp: 2 };
173
+ const sourceDiff = sourceOrder[a.source] - sourceOrder[b.source];
174
+ if (sourceDiff !== 0) return sourceDiff;
175
+ return a.name.localeCompare(b.name);
176
+ });
177
+ return { skills: allSkills, errors: allErrors };
178
+ }
179
+ async function skillsScanCommand(options) {
180
+ try {
181
+ const result = await scanSkills();
182
+ if (options.json) {
183
+ console.log(JSON.stringify(result, null, 2));
184
+ return;
185
+ }
186
+ if (result.skills.length === 0) {
187
+ console.log(fmt.bold("Skills Scan"));
188
+ console.log("\nNo skills found.\n");
189
+ console.log("Skills can be placed in:");
190
+ console.log(` - Project: ${getProjectSkillsPath()}`);
191
+ console.log(` - Global: ${getGlobalSkillsPath()}`);
192
+ return;
193
+ }
194
+ console.log(fmt.bold("Available Skills"));
195
+ console.log("");
196
+ const projectSkills = result.skills.filter((s) => s.source === "project");
197
+ const globalSkills = result.skills.filter((s) => s.source === "global");
198
+ const mcpSkills = result.skills.filter((s) => s.source === "mcp");
199
+ if (projectSkills.length > 0) {
200
+ console.log(fmt.cyan(`Project Skills (${getProjectSkillsPath()})`));
201
+ for (const skill of projectSkills) {
202
+ console.log(` ${fmt.green(skill.name)}`);
203
+ if (skill.description) {
204
+ console.log(` ${fmt.dim(truncateDescription(skill.description))}`);
205
+ }
206
+ }
207
+ console.log("");
208
+ }
209
+ if (globalSkills.length > 0) {
210
+ console.log(fmt.cyan(`Global Skills (${getGlobalSkillsPath()})`));
211
+ for (const skill of globalSkills) {
212
+ console.log(` ${fmt.green(skill.name)}`);
213
+ if (skill.description) {
214
+ console.log(` ${fmt.dim(truncateDescription(skill.description))}`);
215
+ }
216
+ }
217
+ console.log("");
218
+ }
219
+ if (mcpSkills.length > 0) {
220
+ console.log(fmt.cyan("MCP-Provided Skills"));
221
+ for (const skill of mcpSkills) {
222
+ console.log(` ${fmt.green(skill.name)}`);
223
+ if (skill.description) {
224
+ console.log(` ${fmt.dim(truncateDescription(skill.description))}`);
225
+ }
226
+ }
227
+ console.log("");
228
+ }
229
+ const count = result.skills.length;
230
+ console.log(fmt.success(`Found ${count} skill${count === 1 ? "" : "s"}`));
231
+ if (result.errors.length > 0) {
232
+ console.log("");
233
+ for (const err of result.errors) {
234
+ console.log(fmt.error(`Error: ${err}`));
235
+ }
236
+ }
237
+ } catch (err) {
238
+ const message = toErrorMessage(err);
239
+ if (options.json) {
240
+ console.log(JSON.stringify({ error: message }, null, 2));
241
+ } else {
242
+ console.log(fmt.error(`Skills scan failed: ${message}`));
243
+ }
244
+ process.exit(1);
245
+ }
246
+ }
247
+
248
+ export {
249
+ parseFrontmatter,
250
+ truncateDescription,
251
+ scanSkillEntry,
252
+ scanSkillsDirectory,
253
+ getProjectSkillsPath,
254
+ getGlobalSkillsPath,
255
+ detectMCPSkills,
256
+ scanSkills,
257
+ skillsScanCommand
258
+ };
259
+ //# sourceMappingURL=chunk-UVUDQ4XP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/skills-scan.ts"],"sourcesContent":["/**\n * Skills Scanner - Discover available Claude Code skills.\n *\n * Story 6.6: AOP-1257\n *\n * Acceptance Criteria:\n * - Skills listed with: name, description, location\n * - Skills from project .claude/skills/ included\n * - Skills from ~/.claude/skills/ included\n * - MCP-provided skills detected if available\n */\n\nimport { readdir, readFile, stat, realpath } from 'node:fs/promises';\nimport { join, basename } from 'node:path';\nimport { homedir } from 'node:os';\nimport { z } from 'zod';\nimport { fmt } from '../cli/format.js';\nimport { toErrorMessage } from '../utils/errors.js';\n\n/**\n * Skill information extracted from skill files.\n */\nexport interface SkillInfo {\n name: string;\n description: string;\n location: string;\n source: 'project' | 'global' | 'mcp';\n /** If the skill is a symlink, this is the resolved path */\n resolvedPath?: string;\n}\n\n/**\n * Result of skills scan operation.\n */\nexport interface SkillsScanResult {\n skills: SkillInfo[];\n errors: string[];\n}\n\n/**\n * Zod schema for MCP skill definition within config.\n */\nconst MCPSkillSchema = z.object({\n name: z.string().optional(),\n description: z.string().optional(),\n});\n\n/**\n * Zod schema for MCP server configuration.\n */\nconst MCPServerSchema = z.object({\n skills: z.array(MCPSkillSchema).optional(),\n});\n\n/**\n * Zod schema for MCP config file.\n */\nconst MCPConfigSchema = z.object({\n mcpServers: z.record(z.string(), MCPServerSchema).optional(),\n});\n\n/**\n * Parse YAML frontmatter from a markdown file.\n */\nexport function parseFrontmatter(content: string): { name?: string; description?: string } {\n // Normalize line endings for cross-platform compatibility (Windows CRLF -> LF)\n const normalized = content.replace(/\\r\\n/g, '\\n');\n const frontmatterMatch = normalized.match(/^---\\n([\\s\\S]*?)\\n---/);\n if (!frontmatterMatch || !frontmatterMatch[1]) {\n return {};\n }\n\n const frontmatter = frontmatterMatch[1];\n const result: { name?: string; description?: string } = {};\n\n // Parse name\n const nameMatch = frontmatter.match(/^name:\\s*(.+)$/m);\n if (nameMatch && nameMatch[1]) {\n result.name = nameMatch[1].trim();\n }\n\n // Parse description (may be multi-line)\n const descMatch = frontmatter.match(/^description:\\s*(.+)$/m);\n if (descMatch && descMatch[1]) {\n result.description = descMatch[1].trim();\n }\n\n return result;\n}\n\n/**\n * Truncate a description to fit within a maximum length.\n */\nexport function truncateDescription(description: string, maxLength = 80): string {\n if (description.length <= maxLength) {\n return description;\n }\n return description.substring(0, maxLength - 3) + '...';\n}\n\n/**\n * Scan a skill file or directory for skill information.\n */\nexport async function scanSkillEntry(\n entryPath: string,\n source: 'project' | 'global' | 'mcp'\n): Promise<SkillInfo | null> {\n try {\n const stats = await stat(entryPath);\n let skillPath = entryPath;\n let resolvedPath: string | undefined;\n\n // Check if it's a symlink\n try {\n const realPath = await realpath(entryPath);\n if (realPath !== entryPath) {\n resolvedPath = realPath;\n }\n } catch {\n // Not a symlink or can't resolve\n }\n\n if (stats.isDirectory()) {\n // Look for SKILL.md in the directory\n skillPath = join(entryPath, 'SKILL.md');\n try {\n await stat(skillPath);\n } catch {\n // No SKILL.md, skip this directory\n return null;\n }\n } else if (!entryPath.endsWith('.md')) {\n // Not a markdown file\n return null;\n }\n\n const content = await readFile(skillPath, 'utf-8');\n const { name, description } = parseFrontmatter(content);\n\n if (!name) {\n // No name in frontmatter, derive from path\n const derivedName = basename(entryPath, '.md');\n return {\n name: derivedName,\n description: description || '',\n location: entryPath,\n source,\n resolvedPath,\n };\n }\n\n return {\n name,\n description: description || '',\n location: entryPath,\n source,\n resolvedPath,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Scan a directory for skills.\n */\nexport async function scanSkillsDirectory(\n dirPath: string,\n source: 'project' | 'global' | 'mcp'\n): Promise<{ skills: SkillInfo[]; errors: string[] }> {\n const skills: SkillInfo[] = [];\n const errors: string[] = [];\n\n try {\n const entries = await readdir(dirPath);\n\n for (const entry of entries) {\n // Skip hidden files and common non-skill entries\n if (entry.startsWith('.')) {\n continue;\n }\n\n const entryPath = join(dirPath, entry);\n const skill = await scanSkillEntry(entryPath, source);\n if (skill) {\n skills.push(skill);\n }\n }\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== 'ENOENT') {\n errors.push(`Failed to scan ${dirPath}: ${toErrorMessage(err)}`);\n }\n // ENOENT is fine - directory doesn't exist\n }\n\n return { skills, errors };\n}\n\n/**\n * Get the project skills directory path.\n */\nexport function getProjectSkillsPath(): string {\n return join(process.cwd(), '.claude', 'skills');\n}\n\n/**\n * Get the global skills directory path.\n */\nexport function getGlobalSkillsPath(): string {\n return join(homedir(), '.claude', 'skills');\n}\n\n/**\n * Detect MCP-provided skills by checking environment or MCP config.\n *\n * MCP skills are provided by MCP servers and can be detected through:\n * 1. Claude Code's internal skill registry (if accessible)\n * 2. MCP server configuration files\n * 3. Environment variables set by Claude Code\n *\n * This is a best-effort detection since MCP skills are runtime-provided.\n */\nexport async function detectMCPSkills(): Promise<{ skills: SkillInfo[]; errors: string[] }> {\n const skills: SkillInfo[] = [];\n const errors: string[] = [];\n\n // Check for common MCP skill locations\n const mcpConfigPaths = [\n join(homedir(), '.claude', 'mcp.json'),\n join(homedir(), '.config', 'claude', 'mcp.json'),\n join(process.cwd(), '.claude', 'mcp.json'),\n ];\n\n for (const configPath of mcpConfigPaths) {\n try {\n const content = await readFile(configPath, 'utf-8');\n const json = JSON.parse(content) as unknown;\n const parseResult = MCPConfigSchema.safeParse(json);\n\n if (!parseResult.success) {\n // Invalid config structure, skip this file\n continue;\n }\n\n const config = parseResult.data;\n\n // Look for skill providers in MCP config\n if (config.mcpServers) {\n const servers = config.mcpServers;\n for (const serverName of Object.keys(servers)) {\n const serverConfig = servers[serverName];\n if (serverConfig?.skills) {\n for (const skill of serverConfig.skills) {\n skills.push({\n name: skill.name || serverName,\n description: skill.description || '',\n location: configPath,\n source: 'mcp',\n });\n }\n }\n }\n }\n } catch {\n // Config doesn't exist or isn't valid JSON - that's fine\n }\n }\n\n return { skills, errors };\n}\n\n/**\n * Scan for all available skills from all sources.\n */\nexport async function scanSkills(): Promise<SkillsScanResult> {\n const allSkills: SkillInfo[] = [];\n const allErrors: string[] = [];\n\n // Scan project skills\n const projectResult = await scanSkillsDirectory(getProjectSkillsPath(), 'project');\n allSkills.push(...projectResult.skills);\n allErrors.push(...projectResult.errors);\n\n // Scan global skills\n const globalResult = await scanSkillsDirectory(getGlobalSkillsPath(), 'global');\n allSkills.push(...globalResult.skills);\n allErrors.push(...globalResult.errors);\n\n // Detect MCP skills\n const mcpResult = await detectMCPSkills();\n allSkills.push(...mcpResult.skills);\n allErrors.push(...mcpResult.errors);\n\n // Sort by source (project first, then global, then mcp), then by name\n allSkills.sort((a, b) => {\n const sourceOrder = { project: 0, global: 1, mcp: 2 };\n const sourceDiff = sourceOrder[a.source] - sourceOrder[b.source];\n if (sourceDiff !== 0) return sourceDiff;\n return a.name.localeCompare(b.name);\n });\n\n return { skills: allSkills, errors: allErrors };\n}\n\n/**\n * CLI command handler for skills scan.\n */\nexport async function skillsScanCommand(options: { json?: boolean }): Promise<void> {\n try {\n const result = await scanSkills();\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n if (result.skills.length === 0) {\n console.log(fmt.bold('Skills Scan'));\n console.log('\\nNo skills found.\\n');\n console.log('Skills can be placed in:');\n console.log(` - Project: ${getProjectSkillsPath()}`);\n console.log(` - Global: ${getGlobalSkillsPath()}`);\n return;\n }\n\n console.log(fmt.bold('Available Skills'));\n console.log('');\n\n // Group by source\n const projectSkills = result.skills.filter((s) => s.source === 'project');\n const globalSkills = result.skills.filter((s) => s.source === 'global');\n const mcpSkills = result.skills.filter((s) => s.source === 'mcp');\n\n if (projectSkills.length > 0) {\n console.log(fmt.cyan(`Project Skills (${getProjectSkillsPath()})`));\n for (const skill of projectSkills) {\n console.log(` ${fmt.green(skill.name)}`);\n if (skill.description) {\n console.log(` ${fmt.dim(truncateDescription(skill.description))}`);\n }\n }\n console.log('');\n }\n\n if (globalSkills.length > 0) {\n console.log(fmt.cyan(`Global Skills (${getGlobalSkillsPath()})`));\n for (const skill of globalSkills) {\n console.log(` ${fmt.green(skill.name)}`);\n if (skill.description) {\n console.log(` ${fmt.dim(truncateDescription(skill.description))}`);\n }\n }\n console.log('');\n }\n\n if (mcpSkills.length > 0) {\n console.log(fmt.cyan('MCP-Provided Skills'));\n for (const skill of mcpSkills) {\n console.log(` ${fmt.green(skill.name)}`);\n if (skill.description) {\n console.log(` ${fmt.dim(truncateDescription(skill.description))}`);\n }\n }\n console.log('');\n }\n\n const count = result.skills.length;\n console.log(fmt.success(`Found ${count} skill${count === 1 ? '' : 's'}`));\n\n // Report errors if any\n if (result.errors.length > 0) {\n console.log('');\n for (const err of result.errors) {\n console.log(fmt.error(`Error: ${err}`));\n }\n }\n } catch (err) {\n const message = toErrorMessage(err);\n if (options.json) {\n console.log(JSON.stringify({ error: message }, null, 2));\n } else {\n console.log(fmt.error(`Skills scan failed: ${message}`));\n }\n process.exit(1);\n }\n}\n"],"mappings":"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","names":[]}