Skip to content

Commit f02f942

Browse files
fix: use python3 for correctness checks and add CI (#50)
The benchmark harness hardcoded `python`, which is missing on macOS and many Linux images. Probe python3 first, add npm test, and run checks in GitHub Actions so regressions are caught on every PR. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 2302fbc commit f02f942

4 files changed

Lines changed: 51 additions & 2 deletions

File tree

‎.github/workflows/test.yml‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: test
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
8+
jobs:
9+
test:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
14+
- uses: actions/setup-node@v4
15+
with:
16+
node-version: '22'
17+
18+
- uses: actions/setup-python@v5
19+
with:
20+
python-version: '3.12'
21+
22+
- name: Install Python deps for correctness checks
23+
run: pip install pandas
24+
25+
- name: Check rule copies
26+
run: node scripts/check-rule-copies.js
27+
28+
- name: Run tests
29+
run: npm test

‎README.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,11 @@ When changing the compact rule text, keep the agent copies aligned:
165165

166166
```bash
167167
node scripts/check-rule-copies.js
168+
npm test
168169
```
169170

171+
The correctness benchmark spawns Python for email and CSV checks; `python3` is tried before `python`. CSV checks need `pandas` installed locally.
172+
170173
## FAQ
171174

172175
**Does it need a config file?**

‎benchmarks/correctness.js‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,20 @@ function exec(cmd, opts = {}) {
3838
}
3939
}
4040

41+
// ponytail: probe once at load; macOS and many Linux images ship python3 only.
42+
let pythonCmd;
43+
function python() {
44+
if (pythonCmd) return pythonCmd;
45+
for (const cmd of ['python3', 'python']) {
46+
if (exec(`${cmd} -c "import sys"`).ok) {
47+
pythonCmd = cmd;
48+
return pythonCmd;
49+
}
50+
}
51+
pythonCmd = 'python3';
52+
return pythonCmd;
53+
}
54+
4155
// Write content to a temp file, return the path.
4256
function tmpFile(ext, content) {
4357
const p = path.join(os.tmpdir(), `ponytail-bench-${Date.now()}-${Math.random().toString(36).slice(2)}${ext}`);
@@ -100,7 +114,7 @@ if failures:
100114
print("PASS")
101115
`;
102116
const f = tmpFile('.py', harness);
103-
const result = exec(`python "${f}"`);
117+
const result = exec(`${python()} "${f}"`);
104118
fs.unlinkSync(f);
105119
if (result.ok) return { pass: true, reason: 'Email validator passes all checks' };
106120
return { pass: false, reason: result.stderr || 'Email validator failed' };
@@ -194,7 +208,7 @@ else:
194208
sys.exit(1)
195209
`;
196210
const f = tmpFile('.py', harness);
197-
const result = exec(`python "${f}"`);
211+
const result = exec(`${python()} "${f}"`);
198212
try { fs.unlinkSync(f); } catch (e) {}
199213
try { fs.unlinkSync(csvPath); } catch (e) {}
200214
if (result.ok) return { pass: true, reason: 'CSV sum produces correct result (351)' };

‎package.json‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
"description": "Lazy senior dev mode for AI agents. The best code is the code you never wrote.",
55
"keywords": ["pi-package", "pi", "skills", "ponytail"],
66
"license": "MIT",
7+
"scripts": {
8+
"test": "node --test tests/*.test.js && npm test --prefix pi-extension"
9+
},
710
"pi": {
811
"extensions": ["./pi-extension/index.js"],
912
"skills": ["./skills"]

0 commit comments

Comments
 (0)