# Scrying Pool — Agent Instructions

FoundryVTT v14 module for GM camera visibility control. Ships as raw ES modules (no bundler). Entry: `module.js` → `module.json:esmodules`.

## Commands (run in order: lint → typecheck → test → build)

| Intent | Command |
|--------|---------|
| Lint | `npm run lint` |
| Typecheck | `npm run typecheck` |
| Test (unit) | `npm run test` |
| Test (watch) | `npm run test:watch` |
| Build CSS | `npm run build` |
| Release | `npm run release` |
| E2E test | `npm test` in `tests/e2e/` |

**Watch is broken** — `npm run watch` outputs to `dist/styles/` (gitignored) instead of `styles/`. Use `npm run build` manually.

Version source of truth: `package.json`; `scripts/package.mjs` copies it to `module.json` at release.

## Architecture

- **`module.js`** — wiring diagram ONLY. Imports, constructs with DI, registers hooks. Zero business logic. Never add logic here.
- **`src/contracts/`** — data contracts/DTOs. Must not import from any other `src/` module.
- **`src/utils/`** — utilities. Must not import from any other `src/` module.
- **`src/core/`** — business logic. May import from `contracts/` and `utils/` only.
- **`src/foundry/`** — `FoundryAdapter.js` is the sole gateway to `game.*` APIs. Same import restriction as `core/`.
- **`src/core/` ↔ `src/foundry/`** — never cross-import. Enforced by ESLint `import/no-restricted-paths`.
- **Constructor side-effect-free** — no hooks/socket registration in constructors; call `init()` from `Hooks.once('ready')` in `module.js`.

## Testing

- **Vitest** with `happy-dom`, `globals: false` — always import `describe`, `it`, `expect`, `vi` explicitly.
- **Path aliases** (vitest only): `@src`, `@contracts`, `@utils`, `@tests`.
- **Mock factory** — always use `createFoundryAdapterMock()` from `tests/helpers/foundryAdapterMock.js`. No ad-hoc stubs.
- **Hooks** is stubbed globally via `vi.stubGlobal('Hooks', ...)` in each test's `beforeEach`.
- **E2E tests** live in `tests/e2e/` with separate `package.json`. Need live FoundryVTT at `https://localhost:31000` (user: `gamemaster`). Not run in CI.
- **`@ts-nocheck`** is used at top of many test files — this is normal for this repo.

## FoundryVTT specifics

- Globals injected at runtime: `Hooks`, `game`, `ui`, `canvas`, `foundry`, `CONFIG`, `CONST` — listed as ESLint `readonly` globals.
- Type checking (`tsc --noEmit`) only covers `module.js`. Source files are NOT typechecked.
- Type defs from `@league-of-foundry-developers/foundry-vtt-types` (9.x) + local `src/types/foundry-globals.d.ts`.
- CSS scoped under `.scrying-pool`, token vars prefixed `--sp-*`, compiled from LESS via `npm run build`.

## CI & releases

- **Gitea** (not GitHub) at `uberwald.me/gitea/`. CI uses `RouxAntoine/checkout@v3.5.4`.
- CI: `npm ci` → `npm audit --production` → `npm run lint` → `npm run typecheck` → `npm run test` → `npm run build`.
- Release: triggered on tag publish, substitutes `module.json` URLs, creates `module.zip`, uploads via curl + Gitea API token.

## Design docs

Full project history in `_bmad-output/` — PRDs, architecture specs, epics, deferred work tracking. For deep context start with `_bmad-output/planning-artifacts/architecture.md` and `_bmad-output/planning-artifacts/epics.md`.
