recur-skills 0.0.3 → 0.0.5

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.
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Claude Code skills for integrating Recur - Taiwan's subscription payment platform",
9
- "version": "0.0.3"
9
+ "version": "0.0.5"
10
10
  },
11
11
  "plugins": [
12
12
  {
package/README.md CHANGED
@@ -4,6 +4,14 @@ Claude Code skills to help developers integrate [Recur](https://recur.tw) - Taiw
4
4
 
5
5
  ## Installation
6
6
 
7
+ ### npx skills add (Recommended)
8
+
9
+ ```bash
10
+ npx skills add recur-tw/skills
11
+ ```
12
+
13
+ ### Claude Code Plugin
14
+
7
15
  ```bash
8
16
  /plugin marketplace add recur-tw/skills
9
17
  /plugin install recur-skills@recur-skills
package/dist/cli.d.mts ADDED
@@ -0,0 +1 @@
1
+ export { };
package/dist/cli.mjs ADDED
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { program } from "commander";
4
+ import pc from "picocolors";
5
+ import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync } from "node:fs";
6
+ import { dirname, join } from "node:path";
7
+ import { fileURLToPath } from "node:url";
8
+
9
+ //#region src/index.ts
10
+ const SKILLS_DIR = join(dirname(fileURLToPath(import.meta.url)), "..", "skills");
11
+ /**
12
+ * Parse SKILL.md frontmatter
13
+ */
14
+ function parseFrontmatter(content) {
15
+ const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
16
+ if (!match) return {
17
+ data: {},
18
+ content
19
+ };
20
+ const data = {};
21
+ const lines = match[1].split("\n");
22
+ for (const line of lines) {
23
+ const colonIndex = line.indexOf(":");
24
+ if (colonIndex > 0) {
25
+ const key = line.slice(0, colonIndex).trim();
26
+ data[key] = line.slice(colonIndex + 1).trim();
27
+ }
28
+ }
29
+ return {
30
+ data,
31
+ content: match[2]
32
+ };
33
+ }
34
+ /**
35
+ * Get all available skills
36
+ */
37
+ function getAllSkills() {
38
+ if (!existsSync(SKILLS_DIR)) return [];
39
+ const skillDirs = readdirSync(SKILLS_DIR, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
40
+ const skills = [];
41
+ for (const dir of skillDirs) {
42
+ const skillPath = join(SKILLS_DIR, dir, "SKILL.md");
43
+ if (!existsSync(skillPath)) continue;
44
+ const { data, content } = parseFrontmatter(readFileSync(skillPath, "utf-8"));
45
+ skills.push({
46
+ slug: dir,
47
+ name: data.name || dir,
48
+ description: data.description || "",
49
+ content,
50
+ path: skillPath
51
+ });
52
+ }
53
+ return skills;
54
+ }
55
+ /**
56
+ * Get a single skill by slug
57
+ */
58
+ function getSkill(slug) {
59
+ const skillPath = join(SKILLS_DIR, slug, "SKILL.md");
60
+ if (!existsSync(skillPath)) return null;
61
+ const { data, content } = parseFrontmatter(readFileSync(skillPath, "utf-8"));
62
+ return {
63
+ slug,
64
+ name: data.name || slug,
65
+ description: data.description || "",
66
+ content,
67
+ path: skillPath
68
+ };
69
+ }
70
+ /**
71
+ * Get the path to skills directory
72
+ */
73
+ function getSkillsDir() {
74
+ return SKILLS_DIR;
75
+ }
76
+
77
+ //#endregion
78
+ //#region src/cli.ts
79
+ const SKILLS_SOURCE = join(dirname(fileURLToPath(import.meta.url)), "..", "skills");
80
+ program.name("recur-skills").description("Claude Code skills for Recur payment integration").version("0.0.1");
81
+ program.command("list").description("List all available skills").action(() => {
82
+ const skills = getAllSkills();
83
+ if (skills.length === 0) {
84
+ console.log(pc.yellow("No skills found."));
85
+ return;
86
+ }
87
+ console.log(pc.bold("\n📦 Available Recur Skills\n"));
88
+ for (const skill of skills) {
89
+ console.log(pc.cyan(` ${skill.name}`));
90
+ console.log(pc.dim(` ${skill.description}\n`));
91
+ }
92
+ console.log(pc.dim(`Total: ${skills.length} skills\n`));
93
+ });
94
+ program.command("info <skill>").description("Show detailed information about a skill").action((skillName) => {
95
+ const skill = getSkill(skillName);
96
+ if (!skill) {
97
+ console.log(pc.red(`Skill "${skillName}" not found.`));
98
+ console.log(pc.dim("\nRun `recur-skills list` to see available skills."));
99
+ process.exit(1);
100
+ }
101
+ console.log(pc.bold(`\n📦 ${skill.name}\n`));
102
+ console.log(pc.dim("Description:"));
103
+ console.log(` ${skill.description}\n`);
104
+ console.log(pc.dim("Path:"));
105
+ console.log(` ${skill.path}\n`);
106
+ });
107
+ program.command("install [skills...]").description("Install skills to your Claude Code skills directory").option("-g, --global", "Install to global ~/.claude/skills/", false).option("-p, --project", "Install to project .claude/skills/", false).option("-a, --all", "Install all skills", false).action((skillNames, options) => {
108
+ let targetDir;
109
+ if (options.global) targetDir = join(process.env.HOME || "~", ".claude", "skills");
110
+ else if (options.project) targetDir = join(process.cwd(), ".claude", "skills");
111
+ else targetDir = join(process.env.HOME || "~", ".claude", "skills");
112
+ let toInstall;
113
+ if (options.all) toInstall = readdirSync(SKILLS_SOURCE, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
114
+ else if (skillNames.length === 0) {
115
+ console.log(pc.yellow("Please specify skills to install or use --all"));
116
+ console.log(pc.dim("\nExamples:"));
117
+ console.log(pc.dim(" recur-skills install recur-quickstart"));
118
+ console.log(pc.dim(" recur-skills install recur-checkout recur-webhooks"));
119
+ console.log(pc.dim(" recur-skills install --all"));
120
+ process.exit(1);
121
+ } else toInstall = skillNames;
122
+ if (!existsSync(targetDir)) mkdirSync(targetDir, { recursive: true });
123
+ console.log(pc.bold(`\n📦 Installing skills to ${targetDir}\n`));
124
+ let installed = 0;
125
+ for (const skillName of toInstall) {
126
+ const sourcePath = join(SKILLS_SOURCE, skillName);
127
+ const destPath = join(targetDir, skillName);
128
+ if (!existsSync(sourcePath)) {
129
+ console.log(pc.red(` ✗ ${skillName} - not found`));
130
+ continue;
131
+ }
132
+ try {
133
+ cpSync(sourcePath, destPath, { recursive: true });
134
+ console.log(pc.green(` ✓ ${skillName}`));
135
+ installed++;
136
+ } catch (error) {
137
+ console.log(pc.red(` ✗ ${skillName} - ${error}`));
138
+ }
139
+ }
140
+ console.log(pc.dim(`\nInstalled ${installed}/${toInstall.length} skills\n`));
141
+ if (installed > 0) {
142
+ console.log(pc.cyan("Skills are now available in Claude Code!"));
143
+ console.log(pc.dim("Claude will automatically use them when relevant,"));
144
+ console.log(pc.dim("or you can invoke them directly with /skill-name\n"));
145
+ }
146
+ });
147
+ program.command("path").description("Show the path to the skills directory").action(() => {
148
+ console.log(getSkillsDir());
149
+ });
150
+ program.parse();
151
+
152
+ //#endregion
153
+ export { };
154
+ //# sourceMappingURL=cli.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.mjs","names":["data: Record<string, string>","skills: Skill[]","targetDir: string","toInstall: string[]"],"sources":["../src/index.ts","../src/cli.ts"],"sourcesContent":["import { readFileSync, readdirSync, existsSync } from 'node:fs'\nimport { join, dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\nconst SKILLS_DIR = join(__dirname, '..', 'skills')\n\nexport interface SkillMetadata {\n name: string\n description: string\n}\n\nexport interface Skill extends SkillMetadata {\n slug: string\n content: string\n path: string\n}\n\n/**\n * Parse SKILL.md frontmatter\n */\nfunction parseFrontmatter(content: string): { data: Record<string, string>; content: string } {\n const match = content.match(/^---\\n([\\s\\S]*?)\\n---\\n([\\s\\S]*)$/)\n if (!match) {\n return { data: {}, content }\n }\n\n const data: Record<string, string> = {}\n const lines = match[1].split('\\n')\n for (const line of lines) {\n const colonIndex = line.indexOf(':')\n if (colonIndex > 0) {\n const key = line.slice(0, colonIndex).trim()\n const value = line.slice(colonIndex + 1).trim()\n data[key] = value\n }\n }\n\n return { data, content: match[2] }\n}\n\n/**\n * Get all available skills\n */\nexport function getAllSkills(): Skill[] {\n if (!existsSync(SKILLS_DIR)) {\n return []\n }\n\n const skillDirs = readdirSync(SKILLS_DIR, { withFileTypes: true })\n .filter(dirent => dirent.isDirectory())\n .map(dirent => dirent.name)\n\n const skills: Skill[] = []\n\n for (const dir of skillDirs) {\n const skillPath = join(SKILLS_DIR, dir, 'SKILL.md')\n if (!existsSync(skillPath)) continue\n\n const rawContent = readFileSync(skillPath, 'utf-8')\n const { data, content } = parseFrontmatter(rawContent)\n\n skills.push({\n slug: dir,\n name: data.name || dir,\n description: data.description || '',\n content,\n path: skillPath,\n })\n }\n\n return skills\n}\n\n/**\n * Get a single skill by slug\n */\nexport function getSkill(slug: string): Skill | null {\n const skillPath = join(SKILLS_DIR, slug, 'SKILL.md')\n if (!existsSync(skillPath)) return null\n\n const rawContent = readFileSync(skillPath, 'utf-8')\n const { data, content } = parseFrontmatter(rawContent)\n\n return {\n slug,\n name: data.name || slug,\n description: data.description || '',\n content,\n path: skillPath,\n }\n}\n\n/**\n * Get skill names only (for listing)\n */\nexport function getSkillNames(): string[] {\n if (!existsSync(SKILLS_DIR)) {\n return []\n }\n\n return readdirSync(SKILLS_DIR, { withFileTypes: true })\n .filter(dirent => dirent.isDirectory())\n .filter(dirent => existsSync(join(SKILLS_DIR, dirent.name, 'SKILL.md')))\n .map(dirent => dirent.name)\n}\n\n/**\n * Get the path to skills directory\n */\nexport function getSkillsDir(): string {\n return SKILLS_DIR\n}\n","import { program } from 'commander'\nimport pc from 'picocolors'\nimport { existsSync, mkdirSync, cpSync, readdirSync } from 'node:fs'\nimport { join, dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { getAllSkills, getSkill, getSkillsDir } from './index.js'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\nconst SKILLS_SOURCE = join(__dirname, '..', 'skills')\n\nprogram\n .name('recur-skills')\n .description('Claude Code skills for Recur payment integration')\n .version('0.0.1')\n\nprogram\n .command('list')\n .description('List all available skills')\n .action(() => {\n const skills = getAllSkills()\n\n if (skills.length === 0) {\n console.log(pc.yellow('No skills found.'))\n return\n }\n\n console.log(pc.bold('\\n📦 Available Recur Skills\\n'))\n\n for (const skill of skills) {\n console.log(pc.cyan(` ${skill.name}`))\n console.log(pc.dim(` ${skill.description}\\n`))\n }\n\n console.log(pc.dim(`Total: ${skills.length} skills\\n`))\n })\n\nprogram\n .command('info <skill>')\n .description('Show detailed information about a skill')\n .action((skillName: string) => {\n const skill = getSkill(skillName)\n\n if (!skill) {\n console.log(pc.red(`Skill \"${skillName}\" not found.`))\n console.log(pc.dim('\\nRun `recur-skills list` to see available skills.'))\n process.exit(1)\n }\n\n console.log(pc.bold(`\\n📦 ${skill.name}\\n`))\n console.log(pc.dim('Description:'))\n console.log(` ${skill.description}\\n`)\n console.log(pc.dim('Path:'))\n console.log(` ${skill.path}\\n`)\n })\n\nprogram\n .command('install [skills...]')\n .description('Install skills to your Claude Code skills directory')\n .option('-g, --global', 'Install to global ~/.claude/skills/', false)\n .option('-p, --project', 'Install to project .claude/skills/', false)\n .option('-a, --all', 'Install all skills', false)\n .action((skillNames: string[], options: { global: boolean; project: boolean; all: boolean }) => {\n // Determine target directory\n let targetDir: string\n if (options.global) {\n targetDir = join(process.env.HOME || '~', '.claude', 'skills')\n } else if (options.project) {\n targetDir = join(process.cwd(), '.claude', 'skills')\n } else {\n // Default to global\n targetDir = join(process.env.HOME || '~', '.claude', 'skills')\n }\n\n // Determine which skills to install\n let toInstall: string[]\n if (options.all) {\n toInstall = readdirSync(SKILLS_SOURCE, { withFileTypes: true })\n .filter(d => d.isDirectory())\n .map(d => d.name)\n } else if (skillNames.length === 0) {\n console.log(pc.yellow('Please specify skills to install or use --all'))\n console.log(pc.dim('\\nExamples:'))\n console.log(pc.dim(' recur-skills install recur-quickstart'))\n console.log(pc.dim(' recur-skills install recur-checkout recur-webhooks'))\n console.log(pc.dim(' recur-skills install --all'))\n process.exit(1)\n } else {\n toInstall = skillNames\n }\n\n // Create target directory\n if (!existsSync(targetDir)) {\n mkdirSync(targetDir, { recursive: true })\n }\n\n console.log(pc.bold(`\\n📦 Installing skills to ${targetDir}\\n`))\n\n let installed = 0\n for (const skillName of toInstall) {\n const sourcePath = join(SKILLS_SOURCE, skillName)\n const destPath = join(targetDir, skillName)\n\n if (!existsSync(sourcePath)) {\n console.log(pc.red(` ✗ ${skillName} - not found`))\n continue\n }\n\n try {\n cpSync(sourcePath, destPath, { recursive: true })\n console.log(pc.green(` ✓ ${skillName}`))\n installed++\n } catch (error) {\n console.log(pc.red(` ✗ ${skillName} - ${error}`))\n }\n }\n\n console.log(pc.dim(`\\nInstalled ${installed}/${toInstall.length} skills\\n`))\n\n if (installed > 0) {\n console.log(pc.cyan('Skills are now available in Claude Code!'))\n console.log(pc.dim('Claude will automatically use them when relevant,'))\n console.log(pc.dim('or you can invoke them directly with /skill-name\\n'))\n }\n })\n\nprogram\n .command('path')\n .description('Show the path to the skills directory')\n .action(() => {\n console.log(getSkillsDir())\n })\n\nprogram.parse()\n"],"mappings":"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"}
@@ -1,11 +1,12 @@
1
+ //#region src/index.d.ts
1
2
  interface SkillMetadata {
2
- name: string;
3
- description: string;
3
+ name: string;
4
+ description: string;
4
5
  }
5
6
  interface Skill extends SkillMetadata {
6
- slug: string;
7
- content: string;
8
- path: string;
7
+ slug: string;
8
+ content: string;
9
+ path: string;
9
10
  }
10
11
  /**
11
12
  * Get all available skills
@@ -23,5 +24,6 @@ declare function getSkillNames(): string[];
23
24
  * Get the path to skills directory
24
25
  */
25
26
  declare function getSkillsDir(): string;
26
-
27
- export { type Skill, type SkillMetadata, getAllSkills, getSkill, getSkillNames, getSkillsDir };
27
+ //#endregion
28
+ export { Skill, SkillMetadata, getAllSkills, getSkill, getSkillNames, getSkillsDir };
29
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";UAOiB,aAAA;EAAA,IAAA,EAAA,MAAA;EAKA,WAAM,EAAA,MAAQ;AAgC/B;AAiCgB,UAjEC,KAAA,SAAc,aAiEc,CAAA;EAmB7B,IAAA,EAAA,MAAA;EAcA,OAAA,EAAA,MAAY;;;;;;iBAlEZ,YAAA,CAAA,GAAgB;;;;iBAiChB,QAAA,gBAAwB;;;;iBAmBxB,aAAA,CAAA;;;;iBAcA,YAAA,CAAA"}
package/dist/index.mjs ADDED
@@ -0,0 +1,82 @@
1
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ //#region src/index.ts
6
+ const SKILLS_DIR = join(dirname(fileURLToPath(import.meta.url)), "..", "skills");
7
+ /**
8
+ * Parse SKILL.md frontmatter
9
+ */
10
+ function parseFrontmatter(content) {
11
+ const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
12
+ if (!match) return {
13
+ data: {},
14
+ content
15
+ };
16
+ const data = {};
17
+ const lines = match[1].split("\n");
18
+ for (const line of lines) {
19
+ const colonIndex = line.indexOf(":");
20
+ if (colonIndex > 0) {
21
+ const key = line.slice(0, colonIndex).trim();
22
+ data[key] = line.slice(colonIndex + 1).trim();
23
+ }
24
+ }
25
+ return {
26
+ data,
27
+ content: match[2]
28
+ };
29
+ }
30
+ /**
31
+ * Get all available skills
32
+ */
33
+ function getAllSkills() {
34
+ if (!existsSync(SKILLS_DIR)) return [];
35
+ const skillDirs = readdirSync(SKILLS_DIR, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
36
+ const skills = [];
37
+ for (const dir of skillDirs) {
38
+ const skillPath = join(SKILLS_DIR, dir, "SKILL.md");
39
+ if (!existsSync(skillPath)) continue;
40
+ const { data, content } = parseFrontmatter(readFileSync(skillPath, "utf-8"));
41
+ skills.push({
42
+ slug: dir,
43
+ name: data.name || dir,
44
+ description: data.description || "",
45
+ content,
46
+ path: skillPath
47
+ });
48
+ }
49
+ return skills;
50
+ }
51
+ /**
52
+ * Get a single skill by slug
53
+ */
54
+ function getSkill(slug) {
55
+ const skillPath = join(SKILLS_DIR, slug, "SKILL.md");
56
+ if (!existsSync(skillPath)) return null;
57
+ const { data, content } = parseFrontmatter(readFileSync(skillPath, "utf-8"));
58
+ return {
59
+ slug,
60
+ name: data.name || slug,
61
+ description: data.description || "",
62
+ content,
63
+ path: skillPath
64
+ };
65
+ }
66
+ /**
67
+ * Get skill names only (for listing)
68
+ */
69
+ function getSkillNames() {
70
+ if (!existsSync(SKILLS_DIR)) return [];
71
+ return readdirSync(SKILLS_DIR, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).filter((dirent) => existsSync(join(SKILLS_DIR, dirent.name, "SKILL.md"))).map((dirent) => dirent.name);
72
+ }
73
+ /**
74
+ * Get the path to skills directory
75
+ */
76
+ function getSkillsDir() {
77
+ return SKILLS_DIR;
78
+ }
79
+
80
+ //#endregion
81
+ export { getAllSkills, getSkill, getSkillNames, getSkillsDir };
82
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["data: Record<string, string>","skills: Skill[]"],"sources":["../src/index.ts"],"sourcesContent":["import { readFileSync, readdirSync, existsSync } from 'node:fs'\nimport { join, dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\nconst SKILLS_DIR = join(__dirname, '..', 'skills')\n\nexport interface SkillMetadata {\n name: string\n description: string\n}\n\nexport interface Skill extends SkillMetadata {\n slug: string\n content: string\n path: string\n}\n\n/**\n * Parse SKILL.md frontmatter\n */\nfunction parseFrontmatter(content: string): { data: Record<string, string>; content: string } {\n const match = content.match(/^---\\n([\\s\\S]*?)\\n---\\n([\\s\\S]*)$/)\n if (!match) {\n return { data: {}, content }\n }\n\n const data: Record<string, string> = {}\n const lines = match[1].split('\\n')\n for (const line of lines) {\n const colonIndex = line.indexOf(':')\n if (colonIndex > 0) {\n const key = line.slice(0, colonIndex).trim()\n const value = line.slice(colonIndex + 1).trim()\n data[key] = value\n }\n }\n\n return { data, content: match[2] }\n}\n\n/**\n * Get all available skills\n */\nexport function getAllSkills(): Skill[] {\n if (!existsSync(SKILLS_DIR)) {\n return []\n }\n\n const skillDirs = readdirSync(SKILLS_DIR, { withFileTypes: true })\n .filter(dirent => dirent.isDirectory())\n .map(dirent => dirent.name)\n\n const skills: Skill[] = []\n\n for (const dir of skillDirs) {\n const skillPath = join(SKILLS_DIR, dir, 'SKILL.md')\n if (!existsSync(skillPath)) continue\n\n const rawContent = readFileSync(skillPath, 'utf-8')\n const { data, content } = parseFrontmatter(rawContent)\n\n skills.push({\n slug: dir,\n name: data.name || dir,\n description: data.description || '',\n content,\n path: skillPath,\n })\n }\n\n return skills\n}\n\n/**\n * Get a single skill by slug\n */\nexport function getSkill(slug: string): Skill | null {\n const skillPath = join(SKILLS_DIR, slug, 'SKILL.md')\n if (!existsSync(skillPath)) return null\n\n const rawContent = readFileSync(skillPath, 'utf-8')\n const { data, content } = parseFrontmatter(rawContent)\n\n return {\n slug,\n name: data.name || slug,\n description: data.description || '',\n content,\n path: skillPath,\n }\n}\n\n/**\n * Get skill names only (for listing)\n */\nexport function getSkillNames(): string[] {\n if (!existsSync(SKILLS_DIR)) {\n return []\n }\n\n return readdirSync(SKILLS_DIR, { withFileTypes: true })\n .filter(dirent => dirent.isDirectory())\n .filter(dirent => existsSync(join(SKILLS_DIR, dirent.name, 'SKILL.md')))\n .map(dirent => dirent.name)\n}\n\n/**\n * Get the path to skills directory\n */\nexport function getSkillsDir(): string {\n return SKILLS_DIR\n}\n"],"mappings":";;;;;AAKA,MAAM,aAAa,KADD,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC,EACtB,MAAM,SAAS;;;;AAgBlD,SAAS,iBAAiB,SAAoE;CAC5F,MAAM,QAAQ,QAAQ,MAAM,oCAAoC;AAChE,KAAI,CAAC,MACH,QAAO;EAAE,MAAM,EAAE;EAAE;EAAS;CAG9B,MAAMA,OAA+B,EAAE;CACvC,MAAM,QAAQ,MAAM,GAAG,MAAM,KAAK;AAClC,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,aAAa,KAAK,QAAQ,IAAI;AACpC,MAAI,aAAa,GAAG;GAClB,MAAM,MAAM,KAAK,MAAM,GAAG,WAAW,CAAC,MAAM;AAE5C,QAAK,OADS,KAAK,MAAM,aAAa,EAAE,CAAC,MAAM;;;AAKnD,QAAO;EAAE;EAAM,SAAS,MAAM;EAAI;;;;;AAMpC,SAAgB,eAAwB;AACtC,KAAI,CAAC,WAAW,WAAW,CACzB,QAAO,EAAE;CAGX,MAAM,YAAY,YAAY,YAAY,EAAE,eAAe,MAAM,CAAC,CAC/D,QAAO,WAAU,OAAO,aAAa,CAAC,CACtC,KAAI,WAAU,OAAO,KAAK;CAE7B,MAAMC,SAAkB,EAAE;AAE1B,MAAK,MAAM,OAAO,WAAW;EAC3B,MAAM,YAAY,KAAK,YAAY,KAAK,WAAW;AACnD,MAAI,CAAC,WAAW,UAAU,CAAE;EAG5B,MAAM,EAAE,MAAM,YAAY,iBADP,aAAa,WAAW,QAAQ,CACG;AAEtD,SAAO,KAAK;GACV,MAAM;GACN,MAAM,KAAK,QAAQ;GACnB,aAAa,KAAK,eAAe;GACjC;GACA,MAAM;GACP,CAAC;;AAGJ,QAAO;;;;;AAMT,SAAgB,SAAS,MAA4B;CACnD,MAAM,YAAY,KAAK,YAAY,MAAM,WAAW;AACpD,KAAI,CAAC,WAAW,UAAU,CAAE,QAAO;CAGnC,MAAM,EAAE,MAAM,YAAY,iBADP,aAAa,WAAW,QAAQ,CACG;AAEtD,QAAO;EACL;EACA,MAAM,KAAK,QAAQ;EACnB,aAAa,KAAK,eAAe;EACjC;EACA,MAAM;EACP;;;;;AAMH,SAAgB,gBAA0B;AACxC,KAAI,CAAC,WAAW,WAAW,CACzB,QAAO,EAAE;AAGX,QAAO,YAAY,YAAY,EAAE,eAAe,MAAM,CAAC,CACpD,QAAO,WAAU,OAAO,aAAa,CAAC,CACtC,QAAO,WAAU,WAAW,KAAK,YAAY,OAAO,MAAM,WAAW,CAAC,CAAC,CACvE,KAAI,WAAU,OAAO,KAAK;;;;;AAM/B,SAAgB,eAAuB;AACrC,QAAO"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "recur-skills",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "Claude Code skills for Recur - Taiwan's subscription payment platform",
5
5
  "keywords": [
6
6
  "recur",
@@ -25,15 +25,15 @@
25
25
  "type": "module",
26
26
  "exports": {
27
27
  ".": {
28
- "import": "./dist/index.js",
29
- "types": "./dist/index.d.ts"
28
+ "import": "./dist/index.mjs",
29
+ "types": "./dist/index.d.mts"
30
30
  },
31
31
  "./skills/*": "./skills/*"
32
32
  },
33
- "main": "./dist/index.js",
34
- "types": "./dist/index.d.ts",
33
+ "main": "./dist/index.mjs",
34
+ "types": "./dist/index.d.mts",
35
35
  "bin": {
36
- "recur-skills": "./dist/cli.js"
36
+ "recur-skills": "./dist/cli.mjs"
37
37
  },
38
38
  "files": [
39
39
  "dist",
@@ -41,12 +41,12 @@
41
41
  ".claude-plugin"
42
42
  ],
43
43
  "scripts": {
44
- "build": "tsup",
45
- "dev": "tsup --watch",
44
+ "build": "tsdown",
45
+ "dev": "tsdown --watch",
46
46
  "lint": "eslint src/",
47
47
  "typecheck": "tsc --noEmit",
48
48
  "prepublishOnly": "pnpm build",
49
- "version": "node scripts/sync-version.js && git add .claude-plugin/marketplace.json"
49
+ "version": "node scripts/sync-version.js && git add .claude-plugin/marketplace.json skills/*/SKILL.md"
50
50
  },
51
51
  "dependencies": {
52
52
  "commander": "^12.1.0",
@@ -54,7 +54,7 @@
54
54
  },
55
55
  "devDependencies": {
56
56
  "@types/node": "^22.0.0",
57
- "tsup": "^8.3.5",
57
+ "tsdown": "^0.18.4",
58
58
  "typescript": "^5.7.3"
59
59
  },
60
60
  "engines": {
@@ -1,6 +1,10 @@
1
1
  ---
2
2
  name: recur-checkout
3
3
  description: Implement Recur checkout flows including embedded, modal, and redirect modes. Use when adding payment buttons, checkout forms, subscription purchase flows, or when user mentions "checkout", "結帳", "付款按鈕", "embedded checkout".
4
+ license: MIT
5
+ metadata:
6
+ author: recur
7
+ version: "0.0.5"
4
8
  ---
5
9
 
6
10
  # Recur Checkout Integration
@@ -1,6 +1,10 @@
1
1
  ---
2
2
  name: recur-entitlements
3
3
  description: Implement access control and permission checking with Recur entitlements API. Use when building paywalls, checking subscription status, gating premium features, or when user mentions "paywall", "權限檢查", "entitlements", "access control", "premium features".
4
+ license: MIT
5
+ metadata:
6
+ author: recur
7
+ version: "0.0.5"
4
8
  ---
5
9
 
6
10
  # Recur Entitlements & Access Control
@@ -1,6 +1,10 @@
1
1
  ---
2
2
  name: recur-help
3
3
  description: List all available Recur skills and how to use them. Use when user asks "what can Recur do", "Recur skills", "Recur 有什麼功能", "help with Recur", "如何使用 Recur skills".
4
+ license: MIT
5
+ metadata:
6
+ author: recur
7
+ version: "0.0.5"
4
8
  ---
5
9
 
6
10
  # Recur Skills 使用指南
@@ -1,6 +1,10 @@
1
1
  ---
2
2
  name: recur-quickstart
3
3
  description: Quick setup guide for Recur payment integration. Use when starting a new Recur integration, setting up API keys, installing the SDK, or when user mentions "integrate Recur", "setup Recur", "Recur 串接", "金流設定".
4
+ license: MIT
5
+ metadata:
6
+ author: recur
7
+ version: "0.0.5"
4
8
  ---
5
9
 
6
10
  # Recur Quickstart
@@ -1,6 +1,10 @@
1
1
  ---
2
2
  name: recur-webhooks
3
3
  description: Set up and handle Recur webhook events for payment notifications. Use when implementing webhook handlers, verifying signatures, handling subscription events, or when user mentions "webhook", "付款通知", "訂閱事件", "payment notification".
4
+ license: MIT
5
+ metadata:
6
+ author: recur
7
+ version: "0.0.5"
4
8
  ---
5
9
 
6
10
  # Recur Webhook Integration
package/dist/cli.js DELETED
@@ -1,163 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/cli.ts
4
- import { program } from "commander";
5
- import pc from "picocolors";
6
- import { existsSync as existsSync2, mkdirSync, cpSync, readdirSync as readdirSync2 } from "fs";
7
- import { join as join2, dirname as dirname2 } from "path";
8
- import { fileURLToPath as fileURLToPath2 } from "url";
9
-
10
- // src/index.ts
11
- import { readFileSync, readdirSync, existsSync } from "fs";
12
- import { join, dirname } from "path";
13
- import { fileURLToPath } from "url";
14
- var __dirname = dirname(fileURLToPath(import.meta.url));
15
- var SKILLS_DIR = join(__dirname, "..", "skills");
16
- function parseFrontmatter(content) {
17
- const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
18
- if (!match) {
19
- return { data: {}, content };
20
- }
21
- const data = {};
22
- const lines = match[1].split("\n");
23
- for (const line of lines) {
24
- const colonIndex = line.indexOf(":");
25
- if (colonIndex > 0) {
26
- const key = line.slice(0, colonIndex).trim();
27
- const value = line.slice(colonIndex + 1).trim();
28
- data[key] = value;
29
- }
30
- }
31
- return { data, content: match[2] };
32
- }
33
- function getAllSkills() {
34
- if (!existsSync(SKILLS_DIR)) {
35
- return [];
36
- }
37
- const skillDirs = readdirSync(SKILLS_DIR, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
38
- const skills = [];
39
- for (const dir of skillDirs) {
40
- const skillPath = join(SKILLS_DIR, dir, "SKILL.md");
41
- if (!existsSync(skillPath)) continue;
42
- const rawContent = readFileSync(skillPath, "utf-8");
43
- const { data, content } = parseFrontmatter(rawContent);
44
- skills.push({
45
- slug: dir,
46
- name: data.name || dir,
47
- description: data.description || "",
48
- content,
49
- path: skillPath
50
- });
51
- }
52
- return skills;
53
- }
54
- function getSkill(slug) {
55
- const skillPath = join(SKILLS_DIR, slug, "SKILL.md");
56
- if (!existsSync(skillPath)) return null;
57
- const rawContent = readFileSync(skillPath, "utf-8");
58
- const { data, content } = parseFrontmatter(rawContent);
59
- return {
60
- slug,
61
- name: data.name || slug,
62
- description: data.description || "",
63
- content,
64
- path: skillPath
65
- };
66
- }
67
- function getSkillsDir() {
68
- return SKILLS_DIR;
69
- }
70
-
71
- // src/cli.ts
72
- var __dirname2 = dirname2(fileURLToPath2(import.meta.url));
73
- var SKILLS_SOURCE = join2(__dirname2, "..", "skills");
74
- program.name("recur-skills").description("Claude Code skills for Recur payment integration").version("0.0.1");
75
- program.command("list").description("List all available skills").action(() => {
76
- const skills = getAllSkills();
77
- if (skills.length === 0) {
78
- console.log(pc.yellow("No skills found."));
79
- return;
80
- }
81
- console.log(pc.bold("\n\u{1F4E6} Available Recur Skills\n"));
82
- for (const skill of skills) {
83
- console.log(pc.cyan(` ${skill.name}`));
84
- console.log(pc.dim(` ${skill.description}
85
- `));
86
- }
87
- console.log(pc.dim(`Total: ${skills.length} skills
88
- `));
89
- });
90
- program.command("info <skill>").description("Show detailed information about a skill").action((skillName) => {
91
- const skill = getSkill(skillName);
92
- if (!skill) {
93
- console.log(pc.red(`Skill "${skillName}" not found.`));
94
- console.log(pc.dim("\nRun `recur-skills list` to see available skills."));
95
- process.exit(1);
96
- }
97
- console.log(pc.bold(`
98
- \u{1F4E6} ${skill.name}
99
- `));
100
- console.log(pc.dim("Description:"));
101
- console.log(` ${skill.description}
102
- `);
103
- console.log(pc.dim("Path:"));
104
- console.log(` ${skill.path}
105
- `);
106
- });
107
- program.command("install [skills...]").description("Install skills to your Claude Code skills directory").option("-g, --global", "Install to global ~/.claude/skills/", false).option("-p, --project", "Install to project .claude/skills/", false).option("-a, --all", "Install all skills", false).action((skillNames, options) => {
108
- let targetDir;
109
- if (options.global) {
110
- targetDir = join2(process.env.HOME || "~", ".claude", "skills");
111
- } else if (options.project) {
112
- targetDir = join2(process.cwd(), ".claude", "skills");
113
- } else {
114
- targetDir = join2(process.env.HOME || "~", ".claude", "skills");
115
- }
116
- let toInstall;
117
- if (options.all) {
118
- toInstall = readdirSync2(SKILLS_SOURCE, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
119
- } else if (skillNames.length === 0) {
120
- console.log(pc.yellow("Please specify skills to install or use --all"));
121
- console.log(pc.dim("\nExamples:"));
122
- console.log(pc.dim(" recur-skills install recur-quickstart"));
123
- console.log(pc.dim(" recur-skills install recur-checkout recur-webhooks"));
124
- console.log(pc.dim(" recur-skills install --all"));
125
- process.exit(1);
126
- } else {
127
- toInstall = skillNames;
128
- }
129
- if (!existsSync2(targetDir)) {
130
- mkdirSync(targetDir, { recursive: true });
131
- }
132
- console.log(pc.bold(`
133
- \u{1F4E6} Installing skills to ${targetDir}
134
- `));
135
- let installed = 0;
136
- for (const skillName of toInstall) {
137
- const sourcePath = join2(SKILLS_SOURCE, skillName);
138
- const destPath = join2(targetDir, skillName);
139
- if (!existsSync2(sourcePath)) {
140
- console.log(pc.red(` \u2717 ${skillName} - not found`));
141
- continue;
142
- }
143
- try {
144
- cpSync(sourcePath, destPath, { recursive: true });
145
- console.log(pc.green(` \u2713 ${skillName}`));
146
- installed++;
147
- } catch (error) {
148
- console.log(pc.red(` \u2717 ${skillName} - ${error}`));
149
- }
150
- }
151
- console.log(pc.dim(`
152
- Installed ${installed}/${toInstall.length} skills
153
- `));
154
- if (installed > 0) {
155
- console.log(pc.cyan("Skills are now available in Claude Code!"));
156
- console.log(pc.dim("Claude will automatically use them when relevant,"));
157
- console.log(pc.dim("or you can invoke them directly with /skill-name\n"));
158
- }
159
- });
160
- program.command("path").description("Show the path to the skills directory").action(() => {
161
- console.log(getSkillsDir());
162
- });
163
- program.parse();
package/dist/index.js DELETED
@@ -1,72 +0,0 @@
1
- // src/index.ts
2
- import { readFileSync, readdirSync, existsSync } from "fs";
3
- import { join, dirname } from "path";
4
- import { fileURLToPath } from "url";
5
- var __dirname = dirname(fileURLToPath(import.meta.url));
6
- var SKILLS_DIR = join(__dirname, "..", "skills");
7
- function parseFrontmatter(content) {
8
- const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
9
- if (!match) {
10
- return { data: {}, content };
11
- }
12
- const data = {};
13
- const lines = match[1].split("\n");
14
- for (const line of lines) {
15
- const colonIndex = line.indexOf(":");
16
- if (colonIndex > 0) {
17
- const key = line.slice(0, colonIndex).trim();
18
- const value = line.slice(colonIndex + 1).trim();
19
- data[key] = value;
20
- }
21
- }
22
- return { data, content: match[2] };
23
- }
24
- function getAllSkills() {
25
- if (!existsSync(SKILLS_DIR)) {
26
- return [];
27
- }
28
- const skillDirs = readdirSync(SKILLS_DIR, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
29
- const skills = [];
30
- for (const dir of skillDirs) {
31
- const skillPath = join(SKILLS_DIR, dir, "SKILL.md");
32
- if (!existsSync(skillPath)) continue;
33
- const rawContent = readFileSync(skillPath, "utf-8");
34
- const { data, content } = parseFrontmatter(rawContent);
35
- skills.push({
36
- slug: dir,
37
- name: data.name || dir,
38
- description: data.description || "",
39
- content,
40
- path: skillPath
41
- });
42
- }
43
- return skills;
44
- }
45
- function getSkill(slug) {
46
- const skillPath = join(SKILLS_DIR, slug, "SKILL.md");
47
- if (!existsSync(skillPath)) return null;
48
- const rawContent = readFileSync(skillPath, "utf-8");
49
- const { data, content } = parseFrontmatter(rawContent);
50
- return {
51
- slug,
52
- name: data.name || slug,
53
- description: data.description || "",
54
- content,
55
- path: skillPath
56
- };
57
- }
58
- function getSkillNames() {
59
- if (!existsSync(SKILLS_DIR)) {
60
- return [];
61
- }
62
- return readdirSync(SKILLS_DIR, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).filter((dirent) => existsSync(join(SKILLS_DIR, dirent.name, "SKILL.md"))).map((dirent) => dirent.name);
63
- }
64
- function getSkillsDir() {
65
- return SKILLS_DIR;
66
- }
67
- export {
68
- getAllSkills,
69
- getSkill,
70
- getSkillNames,
71
- getSkillsDir
72
- };