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 @@
1
+ {"version":3,"sources":["../src/parser/signatures.ts"],"sourcesContent":["/**\n * AST Signature Extraction — extract function signatures from parsed ASTs.\n *\n * Shared between `extract --code` (G4) and `suggest` (G3).\n * Uses oxc-parser's typed Program AST to find exported functions\n * with their parameter types, return types, and metadata.\n */\n\nimport type { Program } from '@oxc-project/types';\n\nexport interface ExtractedParam {\n name: string;\n type?: string;\n rest?: boolean;\n hasDefault?: boolean;\n}\n\nexport interface AstComment {\n type: 'Block' | 'Line';\n value: string;\n start: number;\n end: number;\n}\n\nexport interface ExtractedSignature {\n name: string;\n line: number;\n endLine: number;\n exported: boolean;\n exportDefault: boolean;\n async: boolean;\n params: ExtractedParam[];\n returnType?: string;\n hasJSDoc: boolean;\n}\n\n/**\n * Convert an oxc TSTypeAnnotation node to a human-readable type string.\n */\nfunction typeAnnotationToString(typeAnnotation: unknown): string | undefined {\n if (!typeAnnotation || typeof typeAnnotation !== 'object') return undefined;\n const ta = typeAnnotation as Record<string, unknown>;\n\n // Unwrap TSTypeAnnotation wrapper\n const inner = ta['type'] === 'TSTypeAnnotation'\n ? ta['typeAnnotation'] as Record<string, unknown>\n : ta;\n\n if (!inner || typeof inner !== 'object') return undefined;\n\n switch (inner['type']) {\n case 'TSStringKeyword': return 'string';\n case 'TSNumberKeyword': return 'number';\n case 'TSBooleanKeyword': return 'boolean';\n case 'TSVoidKeyword': return 'void';\n case 'TSAnyKeyword': return 'any';\n case 'TSUnknownKeyword': return 'unknown';\n case 'TSNullKeyword': return 'null';\n case 'TSUndefinedKeyword': return 'undefined';\n case 'TSNeverKeyword': return 'never';\n case 'TSBigIntKeyword': return 'bigint';\n case 'TSSymbolKeyword': return 'symbol';\n case 'TSObjectKeyword': return 'object';\n\n case 'TSArrayType': {\n const elemType = typeAnnotationToString(inner['elementType']);\n return elemType ? `${elemType}[]` : 'unknown[]';\n }\n\n case 'TSTypeReference': {\n const typeName = inner['typeName'] as Record<string, unknown> | undefined;\n const name = typeName?.['name'] as string | undefined;\n if (!name) return undefined;\n\n const typeArgs = inner['typeArguments'] as Record<string, unknown> | undefined;\n if (typeArgs && Array.isArray(typeArgs['params'])) {\n const args = (typeArgs['params'] as unknown[])\n .map(a => typeAnnotationToString(a))\n .filter(Boolean);\n if (args.length > 0) return `${name}<${args.join(', ')}>`;\n }\n return name;\n }\n\n case 'TSUnionType': {\n const types = (inner['types'] as unknown[] | undefined);\n if (!types) return undefined;\n const parts = types.map(t => typeAnnotationToString(t)).filter(Boolean);\n return parts.join(' | ');\n }\n\n case 'TSIntersectionType': {\n const types = (inner['types'] as unknown[] | undefined);\n if (!types) return undefined;\n const parts = types.map(t => typeAnnotationToString(t)).filter(Boolean);\n return parts.join(' & ');\n }\n\n case 'TSLiteralType': {\n const literal = inner['literal'] as Record<string, unknown> | undefined;\n if (!literal) return undefined;\n if (literal['type'] === 'StringLiteral') return `'${literal['value']}'`;\n if (literal['type'] === 'NumericLiteral') return String(literal['value']);\n if (literal['type'] === 'BooleanLiteral') return String(literal['value']);\n return undefined;\n }\n\n case 'TSTupleType': {\n const elems = (inner['elementTypes'] as unknown[] | undefined);\n if (!elems) return undefined;\n const parts = elems.map(t => typeAnnotationToString(t)).filter(Boolean);\n return `[${parts.join(', ')}]`;\n }\n\n case 'TSFunctionType': return 'Function';\n case 'TSTypePredicate': return 'boolean';\n\n default:\n return undefined;\n }\n}\n\n/**\n * Extract parameter info from an oxc function parameter node.\n */\nfunction extractParam(param: Record<string, unknown>): ExtractedParam | undefined {\n switch (param['type']) {\n case 'Identifier': {\n return {\n name: param['name'] as string,\n type: typeAnnotationToString(param['typeAnnotation']),\n };\n }\n\n case 'AssignmentPattern': {\n // Default parameter: left is the identifier, right is the default value\n const left = param['left'] as Record<string, unknown> | undefined;\n if (!left) return undefined;\n const base = extractParam(left);\n if (base) base.hasDefault = true;\n return base;\n }\n\n case 'RestElement': {\n const arg = param['argument'] as Record<string, unknown> | undefined;\n if (!arg) return undefined;\n const name = arg['name'] as string | undefined;\n // Type annotation may be on RestElement itself or on the argument\n const typeAnno = param['typeAnnotation'] ?? arg['typeAnnotation'];\n return {\n name: name ?? '...args',\n type: typeAnnotationToString(typeAnno),\n rest: true,\n };\n }\n\n case 'ObjectPattern':\n return { name: 'options', type: typeAnnotationToString(param['typeAnnotation']) };\n\n case 'ArrayPattern':\n return { name: 'items', type: typeAnnotationToString(param['typeAnnotation']) };\n\n default:\n return undefined;\n }\n}\n\n/**\n * Check if a JSDoc block comment immediately precedes the given position.\n * Uses AST comment nodes instead of regex scanning through source.\n * Allows whitespace and keywords (export, default, async) between comment and node.\n */\nfunction hasJSDocBefore(nodeStart: number, sourceCode: string, comments: AstComment[]): boolean {\n // Find the closest block comment that ends before this node\n for (let i = comments.length - 1; i >= 0; i--) {\n const comment = comments[i]!;\n if (comment.type !== 'Block' || !comment.value.startsWith('*')) continue;\n if (comment.end > nodeStart) continue;\n // Check that only whitespace/keywords appear between comment end and node start\n const between = sourceCode.substring(comment.end, nodeStart);\n if (/^\\s*(export\\s+)?(default\\s+)?(async\\s+)?$/.test(between)) return true;\n // If there's non-whitespace/keyword content, this comment isn't for this node\n break;\n }\n return false;\n}\n\n/**\n * Extract function signature from a function/arrow node.\n */\nfunction extractFunctionSignature(\n node: Record<string, unknown>,\n name: string,\n exported: boolean,\n exportDefault: boolean,\n sourceCode: string,\n comments: AstComment[],\n): ExtractedSignature | undefined {\n const params = (node['params'] as unknown[]) ?? [];\n const extractedParams: ExtractedParam[] = [];\n\n for (const p of params) {\n if (p && typeof p === 'object') {\n const ep = extractParam(p as Record<string, unknown>);\n if (ep) extractedParams.push(ep);\n }\n }\n\n const start = node['start'] as number | undefined;\n const end = node['end'] as number | undefined;\n\n // Calculate line numbers from character offsets\n let line = 1;\n let endLine = 1;\n if (start !== undefined) {\n line = sourceCode.substring(0, start).split('\\n').length;\n }\n if (end !== undefined) {\n endLine = sourceCode.substring(0, end).split('\\n').length;\n }\n\n const hasJSDoc = start !== undefined ? hasJSDocBefore(start, sourceCode, comments) : false;\n\n return {\n name,\n line,\n endLine,\n exported,\n exportDefault,\n async: (node['async'] as boolean) ?? false,\n params: extractedParams,\n returnType: typeAnnotationToString(node['returnType']),\n hasJSDoc,\n };\n}\n\n/**\n * Extract all function signatures from a parsed AST Program.\n * @param comments - AST comment nodes from oxc-parser for JSDoc detection. Falls back to regex scan if omitted.\n */\nexport function extractSignatures(ast: Program, sourceCode: string, comments: AstComment[] = []): ExtractedSignature[] {\n const signatures: ExtractedSignature[] = [];\n const body = (ast as unknown as Record<string, unknown>)['body'] as unknown[];\n if (!Array.isArray(body)) return signatures;\n\n // Pre-scan: collect names exported via specifiers (e.g. `export { foo, bar }`)\n const exportedNames = new Set<string>();\n for (const node of body) {\n if (!node || typeof node !== 'object') continue;\n const n = node as Record<string, unknown>;\n if (n['type'] === 'ExportNamedDeclaration' && !n['declaration']) {\n const specifiers = n['specifiers'] as unknown[] | undefined;\n if (specifiers) {\n for (const spec of specifiers) {\n const s = spec as Record<string, unknown>;\n // exported.name is the public name; fall back to local.name\n const exported = s['exported'] as Record<string, unknown> | undefined;\n const local = s['local'] as Record<string, unknown> | undefined;\n const name = (exported?.['name'] ?? local?.['name']) as string | undefined;\n if (name) exportedNames.add(name);\n }\n }\n }\n }\n\n for (const node of body) {\n if (!node || typeof node !== 'object') continue;\n const n = node as Record<string, unknown>;\n\n switch (n['type']) {\n case 'ExportNamedDeclaration': {\n const decl = n['declaration'] as Record<string, unknown> | undefined;\n if (!decl) break; // specifier-only exports handled via pre-scan\n\n if (decl['type'] === 'FunctionDeclaration') {\n const id = decl['id'] as Record<string, unknown> | undefined;\n const name = id?.['name'] as string | undefined;\n if (name) {\n const sig = extractFunctionSignature(decl, name, true, false, sourceCode, comments);\n if (sig) signatures.push(sig);\n }\n } else if (decl['type'] === 'VariableDeclaration') {\n const declarators = decl['declarations'] as unknown[] | undefined;\n if (declarators) {\n for (const d of declarators) {\n const declarator = d as Record<string, unknown>;\n const id = declarator['id'] as Record<string, unknown> | undefined;\n const init = declarator['init'] as Record<string, unknown> | undefined;\n const name = id?.['name'] as string | undefined;\n\n if (name && init && (init['type'] === 'ArrowFunctionExpression' || init['type'] === 'FunctionExpression')) {\n const sig = extractFunctionSignature(init, name, true, false, sourceCode, comments);\n if (sig) signatures.push(sig);\n }\n }\n }\n }\n break;\n }\n\n case 'ExportDefaultDeclaration': {\n const decl = n['declaration'] as Record<string, unknown> | undefined;\n if (!decl) break;\n\n if (decl['type'] === 'FunctionDeclaration') {\n const id = decl['id'] as Record<string, unknown> | undefined;\n const name = (id?.['name'] as string) ?? 'default';\n const sig = extractFunctionSignature(decl, name, true, true, sourceCode, comments);\n if (sig) signatures.push(sig);\n } else if (decl['type'] === 'ArrowFunctionExpression' || decl['type'] === 'FunctionExpression') {\n const sig = extractFunctionSignature(decl, 'default', true, true, sourceCode, comments);\n if (sig) signatures.push(sig);\n }\n break;\n }\n\n case 'FunctionDeclaration': {\n // Top-level function — may be exported via `export { name }`\n const id = n['id'] as Record<string, unknown> | undefined;\n const name = id?.['name'] as string | undefined;\n if (name) {\n const exported = exportedNames.has(name);\n const sig = extractFunctionSignature(n, name, exported, false, sourceCode, comments);\n if (sig) signatures.push(sig);\n }\n break;\n }\n\n case 'VariableDeclaration': {\n // Top-level arrow/function expressions — may be exported via `export { name }`\n const declarators = n['declarations'] as unknown[] | undefined;\n if (declarators) {\n for (const d of declarators) {\n const declarator = d as Record<string, unknown>;\n const id = declarator['id'] as Record<string, unknown> | undefined;\n const init = declarator['init'] as Record<string, unknown> | undefined;\n const name = id?.['name'] as string | undefined;\n\n if (name && init && (init['type'] === 'ArrowFunctionExpression' || init['type'] === 'FunctionExpression')) {\n const exported = exportedNames.has(name);\n const sig = extractFunctionSignature(init, name, exported, false, sourceCode, comments);\n if (sig) signatures.push(sig);\n }\n }\n }\n break;\n }\n }\n }\n\n return signatures;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,182 @@
1
+ import {
2
+ getRegistryPath,
3
+ loadRegistry,
4
+ saveRegistry
5
+ } from "./chunk-YKJO3ZFY.js";
6
+ import {
7
+ fmt
8
+ } from "./chunk-S6Z5G5DB.js";
9
+ import {
10
+ toErrorMessage
11
+ } from "./chunk-PLQJM2KT.js";
12
+
13
+ // src/commands/skills-assign.ts
14
+ function getSkills(atom) {
15
+ const skills = atom.skills ? [...atom.skills] : [];
16
+ if (atom.skill && !skills.includes(atom.skill)) {
17
+ skills.push(atom.skill);
18
+ }
19
+ return skills;
20
+ }
21
+ async function assignSkill(atomName, skillName) {
22
+ const projectRoot = process.cwd();
23
+ const registry = await loadRegistry(getRegistryPath(projectRoot));
24
+ const atom = registry.atoms[atomName];
25
+ if (!atom) {
26
+ throw new Error(`Atom "${atomName}" not found in registry. Register it first with \`atomic register\`.`);
27
+ }
28
+ const currentSkills = getSkills(atom);
29
+ if (currentSkills.includes(skillName)) {
30
+ return {
31
+ success: true,
32
+ atomName,
33
+ skills: currentSkills,
34
+ action: "assigned",
35
+ message: `Skill "${skillName}" is already assigned to atom "${atomName}"`
36
+ };
37
+ }
38
+ const newSkills = [...currentSkills, skillName];
39
+ registry.atoms[atomName] = {
40
+ ...atom,
41
+ skills: newSkills
42
+ };
43
+ await saveRegistry(getRegistryPath(projectRoot), registry);
44
+ return {
45
+ success: true,
46
+ atomName,
47
+ skills: newSkills,
48
+ action: "assigned"
49
+ };
50
+ }
51
+ async function removeSkill(atomName, skillName) {
52
+ const projectRoot = process.cwd();
53
+ const registry = await loadRegistry(getRegistryPath(projectRoot));
54
+ const atom = registry.atoms[atomName];
55
+ if (!atom) {
56
+ throw new Error(`Atom "${atomName}" not found in registry.`);
57
+ }
58
+ const currentSkills = getSkills(atom);
59
+ if (!currentSkills.includes(skillName)) {
60
+ return {
61
+ success: true,
62
+ atomName,
63
+ skills: currentSkills,
64
+ action: "removed",
65
+ message: `Skill "${skillName}" is not assigned to atom "${atomName}"`
66
+ };
67
+ }
68
+ const newSkills = currentSkills.filter((s) => s !== skillName);
69
+ registry.atoms[atomName] = {
70
+ ...atom,
71
+ skills: newSkills,
72
+ // Clear legacy skill field if it matches
73
+ skill: atom.skill === skillName ? void 0 : atom.skill
74
+ };
75
+ await saveRegistry(getRegistryPath(projectRoot), registry);
76
+ return {
77
+ success: true,
78
+ atomName,
79
+ skills: newSkills,
80
+ action: "removed"
81
+ };
82
+ }
83
+ async function listAtomSkills(atomName) {
84
+ const projectRoot = process.cwd();
85
+ const registry = await loadRegistry(getRegistryPath(projectRoot));
86
+ const atom = registry.atoms[atomName];
87
+ if (!atom) {
88
+ throw new Error(`Atom "${atomName}" not found in registry.`);
89
+ }
90
+ const skills = getSkills(atom);
91
+ return {
92
+ success: true,
93
+ atomName,
94
+ skills,
95
+ action: "listed"
96
+ };
97
+ }
98
+ async function skillsAssignCommand(atomName, options) {
99
+ try {
100
+ const result = await assignSkill(atomName, options.skill);
101
+ if (options.json) {
102
+ console.log(JSON.stringify(result, null, 2));
103
+ return;
104
+ }
105
+ if (result.message) {
106
+ console.log(fmt.dim(result.message));
107
+ } else {
108
+ console.log(fmt.success(`Assigned skill "${options.skill}" to atom "${atomName}"`));
109
+ }
110
+ console.log(` Skills: ${result.skills.join(", ") || "(none)"}`);
111
+ } catch (err) {
112
+ const message = toErrorMessage(err);
113
+ if (options.json) {
114
+ console.log(JSON.stringify({ success: false, error: message }, null, 2));
115
+ } else {
116
+ console.log(fmt.error(`Skill assignment failed: ${message}`));
117
+ }
118
+ process.exit(1);
119
+ }
120
+ }
121
+ async function skillsRemoveCommand(atomName, options) {
122
+ try {
123
+ const result = await removeSkill(atomName, options.skill);
124
+ if (options.json) {
125
+ console.log(JSON.stringify(result, null, 2));
126
+ return;
127
+ }
128
+ if (result.message) {
129
+ console.log(fmt.dim(result.message));
130
+ } else {
131
+ console.log(fmt.success(`Removed skill "${options.skill}" from atom "${atomName}"`));
132
+ }
133
+ console.log(` Skills: ${result.skills.join(", ") || "(none)"}`);
134
+ } catch (err) {
135
+ const message = toErrorMessage(err);
136
+ if (options.json) {
137
+ console.log(JSON.stringify({ success: false, error: message }, null, 2));
138
+ } else {
139
+ console.log(fmt.error(`Skill removal failed: ${message}`));
140
+ }
141
+ process.exit(1);
142
+ }
143
+ }
144
+ async function skillsListAtomCommand(atomName, options) {
145
+ try {
146
+ const result = await listAtomSkills(atomName);
147
+ if (options.json) {
148
+ console.log(JSON.stringify(result, null, 2));
149
+ return;
150
+ }
151
+ console.log(fmt.bold(`Skills for "${atomName}"`));
152
+ console.log("");
153
+ if (result.skills.length === 0) {
154
+ console.log(fmt.dim("No skills assigned to this atom."));
155
+ console.log("");
156
+ console.log(`Use ${fmt.cyan("atomic skills assign " + atomName + " --skill <name>")} to assign a skill.`);
157
+ } else {
158
+ for (const skill of result.skills) {
159
+ console.log(` ${fmt.green(skill)}`);
160
+ }
161
+ console.log("");
162
+ console.log(fmt.dim(`${result.skills.length} skill${result.skills.length === 1 ? "" : "s"} assigned`));
163
+ }
164
+ } catch (err) {
165
+ const message = toErrorMessage(err);
166
+ if (options.json) {
167
+ console.log(JSON.stringify({ success: false, error: message }, null, 2));
168
+ } else {
169
+ console.log(fmt.error(`Failed to list skills: ${message}`));
170
+ }
171
+ process.exit(1);
172
+ }
173
+ }
174
+ export {
175
+ assignSkill,
176
+ listAtomSkills,
177
+ removeSkill,
178
+ skillsAssignCommand,
179
+ skillsListAtomCommand,
180
+ skillsRemoveCommand
181
+ };
182
+ //# sourceMappingURL=skills-assign-IHOXX4AI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/skills-assign.ts"],"sourcesContent":["/**\n * Skill Assignment - Assign, list, and remove skills from atoms.\n *\n * Story 6.8: AOP-1259\n *\n * Acceptance Criteria:\n * - atomic skills assign <atom> --skill <name> updates atom's skill field\n * - Registration updated in .atomic/registry.json\n * - Subsequent executions load the skill\n * - atomic skills list <atom> shows assigned skills\n * - atomic skills remove <atom> --skill <name> removes assignment\n */\n\nimport { fmt } from '../cli/format.js';\nimport { loadRegistry, saveRegistry, getRegistryPath } from '../storage/index.js';\nimport type { RegistryAtom } from '../schemas/registry.js';\nimport { toErrorMessage } from '../utils/errors.js';\n\n/**\n * Result of skill assignment operations.\n */\nexport interface SkillAssignResult {\n success: boolean;\n atomName: string;\n skills: string[];\n action: 'assigned' | 'removed' | 'listed';\n message?: string;\n}\n\n/**\n * Get the skills array from an atom entry.\n * Handles both the old 'skill' field and new 'skills' array.\n */\nfunction getSkills(atom: RegistryAtom): string[] {\n const skills: string[] = atom.skills ? [...atom.skills] : [];\n // Include legacy 'skill' field if not already in skills array\n if (atom.skill && !skills.includes(atom.skill)) {\n skills.push(atom.skill);\n }\n return skills;\n}\n\n/**\n * Assign a skill to an atom.\n */\nexport async function assignSkill(\n atomName: string,\n skillName: string\n): Promise<SkillAssignResult> {\n const projectRoot = process.cwd();\n const registry = await loadRegistry(getRegistryPath(projectRoot));\n\n const atom = registry.atoms[atomName];\n if (!atom) {\n throw new Error(`Atom \"${atomName}\" not found in registry. Register it first with \\`atomic register\\`.`);\n }\n\n const currentSkills = getSkills(atom);\n\n if (currentSkills.includes(skillName)) {\n return {\n success: true,\n atomName,\n skills: currentSkills,\n action: 'assigned',\n message: `Skill \"${skillName}\" is already assigned to atom \"${atomName}\"`,\n };\n }\n\n // Add the skill\n const newSkills = [...currentSkills, skillName];\n registry.atoms[atomName] = {\n ...atom,\n skills: newSkills,\n };\n\n await saveRegistry(getRegistryPath(projectRoot), registry);\n\n return {\n success: true,\n atomName,\n skills: newSkills,\n action: 'assigned',\n };\n}\n\n/**\n * Remove a skill from an atom.\n */\nexport async function removeSkill(\n atomName: string,\n skillName: string\n): Promise<SkillAssignResult> {\n const projectRoot = process.cwd();\n const registry = await loadRegistry(getRegistryPath(projectRoot));\n\n const atom = registry.atoms[atomName];\n if (!atom) {\n throw new Error(`Atom \"${atomName}\" not found in registry.`);\n }\n\n const currentSkills = getSkills(atom);\n\n if (!currentSkills.includes(skillName)) {\n return {\n success: true,\n atomName,\n skills: currentSkills,\n action: 'removed',\n message: `Skill \"${skillName}\" is not assigned to atom \"${atomName}\"`,\n };\n }\n\n // Remove the skill\n const newSkills = currentSkills.filter((s) => s !== skillName);\n registry.atoms[atomName] = {\n ...atom,\n skills: newSkills,\n // Clear legacy skill field if it matches\n skill: atom.skill === skillName ? undefined : atom.skill,\n };\n\n await saveRegistry(getRegistryPath(projectRoot), registry);\n\n return {\n success: true,\n atomName,\n skills: newSkills,\n action: 'removed',\n };\n}\n\n/**\n * List skills assigned to an atom.\n */\nexport async function listAtomSkills(atomName: string): Promise<SkillAssignResult> {\n const projectRoot = process.cwd();\n const registry = await loadRegistry(getRegistryPath(projectRoot));\n\n const atom = registry.atoms[atomName];\n if (!atom) {\n throw new Error(`Atom \"${atomName}\" not found in registry.`);\n }\n\n const skills = getSkills(atom);\n\n return {\n success: true,\n atomName,\n skills,\n action: 'listed',\n };\n}\n\n/**\n * CLI command handler for skills assign.\n */\nexport async function skillsAssignCommand(\n atomName: string,\n options: { skill: string; json?: boolean }\n): Promise<void> {\n try {\n const result = await assignSkill(atomName, options.skill);\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n if (result.message) {\n console.log(fmt.dim(result.message));\n } else {\n console.log(fmt.success(`Assigned skill \"${options.skill}\" to atom \"${atomName}\"`));\n }\n console.log(` Skills: ${result.skills.join(', ') || '(none)'}`);\n } catch (err) {\n const message = toErrorMessage(err);\n if (options.json) {\n console.log(JSON.stringify({ success: false, error: message }, null, 2));\n } else {\n console.log(fmt.error(`Skill assignment failed: ${message}`));\n }\n process.exit(1);\n }\n}\n\n/**\n * CLI command handler for skills remove.\n */\nexport async function skillsRemoveCommand(\n atomName: string,\n options: { skill: string; json?: boolean }\n): Promise<void> {\n try {\n const result = await removeSkill(atomName, options.skill);\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n if (result.message) {\n console.log(fmt.dim(result.message));\n } else {\n console.log(fmt.success(`Removed skill \"${options.skill}\" from atom \"${atomName}\"`));\n }\n console.log(` Skills: ${result.skills.join(', ') || '(none)'}`);\n } catch (err) {\n const message = toErrorMessage(err);\n if (options.json) {\n console.log(JSON.stringify({ success: false, error: message }, null, 2));\n } else {\n console.log(fmt.error(`Skill removal failed: ${message}`));\n }\n process.exit(1);\n }\n}\n\n/**\n * CLI command handler for skills list <atom>.\n */\nexport async function skillsListAtomCommand(\n atomName: string,\n options: { json?: boolean }\n): Promise<void> {\n try {\n const result = await listAtomSkills(atomName);\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n console.log(fmt.bold(`Skills for \"${atomName}\"`));\n console.log('');\n\n if (result.skills.length === 0) {\n console.log(fmt.dim('No skills assigned to this atom.'));\n console.log('');\n console.log(`Use ${fmt.cyan('atomic skills assign ' + atomName + ' --skill <name>')} to assign a skill.`);\n } else {\n for (const skill of result.skills) {\n console.log(` ${fmt.green(skill)}`);\n }\n console.log('');\n console.log(fmt.dim(`${result.skills.length} skill${result.skills.length === 1 ? '' : 's'} assigned`));\n }\n } catch (err) {\n const message = toErrorMessage(err);\n if (options.json) {\n console.log(JSON.stringify({ success: false, error: message }, null, 2));\n } else {\n console.log(fmt.error(`Failed to list skills: ${message}`));\n }\n process.exit(1);\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,20 @@
1
+ import {
2
+ extractSkillInstructions,
3
+ formatLoadedSkills,
4
+ loadSkill,
5
+ loadSkillsForAtom
6
+ } from "./chunk-55AP34JO.js";
7
+ import {
8
+ buildSkillContext
9
+ } from "./chunk-6MDHM2B4.js";
10
+ import "./chunk-UVUDQ4XP.js";
11
+ import "./chunk-S6Z5G5DB.js";
12
+ import "./chunk-PLQJM2KT.js";
13
+ export {
14
+ buildSkillContext,
15
+ extractSkillInstructions,
16
+ formatLoadedSkills,
17
+ loadSkill,
18
+ loadSkillsForAtom
19
+ };
20
+ //# sourceMappingURL=skills-load-JSD5UG2K.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,25 @@
1
+ import {
2
+ detectMCPSkills,
3
+ getGlobalSkillsPath,
4
+ getProjectSkillsPath,
5
+ parseFrontmatter,
6
+ scanSkillEntry,
7
+ scanSkills,
8
+ scanSkillsDirectory,
9
+ skillsScanCommand,
10
+ truncateDescription
11
+ } from "./chunk-UVUDQ4XP.js";
12
+ import "./chunk-S6Z5G5DB.js";
13
+ import "./chunk-PLQJM2KT.js";
14
+ export {
15
+ detectMCPSkills,
16
+ getGlobalSkillsPath,
17
+ getProjectSkillsPath,
18
+ parseFrontmatter,
19
+ scanSkillEntry,
20
+ scanSkills,
21
+ scanSkillsDirectory,
22
+ skillsScanCommand,
23
+ truncateDescription
24
+ };
25
+ //# sourceMappingURL=skills-scan-WACJFRJN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,269 @@
1
+ import {
2
+ StorageNotInitializedError,
3
+ getRegistryPath,
4
+ loadRegistry
5
+ } from "./chunk-YKJO3ZFY.js";
6
+ import {
7
+ scanSkills
8
+ } from "./chunk-UVUDQ4XP.js";
9
+ import {
10
+ fmt
11
+ } from "./chunk-S6Z5G5DB.js";
12
+ import {
13
+ toErrorMessage
14
+ } from "./chunk-PLQJM2KT.js";
15
+
16
+ // src/commands/skills-suggest.ts
17
+ var SKILL_CATEGORIES = [
18
+ {
19
+ name: "testing",
20
+ keywords: ["test", "testing", "spec", "assertion", "expect", "verify", "validate"],
21
+ descriptionKeywords: ["test", "verify", "validate", "check", "assert"],
22
+ inputKeywords: ["test", "spec", "fixture", "mock", "stub"],
23
+ outputKeywords: ["result", "pass", "fail", "coverage", "report"],
24
+ explanationTemplate: "This atom appears to involve testing or validation. A testing skill can help with writing comprehensive test cases and assertions."
25
+ },
26
+ {
27
+ name: "code-review",
28
+ keywords: ["review", "lint", "analyze", "quality", "style", "format"],
29
+ descriptionKeywords: ["review", "analyze", "check", "quality", "lint", "format"],
30
+ inputKeywords: ["code", "source", "file", "diff", "patch"],
31
+ outputKeywords: ["issues", "suggestions", "warnings", "errors", "feedback"],
32
+ explanationTemplate: "This atom works with code analysis or quality checks. A code-review skill can provide structured feedback and improvement suggestions."
33
+ },
34
+ {
35
+ name: "documentation",
36
+ keywords: ["doc", "document", "readme", "markdown", "comment", "explain"],
37
+ descriptionKeywords: ["document", "explain", "describe", "write", "generate"],
38
+ inputKeywords: ["code", "function", "api", "module", "interface"],
39
+ outputKeywords: ["markdown", "readme", "doc", "documentation", "comment"],
40
+ explanationTemplate: "This atom involves documentation generation or management. A documentation skill can help create clear, comprehensive docs."
41
+ },
42
+ {
43
+ name: "refactoring",
44
+ keywords: ["refactor", "restructure", "improve", "optimize", "clean"],
45
+ descriptionKeywords: ["refactor", "improve", "optimize", "restructure", "simplify"],
46
+ inputKeywords: ["code", "function", "class", "module", "component"],
47
+ outputKeywords: ["code", "improved", "optimized", "refactored", "cleaned"],
48
+ explanationTemplate: "This atom focuses on code improvement or restructuring. A refactoring skill can guide systematic code improvements."
49
+ },
50
+ {
51
+ name: "generation",
52
+ keywords: ["generate", "create", "scaffold", "template", "boilerplate"],
53
+ descriptionKeywords: ["generate", "create", "scaffold", "build", "produce"],
54
+ inputKeywords: ["config", "params", "options", "template", "schema"],
55
+ outputKeywords: ["code", "file", "component", "module", "template"],
56
+ explanationTemplate: "This atom generates code or content from templates. A generation skill can help produce consistent, well-structured output."
57
+ },
58
+ {
59
+ name: "data-processing",
60
+ keywords: ["data", "transform", "parse", "convert", "process", "extract"],
61
+ descriptionKeywords: ["transform", "parse", "convert", "process", "extract", "map"],
62
+ inputKeywords: ["data", "json", "csv", "xml", "input", "raw"],
63
+ outputKeywords: ["data", "result", "transformed", "processed", "output"],
64
+ explanationTemplate: "This atom processes or transforms data. A data-processing skill can help with data validation and transformation patterns."
65
+ },
66
+ {
67
+ name: "api-integration",
68
+ keywords: ["api", "http", "request", "fetch", "endpoint", "rest", "graphql"],
69
+ descriptionKeywords: ["api", "fetch", "request", "call", "integrate", "connect"],
70
+ inputKeywords: ["url", "endpoint", "params", "headers", "body", "query"],
71
+ outputKeywords: ["response", "data", "result", "status", "error"],
72
+ explanationTemplate: "This atom interacts with external APIs. An API integration skill can help with proper error handling and response processing."
73
+ },
74
+ {
75
+ name: "file-operations",
76
+ keywords: ["file", "read", "write", "path", "directory", "filesystem"],
77
+ descriptionKeywords: ["file", "read", "write", "save", "load", "store"],
78
+ inputKeywords: ["path", "file", "directory", "filename", "content"],
79
+ outputKeywords: ["content", "file", "saved", "written", "created"],
80
+ explanationTemplate: "This atom works with files or the filesystem. A file-operations skill can help with safe file handling and path management."
81
+ }
82
+ ];
83
+ function extractSchemaKeywords(schema) {
84
+ const keywords = [];
85
+ let schemaStr;
86
+ try {
87
+ schemaStr = JSON.stringify(schema);
88
+ } catch {
89
+ return [];
90
+ }
91
+ const fieldMatches = schemaStr.match(/"([a-z_][a-z0-9_]*)"/gi) || [];
92
+ for (const match of fieldMatches) {
93
+ const field = match.replace(/"/g, "").toLowerCase();
94
+ if (field.length > 2 && !["type", "object", "string", "number", "boolean"].includes(field)) {
95
+ keywords.push(field);
96
+ }
97
+ }
98
+ return [...new Set(keywords)];
99
+ }
100
+ function calculateKeywordMatch(targetKeywords, categoryKeywords) {
101
+ const matched = [];
102
+ let score = 0;
103
+ for (const target of targetKeywords) {
104
+ const targetLower = target.toLowerCase();
105
+ for (const keyword of categoryKeywords) {
106
+ if (targetLower.includes(keyword) || keyword.includes(targetLower)) {
107
+ matched.push(keyword);
108
+ score += targetLower === keyword ? 1 : 0.5;
109
+ }
110
+ }
111
+ }
112
+ return { score, matched: [...new Set(matched)] };
113
+ }
114
+ function analyzeAtom(atomName, description, inputKeywords, outputKeywords) {
115
+ const suggestions = [];
116
+ const descWords = description.toLowerCase().split(/\s+/).filter((word) => word.length > 2);
117
+ for (const category of SKILL_CATEGORIES) {
118
+ let totalScore = 0;
119
+ const allMatched = [];
120
+ const descMatch = calculateKeywordMatch(descWords, category.descriptionKeywords);
121
+ totalScore += descMatch.score * 2;
122
+ allMatched.push(...descMatch.matched);
123
+ const inputMatch = calculateKeywordMatch(inputKeywords, category.inputKeywords);
124
+ totalScore += inputMatch.score;
125
+ allMatched.push(...inputMatch.matched);
126
+ const outputMatch = calculateKeywordMatch(outputKeywords, category.outputKeywords);
127
+ totalScore += outputMatch.score;
128
+ allMatched.push(...outputMatch.matched);
129
+ const nameMatch = calculateKeywordMatch([atomName], category.keywords);
130
+ totalScore += nameMatch.score * 1.5;
131
+ allMatched.push(...nameMatch.matched);
132
+ const MATCH_RATE_BASELINE = 0.3;
133
+ const maxPossibleScore = (category.descriptionKeywords.length * 2 + category.inputKeywords.length + category.outputKeywords.length + category.keywords.length * 1.5) * MATCH_RATE_BASELINE;
134
+ const confidence = Math.min(totalScore / maxPossibleScore, 1);
135
+ if (confidence > 0.1) {
136
+ suggestions.push({
137
+ skillName: category.name,
138
+ confidence,
139
+ explanation: category.explanationTemplate,
140
+ matchedKeywords: [...new Set(allMatched)],
141
+ category: category.name
142
+ });
143
+ }
144
+ }
145
+ suggestions.sort((a, b) => b.confidence - a.confidence);
146
+ return suggestions;
147
+ }
148
+ async function loadAtomDefinition(atomName) {
149
+ try {
150
+ const registryPath = getRegistryPath(process.cwd());
151
+ const registry = await loadRegistry(registryPath);
152
+ const atom = registry.atoms[atomName];
153
+ if (atom) {
154
+ return {
155
+ description: atom.description,
156
+ input: atom.inputSchema ?? {},
157
+ output: atom.outputSchema ?? {}
158
+ };
159
+ }
160
+ return null;
161
+ } catch (error) {
162
+ if (!(error instanceof StorageNotInitializedError)) {
163
+ const message = toErrorMessage(error);
164
+ console.error(`Warning: Failed to load atom "${atomName}" from registry: ${message}`);
165
+ }
166
+ return null;
167
+ }
168
+ }
169
+ async function suggestSkills(atomName) {
170
+ const atomDef = await loadAtomDefinition(atomName);
171
+ let description = "";
172
+ let inputKeywords = [];
173
+ let outputKeywords = [];
174
+ if (atomDef) {
175
+ description = atomDef.description;
176
+ inputKeywords = extractSchemaKeywords(atomDef.input);
177
+ outputKeywords = extractSchemaKeywords(atomDef.output);
178
+ } else {
179
+ description = atomName.replace(/[_-]/g, " ");
180
+ }
181
+ const suggestions = analyzeAtom(atomName, description, inputKeywords, outputKeywords);
182
+ let availableSkills = [];
183
+ try {
184
+ const scanResult = await scanSkills();
185
+ availableSkills = scanResult.skills;
186
+ } catch {
187
+ }
188
+ for (const suggestion of suggestions) {
189
+ const categoryTokens = suggestion.category.toLowerCase().split(/[-_]/);
190
+ const matchingSkill = availableSkills.find((s) => {
191
+ const skillName = s.name.toLowerCase();
192
+ const skillTokens = skillName.split(/[-_]/);
193
+ if (skillName === suggestion.category) {
194
+ return true;
195
+ }
196
+ return skillTokens.some((token) => categoryTokens.includes(token)) || categoryTokens.some((token) => skillTokens.includes(token));
197
+ });
198
+ if (matchingSkill) {
199
+ suggestion.explanation += ` The "${matchingSkill.name}" skill is available for this.`;
200
+ }
201
+ }
202
+ return {
203
+ atomName,
204
+ suggestions,
205
+ availableSkills
206
+ };
207
+ }
208
+ async function skillsSuggestCommand(atomName, options) {
209
+ try {
210
+ const result = await suggestSkills(atomName);
211
+ if (options.json) {
212
+ console.log(JSON.stringify(result, null, 2));
213
+ return;
214
+ }
215
+ console.log(fmt.bold(`Skill Suggestions for "${atomName}"`));
216
+ console.log("");
217
+ if (result.suggestions.length === 0) {
218
+ console.log(fmt.dim("No skill suggestions found for this atom."));
219
+ console.log("");
220
+ console.log("This could mean:");
221
+ console.log(" - The atom name/description is too generic");
222
+ console.log(" - No matching skill categories were found");
223
+ console.log("");
224
+ return;
225
+ }
226
+ for (const suggestion of result.suggestions) {
227
+ const confidencePercent = Math.round(suggestion.confidence * 100);
228
+ const barLength = Math.round(suggestion.confidence * 20);
229
+ const bar = "\u2588".repeat(barLength) + "\u2591".repeat(20 - barLength);
230
+ console.log(fmt.cyan(`${suggestion.skillName}`));
231
+ console.log(` ${fmt.dim("Confidence:")} ${bar} ${confidencePercent}%`);
232
+ console.log(` ${fmt.dim("Why:")} ${suggestion.explanation}`);
233
+ if (suggestion.matchedKeywords.length > 0) {
234
+ console.log(` ${fmt.dim("Matched:")} ${suggestion.matchedKeywords.join(", ")}`);
235
+ }
236
+ console.log("");
237
+ }
238
+ const relevantSkills = result.availableSkills.filter(
239
+ (skill) => result.suggestions.some(
240
+ (s) => skill.name.toLowerCase().includes(s.category) || s.category.includes(skill.name.toLowerCase())
241
+ )
242
+ );
243
+ if (relevantSkills.length > 0) {
244
+ console.log(fmt.bold("Available Skills"));
245
+ for (const skill of relevantSkills) {
246
+ console.log(` ${fmt.green(skill.name)} (${skill.source})`);
247
+ }
248
+ console.log("");
249
+ }
250
+ } catch (err) {
251
+ const message = toErrorMessage(err);
252
+ if (options.json) {
253
+ console.log(JSON.stringify({ error: message }, null, 2));
254
+ } else {
255
+ console.log(fmt.error(`Skill suggestion failed: ${message}`));
256
+ }
257
+ process.exit(1);
258
+ }
259
+ }
260
+ export {
261
+ SKILL_CATEGORIES,
262
+ analyzeAtom,
263
+ calculateKeywordMatch,
264
+ extractSchemaKeywords,
265
+ loadAtomDefinition,
266
+ skillsSuggestCommand,
267
+ suggestSkills
268
+ };
269
+ //# sourceMappingURL=skills-suggest-JFI2NUJI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/skills-suggest.ts"],"sourcesContent":["/**\n * Skill Suggestion - Recommend skills for an atom.\n *\n * Story 6.7: AOP-1258\n *\n * Acceptance Criteria:\n * - System analyzes atom description and input/output\n * - Suggests relevant skills (e.g., 'testing', 'code-review')\n * - Shows confidence score for each suggestion\n * - Explains why each skill might be useful\n */\n\nimport { fmt } from '../cli/format.js';\nimport { loadRegistry, getRegistryPath, StorageNotInitializedError } from '../storage/index.js';\nimport { scanSkills, SkillInfo } from './skills-scan.js';\nimport { toErrorMessage } from '../utils/errors.js';\n\n/**\n * Skill category with matching keywords and explanation template.\n */\nexport interface SkillCategory {\n name: string;\n keywords: string[];\n descriptionKeywords: string[];\n inputKeywords: string[];\n outputKeywords: string[];\n explanationTemplate: string;\n}\n\n/**\n * Built-in skill categories for matching.\n */\nexport const SKILL_CATEGORIES: SkillCategory[] = [\n {\n name: 'testing',\n keywords: ['test', 'testing', 'spec', 'assertion', 'expect', 'verify', 'validate'],\n descriptionKeywords: ['test', 'verify', 'validate', 'check', 'assert'],\n inputKeywords: ['test', 'spec', 'fixture', 'mock', 'stub'],\n outputKeywords: ['result', 'pass', 'fail', 'coverage', 'report'],\n explanationTemplate:\n 'This atom appears to involve testing or validation. A testing skill can help with writing comprehensive test cases and assertions.',\n },\n {\n name: 'code-review',\n keywords: ['review', 'lint', 'analyze', 'quality', 'style', 'format'],\n descriptionKeywords: ['review', 'analyze', 'check', 'quality', 'lint', 'format'],\n inputKeywords: ['code', 'source', 'file', 'diff', 'patch'],\n outputKeywords: ['issues', 'suggestions', 'warnings', 'errors', 'feedback'],\n explanationTemplate:\n 'This atom works with code analysis or quality checks. A code-review skill can provide structured feedback and improvement suggestions.',\n },\n {\n name: 'documentation',\n keywords: ['doc', 'document', 'readme', 'markdown', 'comment', 'explain'],\n descriptionKeywords: ['document', 'explain', 'describe', 'write', 'generate'],\n inputKeywords: ['code', 'function', 'api', 'module', 'interface'],\n outputKeywords: ['markdown', 'readme', 'doc', 'documentation', 'comment'],\n explanationTemplate:\n 'This atom involves documentation generation or management. A documentation skill can help create clear, comprehensive docs.',\n },\n {\n name: 'refactoring',\n keywords: ['refactor', 'restructure', 'improve', 'optimize', 'clean'],\n descriptionKeywords: ['refactor', 'improve', 'optimize', 'restructure', 'simplify'],\n inputKeywords: ['code', 'function', 'class', 'module', 'component'],\n outputKeywords: ['code', 'improved', 'optimized', 'refactored', 'cleaned'],\n explanationTemplate:\n 'This atom focuses on code improvement or restructuring. A refactoring skill can guide systematic code improvements.',\n },\n {\n name: 'generation',\n keywords: ['generate', 'create', 'scaffold', 'template', 'boilerplate'],\n descriptionKeywords: ['generate', 'create', 'scaffold', 'build', 'produce'],\n inputKeywords: ['config', 'params', 'options', 'template', 'schema'],\n outputKeywords: ['code', 'file', 'component', 'module', 'template'],\n explanationTemplate:\n 'This atom generates code or content from templates. A generation skill can help produce consistent, well-structured output.',\n },\n {\n name: 'data-processing',\n keywords: ['data', 'transform', 'parse', 'convert', 'process', 'extract'],\n descriptionKeywords: ['transform', 'parse', 'convert', 'process', 'extract', 'map'],\n inputKeywords: ['data', 'json', 'csv', 'xml', 'input', 'raw'],\n outputKeywords: ['data', 'result', 'transformed', 'processed', 'output'],\n explanationTemplate:\n 'This atom processes or transforms data. A data-processing skill can help with data validation and transformation patterns.',\n },\n {\n name: 'api-integration',\n keywords: ['api', 'http', 'request', 'fetch', 'endpoint', 'rest', 'graphql'],\n descriptionKeywords: ['api', 'fetch', 'request', 'call', 'integrate', 'connect'],\n inputKeywords: ['url', 'endpoint', 'params', 'headers', 'body', 'query'],\n outputKeywords: ['response', 'data', 'result', 'status', 'error'],\n explanationTemplate:\n 'This atom interacts with external APIs. An API integration skill can help with proper error handling and response processing.',\n },\n {\n name: 'file-operations',\n keywords: ['file', 'read', 'write', 'path', 'directory', 'filesystem'],\n descriptionKeywords: ['file', 'read', 'write', 'save', 'load', 'store'],\n inputKeywords: ['path', 'file', 'directory', 'filename', 'content'],\n outputKeywords: ['content', 'file', 'saved', 'written', 'created'],\n explanationTemplate:\n 'This atom works with files or the filesystem. A file-operations skill can help with safe file handling and path management.',\n },\n];\n\n/**\n * Result of skill suggestion analysis.\n */\nexport interface SkillSuggestion {\n skillName: string;\n confidence: number;\n explanation: string;\n matchedKeywords: string[];\n category: string;\n}\n\n/**\n * Result of the suggest operation.\n */\nexport interface SuggestResult {\n atomName: string;\n suggestions: SkillSuggestion[];\n availableSkills: SkillInfo[];\n}\n\n/**\n * Extract keywords from a Zod schema for matching.\n */\nexport function extractSchemaKeywords(schema: unknown): string[] {\n const keywords: string[] = [];\n let schemaStr: string;\n try {\n schemaStr = JSON.stringify(schema);\n } catch {\n // Handle circular references or other stringify errors\n return [];\n }\n\n // Extract potential field names from the schema string\n const fieldMatches = schemaStr.match(/\"([a-z_][a-z0-9_]*)\"/gi) || [];\n for (const match of fieldMatches) {\n const field = match.replace(/\"/g, '').toLowerCase();\n if (field.length > 2 && !['type', 'object', 'string', 'number', 'boolean'].includes(field)) {\n keywords.push(field);\n }\n }\n\n return [...new Set(keywords)];\n}\n\n/**\n * Calculate similarity score between two keyword sets.\n */\nexport function calculateKeywordMatch(\n targetKeywords: string[],\n categoryKeywords: string[]\n): { score: number; matched: string[] } {\n const matched: string[] = [];\n let score = 0;\n\n for (const target of targetKeywords) {\n const targetLower = target.toLowerCase();\n for (const keyword of categoryKeywords) {\n if (targetLower.includes(keyword) || keyword.includes(targetLower)) {\n matched.push(keyword);\n // Exact match scores higher\n score += targetLower === keyword ? 1.0 : 0.5;\n }\n }\n }\n\n return { score, matched: [...new Set(matched)] };\n}\n\n/**\n * Analyze an atom and suggest relevant skills.\n */\nexport function analyzeAtom(\n atomName: string,\n description: string,\n inputKeywords: string[],\n outputKeywords: string[]\n): SkillSuggestion[] {\n const suggestions: SkillSuggestion[] = [];\n // Filter empty/short tokens to avoid false positives (empty string matches everything)\n const descWords = description\n .toLowerCase()\n .split(/\\s+/)\n .filter((word) => word.length > 2);\n\n for (const category of SKILL_CATEGORIES) {\n let totalScore = 0;\n const allMatched: string[] = [];\n\n // Match description\n const descMatch = calculateKeywordMatch(descWords, category.descriptionKeywords);\n totalScore += descMatch.score * 2; // Description weighted higher\n allMatched.push(...descMatch.matched);\n\n // Match input schema keywords\n const inputMatch = calculateKeywordMatch(inputKeywords, category.inputKeywords);\n totalScore += inputMatch.score;\n allMatched.push(...inputMatch.matched);\n\n // Match output schema keywords\n const outputMatch = calculateKeywordMatch(outputKeywords, category.outputKeywords);\n totalScore += outputMatch.score;\n allMatched.push(...outputMatch.matched);\n\n // Match atom name\n const nameMatch = calculateKeywordMatch([atomName], category.keywords);\n totalScore += nameMatch.score * 1.5;\n allMatched.push(...nameMatch.matched);\n\n // Normalize score to 0-1 range\n // We use 30% of max possible matches as our \"perfect score\" baseline,\n // since typical good matches won't hit every keyword\n const MATCH_RATE_BASELINE = 0.3;\n const maxPossibleScore =\n (category.descriptionKeywords.length * 2 +\n category.inputKeywords.length +\n category.outputKeywords.length +\n category.keywords.length * 1.5) *\n MATCH_RATE_BASELINE;\n const confidence = Math.min(totalScore / maxPossibleScore, 1.0);\n\n if (confidence > 0.1) {\n // Only suggest if above threshold\n suggestions.push({\n skillName: category.name,\n confidence,\n explanation: category.explanationTemplate,\n matchedKeywords: [...new Set(allMatched)],\n category: category.name,\n });\n }\n }\n\n // Sort by confidence descending\n suggestions.sort((a, b) => b.confidence - a.confidence);\n\n return suggestions;\n}\n\n/**\n * Load an atom definition from the registry.\n */\nexport async function loadAtomDefinition(\n atomName: string\n): Promise<{ description: string; input: unknown; output: unknown } | null> {\n try {\n const registryPath = getRegistryPath(process.cwd());\n const registry = await loadRegistry(registryPath);\n\n const atom = registry.atoms[atomName];\n if (atom) {\n return {\n description: atom.description,\n input: atom.inputSchema ?? {},\n output: atom.outputSchema ?? {},\n };\n }\n\n return null;\n } catch (error) {\n // Storage not initialized is expected - atom may not be in registry\n if (!(error instanceof StorageNotInitializedError)) {\n const message = toErrorMessage(error);\n console.error(`Warning: Failed to load atom \"${atomName}\" from registry: ${message}`);\n }\n return null;\n }\n}\n\n/**\n * Suggest skills for an atom.\n */\nexport async function suggestSkills(atomName: string): Promise<SuggestResult> {\n // Load atom definition\n const atomDef = await loadAtomDefinition(atomName);\n\n let description = '';\n let inputKeywords: string[] = [];\n let outputKeywords: string[] = [];\n\n if (atomDef) {\n description = atomDef.description;\n inputKeywords = extractSchemaKeywords(atomDef.input);\n outputKeywords = extractSchemaKeywords(atomDef.output);\n } else {\n // If atom not found in registry, use the name for basic matching\n description = atomName.replace(/[_-]/g, ' ');\n }\n\n // Analyze and get suggestions\n const suggestions = analyzeAtom(atomName, description, inputKeywords, outputKeywords);\n\n // Get available skills to cross-reference\n let availableSkills: SkillInfo[] = [];\n try {\n const scanResult = await scanSkills();\n availableSkills = scanResult.skills;\n } catch {\n // Continue without available skills if scan fails\n }\n\n // Enhance suggestions with actual skill availability\n for (const suggestion of suggestions) {\n const categoryTokens = suggestion.category.toLowerCase().split(/[-_]/);\n const matchingSkill = availableSkills.find((s) => {\n const skillName = s.name.toLowerCase();\n const skillTokens = skillName.split(/[-_]/);\n // Exact match\n if (skillName === suggestion.category) {\n return true;\n }\n // Token-based matching: skill tokens contain category or vice versa\n return (\n skillTokens.some((token) => categoryTokens.includes(token)) ||\n categoryTokens.some((token) => skillTokens.includes(token))\n );\n });\n if (matchingSkill) {\n suggestion.explanation += ` The \"${matchingSkill.name}\" skill is available for this.`;\n }\n }\n\n return {\n atomName,\n suggestions,\n availableSkills,\n };\n}\n\n/**\n * CLI command handler for skills suggest.\n */\nexport async function skillsSuggestCommand(\n atomName: string,\n options: { json?: boolean }\n): Promise<void> {\n try {\n const result = await suggestSkills(atomName);\n\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n console.log(fmt.bold(`Skill Suggestions for \"${atomName}\"`));\n console.log('');\n\n if (result.suggestions.length === 0) {\n console.log(fmt.dim('No skill suggestions found for this atom.'));\n console.log('');\n console.log('This could mean:');\n console.log(' - The atom name/description is too generic');\n console.log(' - No matching skill categories were found');\n console.log('');\n return;\n }\n\n for (const suggestion of result.suggestions) {\n // Confidence bar\n const confidencePercent = Math.round(suggestion.confidence * 100);\n const barLength = Math.round(suggestion.confidence * 20);\n const bar = '█'.repeat(barLength) + '░'.repeat(20 - barLength);\n\n console.log(fmt.cyan(`${suggestion.skillName}`));\n console.log(` ${fmt.dim('Confidence:')} ${bar} ${confidencePercent}%`);\n console.log(` ${fmt.dim('Why:')} ${suggestion.explanation}`);\n if (suggestion.matchedKeywords.length > 0) {\n console.log(` ${fmt.dim('Matched:')} ${suggestion.matchedKeywords.join(', ')}`);\n }\n console.log('');\n }\n\n // Show available skills that might help\n const relevantSkills = result.availableSkills.filter((skill) =>\n result.suggestions.some(\n (s) =>\n skill.name.toLowerCase().includes(s.category) ||\n s.category.includes(skill.name.toLowerCase())\n )\n );\n\n if (relevantSkills.length > 0) {\n console.log(fmt.bold('Available Skills'));\n for (const skill of relevantSkills) {\n console.log(` ${fmt.green(skill.name)} (${skill.source})`);\n }\n console.log('');\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(`Skill suggestion failed: ${message}`));\n }\n process.exit(1);\n }\n}\n"],"mappings":"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","names":[]}