chore(.agents/skills,AGENTS.md): new harness prompt

This commit is contained in:
Neko Ayaka
2026-08-04 19:24:12 +08:00
parent 55bd16e175
commit 7de2e2bf46
7 changed files with 151 additions and 204 deletions
@@ -0,0 +1,43 @@
---
name: enforce-rules-for-unocss
description: Enforce AIRI's UnoCSS, Vue styling, shared UI component, animation, icon, and color-mode practices. Use when creating, editing, refactoring, or reviewing Vue templates, component styles, utility classes, UnoCSS configuration, animations, icons, UI primitives, packages/ui components, or VueUse dark-mode behavior in the AIRI monorepo.
---
# Enforce AIRI UnoCSS Rules
Apply these rules to every affected UI file in AIRI.
## Compose Utility Classes Readably
- Prefer UnoCSS over Tailwind CSS.
- In Vue templates, bind grouped class arrays for readability:
```vue
:class="[
'px-2 py-1',
'flex items-center',
'bg-white/50 dark:bg-black/50',
]"
```
- Do not use long inline class strings such as `class="px-2 py-1 flex items-center bg-white/50 dark:bg-black/50"`.
- Do not use attributify-style groups such as `px="2" py="1" flex="~ items-center" bg="white/50 dark:black/50"`.
- When touching legacy utility classes, progressively refactor them into readable grouped arrays.
## Reuse Project Styling Infrastructure
- Use or extend shortcuts and rules in `uno.config.ts` when styles should be standardized or reused.
- Search `apps/stage-web/src/styles` for existing animations before adding one. Reuse or extend an existing animation when it fits.
- Consult `apps/stage-web/tsconfig.json` and `uno.config.ts` when configuration context is needed.
- Keep animations intuitive, lively, and readable.
## Build on Shared UI Primitives
- Build primitives on `@proj-airi/ui`, which is based on reka-ui, instead of raw DOM controls.
- Read `docs/ai/context/ui-components.md` for the component API and `packages/ui/src/components/Form` for implementation patterns.
- When adding or updating a component in `packages/ui`, update `docs/ai/context/ui-components.md` with its description, props, slots, and emits.
- Use Iconify icon sets instead of bespoke SVGs.
## Preserve Theme Behavior
- When using VueUse `useDark`, set `disableTransition: false` or use an existing composable from `packages/ui`.
@@ -0,0 +1,4 @@
interface:
display_name: "Enforce UnoCSS Rules"
short_description: "Apply AIRI styling and component standards"
default_prompt: "Use $enforce-rules-for-unocss to implement or review AIRI UI styling."
@@ -0,0 +1,51 @@
---
name: enforce-rules-for-vitest
description: Enforce AIRI's testing and Vitest practices. Use when creating, editing, reviewing, or debugging tests; reproducing a reported bug or issue; changing Vitest configuration; mocking IPC, services, providers, platform APIs, or imports; or diagnosing test import and runtime-boundary failures in the AIRI monorepo.
---
# Enforce AIRI Vitest Rules
Apply these rules to every test change in AIRI.
## Choose the Test Scope
- Use the Vitest project that owns the affected code and keep runs targeted for speed.
- Grow component and end-to-end coverage progressively. Prefer Vitest browser mode when the behavior depends on DOM or Web Platform APIs.
- Use the smallest automated test that faithfully exercises the behavior: prefer a unit test, then the smallest suitable higher-level test.
## Reproduce Bugs Before Fixing Them
1. For an investigated bug or issue, try to add a test-only reproduction before changing production code.
2. When reproduction is possible, include the tracker identifier in the test case name:
- Use `Issue #<number>` for a GitHub issue.
- Use the Linear issue key for an internal Linear bug.
3. Put the actual report URL in a comment directly above the regression test. Use the GitHub issue URL, Discord message or thread URL, or Linear issue URL as appropriate.
4. Confirm that the reproduction fails for the reported reason before implementing the fix.
## Mock Real Boundaries
- Mock Electron IPC and Electron services with `vi.fn` or `vi.mock`; never require a real Electron runtime.
- For external providers and services, add mock-based tests and, when feasible, integration-style tests guarded by environment variables, but do not mock Pinia, Vue components. Vitest import mocks are allowed for these boundaries.
- Assert observable behavior, including mock calls and parameters, with explicit `expect` statements.
- Prefer one assertion per line so failures remain readable.
## Preserve Runtime Integrity
- Do not test impossible runtime states. Avoid assertions against constants that cannot change or object mutations that can only occur inside the same test setup.
- Do not replace `globalThis` properties or built-in modules with direct `Object.defineProperty(...)` mocks.
- When behavior depends on a different Node global or built-in state, use `node:worker_threads` to load an isolated worker or build a minimal CLI reproduction.
- For DOM and Web Platform APIs, use Vitest browser mode instead of hard-mocking platform internals. Progressively refactor existing direct platform mocks when touched.
## Fix Import Boundaries, Not Tests
Never use Vitest mocks, hoisting, dynamic imports, `as unknown as`, or test-only alternate import paths to conceal a real import failure.
If a test cannot import a module, investigate and fix the production boundary:
- package exports and declarations;
- import-time side effects;
- mixed Node and browser type dependencies;
- circular imports;
- an incorrect public module shape.
Keep the test importing the same supported boundary that production consumers use.
@@ -0,0 +1,4 @@
interface:
display_name: "Enforce Vitest Rules"
short_description: "Apply AIRI testing and Vitest standards"
default_prompt: "Use $enforce-rules-for-vitest to implement or review tests under AIRI's testing standards."
@@ -1,89 +0,0 @@
---
name: server-gateway-refactor
description: Use when refactoring AIRI apps/server routes that mix Hono route wiring, business operation orchestration, external gateway calls, billing, rate limiting, telemetry, or websocket session state. Applies especially to OpenAI-compatible, speech, Stripe, and websocket gateway surfaces.
---
# Server Gateway Refactor
Use this skill when an `apps/server` route file has grown into a mixed transport/business/infra module and the user wants it engineered rather than merely split by line count.
## First Read
Start from the exact route file the user named. Read nearby tests and domain services before editing. Use `rg` for call sites and avoid deleting legacy routes without checking tests/docs/env references.
Look for these responsibilities:
- HTTP/WebSocket transport shape: Hono routes, auth, request parsing, response mounting, upgrade setup.
- Gateway operation shape: authenticated user, parsed body/query, operation id, model/provider routing, external calls.
- Infra behavior: billing, rate limiting, telemetry/tracing, request logs, PostHog, retries, cache.
- Domain services: persistence, Stripe records, character/provider ownership, chat messages, flux transactions.
## Boundary Rules
- Keep Hono middleware as Hono middleware only when it can run from raw `Context`: auth, config availability, static files, IP-level limits.
- Use gateway middleware when the decision needs parsed gateway context: user id, operation id, request body, requested model, resolved model, streaming lifecycle, usage, or billing state.
- Prefer route-group scoped middleware for endpoint-specific behavior:
- Good: `gateway.route('openai').use('chat.completions', rateLimit).post(...)`
- Avoid: global gateway `.use('chat.completions', ...)` when the middleware is only meaningful for one endpoint group.
- Do not create handler files that only pass through parse + operation. Inline thin adapters in the route index unless they hide meaningful protocol decisions.
- Do not split by execution order alone. A module boundary should own a policy, operation, middleware, or external boundary.
## Naming
- File names use kebab-case, not camelCase.
- Use HTTP names for transport files and operation names for business files.
- Prefer `middlewares/` for both Hono and gateway middleware in this project when they are part of a route gateway surface.
- Prefer `operations/<operation>/index.ts` for reusable operation orchestration.
- Avoid `gateway` as a domain name unless the module really owns route/runtime composition.
## Preferred Shape
For gateway-like HTTP surfaces:
```ts
const gateway = createXGateway(deps)
.useHono('*', '*', authGuard)
.useHono('surface', '/path/*', configGuard(...))
const surfaceRoutes = gateway.route('surface')
.use('operation.id', operationMiddleware(...))
.post('/path', surface.handler(
'operation.id',
async (c) => parseInput(c),
operation(deps),
))
.route
```
Keep route index readable:
- It should show route groups, endpoint paths, and endpoint-scoped middleware.
- It may inline small parse adapters.
- It should not contain long external-provider workflows, webhook switches, or billing settlement logic.
## Candidate Signals
Use this pattern when:
- One route file exceeds roughly 200-300 lines and mixes route wiring with external provider orchestration.
- There are endpoint-specific middleware needs that cannot be represented as Hono middleware.
- Tests describe operation behavior more than route matching.
- The route has multiple business operations under one transport surface.
Do not force this pattern when:
- A CRUD route is already thin and delegates to a domain service.
- The route mostly mounts framework-owned handlers, static assets, or metadata endpoints.
- The logic belongs in an existing domain service instead of a new route gateway.
## Verification
After changes, run targeted validation before broader checks:
```sh
pnpm exec vitest run apps/server/src/routes/<route>/route.test.ts
pnpm -F @proj-airi/server typecheck
pnpm exec eslint <changed files>
```
If full `pnpm lint` fails from unrelated repo-wide issues, report that separately and keep targeted lint evidence.