loadouts 0.2.1 → 0.2.2

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 (44) hide show
  1. package/README.md +3 -1
  2. package/dist/builtins/index.d.ts.map +1 -1
  3. package/dist/builtins/index.js +26 -13
  4. package/dist/builtins/index.js.map +1 -1
  5. package/dist/builtins/tools/cursor.js +2 -2
  6. package/dist/builtins/tools/cursor.js.map +1 -1
  7. package/dist/builtins/tools/opencode.d.ts.map +1 -1
  8. package/dist/builtins/tools/opencode.js +8 -2
  9. package/dist/builtins/tools/opencode.js.map +1 -1
  10. package/dist/cli/commands/check.d.ts.map +1 -1
  11. package/dist/cli/commands/check.js +17 -1
  12. package/dist/cli/commands/check.js.map +1 -1
  13. package/dist/cli/commands/install.d.ts +2 -2
  14. package/dist/cli/commands/install.d.ts.map +1 -1
  15. package/dist/cli/commands/install.js +130 -15
  16. package/dist/cli/commands/install.js.map +1 -1
  17. package/dist/cli/commands/rule.js +11 -7
  18. package/dist/cli/commands/rule.js.map +1 -1
  19. package/dist/cli/commands/sanitize.d.ts +3 -2
  20. package/dist/cli/commands/sanitize.d.ts.map +1 -1
  21. package/dist/cli/commands/sanitize.js +27 -13
  22. package/dist/cli/commands/sanitize.js.map +1 -1
  23. package/dist/cli/commands/skill.d.ts.map +1 -1
  24. package/dist/cli/commands/skill.js +23 -14
  25. package/dist/cli/commands/skill.js.map +1 -1
  26. package/dist/cli/commands/status.d.ts.map +1 -1
  27. package/dist/cli/commands/status.js +15 -10
  28. package/dist/cli/commands/status.js.map +1 -1
  29. package/dist/core/config.d.ts +73 -13
  30. package/dist/core/config.d.ts.map +1 -1
  31. package/dist/core/config.js +224 -34
  32. package/dist/core/config.js.map +1 -1
  33. package/dist/core/import-discovery.d.ts +2 -0
  34. package/dist/core/import-discovery.d.ts.map +1 -1
  35. package/dist/core/import-discovery.js +129 -1
  36. package/dist/core/import-discovery.js.map +1 -1
  37. package/dist/core/schema.d.ts +91 -11
  38. package/dist/core/schema.d.ts.map +1 -1
  39. package/dist/core/schema.js +28 -0
  40. package/dist/core/schema.js.map +1 -1
  41. package/docs/commands.md +4 -2
  42. package/docs/index.md +1 -0
  43. package/docs/quickstart.md +4 -1
  44. package/package.json +1 -1
@@ -1,8 +1,24 @@
1
1
  /**
2
2
  * Parse source configs and loadout definitions
3
3
  */
4
- import { type RuleFrontmatter } from "./schema.js";
4
+ import { type RuleFrontmatter, type CanonicalRuleFrontmatter, type SkillFrontmatter, type Frontmatter } from "./schema.js";
5
5
  import type { RootConfig, LoadoutDefinition, LoadoutRoot } from "./types.js";
6
+ export interface FrontmatterSanitizationResult<T extends Frontmatter> {
7
+ frontmatter: T;
8
+ changes: string[];
9
+ }
10
+ export interface FileSanitizationResult {
11
+ modified: boolean;
12
+ changes: string[];
13
+ }
14
+ export type RawFrontmatter = Record<string, unknown>;
15
+ /**
16
+ * Parse markdown frontmatter without schema validation.
17
+ */
18
+ export declare function parseMarkdownFrontmatter(content: string): {
19
+ frontmatter: RawFrontmatter;
20
+ body: string;
21
+ };
6
22
  /**
7
23
  * Parse the root config from a .loadouts/ directory.
8
24
  * Returns default config if file doesn't exist.
@@ -28,37 +44,81 @@ export declare function findLoadoutDefinition(name: string, roots: LoadoutRoot[]
28
44
  * Returns the frontmatter object and the body content.
29
45
  */
30
46
  export declare function parseFrontmatter(content: string): {
31
- frontmatter: RuleFrontmatter;
47
+ frontmatter: Frontmatter;
48
+ body: string;
49
+ };
50
+ /**
51
+ * Parse skill frontmatter from a SKILL.md file.
52
+ */
53
+ export declare function parseSkillFrontmatter(content: string): {
54
+ frontmatter: SkillFrontmatter;
32
55
  body: string;
33
56
  };
57
+ /**
58
+ * Serialize markdown frontmatter without schema constraints.
59
+ */
60
+ export declare function serializeMarkdownFrontmatter(frontmatter: RawFrontmatter, body: string): string;
34
61
  /**
35
62
  * Serialize frontmatter and body back to markdown.
36
63
  */
37
- export declare function serializeFrontmatter(frontmatter: RuleFrontmatter, body: string): string;
64
+ export declare function serializeFrontmatter(frontmatter: Frontmatter, body: string): string;
65
+ /**
66
+ * Sanitize rule frontmatter for canonical v1 portability.
67
+ */
68
+ export declare function sanitizeRuleFrontmatter(frontmatter: RuleFrontmatter, ruleName?: string): CanonicalRuleFrontmatter;
38
69
  /**
39
- * Sanitize rule frontmatter for maximum cross-tool compatibility.
40
- *
41
- * Required fields for portability:
42
- * - `description` - Cursor "Apply Intelligently" routing
43
- * - `paths` - Claude Code file scoping
44
- * - `globs` - Cursor/OpenCode file scoping
45
- *
46
- * If paths/globs are set, ensures both are present and equal.
47
- * If description is missing and we have a rule name, generates one.
70
+ * Sanitize rule frontmatter and return a concise change summary.
48
71
  */
49
- export declare function sanitizeRuleFrontmatter(frontmatter: RuleFrontmatter, ruleName?: string): RuleFrontmatter;
72
+ export declare function sanitizeRuleFrontmatterWithSummary(frontmatter: RuleFrontmatter, ruleName?: string): FrontmatterSanitizationResult<CanonicalRuleFrontmatter>;
50
73
  /**
51
74
  * Check if a rule file needs sanitization.
52
75
  * Returns true if the file would be modified by sanitization.
53
76
  */
54
77
  export declare function ruleNeedsSanitization(filePath: string): boolean;
78
+ /**
79
+ * Return a concise list of rule-frontmatter sanitization changes.
80
+ */
81
+ export declare function ruleSanitizationChanges(filePath: string): string[];
55
82
  /**
56
83
  * Sanitize a rule file in place.
57
84
  * Returns true if the file was modified.
58
85
  */
59
86
  export declare function sanitizeRuleFile(filePath: string): boolean;
87
+ /**
88
+ * Sanitize a rule file in place and return change details.
89
+ */
90
+ export declare function sanitizeRuleFileWithSummary(filePath: string): FileSanitizationResult;
60
91
  /**
61
92
  * Find all rules that need sanitization in a loadout root.
62
93
  */
63
94
  export declare function findUnsanitizedRules(loadoutRoot: string): string[];
95
+ /**
96
+ * Sanitize skill frontmatter for canonical v1 portability.
97
+ */
98
+ export declare function sanitizeSkillFrontmatter(frontmatter: SkillFrontmatter, skillName?: string): SkillFrontmatter;
99
+ /**
100
+ * Sanitize skill frontmatter and return a concise change summary.
101
+ */
102
+ export declare function sanitizeSkillFrontmatterWithSummary(frontmatter: SkillFrontmatter, skillName?: string): FrontmatterSanitizationResult<SkillFrontmatter>;
103
+ /**
104
+ * Check if a skill file needs sanitization.
105
+ */
106
+ export declare function skillNeedsSanitization(filePath: string): boolean;
107
+ /**
108
+ * Return a concise list of skill-frontmatter sanitization changes.
109
+ */
110
+ export declare function skillSanitizationChanges(filePath: string): string[];
111
+ /**
112
+ * Sanitize a skill file in place.
113
+ * Returns true if the file was modified.
114
+ */
115
+ export declare function sanitizeSkillFile(filePath: string): boolean;
116
+ /**
117
+ * Sanitize a skill file in place and return change details.
118
+ */
119
+ export declare function sanitizeSkillFileWithSummary(filePath: string): FileSanitizationResult;
120
+ /**
121
+ * Find all skills that need sanitization in a loadout root.
122
+ */
123
+ export declare function findUnsanitizedSkills(loadoutRoot: string): string[];
64
124
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EACV,UAAU,EACV,iBAAiB,EACjB,WAAW,EACZ,MAAM,YAAY,CAAC;AAKpB;;;GAGG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,UAAU,CAU/D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CAI1E;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAU1D;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,WAAW,EAAE,GACnB;IAAE,UAAU,EAAE,iBAAiB,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAoB5D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG;IACjD,WAAW,EAAE,eAAe,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;CACd,CAYA;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,eAAe,EAC5B,IAAI,EAAE,MAAM,GACX,MAAM,CAOR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,eAAe,EAC5B,QAAQ,CAAC,EAAE,MAAM,GAChB,eAAe,CAoBjB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAO/D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAkB1D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAalE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"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"}
@@ -4,9 +4,38 @@
4
4
  import * as path from "node:path";
5
5
  import * as yaml from "yaml";
6
6
  import { readFile, writeFile, fileExists, isDirectory, listFiles } from "../lib/fs.js";
7
- import { RootConfigSchema, LoadoutDefinitionSchema, RuleFrontmatterSchema, } from "./schema.js";
7
+ import { RootConfigSchema, LoadoutDefinitionSchema, FrontmatterSchema, SkillFrontmatterSchema, CanonicalRuleFrontmatterSchema, } from "./schema.js";
8
8
  const ROOT_CONFIG_FILE = "loadouts.yaml";
9
9
  const LOADOUTS_DIR = "loadouts";
10
+ const RULES_DIR = "rules";
11
+ const SKILLS_DIR = "skills";
12
+ /**
13
+ * Parse markdown frontmatter without schema validation.
14
+ */
15
+ export function parseMarkdownFrontmatter(content) {
16
+ const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
17
+ if (!match) {
18
+ return { frontmatter: {}, body: content };
19
+ }
20
+ const [, frontmatterStr, body] = match;
21
+ const parsed = yaml.parse(frontmatterStr);
22
+ const frontmatter = parsed && typeof parsed === "object" && !Array.isArray(parsed)
23
+ ? parsed
24
+ : {};
25
+ return { frontmatter, body };
26
+ }
27
+ function stableStringify(value) {
28
+ if (Array.isArray(value)) {
29
+ return `[${value.map((v) => stableStringify(v)).join(",")}]`;
30
+ }
31
+ if (value && typeof value === "object") {
32
+ const entries = Object.entries(value).sort(([a], [b]) => a.localeCompare(b));
33
+ return `{${entries
34
+ .map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`)
35
+ .join(",")}}`;
36
+ }
37
+ return JSON.stringify(value);
38
+ }
10
39
  /**
11
40
  * Parse the root config from a .loadouts/ directory.
12
41
  * Returns default config if file doesn't exist.
@@ -66,19 +95,22 @@ export function findLoadoutDefinition(name, roots) {
66
95
  * Returns the frontmatter object and the body content.
67
96
  */
68
97
  export function parseFrontmatter(content) {
69
- const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
70
- if (!match) {
71
- return { frontmatter: {}, body: content };
72
- }
73
- const [, frontmatterStr, body] = match;
74
- const parsed = yaml.parse(frontmatterStr) || {};
75
- const frontmatter = RuleFrontmatterSchema.parse(parsed);
98
+ const { frontmatter: parsed, body } = parseMarkdownFrontmatter(content);
99
+ const frontmatter = FrontmatterSchema.parse(parsed);
76
100
  return { frontmatter, body };
77
101
  }
78
102
  /**
79
- * Serialize frontmatter and body back to markdown.
103
+ * Parse skill frontmatter from a SKILL.md file.
80
104
  */
81
- export function serializeFrontmatter(frontmatter, body) {
105
+ export function parseSkillFrontmatter(content) {
106
+ const { frontmatter: parsed, body } = parseMarkdownFrontmatter(content);
107
+ const frontmatter = SkillFrontmatterSchema.parse(parsed);
108
+ return { frontmatter, body };
109
+ }
110
+ /**
111
+ * Serialize markdown frontmatter without schema constraints.
112
+ */
113
+ export function serializeMarkdownFrontmatter(frontmatter, body) {
82
114
  if (Object.keys(frontmatter).length === 0) {
83
115
  return body;
84
116
  }
@@ -86,70 +118,120 @@ export function serializeFrontmatter(frontmatter, body) {
86
118
  return `---\n${frontmatterStr}\n---\n${body}`;
87
119
  }
88
120
  /**
89
- * Sanitize rule frontmatter for maximum cross-tool compatibility.
90
- *
91
- * Required fields for portability:
92
- * - `description` - Cursor "Apply Intelligently" routing
93
- * - `paths` - Claude Code file scoping
94
- * - `globs` - Cursor/OpenCode file scoping
95
- *
96
- * If paths/globs are set, ensures both are present and equal.
97
- * If description is missing and we have a rule name, generates one.
121
+ * Serialize frontmatter and body back to markdown.
122
+ */
123
+ export function serializeFrontmatter(frontmatter, body) {
124
+ return serializeMarkdownFrontmatter(frontmatter, body);
125
+ }
126
+ /**
127
+ * Sanitize rule frontmatter for canonical v1 portability.
98
128
  */
99
129
  export function sanitizeRuleFrontmatter(frontmatter, ruleName) {
130
+ return sanitizeRuleFrontmatterWithSummary(frontmatter, ruleName).frontmatter;
131
+ }
132
+ /**
133
+ * Sanitize rule frontmatter and return a concise change summary.
134
+ */
135
+ export function sanitizeRuleFrontmatterWithSummary(frontmatter, ruleName) {
100
136
  const result = { ...frontmatter };
101
- // Mirror paths <-> globs for Cursor/OpenCode compatibility
102
- if (result.paths && !result.globs) {
103
- result.globs = result.paths;
137
+ const changes = [];
138
+ const explicitAlwaysApply = result.alwaysApply;
139
+ const hadGlobsAlias = "globs" in result;
140
+ const pathsBeforeAliasHandling = result.paths;
141
+ const globsBeforeAliasHandling = result.globs;
142
+ if (Array.isArray(pathsBeforeAliasHandling)
143
+ && Array.isArray(globsBeforeAliasHandling)
144
+ && stableStringify(pathsBeforeAliasHandling) !== stableStringify(globsBeforeAliasHandling)) {
145
+ changes.push("~ conflicting alias ignored: globs (kept paths)");
104
146
  }
105
- else if (result.globs && !result.paths) {
147
+ if (result.globs && !result.paths) {
106
148
  result.paths = result.globs;
149
+ changes.push("~ globs -> paths");
150
+ }
151
+ if (hadGlobsAlias) {
152
+ delete result.globs;
153
+ if (!changes.includes("~ globs -> paths")) {
154
+ changes.push("~ removed alias: globs");
155
+ }
156
+ }
157
+ if ("alwaysApply" in result) {
158
+ delete result.alwaysApply;
159
+ changes.push("~ alwaysApply -> activation");
160
+ }
161
+ let canonicalActivation;
162
+ if (typeof explicitAlwaysApply === "boolean") {
163
+ canonicalActivation = explicitAlwaysApply || result.paths === undefined
164
+ ? "always"
165
+ : "scoped";
166
+ }
167
+ else if (result.activation === "always" || result.activation === "scoped") {
168
+ canonicalActivation = result.activation;
169
+ }
170
+ else {
171
+ canonicalActivation = result.paths === undefined ? "always" : "scoped";
172
+ }
173
+ if (result.activation !== canonicalActivation) {
174
+ result.activation = canonicalActivation;
175
+ changes.push(`~ activation -> ${canonicalActivation}`);
107
176
  }
108
- // Ensure description exists for Cursor "Apply Intelligently" mode
109
177
  if (!result.description && ruleName) {
110
- // Generate a description from the rule name
111
178
  const humanName = ruleName
112
179
  .replace(/[-_]/g, " ")
113
180
  .replace(/\b\w/g, (c) => c.toUpperCase());
114
181
  result.description = `${humanName} guidelines`;
182
+ changes.push("~ added description");
115
183
  }
116
- return result;
184
+ return {
185
+ frontmatter: CanonicalRuleFrontmatterSchema.parse(result),
186
+ changes,
187
+ };
117
188
  }
118
189
  /**
119
190
  * Check if a rule file needs sanitization.
120
191
  * Returns true if the file would be modified by sanitization.
121
192
  */
122
193
  export function ruleNeedsSanitization(filePath) {
194
+ return ruleSanitizationChanges(filePath).length > 0;
195
+ }
196
+ /**
197
+ * Return a concise list of rule-frontmatter sanitization changes.
198
+ */
199
+ export function ruleSanitizationChanges(filePath) {
123
200
  const content = readFile(filePath);
124
201
  const { frontmatter } = parseFrontmatter(content);
125
202
  const ruleName = path.basename(filePath, ".md");
126
- const sanitized = sanitizeRuleFrontmatter(frontmatter, ruleName);
127
- return JSON.stringify(frontmatter) !== JSON.stringify(sanitized);
203
+ return sanitizeRuleFrontmatterWithSummary(frontmatter, ruleName).changes;
128
204
  }
129
205
  /**
130
206
  * Sanitize a rule file in place.
131
207
  * Returns true if the file was modified.
132
208
  */
133
209
  export function sanitizeRuleFile(filePath) {
210
+ return sanitizeRuleFileWithSummary(filePath).modified;
211
+ }
212
+ /**
213
+ * Sanitize a rule file in place and return change details.
214
+ */
215
+ export function sanitizeRuleFileWithSummary(filePath) {
134
216
  const content = readFile(filePath);
135
217
  const { frontmatter, body } = parseFrontmatter(content);
136
218
  const ruleName = path.basename(filePath, ".md");
137
- const sanitized = sanitizeRuleFrontmatter(frontmatter, ruleName);
219
+ const { frontmatter: sanitized, changes } = sanitizeRuleFrontmatterWithSummary(frontmatter, ruleName);
138
220
  // Check if anything changed
139
- const originalStr = JSON.stringify(frontmatter);
140
- const sanitizedStr = JSON.stringify(sanitized);
221
+ const originalStr = stableStringify(frontmatter);
222
+ const sanitizedStr = stableStringify(sanitized);
141
223
  if (originalStr === sanitizedStr) {
142
- return false;
224
+ return { modified: false, changes: [] };
143
225
  }
144
226
  const newContent = serializeFrontmatter(sanitized, body);
145
227
  writeFile(filePath, newContent);
146
- return true;
228
+ return { modified: true, changes };
147
229
  }
148
230
  /**
149
231
  * Find all rules that need sanitization in a loadout root.
150
232
  */
151
233
  export function findUnsanitizedRules(loadoutRoot) {
152
- const rulesDir = path.join(loadoutRoot, "rules");
234
+ const rulesDir = path.join(loadoutRoot, RULES_DIR);
153
235
  if (!isDirectory(rulesDir))
154
236
  return [];
155
237
  const unsanitized = [];
@@ -163,4 +245,112 @@ export function findUnsanitizedRules(loadoutRoot) {
163
245
  }
164
246
  return unsanitized;
165
247
  }
248
+ /**
249
+ * Sanitize skill frontmatter for canonical v1 portability.
250
+ */
251
+ export function sanitizeSkillFrontmatter(frontmatter, skillName) {
252
+ return sanitizeSkillFrontmatterWithSummary(frontmatter, skillName).frontmatter;
253
+ }
254
+ /**
255
+ * Sanitize skill frontmatter and return a concise change summary.
256
+ */
257
+ export function sanitizeSkillFrontmatterWithSummary(frontmatter, skillName) {
258
+ const result = { ...frontmatter };
259
+ const changes = [];
260
+ if (!result.name && skillName) {
261
+ result.name = skillName;
262
+ changes.push("~ added name");
263
+ }
264
+ if (!result.description) {
265
+ result.description = skillName
266
+ ? `${skillName} skill for AI coding agents`
267
+ : "Skill for AI coding agents";
268
+ changes.push("~ added description");
269
+ }
270
+ const disableModelInvocation = result["disable-model-invocation"];
271
+ const canonicalModelInvocable = result["model-invocable"];
272
+ if (typeof disableModelInvocation === "boolean") {
273
+ const aliasModelInvocable = !disableModelInvocation;
274
+ if (typeof canonicalModelInvocable === "boolean") {
275
+ if (canonicalModelInvocable !== aliasModelInvocable) {
276
+ changes.push("~ conflicting alias ignored: disable-model-invocation (kept model-invocable)");
277
+ }
278
+ }
279
+ else {
280
+ result["model-invocable"] = aliasModelInvocable;
281
+ changes.push(`~ disable-model-invocation -> model-invocable: ${aliasModelInvocable}`);
282
+ }
283
+ delete result["disable-model-invocation"];
284
+ changes.push("~ removed alias: disable-model-invocation");
285
+ }
286
+ if (typeof result["user-invocable"] !== "boolean") {
287
+ result["user-invocable"] = true;
288
+ changes.push("~ user-invocable -> true");
289
+ }
290
+ if (typeof result["model-invocable"] !== "boolean") {
291
+ result["model-invocable"] = true;
292
+ changes.push("~ model-invocable -> true");
293
+ }
294
+ return { frontmatter: result, changes };
295
+ }
296
+ /**
297
+ * Check if a skill file needs sanitization.
298
+ */
299
+ export function skillNeedsSanitization(filePath) {
300
+ return skillSanitizationChanges(filePath).length > 0;
301
+ }
302
+ /**
303
+ * Return a concise list of skill-frontmatter sanitization changes.
304
+ */
305
+ export function skillSanitizationChanges(filePath) {
306
+ const content = readFile(filePath);
307
+ const { frontmatter } = parseSkillFrontmatter(content);
308
+ const skillName = path.basename(path.dirname(filePath));
309
+ return sanitizeSkillFrontmatterWithSummary(frontmatter, skillName).changes;
310
+ }
311
+ /**
312
+ * Sanitize a skill file in place.
313
+ * Returns true if the file was modified.
314
+ */
315
+ export function sanitizeSkillFile(filePath) {
316
+ return sanitizeSkillFileWithSummary(filePath).modified;
317
+ }
318
+ /**
319
+ * Sanitize a skill file in place and return change details.
320
+ */
321
+ export function sanitizeSkillFileWithSummary(filePath) {
322
+ const content = readFile(filePath);
323
+ const { frontmatter, body } = parseSkillFrontmatter(content);
324
+ const skillName = path.basename(path.dirname(filePath));
325
+ const { frontmatter: sanitized, changes } = sanitizeSkillFrontmatterWithSummary(frontmatter, skillName);
326
+ const originalStr = stableStringify(frontmatter);
327
+ const sanitizedStr = stableStringify(sanitized);
328
+ if (originalStr === sanitizedStr) {
329
+ return { modified: false, changes: [] };
330
+ }
331
+ const newContent = serializeFrontmatter(sanitized, body);
332
+ writeFile(filePath, newContent);
333
+ return { modified: true, changes };
334
+ }
335
+ /**
336
+ * Find all skills that need sanitization in a loadout root.
337
+ */
338
+ export function findUnsanitizedSkills(loadoutRoot) {
339
+ const skillsDir = path.join(loadoutRoot, SKILLS_DIR);
340
+ if (!isDirectory(skillsDir))
341
+ return [];
342
+ const unsanitized = [];
343
+ for (const entry of listFiles(skillsDir)) {
344
+ const skillDir = path.join(skillsDir, entry);
345
+ if (!isDirectory(skillDir))
346
+ continue;
347
+ const skillMdPath = path.join(skillDir, "SKILL.md");
348
+ if (!fileExists(skillMdPath))
349
+ continue;
350
+ if (skillNeedsSanitization(skillMdPath)) {
351
+ unsanitized.push(entry);
352
+ }
353
+ }
354
+ return unsanitized;
355
+ }
166
356
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"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"}
@@ -37,6 +37,8 @@ export interface DiscoveryOptions {
37
37
  tools?: string[];
38
38
  /** Filter to specific kinds */
39
39
  kinds?: ImportableKind[];
40
+ /** Restrict discovery to one explicit source file or directory */
41
+ sourcePath?: string;
40
42
  /** Path to .loadouts/ directory (to check for existing artifacts) */
41
43
  loadoutPath?: string;
42
44
  }
@@ -1 +1 @@
1
- {"version":3,"file":"import-discovery.d.ts","sourceRoot":"","sources":["../../src/core/import-discovery.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAMxC,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AAEpC,MAAM,WAAW,kBAAkB;IACjC,oBAAoB;IACpB,IAAI,EAAE,cAAc,CAAC;IACrB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,WAAW,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,KAAK,EAAE,IAAI,CAAC;IACZ,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,+BAA+B;IAC/B,SAAS,EAAE,kBAAkB,EAAE,CAAC;IAChC,8CAA8C;IAC9C,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC7C,oCAAoC;IACpC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,sBAAsB;IACtB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IACzB,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAsaD;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,gBAAqB,GAC7B,eAAe,CAgDjB;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,kBAAkB,EAAE,GAC9B,MAAM,CAAC,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAOtC;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIhD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAWrD"}
1
+ {"version":3,"file":"import-discovery.d.ts","sourceRoot":"","sources":["../../src/core/import-discovery.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAMxC,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AAEpC,MAAM,WAAW,kBAAkB;IACjC,oBAAoB;IACpB,IAAI,EAAE,cAAc,CAAC;IACrB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,WAAW,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,6BAA6B;IAC7B,KAAK,EAAE,IAAI,CAAC;IACZ,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,+BAA+B;IAC/B,SAAS,EAAE,kBAAkB,EAAE,CAAC;IAChC,8CAA8C;IAC9C,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC7C,oCAAoC;IACpC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,sBAAsB;IACtB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IACzB,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AA6jBD;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,gBAAqB,GAC7B,eAAe,CA2DjB;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,kBAAkB,EAAE,GAC9B,MAAM,CAAC,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAOtC;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIhD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAWrD"}
@@ -84,6 +84,126 @@ function toDisplayPath(scanRoot, absolutePath) {
84
84
  }
85
85
  return toPosix(absolutePath);
86
86
  }
87
+ function isPathWithin(parentPath, childPath) {
88
+ const rel = path.relative(parentPath, childPath);
89
+ return rel === "" || (!!rel && !rel.startsWith("..") && !path.isAbsolute(rel));
90
+ }
91
+ function matchesSourcePath(artifact, sourcePath) {
92
+ if (artifact.kind === "skill" && isPathWithin(artifact.sourcePath, sourcePath)) {
93
+ return true;
94
+ }
95
+ return isPathWithin(sourcePath, artifact.sourcePath) || artifact.sourcePath === sourcePath;
96
+ }
97
+ function sourceAllowsKind(kindId, kinds) {
98
+ return !kinds || kinds.length === 0 || kinds.includes(kindId);
99
+ }
100
+ function buildSourceArtifact(scanRoot, kind, sourcePath, destPath, name) {
101
+ const metadata = readArtifactMetadata(sourcePath);
102
+ if (!metadata)
103
+ return null;
104
+ return {
105
+ kind,
106
+ name,
107
+ sourcePath,
108
+ displayPath: toDisplayPath(scanRoot, sourcePath),
109
+ tool: "source",
110
+ size: metadata.size,
111
+ mtime: metadata.mtime,
112
+ destPath,
113
+ };
114
+ }
115
+ function buildRuleSourceArtifact(scanRoot, sourcePath) {
116
+ const ext = path.extname(sourcePath).toLowerCase();
117
+ if (ext !== ".md" && ext !== ".mdc")
118
+ return null;
119
+ const stem = path.basename(sourcePath, ext);
120
+ if (!stem || stem === "AGENTS" || stem === "CLAUDE")
121
+ return null;
122
+ return buildSourceArtifact(scanRoot, "rule", sourcePath, `rules/${stem}.md`, stem);
123
+ }
124
+ function buildInstructionSourceArtifact(scanRoot, sourcePath) {
125
+ const basename = path.basename(sourcePath);
126
+ if (basename !== "AGENTS.md" && basename !== "CLAUDE.md" && !/^AGENTS\.[^.]+\.md$/.test(basename)) {
127
+ return null;
128
+ }
129
+ return buildSourceArtifact(scanRoot, "instruction", sourcePath, "instructions/AGENTS.base.md", "AGENTS.md");
130
+ }
131
+ function buildSkillSourceArtifact(scanRoot, skillDir) {
132
+ const skillMdPath = path.join(skillDir, "SKILL.md");
133
+ if (!fileExists(skillMdPath))
134
+ return null;
135
+ const name = path.basename(skillDir);
136
+ return buildSourceArtifact(scanRoot, "skill", skillDir, `skills/${name}`, name);
137
+ }
138
+ function discoverDirectSourceArtifacts(scanRoot, sourcePath, kinds) {
139
+ const artifacts = [];
140
+ if (!fileExists(sourcePath))
141
+ return artifacts;
142
+ if (!isDirectory(sourcePath)) {
143
+ if (sourceAllowsKind("instruction", kinds)) {
144
+ const instruction = buildInstructionSourceArtifact(scanRoot, sourcePath);
145
+ if (instruction)
146
+ artifacts.push(instruction);
147
+ }
148
+ if (sourceAllowsKind("skill", kinds) && path.basename(sourcePath) === "SKILL.md") {
149
+ const skill = buildSkillSourceArtifact(scanRoot, path.dirname(sourcePath));
150
+ if (skill)
151
+ artifacts.push(skill);
152
+ }
153
+ if (sourceAllowsKind("rule", kinds)) {
154
+ const rule = buildRuleSourceArtifact(scanRoot, sourcePath);
155
+ if (rule)
156
+ artifacts.push(rule);
157
+ }
158
+ return artifacts;
159
+ }
160
+ if (sourceAllowsKind("skill", kinds)) {
161
+ const directSkill = buildSkillSourceArtifact(scanRoot, sourcePath);
162
+ if (directSkill)
163
+ artifacts.push(directSkill);
164
+ }
165
+ const basename = path.basename(sourcePath);
166
+ const rulesRoot = basename === "rules" ? sourcePath : path.join(sourcePath, "rules");
167
+ if (sourceAllowsKind("rule", kinds) && isDirectory(rulesRoot)) {
168
+ for (const rel of walkDir(rulesRoot)) {
169
+ const rule = buildRuleSourceArtifact(scanRoot, path.join(rulesRoot, rel));
170
+ if (rule)
171
+ artifacts.push(rule);
172
+ }
173
+ }
174
+ const skillsRoot = basename === "skills" ? sourcePath : path.join(sourcePath, "skills");
175
+ if (sourceAllowsKind("skill", kinds) && isDirectory(skillsRoot)) {
176
+ for (const entry of listFiles(skillsRoot)) {
177
+ const skillDir = path.join(skillsRoot, entry);
178
+ if (!isDirectory(skillDir))
179
+ continue;
180
+ const skill = buildSkillSourceArtifact(scanRoot, skillDir);
181
+ if (skill)
182
+ artifacts.push(skill);
183
+ }
184
+ }
185
+ const instructionsRoot = basename === "instructions" ? sourcePath : path.join(sourcePath, "instructions");
186
+ if (sourceAllowsKind("instruction", kinds) && isDirectory(instructionsRoot)) {
187
+ for (const rel of walkDir(instructionsRoot)) {
188
+ const instruction = buildInstructionSourceArtifact(scanRoot, path.join(instructionsRoot, rel));
189
+ if (instruction)
190
+ artifacts.push(instruction);
191
+ }
192
+ }
193
+ return artifacts;
194
+ }
195
+ function dedupeArtifacts(artifacts) {
196
+ const seen = new Set();
197
+ const deduped = [];
198
+ for (const artifact of artifacts) {
199
+ const key = `${artifact.kind}:${artifact.sourcePath}:${artifact.destPath}`;
200
+ if (seen.has(key))
201
+ continue;
202
+ seen.add(key);
203
+ deduped.push(artifact);
204
+ }
205
+ return deduped;
206
+ }
87
207
  /**
88
208
  * Build a regex matcher for a concrete template path.
89
209
  * Supported tokens: {base} {home} {stem} {ext} {name} {relative} {kind}
@@ -369,6 +489,7 @@ export function discoverImportableArtifacts(scanRoot, options = {}) {
369
489
  const artifacts = [];
370
490
  const warnings = [];
371
491
  const { scope = "project", tools, kinds, loadoutPath } = options;
492
+ const sourcePath = options.sourcePath ? path.resolve(options.sourcePath) : undefined;
372
493
  const allTools = registry.allToolNames();
373
494
  const toolsToScan = tools
374
495
  ? allTools.filter((tool) => tools.includes(tool))
@@ -386,10 +507,17 @@ export function discoverImportableArtifacts(scanRoot, options = {}) {
386
507
  if (!kinds || kinds.length === 0 || kinds.includes("instruction")) {
387
508
  artifacts.push(...discoverInstructions(scanRoot, loadoutPath));
388
509
  }
510
+ if (sourcePath) {
511
+ artifacts.push(...discoverDirectSourceArtifacts(scanRoot, sourcePath, kinds));
512
+ }
389
513
  // Filter out artifacts already present in .loadouts/.
390
- const filteredArtifacts = loadoutPath
514
+ const existingFilteredArtifacts = loadoutPath
391
515
  ? artifacts.filter((artifact) => !artifactExistsInLoadout(loadoutPath, artifact))
392
516
  : artifacts;
517
+ const sourceFilteredArtifacts = sourcePath
518
+ ? existingFilteredArtifacts.filter((artifact) => matchesSourcePath(artifact, sourcePath))
519
+ : existingFilteredArtifacts;
520
+ const filteredArtifacts = dedupeArtifacts(sourceFilteredArtifacts);
393
521
  // Detect conflicts by canonical destination path.
394
522
  const byDest = new Map();
395
523
  for (const artifact of filteredArtifacts) {