skiller 0.7.6 → 0.7.7

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 CHANGED
@@ -5,12 +5,12 @@ A Claude-centric fork of [ruler](https://github.com/intellectronica/ruler) with
5
5
  ## 1. Skills as Source of Truth
6
6
 
7
7
  - `.claude/skills/` is the committed source of truth for skills
8
- - **Bidirectional sync** between `.mdc` and `SKILL.md`:
9
- - Create `.claude/skills/foo.mdc` → auto-generates `.claude/skills/foo/SKILL.md`
10
- - Create `.claude/skills/foo/SKILL.md` → auto-generates `.claude/skills/foo.mdc`
11
- - Uses `synced: true` frontmatter to track sync direction
8
+ - **Bidirectional sync** between `.mdc` and `SKILL.md` (sibling pattern):
9
+ - Create `.claude/skills/foo/foo.mdc` → auto-generates `.claude/skills/foo/SKILL.md`
10
+ - Create `.claude/skills/foo/SKILL.md` → auto-generates `.claude/skills/foo/foo.mdc`
11
+ - Sync direction detected via `@reference` body pattern (SKILL.md with `@path` = .mdc is source)
12
12
  - Edit either file, the other stays in sync on next `skiller apply`
13
- - Skill folders from `.claude/rules/` are copied to `.claude/skills/`
13
+ - `.claude/rules/` contents are migrated to `.claude/skills/` and rules directory is deleted
14
14
 
15
15
  ## 2. CLAUDE.md @filename References
16
16
 
@@ -84,7 +84,7 @@ Skiller solves this by providing a **single source of truth** for all your AI ag
84
84
  | AGENTS.md | `AGENTS.md` | (pseudo-agent ensuring root `AGENTS.md` exists) |
85
85
  | GitHub Copilot | `AGENTS.md` | `.vscode/mcp.json` |
86
86
  | Claude Code | `CLAUDE.md` (@filename references) | `.mcp.json` |
87
- | OpenAI Codex CLI | `AGENTS.md` | `.codex/config.toml` (MCP via Skillz) |
87
+ | OpenAI Codex CLI | `AGENTS.md` | `.codex/config.toml` |
88
88
  | Jules | `AGENTS.md` | - |
89
89
  | Cursor | `AGENTS.md` | `.cursor/mcp.json` |
90
90
  | Windsurf | `AGENTS.md` | `.windsurf/mcp_config.json` |
@@ -567,11 +567,12 @@ Skills can be organized flat or nested:
567
567
 
568
568
  ```
569
569
  .claude/skills/
570
- ├── my-skill.mdc # Standalone skill file (auto-syncs to folder)
571
570
  ├── my-skill/
572
- └── SKILL.md # Generated from my-skill.mdc (synced: true)
571
+ ├── my-skill.mdc # Skill content (body)
572
+ │ └── SKILL.md # @reference to my-skill.mdc (frontmatter here)
573
573
  ├── another-skill/
574
- │ ├── SKILL.md # Manually created skill
574
+ │ ├── another-skill.mdc # Generated from SKILL.md body
575
+ │ ├── SKILL.md # Manually created skill (now @reference)
575
576
  │ ├── helper.py # Optional: additional resources (scripts)
576
577
  │ └── reference.md # Optional: additional resources (docs)
577
578
  ```
@@ -587,25 +588,24 @@ Skiller provides bidirectional sync between `.mdc` files and `SKILL.md` folders:
587
588
 
588
589
  | Scenario | Sync Direction |
589
590
  |----------|---------------|
590
- | `.mdc` exists, no `SKILL.md` | → Generate `SKILL.md` with `synced: true` |
591
- | `SKILL.md` has `synced: true` | .mdc `SKILL.md` (regenerate from .mdc) |
592
- | `SKILL.md` without `synced: true` | `SKILL.md` → .mdc (SKILL.md is source of truth) |
591
+ | `.mdc` exists, no `SKILL.md` | → Generate `SKILL.md` with `@reference` to .mdc |
592
+ | `SKILL.md` body is `@reference` | .mdc is source of truth (frontmatter in SKILL.md) |
593
+ | `SKILL.md` has full content | → Generate .mdc from body, update SKILL.md to `@reference` |
593
594
 
594
- The `synced: true` frontmatter flag indicates that the `.mdc` file is the source of truth:
595
+ The `@reference` body pattern indicates that the `.mdc` file contains the skill content:
595
596
 
596
597
  ```yaml
597
598
  ---
598
599
  name: my-skill
599
600
  description: My custom skill
600
- synced: true
601
601
  ---
602
602
 
603
- # Skill content here
603
+ @.claude/skills/my-skill/my-skill.mdc
604
604
  ```
605
605
 
606
- ### Skill Folders from Rules
606
+ ### Rules Migration
607
607
 
608
- Skill folders (directories containing `SKILL.md`) in `.claude/rules/` are automatically copied to `.claude/skills/` during `skiller apply`:
608
+ Content from `.claude/rules/` is automatically migrated to `.claude/skills/` during `skiller apply`, then the rules directory is deleted:
609
609
 
610
610
  ```
611
611
  .claude/rules/docx/
@@ -614,13 +614,16 @@ Skill folders (directories containing `SKILL.md`) in `.claude/rules/` are automa
614
614
  └── templates/ # Subdirectory
615
615
  └── default.docx # Template file
616
616
 
617
- Copied to:
617
+ Migrated to:
618
618
 
619
619
  .claude/skills/docx/
620
- ├── SKILL.md # Copied as-is
620
+ ├── docx.mdc # Generated from SKILL.md body
621
+ ├── SKILL.md # Updated to @reference
621
622
  ├── script.sh # Copied automatically
622
623
  └── templates/ # Copied automatically
623
624
  └── default.docx # Copied automatically
625
+
626
+ .claude/rules/ → Deleted after migration
624
627
  ```
625
628
 
626
629
  ### Configuration
@@ -236,8 +236,10 @@ async function readMarkdownFiles(skillerDir, options) {
236
236
  cursorFiles.push(file);
237
237
  continue;
238
238
  }
239
- // Check if file is in rules/ folder and is .mdc
240
- if (normalizedPath.startsWith('rules/') && file.path.endsWith('.mdc')) {
239
+ // Check if file is in rules/ or skills/ folder and is .mdc
240
+ if ((normalizedPath.startsWith('rules/') ||
241
+ normalizedPath.startsWith('skills/')) &&
242
+ file.path.endsWith('.mdc')) {
241
243
  // Parse frontmatter
242
244
  const parsed = (0, FrontmatterParser_1.parseFrontmatter)(file.content);
243
245
  // Only include if alwaysApply is true
@@ -237,8 +237,26 @@ ${yaml.dump(skillFrontmatter || { name: skillName }, { lineWidth: -1, noRefs: tr
237
237
  else {
238
238
  referencedPath = path.resolve(skillFolderPath, refCheck.referencePath);
239
239
  }
240
+ // One-time migration: for old @.claude/rules/ references, look at the
241
+ // already-migrated skills location. After migration, SKILL.md will have
242
+ // @.claude/skills/ references, so this code path won't be hit again.
243
+ let actualPath = referencedPath;
244
+ if (refCheck.referencePath?.includes('/rules/')) {
245
+ const refFileName = path.basename(refCheck.referencePath);
246
+ const refBaseName = path.basename(refFileName, '.mdc');
247
+ actualPath = path.join(skillsDir, refBaseName, refFileName);
248
+ }
249
+ let referencedContent = null;
240
250
  try {
241
- const referencedContent = await fs.readFile(referencedPath, 'utf8');
251
+ referencedContent = await fs.readFile(actualPath, 'utf8');
252
+ }
253
+ catch {
254
+ // File not found
255
+ }
256
+ if (referencedContent === null) {
257
+ warnings.push(`Cannot migrate ${skillName}: referenced file not found at ${actualPath}`);
258
+ }
259
+ else {
242
260
  // Parse the referenced file for frontmatter
243
261
  const { frontmatter: refFrontmatter, body: refBody } = (0, FrontmatterParser_1.parseFrontmatter)(referencedContent);
244
262
  // Create sibling .mdc - only keep frontmatter for alwaysApply rules
@@ -281,14 +299,10 @@ ${yaml.dump(newFrontmatter, { lineWidth: -1, noRefs: true }).trim()}
281
299
  else {
282
300
  await fs.writeFile(siblingMdcPath, mdcContent, 'utf8');
283
301
  await fs.writeFile(skillMdPath, newSkillMd, 'utf8');
284
- (0, constants_1.logVerboseInfo)(`Migrated ${skillName} from ${refCheck.referencePath} to sibling pattern`, verbose, dryRun);
302
+ (0, constants_1.logVerboseInfo)(`Migrated ${skillName} from ${actualPath} to sibling pattern`, verbose, dryRun);
285
303
  }
286
304
  synced.push(skillName);
287
305
  }
288
- catch {
289
- // Referenced file doesn't exist or can't be read
290
- warnings.push(`Cannot migrate ${skillName}: referenced file ${refCheck.referencePath} not found or unreadable`);
291
- }
292
306
  }
293
307
  }
294
308
  else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skiller",
3
- "version": "0.7.6",
3
+ "version": "0.7.7",
4
4
  "description": "Skiller — apply the same rules to all coding agents",
5
5
  "main": "dist/lib.js",
6
6
  "publishConfig": {