# 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`.