Skip to content

Commit a0c8515

Browse files
chore(ci): add vet stop hook and isolate Playwright e2e
Run bun vet on agent stop with follow-up when it fails. Pin devalue and ws for clean audit, and serve e2e from a dedicated preview port so astro dev on 4321 cannot skew results. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent cada961 commit a0c8515

6 files changed

Lines changed: 104 additions & 12 deletions

File tree

.changeset/cursor-vet-stop-hook.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'pendragon-coding': patch
3+
---
4+
5+
Add Cursor `stop` hook that runs `bun vet` and reopens the agent with fix instructions when the quality gate fails (up to 3 follow-up loops, 15 min timeout). Pin `devalue` and `ws` via overrides so `bun audit` passes. Run Playwright e2e on port 3456 against a fresh preview build so vet does not collide with `astro dev` on 4321.

.cursor/hooks.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"version": 1,
3+
"hooks": {
4+
"stop": [
5+
{
6+
"command": "bun run .cursor/hooks/vet-stop.ts",
7+
"timeout": 900,
8+
"loop_limit": 3
9+
}
10+
]
11+
}
12+
}

.cursor/hooks/vet-stop.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/// <reference types="bun-types-no-globals/lib/index.d.ts" />
2+
3+
import { stdin } from 'bun';
4+
5+
const MAX_OUTPUT_CHARS = 8000;
6+
7+
interface StopHookInput {
8+
status: string;
9+
loop_count: number;
10+
}
11+
12+
async function main(): Promise<number> {
13+
try {
14+
const input = JSON.parse(await stdin.text()) as StopHookInput;
15+
16+
if (input.status !== 'completed') {
17+
console.log(JSON.stringify({}));
18+
return 0;
19+
}
20+
21+
const proc = Bun.spawn(['bun', 'vet'], {
22+
stdout: 'pipe',
23+
stderr: 'pipe',
24+
});
25+
26+
const [stdout, stderr, exitCode] = await Promise.all([
27+
new Response(proc.stdout).text(),
28+
new Response(proc.stderr).text(),
29+
proc.exited,
30+
]);
31+
32+
if (exitCode === 0) {
33+
console.log(JSON.stringify({}));
34+
return 0;
35+
}
36+
37+
const combined = [stdout, stderr]
38+
.filter((chunk) => chunk.length > 0)
39+
.join('\n')
40+
.trim();
41+
const output =
42+
combined.length > MAX_OUTPUT_CHARS
43+
? combined.slice(-MAX_OUTPUT_CHARS)
44+
: combined;
45+
46+
console.log(
47+
JSON.stringify({
48+
followup_message: [
49+
'Quality gate failed: `bun vet` must exit 0 before this session can end.',
50+
'Fix every error and warning, then run `bun vet` again.',
51+
output.length > 0 ? `\n\`\`\`\n${output}\n\`\`\`` : '',
52+
].join(' '),
53+
}),
54+
);
55+
return 0;
56+
} catch (error) {
57+
console.error('[vet-stop] failed', error);
58+
console.log(
59+
JSON.stringify({
60+
followup_message:
61+
'Quality gate error: the vet stop hook crashed. Run `bun vet` manually, fix failures, and retry.',
62+
}),
63+
);
64+
return 0;
65+
}
66+
}
67+
68+
const exitCode = await main();
69+
process.exit(exitCode);

bun.lock

Lines changed: 8 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@
3434
"@happy-dom/global-registrator": "^20.9.0",
3535
"@playwright/test": "^1.60.0",
3636
"@types/bun": "^1.3.14",
37-
"@typescript/native-preview": "^7.0.0-dev.20260514.1",
38-
"astro": "^6.3.3",
39-
"caniuse-lite": "^1.0.30001792",
37+
"@typescript/native-preview": "^7.0.0-dev.20260519.1",
38+
"astro": "^6.3.6",
39+
"caniuse-lite": "^1.0.30001793",
4040
"happy-dom": "^20.9.0",
4141
"oxfmt": "0.43.0",
4242
"oxlint": "1.58.0",
@@ -46,13 +46,15 @@
4646
"overrides": {
4747
"ajv": ">=8.20.0",
4848
"defu": ">=6.1.5",
49+
"devalue": ">=5.8.1",
4950
"fast-uri": ">=3.1.2",
5051
"js-yaml": ">=3.14.2",
5152
"mdast-util-to-hast": ">=13.2.1",
5253
"picomatch": ">=4.0.4",
5354
"postcss": ">=8.5.10",
5455
"rollup": ">=4.59.0",
5556
"svgo": ">=4.0.1",
57+
"ws": ">=8.20.1",
5658
"yaml": ">=2.8.3"
5759
},
5860
"engines": {

playwright.config.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { defineConfig } from '@playwright/test';
22

3-
const baseURL = 'http://localhost:4321';
3+
const port = Number(process.env.PLAYWRIGHT_PORT ?? 3456);
4+
const baseURL = `http://localhost:${port}`;
5+
46
export default defineConfig({
57
testDir: 'src/e2e',
68
testMatch: '**/*.spec.ts',
@@ -10,8 +12,8 @@ export default defineConfig({
1012
},
1113
reporter: [['html', { open: 'never' }], ['list']],
1214
webServer: {
13-
command: 'bun run build && bun run preview',
15+
command: `bun run build && bunx astro preview --port ${port}`,
1416
url: baseURL,
15-
reuseExistingServer: !process.env.CI,
17+
reuseExistingServer: false,
1618
},
1719
});

0 commit comments

Comments
 (0)