fmddr-skills 0.6.0 → 0.6.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 (3) hide show
  1. package/README.md +30 -27
  2. package/bin/install.js +115 -34
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
- # fmddr — Claude Code skills
1
+ # fmddr — agent skills
2
2
 
3
- Four agent skills for working with [`fmddr`](https://github.com/proofsh/fmddr)
4
- from Claude Code:
3
+ Skills for working with [`fmddr`](https://github.com/proofsh/fmddr) from
4
+ Claude Code, Cursor, and any agent that reads `AGENTS.md`.
5
5
 
6
6
  | Skill | Triggers on | Purpose |
7
7
  | --------------- | ------------------------------------------------------------------------- | -------------------------------------------------------------- |
@@ -10,47 +10,50 @@ from Claude Code:
10
10
  | `fmddr-issue` | "report a bug", "file an issue", "feature request" — for fmddr | Open a high-quality issue at proofsh/fmddr (with severity) |
11
11
  | `fmddr-release` | "release fmddr", "cut a patch", "publish to PyPI" | End-to-end release flow: bump, changelog, build, tag, publish |
12
12
 
13
- **Typical first-time flow:**
14
- 1. `npx fmddr-skills` — installs all four skills
15
- 2. In a Claude Code session: "set up fmddr for my DDR" → `fmddr-setup` activates
16
- 3. Now any FileMaker question → `fmddr` activates automatically
17
-
18
13
  ## Install
19
14
 
20
- ### npx (no git required)
15
+ ### Claude Code
21
16
 
22
17
  ```sh
23
- npx fmddr-skills # install all four skills (personal)
24
- npx fmddr-skills fmddr fmddr-setup # install specific skills only
18
+ npx fmddr-skills # personal (~/.claude/skills/)
25
19
  npx fmddr-skills --project # project-scoped (.claude/skills/)
20
+ npx fmddr-skills fmddr fmddr-setup # specific skills only
26
21
  ```
27
22
 
28
- ### Manual personal (one user, all projects)
23
+ In a Claude Code session type `/` to confirm they appear, or ask
24
+ "is the fmddr skill loaded?".
25
+
26
+ ### Cursor
29
27
 
30
28
  ```sh
31
- mkdir -p ~/.claude/skills
32
- cp -R skills/fmddr ~/.claude/skills/
33
- cp -R skills/fmddr-setup ~/.claude/skills/
34
- cp -R skills/fmddr-issue ~/.claude/skills/
35
- cp -R skills/fmddr-release ~/.claude/skills/
29
+ npx fmddr-skills --cursor # writes .cursor/rules/fmddr-*.mdc
36
30
  ```
37
31
 
38
- ### Manual project-scoped (this repo only)
32
+ Installs each skill as a `.mdc` rule file in `.cursor/rules/` of the
33
+ current directory. Rules for `fmddr`, `fmddr-setup`, and
34
+ `fmddr-generate-docs` auto-activate on `.fmp12` / `.xml` / `.fmddr.db`
35
+ files; the others are available on demand. Restart Cursor or open the
36
+ Rules panel after installing.
37
+
38
+ ### AGENTS.md (Codex and other agents)
39
39
 
40
40
  ```sh
41
- mkdir -p .claude/skills
42
- cp -R skills/fmddr .claude/skills/
43
- cp -R skills/fmddr-setup .claude/skills/
44
- cp -R skills/fmddr-issue .claude/skills/
45
- cp -R skills/fmddr-release .claude/skills/
41
+ npx fmddr-skills --agents-md # writes AGENTS.md in the current directory
46
42
  ```
47
43
 
48
- Project skills override personal skills with the same name.
44
+ Writes a single `AGENTS.md` file combining all skill instructions.
45
+ Compatible with any agent that picks up `AGENTS.md` from the project root
46
+ (OpenAI Codex, etc.). Re-run to update after a new version is published.
49
47
 
50
- ## Verify
48
+ ### Manual — Claude Code personal
51
49
 
52
- In a Claude Code session, type `/` and look for the skills, or ask
53
- "is the fmddr skill loaded?" — Claude will list available skills.
50
+ ```sh
51
+ mkdir -p ~/.claude/skills
52
+ cp -R skills/fmddr ~/.claude/skills/
53
+ cp -R skills/fmddr-setup ~/.claude/skills/
54
+ cp -R skills/fmddr-issue ~/.claude/skills/
55
+ cp -R skills/fmddr-release ~/.claude/skills/
56
+ ```
54
57
 
55
58
  ## Layout
56
59
 
package/bin/install.js CHANGED
@@ -7,22 +7,25 @@ const os = require("os");
7
7
 
8
8
  const ALL_SKILLS = ["fmddr", "fmddr-generate-docs", "fmddr-issue", "fmddr-release", "fmddr-setup"];
9
9
 
10
- // Parse args: `npx fmddr-skills [skill1 skill2 ...]`
11
- const requested = process.argv.slice(2).filter(a => !a.startsWith("-"));
12
- const showHelp = process.argv.includes("--help") || process.argv.includes("-h");
13
- const scopeFlag = process.argv.includes("--project") || process.argv.includes("-p")
14
- ? "project"
15
- : "personal";
10
+ const args = process.argv.slice(2);
11
+ const showHelp = args.includes("--help") || args.includes("-h");
12
+ const cursorFlag = args.includes("--cursor");
13
+ const agentsMdFlag = args.includes("--agents-md");
14
+ const scopeFlag = args.includes("--project") || args.includes("-p") ? "project" : "personal";
15
+
16
+ // Positional args are skill names
17
+ const requested = args.filter(a => !a.startsWith("-"));
16
18
 
17
19
  if (showHelp) {
18
20
  console.log(`
19
- fmddr-skills — install Claude Code skills for fmddr
21
+ fmddr-skills — install fmddr agent skills
20
22
 
21
23
  Usage:
22
- npx fmddr-skills install all skills (personal)
23
- npx fmddr-skills fmddr install one skill
24
- npx fmddr-skills fmddr fmddr-issue install two skills
25
- npx fmddr-skills --project install into .claude/skills/ (project-scoped)
24
+ npx fmddr-skills install all skills for Claude Code (personal)
25
+ npx fmddr-skills fmddr fmddr-issue install specific skills only
26
+ npx fmddr-skills --project install into .claude/skills/ (project-scoped)
27
+ npx fmddr-skills --cursor install as Cursor rules (.cursor/rules/)
28
+ npx fmddr-skills --agents-md write AGENTS.md in the current directory
26
29
 
27
30
  Available skills: ${ALL_SKILLS.join(", ")}
28
31
  `);
@@ -31,7 +34,6 @@ Available skills: ${ALL_SKILLS.join(", ")}
31
34
 
32
35
  const toInstall = requested.length > 0 ? requested : ALL_SKILLS;
33
36
 
34
- // Validate
35
37
  for (const name of toInstall) {
36
38
  if (!ALL_SKILLS.includes(name)) {
37
39
  console.error(`Unknown skill: "${name}". Available: ${ALL_SKILLS.join(", ")}`);
@@ -39,38 +41,117 @@ for (const name of toInstall) {
39
41
  }
40
42
  }
41
43
 
42
- // Resolve destination
43
- const dest =
44
- scopeFlag === "project"
45
- ? path.join(process.cwd(), ".claude", "skills")
46
- : path.join(os.homedir(), ".claude", "skills");
44
+ const skillsRoot = path.join(__dirname, "..");
47
45
 
48
- fs.mkdirSync(dest, { recursive: true });
46
+ // ── Helpers ────────────────────────────────────────────────────────────────
49
47
 
50
- // Copy a directory tree recursively
51
48
  function copyDir(src, dst) {
52
49
  fs.mkdirSync(dst, { recursive: true });
53
50
  for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
54
51
  const srcPath = path.join(src, entry.name);
55
52
  const dstPath = path.join(dst, entry.name);
56
- if (entry.isDirectory()) {
57
- copyDir(srcPath, dstPath);
58
- } else {
59
- fs.copyFileSync(srcPath, dstPath);
60
- }
53
+ if (entry.isDirectory()) copyDir(srcPath, dstPath);
54
+ else fs.copyFileSync(srcPath, dstPath);
61
55
  }
62
56
  }
63
57
 
64
- const skillsRoot = path.join(__dirname, "..");
65
- let installed = 0;
58
+ // Parse the YAML frontmatter block at the top of a SKILL.md.
59
+ // Returns { meta: { key: value, ... }, body: "content after frontmatter" }
60
+ function parseFrontmatter(text) {
61
+ const match = text.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
62
+ if (!match) return { meta: {}, body: text };
63
+ const meta = {};
64
+ for (const line of match[1].split(/\r?\n/)) {
65
+ const kv = line.match(/^(\w+):\s*(.*)/);
66
+ if (kv) meta[kv[1]] = kv[2].trim();
67
+ }
68
+ return { meta, body: match[2] };
69
+ }
66
70
 
67
- for (const name of toInstall) {
68
- const src = path.join(skillsRoot, name);
69
- const dst = path.join(dest, name);
70
- copyDir(src, dst);
71
- console.log(` ✓ ${name} → ${dst}`);
72
- installed++;
71
+ // ── Claude Code install ────────────────────────────────────────────────────
72
+
73
+ function installClaudeCode(skills) {
74
+ const dest =
75
+ scopeFlag === "project"
76
+ ? path.join(process.cwd(), ".claude", "skills")
77
+ : path.join(os.homedir(), ".claude", "skills");
78
+ fs.mkdirSync(dest, { recursive: true });
79
+ for (const name of skills) {
80
+ copyDir(path.join(skillsRoot, name), path.join(dest, name));
81
+ console.log(` ✓ ${name} → ${dest}/${name}`);
82
+ }
83
+ console.log(`\nInstalled ${skills.length} skill${skills.length === 1 ? "" : "s"} into ${dest}`);
84
+ console.log("Open a Claude Code session and type / to confirm they appear.");
85
+ }
86
+
87
+ // ── Cursor rules install ───────────────────────────────────────────────────
88
+
89
+ // Globs that make sense for each skill — auto-activates the rule when
90
+ // the user is working on matching files.
91
+ const CURSOR_GLOBS = {
92
+ "fmddr": "**/*.fmp12, **/*.xml, **/*.fmddr.db",
93
+ "fmddr-setup": "**/*.fmp12, **/*.xml, **/*.fmddr.db",
94
+ "fmddr-issue": "",
95
+ "fmddr-release": "",
96
+ "fmddr-generate-docs": "**/*.fmp12, **/*.xml, **/*.fmddr.db",
97
+ };
98
+
99
+ function installCursor(skills) {
100
+ const dest = path.join(process.cwd(), ".cursor", "rules");
101
+ fs.mkdirSync(dest, { recursive: true });
102
+ for (const name of skills) {
103
+ const skillMd = path.join(skillsRoot, name, "SKILL.md");
104
+ if (!fs.existsSync(skillMd)) continue;
105
+ const { meta, body } = parseFrontmatter(fs.readFileSync(skillMd, "utf8"));
106
+ const description = meta.description
107
+ ? meta.description.slice(0, 200) // Cursor shows ~120 chars in the UI
108
+ : `fmddr skill: ${name}`;
109
+ const globs = CURSOR_GLOBS[name] ?? "";
110
+ const frontmatter = [
111
+ "---",
112
+ `description: ${description}`,
113
+ globs ? `globs: ${globs}` : "globs:",
114
+ "alwaysApply: false",
115
+ "---",
116
+ "",
117
+ ].join("\n");
118
+ const outPath = path.join(dest, `${name}.mdc`);
119
+ fs.writeFileSync(outPath, frontmatter + body, "utf8");
120
+ console.log(` ✓ ${name} → ${outPath}`);
121
+ }
122
+ console.log(`\nInstalled ${skills.length} Cursor rule${skills.length === 1 ? "" : "s"} into ${dest}`);
123
+ console.log("Restart Cursor or open the Rules panel to confirm they appear.");
73
124
  }
74
125
 
75
- console.log(`\nInstalled ${installed} skill${installed === 1 ? "" : "s"} into ${dest}`);
76
- console.log("Open a Claude Code session and type / to confirm they appear.");
126
+ // ── AGENTS.md install ──────────────────────────────────────────────────────
127
+
128
+ function installAgentsMd(skills) {
129
+ const outPath = path.join(process.cwd(), "AGENTS.md");
130
+ const sections = [];
131
+
132
+ sections.push(
133
+ "# fmddr Agent Instructions\n",
134
+ "> Generated by `npx fmddr-skills --agents-md`. Re-run to update.\n",
135
+ );
136
+
137
+ for (const name of skills) {
138
+ const skillMd = path.join(skillsRoot, name, "SKILL.md");
139
+ if (!fs.existsSync(skillMd)) continue;
140
+ const { body } = parseFrontmatter(fs.readFileSync(skillMd, "utf8"));
141
+ sections.push(`---\n\n${body.trim()}\n`);
142
+ }
143
+
144
+ fs.writeFileSync(outPath, sections.join("\n"), "utf8");
145
+ console.log(` ✓ Wrote ${outPath}`);
146
+ console.log(`\nAGENTS.md contains instructions for ${skills.length} skill${skills.length === 1 ? "" : "s"}.`);
147
+ }
148
+
149
+ // ── Dispatch ───────────────────────────────────────────────────────────────
150
+
151
+ if (cursorFlag) {
152
+ installCursor(toInstall);
153
+ } else if (agentsMdFlag) {
154
+ installAgentsMd(toInstall);
155
+ } else {
156
+ installClaudeCode(toInstall);
157
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fmddr-skills",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Claude Code skills for fmddr — FileMaker DDR analyzer",
5
5
  "keywords": [
6
6
  "claude-code",