Skip to content

Commit 40ec95e

Browse files
authored
action: add skill script build action (#4)
* docs: update reademe add git env required * action: add skill script build action * action: add skill script build action
1 parent b72e0ed commit 40ec95e

4 files changed

Lines changed: 166 additions & 8 deletions

File tree

.github/scripts/build-skills.mjs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#!/usr/bin/env node
2+
3+
import fs from 'node:fs';
4+
import path from 'node:path';
5+
import { spawnSync } from 'node:child_process';
6+
7+
const repoRoot = process.cwd();
8+
const pluginsDir = path.join(repoRoot, 'plugins');
9+
10+
const errors = [];
11+
const builtScripts = [];
12+
13+
function walk(dir) {
14+
const entries = fs.readdirSync(dir, { withFileTypes: true });
15+
for (const e of entries) {
16+
if (e.name === 'node_modules' || e.name === '.git') continue;
17+
const full = path.join(dir, e.name);
18+
if (e.isDirectory()) walk(full);
19+
else if (e.isFile() && e.name === 'SKILL.md') buildSkillScripts(full);
20+
}
21+
}
22+
23+
function parseFrontmatter(md) {
24+
const lines = md.split(/\r?\n/);
25+
if (lines[0] !== '---') return null;
26+
27+
let end = -1;
28+
for (let i = 1; i < lines.length; i++) {
29+
if (lines[i] === '---') {
30+
end = i;
31+
break;
32+
}
33+
}
34+
if (end === -1) return null;
35+
36+
const fm = {};
37+
for (const l of lines.slice(1, end)) {
38+
const idx = l.indexOf(':');
39+
if (idx === -1) continue;
40+
const key = l.slice(0, idx).trim();
41+
const val = l.slice(idx + 1).trim();
42+
fm[key] = val;
43+
}
44+
45+
const body = lines.slice(end + 1).join('\n');
46+
return { frontmatter: fm, body };
47+
}
48+
49+
function buildSkillScripts(skillMdPath) {
50+
const rel = path.relative(repoRoot, skillMdPath);
51+
const content = fs.readFileSync(skillMdPath, 'utf8');
52+
53+
const parsed = parseFrontmatter(content);
54+
if (!parsed) {
55+
errors.push(`${rel}: missing or invalid frontmatter (expected '---' block)`);
56+
return;
57+
}
58+
59+
const { body } = parsed;
60+
const skillDir = path.dirname(skillMdPath);
61+
62+
const scriptRefs = new Set();
63+
const re = /\bnode\s+scripts\/([^\s"'`]+)\b/g;
64+
let m;
65+
while ((m = re.exec(body)) !== null) {
66+
scriptRefs.add(m[1]);
67+
}
68+
69+
for (const scriptRel of scriptRefs) {
70+
const scriptPath = path.join(skillDir, 'scripts', scriptRel);
71+
const scriptRepoRel = path.relative(repoRoot, scriptPath);
72+
73+
if (!fs.existsSync(scriptPath) || !fs.statSync(scriptPath).isFile()) {
74+
errors.push(`${rel}: referenced script missing: ${scriptRepoRel}`);
75+
continue;
76+
}
77+
78+
// Check if it's a JavaScript file (.js, .mjs)
79+
if (!scriptRel.match(/\.(js|mjs)$/)) {
80+
console.log(`Skipping non-JS script: ${scriptRepoRel}`);
81+
continue;
82+
}
83+
84+
// Build/compile the JavaScript script
85+
console.log(`Building script: ${scriptRepoRel}`);
86+
87+
// Use node --check first for syntax validation
88+
const checkResult = spawnSync(process.execPath, ['--check', scriptPath], {
89+
encoding: 'utf8',
90+
stdio: 'pipe'
91+
});
92+
93+
if (checkResult.status !== 0) {
94+
const out = (checkResult.stderr || checkResult.stdout || '').trim();
95+
errors.push(`${scriptRepoRel}: syntax check failed${out ? `\n${out}` : ''}`);
96+
continue;
97+
}
98+
99+
// For ES modules (.mjs), we can try to load them to ensure they work
100+
if (scriptRel.endsWith('.mjs')) {
101+
// For .mjs files, just ensure they pass syntax check
102+
// Loading them dynamically might cause side effects during build
103+
builtScripts.push(scriptRepoRel);
104+
} else {
105+
// For .js files, just ensure they can be parsed
106+
builtScripts.push(scriptRepoRel);
107+
}
108+
}
109+
}
110+
111+
if (!fs.existsSync(pluginsDir) || !fs.statSync(pluginsDir).isDirectory()) {
112+
console.error(`Skill build failed:\n- plugins directory not found at ${path.relative(repoRoot, pluginsDir)}`);
113+
process.exit(1);
114+
}
115+
116+
walk(pluginsDir);
117+
118+
if (errors.length) {
119+
console.error('Skill build failed:');
120+
for (const e of errors) console.error(`- ${e}`);
121+
process.exit(1);
122+
}
123+
124+
if (builtScripts.length) {
125+
console.log(`Successfully built ${builtScripts.length} script(s):`);
126+
for (const script of builtScripts) {
127+
console.log(`- ${script}`);
128+
}
129+
} else {
130+
console.log('No JavaScript scripts found to build.');
131+
}
132+
133+
console.log('Skill build completed.');

.github/workflows/build.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Build Skills
2+
on:
3+
pull_request:
4+
branches:
5+
- main
6+
push:
7+
branches:
8+
- 'action*'
9+
workflow_call:
10+
11+
jobs:
12+
skills-build:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
17+
- name: Set up Node.js 18
18+
uses: actions/setup-node@v4
19+
with:
20+
node-version: 18
21+
22+
- name: Build skill scripts
23+
shell: bash
24+
run: |
25+
node .github/scripts/build-skills.mjs

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ A collection of plugins to enhance coding productivity and provide GLM Coding Pl
66

77
## Available Plugins
88

9-
| Plugin | Description |
10-
|--------|--------------------------------------------------------|
11-
| **glm-plan-usage** | Query quota and usage statistics for GLM Coding Plan |
12-
| **glm-plan-bug** | Submit case feedback and bug reports for GLM Coding Plan |
9+
| Plugin | Description |
10+
|----------------------|-----------------------------------------------------------------------|
11+
| **glm-plan-usage** | Query quota and usage statistics for GLM Coding Plan |
12+
| **glm-plan-bug** | Submit case feedback and bug reports for GLM Coding Plan |
1313

1414
## Prerequisites
1515

README_CN.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ Claude Code 插件集合,旨在提升编程效率和提供 GLM Coding Plan 相
66

77
## 可用插件
88

9-
| 插件 | 描述 |
10-
|------|------|
11-
| **glm-plan-usage** | 查询 GLM Coding Plan 的配额和使用统计 |
12-
| **glm-plan-bug** | 提交 GLM Coding Plan 的反馈和问题报告 |
9+
| 插件 | 描述 |
10+
|---------------------|------------------------------------|
11+
| **glm-plan-usage** | 查询 GLM Coding Plan 的配额和使用统计 |
12+
| **glm-plan-bug** | 提交 GLM Coding Plan 的反馈和问题报告 |
1313

1414
## 前置要求
1515

0 commit comments

Comments
 (0)