@erclx/aitk 0.96.0 → 0.97.0
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.
- package/claude/.claude-plugin/plugin.json +1 -1
- package/governance/rules/ui/440-surface-capture.md +26 -0
- package/governance/stacks/astro.toml +1 -1
- package/governance/stacks/react.toml +1 -1
- package/package.json +1 -1
- package/tooling/base/reference.md +2 -0
- package/tooling/web/configs/e2e/screenshot.ts +36 -24
- package/tooling/web/reference.md +4 -2
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Require a route capture against a running preview after a page or route surface changes
|
|
3
|
+
paths:
|
|
4
|
+
- '**/routes/**/*.{tsx,jsx,vue,svelte,astro}'
|
|
5
|
+
- '**/pages/**/*.{tsx,jsx,vue,svelte,astro}'
|
|
6
|
+
- '**/app/**/page.{tsx,jsx}'
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Surface capture standards
|
|
10
|
+
|
|
11
|
+
## When to capture
|
|
12
|
+
|
|
13
|
+
- Run `bun run screenshot` after changing what a route renders.
|
|
14
|
+
- Capture against a running preview server. Do not capture against a dev server.
|
|
15
|
+
- Capture every theme the route ships. Do not capture the default theme alone.
|
|
16
|
+
|
|
17
|
+
## What a capture covers
|
|
18
|
+
|
|
19
|
+
- Capture the full page at the viewport its case declares. Do not capture a component in isolation.
|
|
20
|
+
- Add a case to the capture record when adding a route.
|
|
21
|
+
- Remove a route's case in the change that removes the route.
|
|
22
|
+
|
|
23
|
+
## Sharing a capture
|
|
24
|
+
|
|
25
|
+
- Attach a capture to the pull request by hand when a reviewer needs to see it.
|
|
26
|
+
- Do not commit a capture. Do not remove the capture folder from `.gitignore`.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
extends = "node"
|
|
2
|
-
rules = ["210-astro", "350-security-web", "400-ui", "410-a11y", "430-ux-completeness"]
|
|
2
|
+
rules = ["210-astro", "350-security-web", "400-ui", "410-a11y", "430-ux-completeness", "440-surface-capture"]
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
extends = "node"
|
|
2
|
-
rules = ["200-react", "230-nextjs", "250-tailwind", "300-testing-ts", "310-zod", "350-security-web", "400-ui", "410-a11y", "420-forms", "430-ux-completeness"]
|
|
2
|
+
rules = ["200-react", "230-nextjs", "250-tailwind", "300-testing-ts", "310-zod", "350-security-web", "400-ui", "410-a11y", "420-forms", "430-ux-completeness", "440-surface-capture"]
|
package/package.json
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
The base layer covers every project the toolkit scaffolds, whatever language sits on top. It ships formatting, spelling, shell linting, conventional commits, git hooks, CI, and three maintenance scripts. Every other stack extends it, so a decision made here is one every stack inherits.
|
|
6
6
|
|
|
7
|
+
A repository with several language roots layers this stack once at the root and skips it per subtree, since git honors only one `core.hooksPath` and a re-dropped husky silently breaks. `docs/target-projects.md` carries the recipe.
|
|
8
|
+
|
|
7
9
|
## What ships as golden configs
|
|
8
10
|
|
|
9
11
|
Golden config files live in `tooling/base/configs/` and are copied into the target on `aitk tooling sync base .`. They are the source of truth. The reference covers rationale and tradeoffs. Configs show the concrete setup.
|
|
@@ -1,41 +1,53 @@
|
|
|
1
1
|
import type { Page } from '@playwright/test'
|
|
2
|
-
|
|
3
|
-
const ROUTES = [{ name: 'home', path: '/', width: 1280, height: 800 }]
|
|
4
|
-
|
|
5
|
-
type State = { name: string; setup?: (page: Page) => Promise<void> }
|
|
6
|
-
const STATES: State[] = [
|
|
7
|
-
{ name: 'default' },
|
|
8
|
-
{ name: 'dark', setup: async (p) => p.emulateMedia({ colorScheme: 'dark' }) },
|
|
9
|
-
]
|
|
10
|
-
|
|
11
2
|
import { chromium } from '@playwright/test'
|
|
12
3
|
import { mkdir } from 'fs/promises'
|
|
13
4
|
import path from 'path'
|
|
14
5
|
|
|
6
|
+
interface CaptureCase {
|
|
7
|
+
section: string
|
|
8
|
+
theme: string
|
|
9
|
+
route: string
|
|
10
|
+
width: number
|
|
11
|
+
height: number
|
|
12
|
+
setup?: (page: Page) => Promise<void>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const CASES: CaptureCase[] = [
|
|
16
|
+
{ section: 'home', theme: 'default', route: '/', width: 1280, height: 800 },
|
|
17
|
+
{
|
|
18
|
+
section: 'home',
|
|
19
|
+
theme: 'dark',
|
|
20
|
+
route: '/',
|
|
21
|
+
width: 1280,
|
|
22
|
+
height: 800,
|
|
23
|
+
setup: (page) => page.emulateMedia({ colorScheme: 'dark' }),
|
|
24
|
+
},
|
|
25
|
+
]
|
|
26
|
+
|
|
15
27
|
const BASE_URL = process.env.SCREENSHOT_BASE_URL ?? 'http://localhost:4173'
|
|
16
28
|
const OUT_DIR = 'screenshots'
|
|
17
29
|
|
|
18
30
|
const browser = await chromium.launch()
|
|
19
|
-
await mkdir(OUT_DIR, { recursive: true })
|
|
20
31
|
|
|
21
|
-
for (const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
32
|
+
for (const captureCase of CASES) {
|
|
33
|
+
const context = await browser.newContext({
|
|
34
|
+
viewport: { width: captureCase.width, height: captureCase.height },
|
|
35
|
+
})
|
|
36
|
+
const page = await context.newPage()
|
|
37
|
+
|
|
38
|
+
if (captureCase.setup) await captureCase.setup(page)
|
|
27
39
|
|
|
28
|
-
|
|
40
|
+
await page.goto(`${BASE_URL}${captureCase.route}`)
|
|
41
|
+
await page.waitForLoadState('networkidle')
|
|
29
42
|
|
|
30
|
-
|
|
31
|
-
|
|
43
|
+
const sectionDir = path.join(OUT_DIR, captureCase.section)
|
|
44
|
+
await mkdir(sectionDir, { recursive: true })
|
|
32
45
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
46
|
+
const file = path.join(sectionDir, `${captureCase.theme}.png`)
|
|
47
|
+
await page.screenshot({ path: file, fullPage: true })
|
|
48
|
+
console.log(`captured ${file}`)
|
|
36
49
|
|
|
37
|
-
|
|
38
|
-
}
|
|
50
|
+
await context.close()
|
|
39
51
|
}
|
|
40
52
|
|
|
41
53
|
await browser.close()
|
package/tooling/web/reference.md
CHANGED
|
@@ -12,7 +12,7 @@ Golden config files live in `tooling/web/configs/` and are copied into the targe
|
|
|
12
12
|
|
|
13
13
|
- `eslint.config.js`: flat config with `@eslint/js`, `typescript-eslint`, React hooks, import sort, check-file, vitest rules scoped to test files, `eslint-config-prettier` last.
|
|
14
14
|
- `src/test/setup.ts`: `@testing-library/jest-dom` import, `cleanup` after each test.
|
|
15
|
-
- `e2e/screenshot.ts`: capture template.
|
|
15
|
+
- `e2e/screenshot.ts`: capture template. A single `CASES` record at the top carries one entry per output file, each naming a section, a theme, a route, and its own viewport, and the loop below writes `screenshots/<section>/<theme>.png`. Per-project cases extend the one record. A route's themes sit together under its section folder, so the filename carries the theme alone.
|
|
16
16
|
- `.vscode/extensions.json` and `.vscode/settings.json`: editor wiring for ESLint, Tailwind, Playwright, Vitest.
|
|
17
17
|
- `.github/workflows/verify.yml`: `static-checks`, `unit-tests`, `build-verify`, and `e2e-tests` jobs.
|
|
18
18
|
- `scripts/verify.sh`: extends base verify with typecheck, lint, unit tests, and build in the full order.
|
|
@@ -102,7 +102,9 @@ Append rows:
|
|
|
102
102
|
| `bun run test:e2e` | Run Playwright E2E tests. |
|
|
103
103
|
| `bun run screenshot` | Build, preview, then capture screenshots. |
|
|
104
104
|
|
|
105
|
-
`aitk tooling verify <stack>` is the only automated caller of `bun run screenshot`, running it for any stack whose `package.json` declares the script and asserting that PNG files land under `screenshots/`. No ship chain captures a screenshot, so the output path the seed writes is a contract that one verifier reads rather than a default a ship step depends on.
|
|
105
|
+
`aitk tooling verify <stack>` is the only automated caller of `bun run screenshot`, running it for any stack whose `package.json` declares the script and asserting that PNG files land under `screenshots/`. It counts them with a recursive find carrying no depth limit, so the section folders the seed writes satisfy the assertion without a change to it. Do not flatten the layout to protect that check. No ship chain captures a screenshot, so the output path the seed writes is a contract that one verifier reads rather than a default a ship step depends on.
|
|
106
|
+
|
|
107
|
+
`governance/rules/ui/440-surface-capture.md` is what asks a session to run the capture after a route changes. It fires on route and page files rather than on every component, so a shared component changing every screen fires nothing and the operator runs the capture by hand.
|
|
106
108
|
|
|
107
109
|
## Verify script
|
|
108
110
|
|