load-skills 0.1.0 → 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.
- package/README.md +5 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/loadSkills.d.ts.map +1 -1
- package/dist/loadSkills.js +51 -39
- package/dist/types.d.ts +15 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/validateSkill.d.ts +10 -2
- package/dist/validateSkill.d.ts.map +1 -1
- package/dist/validateSkill.js +16 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,12 +26,11 @@ const { skills, report } = await loadSkills({
|
|
|
26
26
|
|
|
27
27
|
`skills` includes loaded skill payloads:
|
|
28
28
|
|
|
29
|
-
- `
|
|
29
|
+
- shape: `Record<string, Skill>` (keyed by skill name)
|
|
30
|
+
- `meta`: typed frontmatter object with required `name` and `description`
|
|
30
31
|
- `content`: `SKILL.md` content without frontmatter
|
|
31
32
|
- `references`: absolute file paths from `references/`
|
|
32
33
|
- `scripts`: script descriptors from `scripts/` as `{ path, type }`
|
|
33
|
-
- `state`: `"valid"` or `"invalid"`
|
|
34
|
-
- `warnings`: warning objects with machine-readable `code`
|
|
35
34
|
|
|
36
35
|
`report` includes one entry per configured path:
|
|
37
36
|
|
|
@@ -42,6 +41,7 @@ const { skills, report } = await loadSkills({
|
|
|
42
41
|
- `skillNames`: included skill names from that path
|
|
43
42
|
- `error` (optional): `path_not_found` or `path_not_directory`
|
|
44
43
|
- `ignoredDuplicates`: map of skipped duplicate skills (first-find-wins), keyed by kept skill name
|
|
44
|
+
- `invalidSkills`: invalid skill entries moved out of `skills`; each item includes `warnings`
|
|
45
45
|
|
|
46
46
|
## Path Priority
|
|
47
47
|
|
|
@@ -49,6 +49,8 @@ const { skills, report } = await loadSkills({
|
|
|
49
49
|
|
|
50
50
|
## Warning codes
|
|
51
51
|
|
|
52
|
+
These warnings appear on `report.invalidSkills[*].warnings`.
|
|
53
|
+
|
|
52
54
|
- `missing_frontmatter`: `SKILL.md` is missing a valid `--- ... ---` frontmatter block.
|
|
53
55
|
- `invalid_yaml_frontmatter`: Frontmatter exists but YAML parsing failed or did not produce an object.
|
|
54
56
|
- `missing_required_meta_name`: Frontmatter is missing required `name`.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { loadSkills } from "./loadSkills.js";
|
|
2
|
-
export type {
|
|
2
|
+
export type { IgnoredDuplicateSkill, InvalidSkill, LoadSkillsConfig, LoadSkillsPathError, LoadSkillsPathReport, LoadSkillsReport, LoadSkillsResult, Skill, SkillMeta, SkillScript, SkillScriptType, SkillWarning, SkillWarningCode, } from "./types.js";
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EACV,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,YAAY,EACV,qBAAqB,EACrB,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,EAChB,KAAK,EACL,SAAS,EACT,WAAW,EACX,eAAe,EACf,YAAY,EACZ,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
|
package/dist/loadSkills.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadSkills.d.ts","sourceRoot":"","sources":["../src/loadSkills.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAGV,gBAAgB,EAChB,gBAAgB,
|
|
1
|
+
{"version":3,"file":"loadSkills.d.ts","sourceRoot":"","sources":["../src/loadSkills.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAGV,gBAAgB,EAChB,gBAAgB,EAKjB,MAAM,YAAY,CAAC;AAOpB,wBAAsB,UAAU,CAC9B,MAAM,CAAC,EAAE,gBAAgB,GACxB,OAAO,CAAC,gBAAgB,CAAC,CAgH3B"}
|
package/dist/loadSkills.js
CHANGED
|
@@ -8,7 +8,8 @@ import { applyValidationRules, validateLargeReferences, } from "./validateSkill.
|
|
|
8
8
|
export async function loadSkills(config) {
|
|
9
9
|
const resolvedConfig = config ?? {};
|
|
10
10
|
const discovery = await discoverSkillFiles(resolvedConfig);
|
|
11
|
-
const
|
|
11
|
+
const skills = {};
|
|
12
|
+
const invalidSkills = [];
|
|
12
13
|
const reportPaths = discovery.report.map((entry) => ({ ...entry }));
|
|
13
14
|
const ignoredDuplicates = {};
|
|
14
15
|
const includedByName = new Map();
|
|
@@ -23,63 +24,74 @@ export async function loadSkills(config) {
|
|
|
23
24
|
skillWarnings.push(...resourceScan.warnings);
|
|
24
25
|
const largeReferenceWarnings = validateLargeReferences(resourceScan.referenceContents);
|
|
25
26
|
skillWarnings.push(...largeReferenceWarnings);
|
|
26
|
-
const
|
|
27
|
+
const validated = applyValidationRules({
|
|
27
28
|
meta: parsed.meta,
|
|
28
29
|
content: parsed.content,
|
|
29
|
-
references: resourceScan.references,
|
|
30
|
-
scripts: resourceScan.scripts,
|
|
31
|
-
state: "valid",
|
|
32
30
|
warnings: skillWarnings,
|
|
33
|
-
skillPath,
|
|
34
|
-
skillFilePath,
|
|
35
31
|
});
|
|
36
32
|
const reportItem = reportPaths[discovered.pathReportIndex];
|
|
37
33
|
if (!reportItem) {
|
|
38
34
|
continue;
|
|
39
35
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
normalizedSkillName: normalizedName,
|
|
50
|
-
ignoredSkillPath: skill.skillPath,
|
|
51
|
-
ignoredSkillFilePath: skill.skillFilePath,
|
|
52
|
-
ignoredFromInputPath: discovered.inputPath,
|
|
53
|
-
keptSkillPath: existing.skillPath,
|
|
54
|
-
keptSkillFilePath: existing.skillFilePath,
|
|
55
|
-
keptFromInputPath: existing.inputPath,
|
|
56
|
-
};
|
|
57
|
-
const key = existing.skillName;
|
|
58
|
-
ignoredDuplicates[key] = [
|
|
59
|
-
...(ignoredDuplicates[key] ?? []),
|
|
60
|
-
ignoredEntry,
|
|
61
|
-
];
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
includedByName.set(normalizedName, {
|
|
65
|
-
skillName: resolvedName,
|
|
66
|
-
skillPath: skill.skillPath,
|
|
67
|
-
skillFilePath: skill.skillFilePath,
|
|
68
|
-
inputPath: discovered.inputPath,
|
|
36
|
+
if (!validated.isValid || !validated.meta) {
|
|
37
|
+
invalidSkills.push({
|
|
38
|
+
meta: parsed.meta,
|
|
39
|
+
content: parsed.content,
|
|
40
|
+
references: resourceScan.references,
|
|
41
|
+
scripts: resourceScan.scripts,
|
|
42
|
+
warnings: validated.warnings,
|
|
43
|
+
skillPath,
|
|
44
|
+
skillFilePath,
|
|
69
45
|
});
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const skill = {
|
|
49
|
+
meta: validated.meta,
|
|
50
|
+
content: parsed.content,
|
|
51
|
+
references: resourceScan.references,
|
|
52
|
+
scripts: resourceScan.scripts,
|
|
53
|
+
skillPath,
|
|
54
|
+
skillFilePath,
|
|
55
|
+
};
|
|
56
|
+
const normalizedName = skill.meta.name.trim().toLowerCase();
|
|
57
|
+
const existing = includedByName.get(normalizedName);
|
|
58
|
+
if (existing) {
|
|
59
|
+
const ignoredEntry = {
|
|
60
|
+
skillName: skill.meta.name,
|
|
61
|
+
normalizedSkillName: normalizedName,
|
|
62
|
+
ignoredSkillPath: skill.skillPath,
|
|
63
|
+
ignoredSkillFilePath: skill.skillFilePath,
|
|
64
|
+
ignoredFromInputPath: discovered.inputPath,
|
|
65
|
+
keptSkillPath: existing.skillPath,
|
|
66
|
+
keptSkillFilePath: existing.skillFilePath,
|
|
67
|
+
keptFromInputPath: existing.inputPath,
|
|
68
|
+
};
|
|
69
|
+
const key = existing.skillName;
|
|
70
|
+
ignoredDuplicates[key] = [
|
|
71
|
+
...(ignoredDuplicates[key] ?? []),
|
|
72
|
+
ignoredEntry,
|
|
73
|
+
];
|
|
74
|
+
continue;
|
|
70
75
|
}
|
|
71
|
-
|
|
72
|
-
|
|
76
|
+
includedByName.set(normalizedName, {
|
|
77
|
+
skillName: skill.meta.name,
|
|
78
|
+
skillPath: skill.skillPath,
|
|
79
|
+
skillFilePath: skill.skillFilePath,
|
|
80
|
+
inputPath: discovered.inputPath,
|
|
81
|
+
});
|
|
82
|
+
skills[skill.meta.name] = skill;
|
|
83
|
+
reportItem.skillNames.push(skill.meta.name);
|
|
73
84
|
reportItem.count += 1;
|
|
74
85
|
}
|
|
75
86
|
for (const reportItem of reportPaths) {
|
|
76
87
|
reportItem.skillNames.sort((a, b) => a.localeCompare(b));
|
|
77
88
|
}
|
|
78
89
|
return {
|
|
79
|
-
skills
|
|
90
|
+
skills,
|
|
80
91
|
report: {
|
|
81
92
|
paths: reportPaths,
|
|
82
93
|
ignoredDuplicates,
|
|
94
|
+
invalidSkills,
|
|
83
95
|
},
|
|
84
96
|
};
|
|
85
97
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export type SkillState = "valid" | "invalid";
|
|
2
1
|
export type SkillScriptType = "javascript" | "typescript" | "python" | "shell" | "ruby" | "other";
|
|
3
2
|
export type SkillWarningCode = "missing_frontmatter" | "invalid_yaml_frontmatter" | "missing_required_meta_name" | "missing_required_meta_description" | "invalid_meta_name" | "invalid_meta_description" | "skill_md_content_size_limit_exceeded" | "reference_large_without_toc" | "resource_read_error";
|
|
4
3
|
export interface SkillWarning {
|
|
@@ -9,12 +8,23 @@ export interface SkillScript {
|
|
|
9
8
|
path: string;
|
|
10
9
|
type: SkillScriptType;
|
|
11
10
|
}
|
|
12
|
-
export
|
|
11
|
+
export type SkillMeta = Record<string, unknown> & {
|
|
12
|
+
name: string;
|
|
13
|
+
description: string;
|
|
14
|
+
};
|
|
15
|
+
export interface Skill {
|
|
16
|
+
meta: SkillMeta;
|
|
17
|
+
content: string;
|
|
18
|
+
references: string[];
|
|
19
|
+
scripts: SkillScript[];
|
|
20
|
+
skillPath: string;
|
|
21
|
+
skillFilePath: string;
|
|
22
|
+
}
|
|
23
|
+
export interface InvalidSkill {
|
|
13
24
|
meta: Record<string, unknown>;
|
|
14
25
|
content: string;
|
|
15
26
|
references: string[];
|
|
16
27
|
scripts: SkillScript[];
|
|
17
|
-
state: SkillState;
|
|
18
28
|
warnings: SkillWarning[];
|
|
19
29
|
skillPath: string;
|
|
20
30
|
skillFilePath: string;
|
|
@@ -45,9 +55,10 @@ export interface IgnoredDuplicateSkill {
|
|
|
45
55
|
export interface LoadSkillsReport {
|
|
46
56
|
paths: LoadSkillsPathReport[];
|
|
47
57
|
ignoredDuplicates: Record<string, IgnoredDuplicateSkill[]>;
|
|
58
|
+
invalidSkills: InvalidSkill[];
|
|
48
59
|
}
|
|
49
60
|
export interface LoadSkillsResult {
|
|
50
|
-
skills:
|
|
61
|
+
skills: Record<string, Skill>;
|
|
51
62
|
report: LoadSkillsReport;
|
|
52
63
|
}
|
|
53
64
|
export interface ParseSkillResult {
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GACvB,YAAY,GACZ,YAAY,GACZ,QAAQ,GACR,OAAO,GACP,MAAM,GACN,OAAO,CAAC;AAEZ,MAAM,MAAM,gBAAgB,GACxB,qBAAqB,GACrB,0BAA0B,GAC1B,4BAA4B,GAC5B,mCAAmC,GACnC,mBAAmB,GACnB,0BAA0B,GAC1B,sCAAsC,GACtC,6BAA6B,GAC7B,qBAAqB,CAAC;AAE1B,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,gBAAgB,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,eAAe,CAAC;CACvB;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,mBAAmB,GAAG,gBAAgB,GAAG,oBAAoB,CAAC;AAE1E,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,CAAC,EAAE,mBAAmB,CAAC;CAC7B;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,oBAAoB,EAAE,CAAC;IAC9B,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,EAAE,CAAC,CAAC;IAC3D,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC9B,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B"}
|
package/dist/validateSkill.d.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function applyValidationRules(
|
|
1
|
+
import type { SkillMeta, SkillWarning } from "./types.js";
|
|
2
|
+
export declare function applyValidationRules(input: {
|
|
3
|
+
meta: Record<string, unknown>;
|
|
4
|
+
content: string;
|
|
5
|
+
warnings: SkillWarning[];
|
|
6
|
+
}): {
|
|
7
|
+
warnings: SkillWarning[];
|
|
8
|
+
isValid: boolean;
|
|
9
|
+
meta?: SkillMeta;
|
|
10
|
+
};
|
|
3
11
|
export declare function validateLargeReferences(references: Array<{
|
|
4
12
|
path: string;
|
|
5
13
|
content: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateSkill.d.ts","sourceRoot":"","sources":["../src/validateSkill.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"validateSkill.d.ts","sourceRoot":"","sources":["../src/validateSkill.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAc1D,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B,GAAG;IACF,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB,CAoDA;AAED,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,GACtE,YAAY,EAAE,CAqBhB"}
|
package/dist/validateSkill.js
CHANGED
|
@@ -9,10 +9,10 @@ const INVALID_WARNING_CODES = new Set([
|
|
|
9
9
|
"reference_large_without_toc",
|
|
10
10
|
"resource_read_error",
|
|
11
11
|
]);
|
|
12
|
-
export function applyValidationRules(
|
|
13
|
-
const warnings = [...
|
|
14
|
-
const metaName =
|
|
15
|
-
const metaDescription =
|
|
12
|
+
export function applyValidationRules(input) {
|
|
13
|
+
const warnings = [...input.warnings];
|
|
14
|
+
const metaName = input.meta.name;
|
|
15
|
+
const metaDescription = input.meta.description;
|
|
16
16
|
if (typeof metaName !== "string" || metaName.trim() === "") {
|
|
17
17
|
warnings.push({
|
|
18
18
|
code: typeof metaName === "undefined"
|
|
@@ -29,20 +29,25 @@ export function applyValidationRules(skill) {
|
|
|
29
29
|
message: "Frontmatter field `description` is required and must be a non-empty string.",
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
|
-
const contentLineCount = getLineCount(
|
|
32
|
+
const contentLineCount = getLineCount(input.content);
|
|
33
33
|
if (contentLineCount > 500) {
|
|
34
34
|
warnings.push({
|
|
35
35
|
code: "skill_md_content_size_limit_exceeded",
|
|
36
36
|
message: `SKILL.md body exceeds the recommended 500-line limit (${contentLineCount} lines).`,
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
const dedupedWarnings = dedupeWarnings(warnings);
|
|
40
|
+
const isValid = !dedupedWarnings.some((warning) => INVALID_WARNING_CODES.has(warning.code));
|
|
41
|
+
if (isValid) {
|
|
42
|
+
return {
|
|
43
|
+
warnings: dedupedWarnings,
|
|
44
|
+
isValid: true,
|
|
45
|
+
meta: input.meta,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
42
48
|
return {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
state,
|
|
49
|
+
warnings: dedupedWarnings,
|
|
50
|
+
isValid: false,
|
|
46
51
|
};
|
|
47
52
|
}
|
|
48
53
|
export function validateLargeReferences(references) {
|