{"version":3,"file":"project-docs-7cMfbyoI.mjs","names":[],"sources":["../src/utils/fs.ts","../src/generators/templates/project-docs.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { writeFile, mkdir, access, readFile } from 'node:fs/promises'\nimport { createRequire } from 'node:module'\nimport { dirname, extname, join } from 'node:path'\n\nlet _dryRun = false\nlet _format = true\n\n/** Enable/disable dry run mode globally for all writeFileSafe calls */\nexport function setDryRun(enabled: boolean): void {\n  _dryRun = enabled\n}\n\n/**\n * Toggle oxfmt post-write formatting. Defaults to enabled — generators\n * always emit formatted output unless the caller opts out (rare; useful\n * for tests that want byte-stable assertions against raw template strings).\n */\nexport function setFormatOnWrite(enabled: boolean): void {\n  _format = enabled\n}\n\n/** Extensions oxfmt can format. Anything else is written verbatim. */\nconst FORMATTABLE = new Set(['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.json', '.md'])\n\n/**\n * Write a file, creating parent directories if needed.\n *\n * After write, runs oxfmt against the file when:\n *   - format-on-write is enabled (default)\n *   - the extension is in {@link FORMATTABLE}\n *   - oxfmt resolves from the user's project (or our own cwd)\n *\n * Failures (missing oxfmt, unparseable source, formatter crash) are\n * swallowed silently — formatting is a polish step, not a correctness\n * gate. The pre-commit hook still catches anything we couldn't format.\n *\n * Skips writing entirely in dry run mode.\n */\nexport async function writeFileSafe(filePath: string, content: string): Promise<void> {\n  if (_dryRun) return\n  await mkdir(dirname(filePath), { recursive: true })\n  await writeFile(filePath, content, 'utf-8')\n  if (_format && FORMATTABLE.has(extname(filePath))) {\n    await formatFile(filePath, content).catch(() => {\n      // Formatter missing or unparseable source — leave the unformatted\n      // file in place. Pre-commit hook will catch shipping-blocker\n      // formatting issues.\n    })\n  }\n}\n\ninterface OxfmtFormatResult {\n  code: string\n  errors: unknown[]\n}\n\ninterface OxfmtModule {\n  format(\n    fileName: string,\n    sourceText: string,\n    options?: Record<string, unknown>,\n  ): Promise<OxfmtFormatResult>\n}\n\nlet _oxfmt: OxfmtModule | null | undefined = undefined\n\n/** Resolve oxfmt from the user's project; cache the result (or null) for the process. */\nasync function resolveOxfmt(cwd: string): Promise<OxfmtModule | null> {\n  if (_oxfmt !== undefined) return _oxfmt\n  try {\n    const req = createRequire(join(cwd, 'package.json'))\n    const oxfmtPath = req.resolve('oxfmt')\n    _oxfmt = (await import(oxfmtPath)) as OxfmtModule\n  } catch {\n    _oxfmt = null\n  }\n  return _oxfmt\n}\n\nasync function formatFile(filePath: string, content: string): Promise<void> {\n  const oxfmt = await resolveOxfmt(process.cwd())\n  if (!oxfmt) return\n  // The CLI binary auto-discovers `.oxfmtrc.json`, but the JS API\n  // does NOT — we walk up from the file being formatted so adopters'\n  // workspace config drives the output. Skip formatting entirely\n  // when no config is found (matches the old prettier failure mode:\n  // raw templates already follow project conventions).\n  const options = await loadOxfmtConfig(filePath)\n  if (options === null) return\n  const result = await oxfmt.format(filePath, content, options)\n  if (result.code === content) return\n  await writeFile(filePath, result.code, 'utf-8')\n}\n\nconst _oxfmtConfigCache = new Map<string, Record<string, unknown> | null>()\n\n/**\n * Walk up from `filePath`'s directory looking for `.oxfmtrc.json`.\n * Returns `null` when no config is found anywhere on the path —\n * generators then leave the raw template alone (which already\n * follows project conventions). Cached per starting directory so\n * the walk is one-shot per generator run.\n */\nasync function loadOxfmtConfig(filePath: string): Promise<Record<string, unknown> | null> {\n  let dir = dirname(filePath)\n  const startDir = dir\n  if (_oxfmtConfigCache.has(startDir)) return _oxfmtConfigCache.get(startDir)!\n  while (true) {\n    const configPath = join(dir, '.oxfmtrc.json')\n    if (existsSync(configPath)) {\n      try {\n        const raw = await readFile(configPath, 'utf-8')\n        const parsed = JSON.parse(raw) as Record<string, unknown>\n        // The `$schema` and `ignorePatterns` fields are runner-only —\n        // strip before passing to format() so it doesn't reject them\n        // as unknown options.\n        delete parsed['$schema']\n        delete parsed.ignorePatterns\n        _oxfmtConfigCache.set(startDir, parsed)\n        return parsed\n      } catch {\n        _oxfmtConfigCache.set(startDir, null)\n        return null\n      }\n    }\n    const parent = dirname(dir)\n    if (parent === dir) {\n      _oxfmtConfigCache.set(startDir, null)\n      return null\n    }\n    dir = parent\n  }\n}\n\n/** Reset cached oxfmt resolution. Tests use this; production code shouldn't. */\nexport function clearFormatCache(): void {\n  _oxfmt = undefined\n  _oxfmtConfigCache.clear()\n}\n\n/** Ensure a directory exists */\nexport async function ensureDirectory(dir: string): Promise<void> {\n  await mkdir(dir, { recursive: true })\n}\n\n/** Check if a file exists */\nexport async function fileExists(filePath: string): Promise<boolean> {\n  try {\n    await access(filePath)\n    return true\n  } catch {\n    return false\n  }\n}\n\n/** Read a JSON file */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function readJsonFile<T = any>(filePath: string): Promise<T> {\n  const content = await readFile(filePath, 'utf-8')\n  return JSON.parse(content)\n}\n","type ProjectTemplate = 'rest' | 'minimal' | 'fullstack'\n\n/** Generate README.md with project documentation */\nexport function generateReadme(name: string, template: ProjectTemplate, pm: string): string {\n  const templateLabels: Record<string, string> = {\n    rest: 'REST API',\n    minimal: 'Minimal',\n    fullstack: 'Fullstack (KickJS API + typed web app)',\n  }\n\n  const packages = ['@forinda/kickjs', '@forinda/kickjs-vite']\n  if (template !== 'minimal') {\n    packages.push('@forinda/kickjs-swagger', '@forinda/kickjs-devtools')\n  }\n\n  return `# ${name}\n\nA **${templateLabels[template] ?? 'REST API'}** built with [KickJS](https://kickjs.app/) — a decorator-driven Node.js framework for TypeScript that runs on Express, Fastify, or h3 (swap the engine in one line).\n\n## Getting Started\n\n\\`\\`\\`bash\n${pm} install\nkick dev\n\\`\\`\\`\n\n## Scripts\n\n| Command | Description |\n|---|---|\n| \\`kick dev\\` | Start dev server with Vite HMR |\n| \\`kick build\\` | Production build |\n| \\`kick start\\` | Run production build |\n| \\`${pm} run test\\` | Run tests with Vitest |\n| \\`kick g module <name>\\` | Generate a DDD module |\n| \\`kick g scaffold <name> <fields...>\\` | Generate CRUD from field definitions |\n| \\`kick add <package>\\` | Add a KickJS package |\n\n## Project Structure\n\n\\`\\`\\`\nsrc/\n├── index.ts           # Application entry point\n├── modules/           # Feature modules (controllers, services, repos)\n│   └── index.ts       # Module registry\n└── ...\n\\`\\`\\`\n\n## Packages\n\n${packages.map((p) => `- \\`${p}\\``).join('\\n')}\n\n## Adding Features\n\n\\`\\`\\`bash\nkick add auth          # Authentication (JWT, API key, OAuth)\nkick add swagger       # OpenAPI documentation\nkick add ws            # WebSocket support\nkick add queue         # Background job processing\nkick add --list        # Show all available packages\n\\`\\`\\`\n\nFor email, scheduled tasks, multi-tenancy, OpenTelemetry, GraphQL, and notifications use the BYO recipes in the [KickJS guides](https://kickjs.app/guide/) — they wire the upstream library through \\`defineAdapter()\\` / \\`definePlugin()\\` directly, so you keep control of the integration.\n\n## Environment Variables\n\nCopy \\`.env.example\\` to \\`.env\\` and configure:\n\n| Variable | Default | Description |\n|---|---|---|\n| \\`PORT\\` | \\`3000\\` | Server port |\n| \\`NODE_ENV\\` | \\`development\\` | Environment |\n\n## Learn More\n\n- [KickJS Documentation](https://kickjs.app/)\n- [CLI Reference](https://kickjs.app/api/cli.html)\n`\n}\n\n/**\n * Generate CLAUDE.md.\n *\n * v4 update: this file is intentionally thin. AGENTS.md is the\n * canonical, multi-agent project reference (Claude / Copilot /\n * Codex / Gemini / etc.) — duplicating it here meant two files\n * drifting out of sync after every framework change. The generated\n * CLAUDE.md now redirects there + adds Claude-specific affordances\n * only.\n */\nexport function generateClaude(name: string, _template: ProjectTemplate, pm: string): string {\n  return `# CLAUDE.md — ${name}\n\n**Read \\`./.agents/AGENTS.md\\` first.** It is the canonical, multi-agent\nreference for this project (Claude, Copilot, Codex, Gemini, etc.) —\nproject conventions, structure, decorator patterns, env wiring, CLI\ngenerators, every gotcha.\n\n**Then browse \\`./.agents/skills/\\`.** Each subdirectory is a single\ntask-oriented skill (\\`add-module/\\`, \\`write-controller-test/\\`,\n\\`bootstrap-export/\\`, \\`deny-list/\\`, …) containing a \\`SKILL.md\\`\nwith YAML frontmatter (\\`name\\`, \\`description\\`) and the recipe body.\nThe structure follows the Claude Code skills convention — agents that\nauto-load skills from \\`.agents/skills/\\` will pick each up by its\nfrontmatter. Use this directory as the playbook when executing common\nKickJS workflows.\n\nThis file is a thin Claude-specific layer on top of those two; when\nthey disagree on anything substantive, treat \\`.agents/AGENTS.md\\` as\nauthoritative and flag the discrepancy.\n\n## Why \\`.agents/\\` + this thin pointer\n\n\\`.agents/AGENTS.md\\` is what every agent reads (Codex, Cursor, Gemini,\nCopilot, Aider, …) — one canonical source so the prose doesn't drift\nacross copies. \\`CLAUDE.md\\` is what Claude Code automatically loads as\nproject context on each conversation, so it stays at the project root.\nKeeping CLAUDE.md slim and pointing at \\`.agents/\\` avoids two\nout-of-sync copies of the same content. Per-agent files\n(\\`.agents/GEMINI.md\\`, \\`.agents/COPILOT.md\\`) live alongside\n\\`AGENTS.md\\` for tool-specific notes that don't belong in the shared\nprose.\n\n## Claude-specific notes\n\n- **Slash commands** — \\`/help\\` for Claude Code commands; \\`/init\\`\n  to refresh project memory if AGENTS.md changes substantially.\n- **Feedback** — file issues at <https://github.com/anthropics/claude-code/issues>.\n- **Persistent memory** — Claude maintains user/feedback/project/\n  reference memories under \\`.claude/memory/\\`. If you ask for\n  something that contradicts a remembered preference, Claude flags\n  it before acting; corrections update memory automatically.\n- **Long-running tasks** — \\`/loop\\` and \\`/schedule\\` for recurring\n  or background work. Useful for \"wait for the deploy then open a\n  cleanup PR\" or \"every Monday triage the issue board\" patterns.\n\n## Quick reference (full version in .agents/AGENTS.md)\n\n\\`\\`\\`bash\n${pm} install            # Install dependencies\nkick dev                 # Dev server with HMR + typegen\nkick build && kick start # Production\n${pm} run test           # Vitest\n${pm} run typecheck      # tsc --noEmit\n${pm} run format         # Prettier\n\\`\\`\\`\n\n## v4 framework reminders\n\nWhen generating or modifying code in this project, stay aligned with the v4 conventions documented in \\`.agents/AGENTS.md\\`:\n\n- **Adapters**: \\`defineAdapter()\\` factory — never \\`class implements AppAdapter\\`.\n- **Plugins**: \\`definePlugin()\\` factory — never plain function returning \\`KickPlugin\\`.\n- **DI tokens**: \\`<scope>/<PascalKey>[/<suffix>]\\` — scope is lowercase, the key segment is **PascalCase** (e.g. \\`'app/Users/repository'\\`, \\`'mycorp/Cache/redis'\\`). First-party uses the reserved \\`'kick/'\\` prefix; this project owns its own scope.\n- **Decorators**: \\`@Controller()\\` (no path arg — mount prefix comes from \\`routes().path\\`).\n- **HTTP runtime**: this app may run on Express, Fastify, or h3 — check \\`kick.config.ts\\` \\`runtime\\` (or \\`bootstrap({ runtime })\\`) before writing engine-specific code. Prefer engine-neutral \\`ctx\\` APIs (\\`ctx.json\\`/\\`ctx.body\\`/\\`ctx.params\\`/\\`ctx.sse\\`); don't assume \\`ctx.req\\` is an Express request. Uploads (\\`@FileUpload\\` → \\`ctx.file\\`/\\`ctx.files\\`) work on all three (\\`kick add upload\\` installs the driver). Full rules in \\`.agents/AGENTS.md\\` → \"HTTP runtime\".\n- **Module entry file** MUST be named \\`<name>.module.ts\\` and live under \\`src/modules/<name>/\\`. The Vite plugin auto-discovers \\`*.module.[tj]sx?\\` for graceful HMR — a misnamed \\`projects.ts\\` silently degrades every save into a full restart.\n- **Env**: schema lives in \\`src/config/index.ts\\`; \\`import './config'\\` MUST be the first import in \\`src/index.ts\\` (side-effect registers the schema before any \\`@Value\\` resolves).\n- **Assets**: drop new template files into \\`src/templates/<namespace>/\\`; the dev watcher auto-rebuilds the \\`KickAssets\\` augmentation + \\`assets.x.y()\\` re-walks on next call. No restart, no manual build.\n- **Context Contributors** (\\`defineContextDecorator\\`) over \\`@Middleware()\\` for ctx-population work.\n- **Repos under tests**: \\`Container.create()\\` for isolation — never \\`new Container()\\` or \\`getInstance().reset()\\`.\n- **Bootstrap export**: \\`src/index.ts\\` must end with \\`export const app = await bootstrap({ ... })\\`. The Vite plugin and \\`createTestApp\\` import the named \\`app\\`; without the export, HMR silently degrades to full restarts.\n- **Thin entry file**: aggregate \\`modules\\`, \\`middleware\\`, \\`plugins\\`, \\`adapters\\` in their own folders (\\`src/modules/index.ts\\`, \\`src/middleware/index.ts\\`, …) and pass them by name to \\`bootstrap()\\` — never inline the lists in \\`src/index.ts\\`.\n- **Refresh these files**: \\`kick g agents -f\\` regenerates \\`CLAUDE.md\\` at the project root and \\`.agents/AGENTS.md\\` + \\`.agents/GEMINI.md\\` + \\`.agents/COPILOT.md\\` + every \\`.agents/skills/<name>/SKILL.md\\` from the latest CLI templates. Hand-edited content is overwritten — keep customisation in \\`.agents/AGENTS.local.md\\` or per-skill \\`SKILL.local.md\\` files alongside.\n\nFor everything else (controllers, services, modules, RequestContext API, generators, CLI commands, package additions, env wiring, troubleshooting) → \\`.agents/AGENTS.md\\`.\n`\n}\n\n/** Generate AGENTS.md with AI agent guide */\nexport function generateAgents(name: string, template: ProjectTemplate, pm: string): string {\n  return `# AGENTS.md — AI Agent Guide for ${name}\n\nThis guide is the **canonical, multi-agent reference** for this KickJS\napplication — Claude, Copilot, Codex, Gemini, etc. all read it first.\nPer-agent files (\\`CLAUDE.md\\`, \\`GEMINI.md\\`, etc.) are thin layers that\nadd tool-specific affordances on top.\n\n## Before You Start\n\n1. Run \\`${pm} install\\` to install dependencies\n2. Run \\`kick dev\\` to verify the app starts${\n    template === 'fullstack'\n      ? `\n\n## Fullstack workspace layout\n\nThis is a WORKSPACE root — the KickJS API lives in \\`server/\\`, the typed web\napp in \\`web/\\`. Run both with \\`${pm === 'pnpm' ? 'pnpm dev' : `${pm} run dev:server + ${pm} run dev:web`}\\`.\n\nThe type loop (do not break it):\n1. \\`server/\\` handlers RETURN their payloads → \\`kick typegen\\` (auto under\n   \\`kick dev\\`) emits \\`server/.kickjs/types/kick__routes.ts\\` incl. the flat\n   \\`KickRoutes.Api\\` map with inferred response types.\n2. \\`web/src/types/kick-routes.d.ts\\` imports that file TYPE-ONLY.\n3. \\`web/src/api.ts\\` = \\`createClient<KickApi>({ baseUrl: '/api/v1' })\\`\n   — every call site is typed from the server's handlers.\n\nRules: kick commands (\\`kick g\\`, \\`kick typegen\\`, \\`kick dev\\`) run in\n\\`server/\\`; never import server runtime code into \\`web/\\` (the d.ts bridge is\ntype-only); prefer return-value handlers so responses stay inferable.`\n      : ''\n  }\n3. Read the [KickJS documentation](https://kickjs.app/) for framework details\n\n## HTTP runtime — DON'T assume Express-only\n\nKickJS is **engine-pluggable**. It runs on **Express (default), Fastify, or h3** —\nchosen with one line: \\`bootstrap({ runtime: fastifyRuntime() })\\`. Before writing\nany engine-specific code, **check which engine this project uses**:\n\n- \\`kick.config.ts\\` → the \\`runtime\\` field (\\`'express'\\` | \\`'fastify'\\` | \\`'h3'\\`), and/or\n- \\`src/index.ts\\` → the \\`runtime:\\` passed to \\`bootstrap()\\`, and/or\n- \\`package.json\\` → \\`fastify\\` / \\`h3\\` in deps.\n\nRules that keep generated code correct on **every** engine:\n\n- **Prefer return-value handlers.** \\`return payload\\` sends 200 json on every\n  engine and lets \\`kick typegen\\` infer the response type into\n  \\`KickRoutes.Api\\` (consumed by the \\`@forinda/kickjs-client\\` typed client);\n  \\`reply(status, body)\\` for non-200, \\`reply.noContent()\\` for 204. A declared\n  \\`{ response: schema }\\` on the route feeds BOTH the OpenAPI success response\n  and the typegen response type. \\`ctx.json(...)\\` stays fully supported but\n  infers \\`unknown\\`.\n- **Lifecycle hooks:** \\`@PostConstruct()\\` after instantiation; \\`@PreDestroy()\\`\n  when a REQUEST-scoped service's request closes (release transactions/handles).\n- **Write to \\`ctx\\`, not the raw request/response.** \\`ctx.json()\\`, \\`ctx.body\\`,\n  \\`ctx.params\\`, \\`ctx.query\\`, \\`ctx.set/get\\`, \\`ctx.sse()\\` are engine-neutral and\n  work identically everywhere. \\`ctx.req\\` / \\`ctx.res\\` are the engine-native\n  objects — their **type follows the active runtime** (Express by default; the\n  \\`kick/runtime\\` typegen retypes them to Fastify / h3 when \\`runtime\\` is set).\n  Don't assume \\`ctx.req\\` is an \\`express.Request\\` in portable code.\n- **Global middleware** in \\`bootstrap({ middleware })\\` is connect-style\n  \\`(req, res, next)\\` — it runs on all engines (Fastify via \\`@fastify/middie\\`,\n  h3 via \\`fromNodeMiddleware\\`). But on Fastify / h3 the engine parses the body\n  natively, so the default \\`express.json()\\` is **auto-skipped** (\\`nativeBodyParsing\\`).\n  Don't add \\`express.json()\\` manually on those engines.\n- **File uploads** work on all three: \\`@FileUpload({ mode, fieldName, ... })\\` →\n  \\`ctx.file\\` / \\`ctx.files\\` (same Multer-shaped object everywhere). Backends:\n  Express \\`multer\\`, Fastify \\`@fastify/multipart\\`, h3 native. Run\n  \\`kick add upload\\` to install the runtime-correct driver. The \\`@FileUpload\\`\n  decorator is **memory-only** (portable); disk / custom-storage (\\`storage\\` /\n  \\`dest\\`) is Express-only via the \\`upload.single/array()\\` middleware.\n- **Engine subpaths**: \\`import { fastifyRuntime } from '@forinda/kickjs/fastify'\\`\n  or \\`h3Runtime\\` from \\`'@forinda/kickjs/h3'\\`. Express is the zero-config default\n  (no import, nothing to install).\n- **Not supported on Fastify / h3**: \\`ctx.render()\\` (no view engine). Calling it\n  throws a clear error rather than failing silently.\n- Run \\`kick doctor\\` to verify the runtime's engine peers + upload driver are installed.\n\n## v4 Conventions (don't skip)\n\nKickJS v4 made a handful of structural changes from v3. Internalise these\nbefore generating or modifying code — they are the source of most agent\nmistakes:\n\n- **Adapters** — \\`defineAdapter()\\` factory. Never write \\`class Foo implements AppAdapter\\`.\n\n  \\`\\`\\`ts\n  export const MyAdapter = defineAdapter<MyOptions>({\n    name: 'MyAdapter',\n    defaults: { ... },\n    build: (config) => ({\n      beforeMount({ app }) { /* ... */ },\n      afterStart({ server }) { /* ... */ },\n    }),\n  })\n  \\`\\`\\`\n\n- **Plugins** — \\`definePlugin()\\` factory. Same shape, never plain function returning \\`KickPlugin\\`.\n\n- **DI tokens** — \\`<scope>/<PascalKey>[/<suffix>]\\`. Scope is lowercase,\n  the key segment is **PascalCase** (the regex enforces both):\n\n  \\`\\`\\`ts\n  const USERS_REPO = createToken<UsersRepo>('app/Users/repository')\n  const DB         = createToken<Database>('app/Db/connection')\n  \\`\\`\\`\n\n  The \\`kick/\\` prefix is reserved for first-party packages; this project\n  owns its own scope (\\`app/\\`, your domain name, etc.).\n\n- **\\`@Controller()\\`** takes **no path argument**. Mount prefix comes from\n  the module's \\`routes()\\` return value, not the decorator. \\`@Controller('/users')\\`\n  is a v3 leftover; the linter and codegen reject it.\n\n- **Env wiring** — \\`src/config/index.ts\\` calls \\`loadEnv(envSchema)\\` as a\n  side effect. \\`src/index.ts\\` MUST have \\`import './config'\\` as its **first**\n  import (before \\`bootstrap()\\`). Without it, \\`ConfigService.get('YOUR_KEY')\\`\n  returns \\`undefined\\` and \\`@Value()\\` only works via raw \\`process.env\\` fallback\n  (Zod coercion + defaults silently skipped).\n\n- **Module entry files MUST be named \\`<name>.module.ts\\`** — see the Vite\n  HMR contract at the top of \"Module Pattern\" below. The CLI enforces this;\n  hand-rolled files must too.\n\n- **Assets** — drop new template files into \\`src/templates/<namespace>/\\`\n  (or wherever \\`kick.config.ts\\` points). The dev watcher auto-rebuilds the\n  \\`KickAssets\\` augmentation; \\`assets.x.y()\\` re-walks on next call. No restart,\n  no manual build step.\n\n- **Context over \\`@Middleware()\\`** — when a middleware's only job is to\n  populate \\`ctx.set('key', value)\\`, use \\`defineHttpContextDecorator()\\`\n  (HTTP) or \\`defineContextDecorator()\\` (transport-agnostic) instead.\n  Typed via \\`ContextMeta\\`, ordered via \\`dependsOn\\`, validated at boot.\n  Reserve \\`@Middleware()\\` for response short-circuit / stream mutation /\n  pre-route-matching work.\n\n  Two ground rules around the data flow — both stem from the fact that\n  every per-request stage gets its OWN \\`RequestContext\\` instance, all\n  reading/writing the SAME \\`AsyncLocalStorage\\`-backed Map:\n  - **\\`resolve\\` and \\`onError\\` must RETURN the value.** The runner\n    writes it via \\`ctx.set(reg.key, value)\\` on your behalf. Direct\n    property assignment (\\`ctx.tenant = …\\`) sticks to the contributor\n    instance only — the handler instance never sees it.\n  - **Read across instances via \\`ctx.set\\` / \\`ctx.get\\`** (or\n    \\`getRequestValue(key)\\` from a service that has no \\`ctx\\` reference\n    — typed via \\`MetaValue<K>\\`). \\`ctx.req\\` works because the underlying\n    Express request is shared; bespoke property assignments don't.\n\n- **Test isolation** — default to \\`Container.create()\\` for fresh DI state.\n  Never \\`new Container()\\` and never \\`getInstance().reset()\\` — both leak\n  registrations between tests.\n\n  \\`\\`\\`ts\n  const container = Container.create()\n  // ... register test-scoped providers, run, discard\n  \\`\\`\\`\n\n- **Bootstrap export** — \\`src/index.ts\\` MUST end with\n  \\`export const app = await bootstrap({ ... })\\`. The Vite plugin imports\n  the named \\`app\\` symbol to drive HMR module swaps; testing helpers\n  (\\`createTestApp\\`) and the OpenAPI introspector also rely on it. Drop\n  the \\`export\\` and \\`kick dev\\` will silently fall back to a full restart\n  on every save while \\`createTestApp\\` complains about a missing handle.\n\n- **Keep \\`src/index.ts\\` thin** — collect plugins, modules, middleware, and\n  adapters in dedicated folders and re-export aggregated arrays. Do **not**\n  inline registration in the entry file:\n\n  \\`\\`\\`ts\n  // src/modules/index.ts — fluent chain (default for \\`modules.style: 'define'\\`)\n  export const modules = defineModules().mount(HelloModule()).mount(UsersModule())\n  // OR with \\`modules.style: 'class'\\`:\n  //   export const modules: AppModuleEntry[] = [HelloModule, UsersModule]\n\n  // src/middleware/index.ts\n  export const middleware = [helmet(), cors(), requestId(), ...]\n\n  // src/plugins/index.ts\n  export const plugins = [MetricsPlugin(), AuditPlugin()]\n\n  // src/adapters/index.ts\n  export const adapters = [SwaggerAdapter({ ... }), DevToolsAdapter()]\n  \\`\\`\\`\n\n  \\`\\`\\`ts\n  // src/index.ts — stays small; one import per category\n  import 'reflect-metadata'\n  import './config'\n  import { bootstrap } from '@forinda/kickjs'\n  import { modules } from './modules'\n  import { middleware } from './middleware'\n  import { plugins } from './plugins'\n  import { adapters } from './adapters'\n\n  export const app = await bootstrap({ modules, middleware, plugins, adapters })\n  \\`\\`\\`\n\n  This keeps the entry file diff-friendly, scales to dozens of modules\n  without git churn, and lets each domain own its own registration list.\n  The generators (\\`kick g module\\`, \\`kick g middleware\\`, \\`kick g plugin\\`,\n  \\`kick g adapter\\`) follow this layout — manual additions should too.\n\nEverything else (controllers, services, modules, RequestContext API, generators,\npackage additions, env access patterns, troubleshooting) is detailed below.\n\n## Where to Find Things\n\n### Application Structure\n\n| What | Where |\n|------|-------|\n| Entry point | \\`src/index.ts\\` |\n| Module registry | \\`src/modules/index.ts\\` |\n| Feature modules | \\`src/modules/<module-name>/\\` |\n| **Module entry file** | \\`src/modules/<name>/<name>.module.ts\\` (filename suffix is required — see Vite HMR contract below) |\n| Env values | \\`.env\\` |\n| Env schema (Zod) | \\`src/config/index.ts\\` |\n| TypeScript config | \\`tsconfig.json\\` |\n| Vite config (HMR) | \\`vite.config.ts\\` |\n| Vitest config | \\`vitest.config.ts\\` |\n| Prettier config | \\`.prettierrc\\` |\n| CLI config | \\`kick.config.ts\\` |\n\n### Module Pattern (${template.toUpperCase()})\n\n> **Vite HMR auto-discovery contract:** module files **must** be named \\`<name>.module.ts\\` (or \\`.tsx\\`/\\`.js\\`/\\`.jsx\\`) and live under \\`src/modules/\\`. The Vite plugin scans for \\`*.module.[tj]sx?\\` to drive graceful HMR rebuilds; renaming a file to \\`projects.ts\\` (no \\`.module\\`) silently breaks HMR — saves trigger a full restart instead of a swap. The CLI generator (\\`kick g module <name>\\`) follows the convention; manual files must too.\n\nEach module in \\`src/modules/<name>/\\` typically contains:\n\n${\n  template === 'rest'\n    ? `\\`\\`\\`\n<name>/\n├── <name>.controller.ts     # HTTP routes (@Controller)\n├── <name>.service.ts        # Business logic (@Service)\n├── <name>.repository.ts     # Data access (@Repository)\n├── dtos/                    # Request/response schemas (Zod)\n└── <name>.module.ts         # Module definition (defineModule factory)\n\\`\\`\\`\n`\n    : `\\`\\`\\`\nsrc/\n├── index.ts                 # Add routes here\n└── ...                      # Custom structure\n\\`\\`\\`\n`\n}\n\n## Checklist: Adding a Feature\n\nFollow the **\\`kickjs-add-module\\`** skill — it has the ordered steps, the\ncanonical \\`defineModule\\` shape, and the \\`import.meta.glob\\` requirement that\nsilently breaks DI when omitted.\n\n## Common Tasks\n\nEach of these has a skill with the steps and the traps:\n\n| Task | Skill |\n| --- | --- |\n| Add a feature module | \\`kickjs-add-module\\` |\n| Add an adapter | \\`kickjs-add-adapter\\` |\n| Add a plugin | \\`kickjs-add-plugin\\` |\n| Add a context contributor | \\`kickjs-context-contributor\\` |\n| Write a controller test | \\`kickjs-write-controller-test\\` |\n| List endpoint with filters / pagination | \\`kickjs-query-parsing-list-endpoint\\` |\n| Serve bundled assets | \\`kickjs-use-asset-manager\\` |\n| Anything else | \\`kickjs-docs-lookup\\` |\n\n## Testing Guidelines\n\nSee the **\\`kickjs-write-controller-test\\`** skill for the canonical test — it\ncarries the call shape, the DI reset, and the env side-effect import, each of\nwhich has its own failure mode.\n\nRun with \\`${pm} run test\\` (\\`test:watch\\` for watch mode).\n\n## Environment Variables\n\nThe schema lives in \\`src/config/index.ts\\` and registers itself with kickjs **at\nmodule load**; \\`src/index.ts\\` imports it (\\`import './config'\\`) before\n\\`bootstrap()\\` so the cache is populated before DI resolves anything. Add a key\nto the schema, put its value in \\`.env\\`, and it is typed everywhere.\n\nRead it with \\`@Value('KEY')\\` for construction-time values, or inject\n\\`ConfigService\\` for dynamic access.\n\nWhen a key reads as \\`undefined\\`, use the **\\`kickjs-env-wiring-check\\`** skill or\nrun \\`kick explain \"ConfigService.get('KEY') returned undefined\"\\`. The cause\ndiffers between app code and tests and the two look identical, which is what\nmakes it slow to spot.\n\n## Standalone Utilities (No DI Required)\n\nThese work anywhere — scripts, plain files, outside \\`@Service\\`/\\`@Controller\\`:\n\n| Utility | Import | Example |\n|---------|--------|---------|\n| \\`Logger.for(name)\\` | \\`@forinda/kickjs\\` | \\`const log = Logger.for('MyScript')\\` |\n| \\`createLogger(name)\\` | \\`@forinda/kickjs\\` | \\`const log = createLogger('Worker')\\` |\n| \\`createToken<T>(name)\\` | \\`@forinda/kickjs\\` | \\`const TOKEN = createToken<string>('app/Db/url')\\` |\n| \\`ref(value)\\` | \\`@forinda/kickjs\\` | \\`const count = ref(0)\\` |\n| \\`computed(fn)\\` | \\`@forinda/kickjs\\` | \\`const doubled = computed(() => count.value * 2)\\` |\n| \\`watch(source, cb)\\` | \\`@forinda/kickjs\\` | \\`watch(() => count.value, (v) => log(v))\\` |\n| \\`reactive(obj)\\` | \\`@forinda/kickjs\\` | \\`const state = reactive({ count: 0 })\\` |\n| \\`HttpException\\` | \\`@forinda/kickjs\\` | \\`throw new HttpException(404, 'Not found')\\` |\n| \\`HttpStatus\\` | \\`@forinda/kickjs\\` | \\`HttpStatus.NOT_FOUND // 404\\` |\n\n## Key Decorators\n\n### HTTP Routes\n| Decorator | Purpose |\n|-----------|---------|\n| \\`@Controller()\\` | Define route prefix |\n| \\`@Get('/'), @Post('/')\\` | HTTP method handlers |\n| \\`@Middleware(fn)\\` | Attach middleware |\n| \\`@Public()\\` | Skip auth (requires auth adapter) |\n| \\`@Roles('admin')\\` | Role-based access |\n\n### Dependency Injection\n| Decorator | Purpose |\n|-----------|---------|\n| \\`defineModule({...})\\` | Define feature module (factory; preferred — paired with \\`defineModules()\\` registry) |\n| \\`defineModules()\\` | Build the modules registry as a chainable list (\\`.mount(X())\\`) |\n| \\`AppModule\\` interface | Legacy module shape — \\`class X implements AppModule\\` (toggle via \\`modules.style: 'class'\\`) |\n| \\`@Service()\\` | Register singleton service |\n| \\`@Repository()\\` | Register repository |\n| \\`@Autowired()\\` | Property injection |\n| \\`@Inject('token')\\` | Token-based injection |\n| \\`@Value('VAR')\\` | Inject env variable |\n\n### Context Decorators\n\nTyped, ordered way to populate \\`ctx.set/get\\` keys before the handler runs.\nUse this **instead of \\`@Middleware()\\`** when the middleware's only output\nis a value other code reads off \\`ctx\\`.\n\n**Authoring** — pick the right factory:\n\n| Factory | When |\n|---------|------|\n| \\`defineHttpContextDecorator(spec)\\` | HTTP only (the common case). \\`Ctx\\` is \\`RequestContext\\`, so \\`ctx.req\\` / \\`ctx.params\\` / \\`ctx.query\\` are typed. |\n| \\`defineContextDecorator(spec)\\` | Transport-agnostic (HTTP + WS + queue + cron). \\`Ctx\\` is \\`ExecutionContext\\` — only \\`get\\` / \\`require\\` / \\`set\\` / \\`requestId\\`. |\n| \\`<either>.withParams<P>()(spec)\\` | The contributor takes per-call params. **Always use the curried form for params** — the positional form forces you to spell \\`K\\` and \\`D\\` and loses \\`deps\\` inference. |\n\nSpec fields: \\`{ key, deps, dependsOn, optional, paramDefaults, requiredParams, onError, resolve }\\`.\n\n**Call sites — all five, precedence high → low:**\n\n| # | Site | Form |\n|---|------|------|\n| 1 | Method | \\`@LoadX\\` / \\`@LoadX({ ... })\\` above a controller method |\n| 2 | Class | \\`@LoadX\\` / \\`@LoadX({ ... })\\` above the controller class |\n| 3 | Module | \\`defineModule({ build: () => ({ contributors: () => [LoadX.registration] }) })\\` — or \\`AppModule.contributors?()\\` in class form |\n| 4 | Adapter | \\`AppAdapter.contributors?(): ContributorRegistration[]\\` |\n| 5 | Global | \\`bootstrap({ contributors: [LoadX.registration] })\\` |\n\nSites 3–5 take **registrations**, not decorators:\n\n- \\`LoadX.registration\\` — uses \\`paramDefaults\\` as-is.\n- \\`LoadX.with({ ...params }).registration\\` — call-site params merged over \\`paramDefaults\\`.\n\nDuplicate keys are resolved by precedence; the lower-precedence one is\ndropped silently, which is how a method-level decorator overrides an\nadapter-shipped default.\n\n**Params:** a **required** field of \\`P\\` with no \\`paramDefaults\\` entry must be\nsupplied at every call site — \\`@LoadX\\` bare, \\`@LoadX()\\`, and \\`.registration\\`\nare compile errors for such a decorator. Never invent a placeholder default\njust to make the type check; add \\`requiredParams: ['field']\\` for runtime\nenforcement at JS call sites.\n\n**Reading values:** \\`ctx.require('key')\\` for values a contributor guarantees\n(throws \\`MissingContextValueError\\`, returns a non-optional type);\n\\`ctx.get('key')\\` for \\`optional: true\\` contributors and ad-hoc keys (returns\n\\`| undefined\\`). Never \\`ctx.get('key')!\\` — it compiles even when the producing\ndecorator isn't applied to the route.\n\n| Concept | Where it lives |\n|---------|----------------|\n| Type augmentation (value types) | \\`declare module '@forinda/kickjs' { interface ContextMeta { ... } }\\` |\n| Type augmentation (key-only) | \\`declare module '@forinda/kickjs' { interface ContextKeys { ... } }\\` — valid in \\`dependsOn\\`, value stays \\`unknown\\` |\n\nCycles and missing \\`dependsOn\\` keys throw at \\`app.setup()\\` (boot fails\nfast). The \\`onError\\` hook is async-permitted.\n\nFull guide: <https://kickjs.app/guide/context-decorators>.\n\n## Common Pitfalls\n\nSee the **\\`kickjs-deny-list\\`** skill — the maintained list of things that\ncompile, run, and are still wrong.\n\nFor a specific failure, \\`kick explain \"<error message>\"\\` beats reading either:\nit matches the message against known causes and prints the fix.\n\n## CLI Commands Reference\n\nSee the **\\`kickjs-cli-commands-cheatsheet\\`** skill for the full table, the\nshell-safe field syntax, and the non-obvious flags. \\`kick --help\\` and\n\\`kick <cmd> --help\\` are authoritative for the installed version.\n\n## Learn More\n\nUse the **\\`kickjs-docs-lookup\\`** skill — it maps questions to the right guide\npage and lists the local tools (\\`kick explain\\`, \\`kick doctor\\`, \\`kick inspect\\`,\n\\`.kickjs/types/\\`) that usually answer faster than a search.\n\nStart at <https://kickjs.app/>.\n\n`\n}\n\n/**\n * One emitted skill — slug becomes the directory name under\n * `.agents/skills/<slug>/SKILL.md`. `frontmatterName` is the value\n * agents use to look the skill up at activation time and follows the\n * `kickjs-<slug>` convention to keep the skill registry namespaced.\n */\nexport interface KickJsSkillFile {\n  /** kebab-case directory name (`add-module`, `write-controller-test`). */\n  slug: string\n  /** Full SKILL.md content with YAML frontmatter + body. */\n  content: string\n}\n\n/**\n * Render every KickJS task-skill as its own `SKILL.md` file, ready to\n * write under `.agents/skills/<slug>/SKILL.md`. Each file follows the\n * standard Claude Code skill format:\n *\n * ```\n * ---\n * name: kickjs-<slug>\n * description: <when to use this skill>\n * ---\n *\n * <body>\n * ```\n *\n * Agents that auto-discover skills from `.agents/skills/` (Claude\n * Code, Copilot CLI plugins, Gemini's activate_skill) pick each up by\n * its frontmatter without us shipping an index file. The legacy\n * single-file format (`kickjs-skills.md`) is gone — adopters with\n * existing root-level copies keep them untouched until they run\n * `kick g agents -f --only skills`, which emits the new layout\n * alongside without deleting the old file.\n */\ninterface KickJsSkill {\n  slug: string\n  frontmatterName: string\n  description: string\n  body: string\n}\n\n/**\n * Single source of truth for the agent skills.\n *\n * Rendered twice — one `SKILL.md` per entry, and the aggregate\n * `kickjs-skills.md`. The aggregate used to restate all of this by hand and had\n * drifted badly: 9 skills against 13, with an env recipe still naming a\n * superseded API. Add a skill here and both outputs pick it up.\n */\nfunction buildSkills(pm: string): KickJsSkill[] {\n  const skills: Array<{\n    slug: string\n    frontmatterName: string\n    description: string\n    body: string\n  }> = [\n    {\n      slug: 'add-module',\n      frontmatterName: 'kickjs-add-module',\n      description:\n        'Use when the user asks to add a new feature module (controller + service + repo + DTOs).',\n      body: `**Trigger phrases**: \"add a users module\", \"scaffold tasks\", \"new feature for X\".\n\n**Steps**:\n1. Run \\`kick g module <name>\\` (use plural form if the project pluralizes — check \\`kick.config.ts\\`).\n2. Verify the new folder under \\`src/modules/<name>/\\` contains \\`<name>.module.ts\\` (filename suffix is mandatory for Vite HMR).\n3. Confirm the module appears in \\`src/modules/index.ts\\` exports — generator does this automatically; verify if you bypassed it.\n4. Open \\`<name>.dto.ts\\` and tighten the Zod schemas to real fields (the generator emits placeholders).\n5. Run \\`${pm} run typecheck\\` and \\`${pm} run test\\` before claiming done.\n\n**Canonical module shape** — \\`defineModule\\` factory, never \\`class implements AppModule\\`:\n\n\\`\\`\\`ts\nexport const TodosModule = defineModule({\n  name: 'TodosModule',\n  build: () => ({\n    register(container) {\n      container.registerFactory(TODO_REPO, () => container.resolve(InMemoryTodoRepository))\n    },\n    routes() {\n      return { path: '/todos', controller: TodosController }\n    },\n  }),\n})\n\\`\\`\\`\n\nThe module file MUST include \\`import.meta.glob([...], { eager: true })\\` for every \\`@Controller\\` / \\`@Service\\` / \\`@Repository\\` / \\`@Component\\` class — without it, decorators never fire and DI silently resolves to \\`undefined\\` (or routes vanish). Use **recursive** patterns (\\`./**/*.controller.ts\\`) so the glob keeps working when you nest files into sub-folders (\\`controllers/\\`, \\`presentation/\\`, …). If you reorganise and a class stops loading, \\`kick typegen\\` flags it as orphaned and \\`kick typegen --fix\\` patches the glob for you.\n\n**Multiple route sets / versioning** — \\`routes()\\` may return an array with per-entry \\`version\\` override:\n\n\\`\\`\\`ts\nroutes() {\n  return [\n    { path: '/todos', controller: TodosController },               // /api/v1/todos\n    { path: '/todos', version: 2, controller: TodosV2Controller }, // /api/v2/todos\n  ]\n}\n\\`\\`\\`\n\n**Conditional / per-tenant mounting** — use \\`bootstrap({ setup(registry) { registry.mount(...) } })\\`, not the static \\`modules\\` array.\n\n**Composition** — \\`defineModules().mount(TodosModule()).mount(UsersModule())\\` (fluent) or \\`AppModuleEntry[]\\` (array form).\n\n**Red flags** (stop and ask):\n- File created as \\`<name>.ts\\` instead of \\`<name>.module.ts\\` — Vite plugin's \\`*.module.[tj]sx?\\` glob doesn't pick it up; every save becomes a full restart.\n- \\`@Controller('/path')\\` with a path argument combined with module \\`routes().path\\` — duplicates the prefix. The decorator path is OpenAPI metadata only.\n- \\`TodosModule\\` in \\`bootstrap({ modules: [TodosModule] })\\` instead of \\`TodosModule()\\` — passing the factory instead of the invoked instance.\n- \\`routes()\\` returning \\`router: …\\` when a \\`controller:\\` would do — controller form is required for OpenAPI/Swagger introspection.\n- Module not registered in \\`src/modules/index.ts\\`.`,\n    },\n    {\n      slug: 'add-adapter',\n      frontmatterName: 'kickjs-add-adapter',\n      description:\n        'Use when wiring a single-concern lifecycle integration (Swagger, DevTools, Sentry, Redis client).',\n      body: `**Steps**:\n1. \\`kick g adapter <name>\\` to scaffold the boilerplate, OR install via \\`kick add <package>\\` for first-party adapters.\n2. The generated file uses \\`defineAdapter()\\` — never \\`class implements AppAdapter\\`.\n3. Add the adapter instance (note the parens) to \\`src/adapters/index.ts\\` — don't inline in \\`src/index.ts\\`.\n4. Pick the right hook and middleware phase deliberately.\n5. Verify with \\`kick dev\\` that the adapter's lifecycle logs fire.\n\n**Canonical shape** — factory closure owns instance state:\n\n\\`\\`\\`ts\nexport const RedisAdapter = defineAdapter<RedisConfig>({\n  name: 'RedisAdapter',\n  defaults: { url: 'redis://localhost' },\n  build: (config) => {\n    const client = createClient(config.url)\n    return {\n      beforeStart: ({ container }) => {\n        container.registerInstance(REDIS_CLIENT, client)\n      },\n      afterStart: () => client.connect(),\n      shutdown: () => client.quit(),\n    }\n  },\n})\n\n// In src/adapters/index.ts:\nexport const adapters = [RedisAdapter({ url: env.REDIS_URL })] // <-- note parens\n\\`\\`\\`\n\n**Lifecycle hook decision tree**:\n- \\`beforeMount\\` — register early routes that should bypass middleware (health, docs UI).\n- \\`beforeStart\\` — DI ready, server not listening yet. **Use this for \\`container.registerInstance(...)\\` calls** so they work under \\`createTestApp\\` too.\n- \\`afterStart\\` — server has \\`ctx.server\\` available. Only use for things that need a listening server (Socket.IO upgrades, port logging). **Doesn't fire under \\`createTestApp\\`.**\n- \\`shutdown\\` — runs concurrently via \\`Promise.allSettled\\`, so one failure doesn't block siblings (but errors are swallowed — log inside).\n\n**Middleware phases** (see \\`MiddlewarePhase\\` JSDoc):\n\\`beforeGlobal\\` | \\`afterGlobal\\` (default) | \\`beforeRoutes\\` | \\`afterRoutes\\` (fires only on fall-through — matched routes that respond skip it).\n\n**Multi-instance** — \\`.scoped('cache', { url: ... })\\` makes \\`name\\` become \\`RedisAdapter:cache\\`. **Deferred config** — \\`.async({ inject, useFactory })\\` for config that depends on DI-resolved services.\n\n**Red flags**:\n- \\`bootstrap({ adapters: [MyAdapter] })\\` — passed the factory, not the instance. Call it: \\`MyAdapter()\\`.\n- Inlining the adapter list directly in \\`src/index.ts\\` — entry file should stay thin.\n- Returning a plain object instead of going through \\`defineAdapter()\\` — type inference for \\`config\\` will be wrong.\n- Using \\`.async()\\` for an adapter that returns \\`middleware()\\` / \\`contributors()\\` / \\`beforeMount()\\` / \\`onRouteMount()\\` — those hooks have already run by the time \\`.async()\\` resolves and are silently skipped.\n- Cross-adapter ordering via array position when it's load-bearing — use \\`dependsOn: ['OtelAdapter']\\`; cycles throw \\`MountCycleError\\` at boot.\n- Using an adapter when the integration ships **modules + DI bindings + middleware** together → that's a plugin. Promote to \\`definePlugin()\\` (see \\`add-plugin\\` skill).\n\n**Nuances**:\n- \\`AdapterContext.server\\` is \\`undefined\\` outside \\`afterStart\\`.\n- \\`shutdown\\` errors are swallowed by \\`Promise.allSettled\\` — wrap in try/catch and log if you care.`,\n    },\n    {\n      slug: 'add-plugin',\n      frontmatterName: 'kickjs-add-plugin',\n      description:\n        'Use when scaffolding a feature that bundles modules + DI + middleware + adapters together (auth, monitoring suite, multi-tenant scaffolding).',\n      body: `**When plugin > adapter**: a plugin is the right answer when the integration ships **more than one** of: a module, a DI binding, middleware, or another adapter. If you have a single hook (\\`beforeStart\\`) and no other contributions, use \\`defineAdapter\\` instead.\n\n**Canonical shape**:\n\n\\`\\`\\`ts\nimport { definePlugin } from '@forinda/kickjs'\n\nexport const AuthPlugin = definePlugin({\n  name: 'AuthPlugin',\n  defaults: { tokenTtl: '1h' },\n  build: (config, { name }) => ({\n    modules: () => [AuthModule()],\n    adapters: () => [JwtAdapter({ ttl: config.tokenTtl })],\n    middleware: () => [requestIdMiddleware()],\n    register(container) {\n      container.registerFactory(TOKEN_SIGNER, () => createSigner(config))\n    },\n    contributors() {\n      return [LoadCurrentUser.registration]\n    },\n    onReady({ server }) {\n      log.info(\\`AuthPlugin listening on port \\${server.address().port}\\`)\n    },\n  }),\n})\n\n// In bootstrap:\nbootstrap({ plugins: [AuthPlugin({ tokenTtl: env.TOKEN_TTL })] }) // <-- parens\n\\`\\`\\`\n\n**Inline plugin literal** — the canonical answer for one-off DI bindings. There's no top-level \\`register:\\` on \\`bootstrap\\` itself:\n\n\\`\\`\\`ts\nbootstrap({\n  plugins: [{ name: 'vector-store', register(c) { c.registerInstance(VECTOR_STORE, store) } }],\n})\n\\`\\`\\`\n\n**Execution order** (memorize):\nplugin \\`register()\\` → plugin \\`middleware()\\` → plugin \\`modules()\\` + user modules → plugin \\`adapters()\\` + user adapters → server listens → plugin \\`onReady()\\`.\n\n**Static vs dynamic modules**: \\`modules()\\` returning an array is introspectable (Swagger, DevTools see it). \\`setup(registry)\\` is imperative — pick the latter when the module set depends on resolved config.\n\n**Multi-instance** — \\`.scoped('users', { url })\\`; derive unique DI tokens from \\`ctx.name\\` inside \\`build\\`:\n\n\\`\\`\\`ts\nbuild: (config, { name }) => ({\n  register(c) {\n    c.registerInstance(createToken(\\`cache/\\${name}\\`), client)\n  },\n})\n\\`\\`\\`\n\n**Precedence**: plugin contributors land at \\`'adapter'\\` precedence — beat global, lose to module/class/method same-key.\n\n**Red flags**:\n- \\`bootstrap({ plugins: [AuthPlugin] })\\` — passed factory. Call it: \\`AuthPlugin()\\`.\n- Reaching for a plugin when an adapter would do (no modules, no DI bindings, no contributors) — overkill; use \\`defineAdapter()\\`.\n- \\`.async()\\` plugin that depends on \\`modules()\\` / \\`middleware()\\` / \\`adapters()\\` / \\`contributors()\\` — those are dropped. \\`.async()\\` only resolves \\`register()\\` + \\`onReady()\\`.\n- Confusing CLI plugins (\\`defineCliPlugin\\` from \\`@forinda/kickjs-cli\\`) with runtime plugins (\\`definePlugin\\` from \\`@forinda/kickjs\\`) — different surfaces, different registration sites.\n- \\`dependsOn: ['SomePlugin']\\` referring to a plugin not in the boot list — throws \\`MissingMountDepError\\` at boot.\n\n**Nuances**:\n- \\`definition\\` is \\`Object.freeze\\`'d metadata; useful for version checks (\\`compare(AuthPlugin.definition.version, '1.2.0')\\`) — not mountable.`,\n    },\n    {\n      slug: 'write-controller-test',\n      frontmatterName: 'kickjs-write-controller-test',\n      description: 'Use when adding a Vitest test that exercises an HTTP route or DI graph.',\n      body: `**Template** (copy/paste, adjust):\n\n\\`\\`\\`ts\nimport { describe, it, expect, beforeEach } from 'vitest'\nimport request from 'supertest'\nimport { Container } from '@forinda/kickjs'\nimport { createTestApp } from '@forinda/kickjs-testing'\n// Side-effect import — registers the env schema, exactly as src/index.ts does.\n// \\`createTestApp\\` never loads the entry file, so without this\n// \\`ConfigService.get('YOUR_KEY')\\` is undefined under test while \\`@Value()\\`\n// still appears to work via its process.env fallback — the two disagree only\n// in tests.\nimport '@/config'\n\ndescribe('UserController', () => {\n  beforeEach(() => Container.reset()) // isolate DI between tests\n\n  it('returns users', async () => {\n    // \\`createTestApp\\` takes an OPTIONS OBJECT and returns\n    // \\`{ app, expressApp, container }\\`. Passing a bare array throws\n    // \"this.options.modules is not iterable\"; the result has no \\`.get()\\`.\n    const { expressApp } = await createTestApp({\n      modules: [UserModule],\n    })\n    const res = await request(expressApp).get('/api/v1/users')\n    expect(res.status).toBe(200)\n  })\n})\n\\`\\`\\`\n\n**Typed handler signature** — pair with \\`kick typegen\\` so \\`ctx.body\\` / \\`params\\` / \\`query\\` are typed by the route's Zod schema:\n\n\\`\\`\\`ts\n@Post('/', { body: createTodoSchema })\nasync create(ctx: Ctx<KickRoutes.TodoController['create']>) {\n  // ctx.body is typed from createTodoSchema; ctx.params from the route.\n  // Returning (vs ctx.created) lets typegen infer the response type.\n  return reply(201, await this.service.create(ctx.body))\n}\n\\`\\`\\`\n\n**Red flags**:\n- \\`new Container()\\` — wrong; use \\`Container.reset()\\` in \\`beforeEach\\` or \\`Container.create()\\` for fully isolated graphs.\n- \\`Container.getInstance().reset()\\` — wrong; same fix.\n- Sharing a container instance across \\`it()\\` blocks — leaks registrations between tests.\n- Injecting a \\`Scope.REQUEST\\` service into a \\`SINGLETON\\` — container throws at resolve. Singletons must resolve request-scoped services explicitly per call.\n- Calling \\`getRequestValue<string>('traceId')\\` — the generic slot is the **key** type, not the value type; widens key and bypasses typed lookup.\n- Asserting on \\`res.body.requestId\\` when \\`requestId()\\` middleware isn't mounted in the test app — value will be \\`undefined\\`.\n- Using \\`Scope.REQUEST\\` services in a test without mounting \\`requestScopeMiddleware()\\` — \\`getRequestValue\\` silently returns \\`undefined\\`; \\`getRequestStore\\` throws.\n\n**Nuances**:\n- \\`@Inject\\` and \\`@Autowired\\` are interchangeable — same runtime, same types; pick by readability.\n- \\`@Value('MISSING_KEY')\\` with no default **throws on property access**, not at construction — tests that exercise the getter will surface the missing-env issue.`,\n    },\n    {\n      slug: 'env-wiring-check',\n      frontmatterName: 'kickjs-env-wiring-check',\n      description:\n        \"Use when ConfigService.get('SOME_KEY') returns undefined or @Value silently falls back to process.env.\",\n      body: `**Fastest path**: \\`kick explain \"ConfigService.get('MY_KEY') returned undefined\"\\` —\npipe a failing run straight in if you prefer (\\`pnpm test 2>&1 | kick explain\\`). It\ndistinguishes the entry-file cause from the test-file one, which is the step most\npeople lose time on. The manual checks below are the same reasoning.\n\n**Diagnosis (in order)**:\n1. Open \\`src/index.ts\\`. The **first non-\\`reflect-metadata\\`** import MUST be \\`import './config'\\`.\n2. Open \\`src/config/index.ts\\`. It MUST run the loader as a top-level side effect — not just declare the schema. This is what \\`kick new\\` generates:\n   \\`\\`\\`ts\n   import { loadEnvFromSchema } from '@forinda/kickjs/config'\n   import { fromZod } from '@forinda/kickjs-schema/zod'\n   const envSchema = fromZod(z.object({ DATABASE_URL: z.string().url() }))\n   export const env = loadEnvFromSchema(envSchema)\n   \\`\\`\\`\n   (\\`loadEnv(zodSchema)\\` from \\`@forinda/kickjs\\` is the equivalent for a bare Zod\n   object. Either is fine — what matters is that it RUNS at module load.)\n3. The new key MUST be declared in the Zod schema. \\`@Value('NEW_KEY')\\` accepts any string at the type level and **falls back to raw \\`process.env\\`** when the schema doesn't know the key — silently skipping Zod coercion.\n4. After adding a key, re-run \\`kick typegen\\` (or restart \\`kick dev\\` if the typegen watcher missed it) so the global \\`KickEnv\\` augmentation picks it up.\n\n5. **In a test?** \\`createTestApp\\` never loads \\`src/index.ts\\`, so the entry's\n   \\`import './config'\\` never runs no matter how correct it is. The test file\n   must import it itself:\n   \\`\\`\\`ts\n   import '@/config'\n   \\`\\`\\`\n   Symptom is identical to the missing-entry-import case, and step 1 will look\n   fine, which is what makes it slow to spot.\n\n**Why \\`@Value\\` \"works\" but \\`ConfigService.get\\` doesn't**: \\`@Value\\` has the \\`process.env\\` fallback that masks missing-side-effect-import bugs; \\`ConfigService\\` has none. If \\`@Value('FOO')\\` returns a value but \\`ConfigService.get('FOO')\\` returns \\`undefined\\`, the side-effect import of \\`./config\\` is missing.\n\n**\\`reloadEnv\\` vs \\`resetEnvCache\\`** — distinct, frequently mixed up:\n- \\`reloadEnv()\\` — re-reads \\`process.env\\` against the **already registered** schema. Use in HMR plugins after \\`.env\\` file changes. Schema survives.\n- \\`resetEnvCache()\\` — drops the registered schema entirely. **Test-only.** Calling it between dev requests drops the project's keys.\n\n**Nuances**:\n- \\`loadEnv()\\` cache is **sticky**: once \\`loadEnv(extendedSchema)\\` runs anywhere, no-arg calls reuse it — but only if it actually ran. Schema downgrades silently if \\`src/config/index.ts\\` isn't imported.\n- \\`createConfigService(envSchema)\\` is deprecated; the typegen-driven \\`ConfigService\\` covers it.\n- \\`dotenv\\` is an **optional peer dep** in v5+ — projects upgrading from older versions may need to add it explicitly.\n- For HMR-friendly \\`.env\\` edits, add \\`envWatchPlugin()\\` to \\`vite.config.ts\\` — calls \\`reloadEnv()\\` automatically.\n\n**Fix recipe**: add the key to the schema; add \\`import './config'\\` as the first non-reflect-metadata import in \\`src/index.ts\\`; add \\`import '@/config'\\` to any test that reads config; re-run \\`kick typegen\\`.`,\n    },\n    {\n      slug: 'bootstrap-export',\n      frontmatterName: 'kickjs-bootstrap-export',\n      description:\n        \"Use when HMR is silently doing full restarts on every save, or createTestApp can't find the app handle.\",\n      body: `**Check** \\`src/index.ts\\`'s last line:\n\n\\`\\`\\`ts\n// CORRECT — Vite plugin + createTestApp import the named \\`app\\` symbol\nexport const app = await bootstrap({ ... })\n\n// WRONG — HMR degrades to full restart, createTestApp loses the handle\nawait bootstrap({ ... })\n\\`\\`\\`\n\nThe Vite plugin imports the named \\`app\\` symbol via \\`virtual:kickjs/app\\`; testing helpers do too. Without the export, both fall back to slower paths (full restart on save, mock handle in tests) **without warning**.\n\n**Red flags**:\n- A bare \\`await bootstrap(...)\\` with no \\`export\\` — fix by adding \\`export const app =\\`.\n- Re-assigning \\`app\\` later in the file (\\`app = somethingElse\\`) — Vite imports by reference at module-load time; reassignments don't propagate.\n- Multiple files calling \\`bootstrap()\\` — only the entry should. Tests use \\`createTestApp\\` instead.`,\n    },\n    {\n      slug: 'thin-entry-file',\n      frontmatterName: 'kickjs-thin-entry-file',\n      description:\n        'Use when src/index.ts is accumulating module/middleware/plugin/adapter literals.',\n      body: `**Refactor target**:\n\n\\`\\`\\`ts\n// src/modules/index.ts — fluent chain (default for \\`modules.style: 'define'\\`)\nexport const modules = defineModules().mount(HelloModule()).mount(UsersModule())\n// OR for class-form projects (\\`modules.style: 'class'\\`):\n//   export const modules: AppModuleEntry[] = [HelloModule, UsersModule]\n\n// src/middleware/index.ts — global middleware uses RAW EXPRESS signature\n//                            (req, res, next), NOT (ctx, next)\n// \\`express.json()\\` is auto-skipped on Fastify and h3, which parse bodies\n// natively — harmless to list, but don't reach for it as the body parser there.\nexport const middleware = [requestId(), express.json(), helmet(), cors(), traceContext()]\n\n// src/plugins/index.ts\nexport const plugins = [MetricsPlugin(), AuthPlugin({ tokenTtl: env.TOKEN_TTL })]\n\n// src/adapters/index.ts\nexport const adapters = [SwaggerAdapter({ ... }), DevToolsAdapter()]\n\n// src/index.ts — stays small\nimport 'reflect-metadata'\nimport './config' // MUST be early — side-effect schema load\nimport { bootstrap } from '@forinda/kickjs'\nimport { modules } from './modules'\nimport { middleware } from './middleware'\nimport { plugins } from './plugins'\nimport { adapters } from './adapters'\nexport const app = await bootstrap({ modules, middleware, plugins, adapters })\n\\`\\`\\`\n\n**One-off DI binding** — inline a literal plugin inside \\`plugins\\`, not a top-level option:\n\n\\`\\`\\`ts\nplugins: [\n  ...plugins,\n  { name: 'vector-store', register(c) { c.registerInstance(VECTOR_STORE, store) } },\n]\n\\`\\`\\`\n\n**Red flags**:\n- Any \\`new SomeAdapter()\\` / \\`SomePlugin()\\` literal inside \\`bootstrap({ ... })\\` instead of imported from a category folder.\n- Mixing middleware signatures: \\`bootstrap({ middleware })\\` is **raw Express** \\`(req, res, next)\\`; \\`@Middleware()\\` decorators are \\`(ctx, next)\\`; adapter middleware is raw Express again. Wrong shape in the wrong slot throws \"Cannot read properties of undefined\".\n- \\`bootstrap({ register: ... })\\` — that option doesn't exist. Use an inline plugin.`,\n    },\n    {\n      slug: 'context-contributor',\n      frontmatterName: 'kickjs-context-contributor',\n      description:\n        \"Use when a middleware's only job is to set ctx values consumed elsewhere — replace with defineHttpContextDecorator (HTTP) or defineContextDecorator (transport-agnostic).\",\n      body: `**Pattern** (HTTP — most common):\n\n\\`\\`\\`ts\nimport { defineHttpContextDecorator, type RequestContext } from '@forinda/kickjs'\n\n// Augment ContextMeta — required for ctx.get('tenant') to be typed\ndeclare module '@forinda/kickjs' {\n  interface ContextMeta {\n    tenant: { id: string; name: string }\n  }\n}\n\n// The \\`declare module\\` block above is all you need. \\`defineAugmentation\\` is\n// DEPRECATED — it only added a typegen catalogue entry, never any types.\n\nconst LoadTenant = defineHttpContextDecorator({\n  key: 'tenant',\n  deps: { repo: TENANT_REPO }, // typed DI\n  resolve: (ctx, { repo }) => repo.findById(ctx.req.headers['x-tenant-id'] as string),\n})\n\nconst LoadProject = defineHttpContextDecorator({\n  key: 'project',\n  dependsOn: ['tenant'], // typo'd key = tsc error\n  resolve: (ctx) => projectsRepo.find(ctx.get('tenant')!.id, ctx.params.id),\n})\n\n@LoadTenant\n@LoadProject\n@Get('/projects/:id')\ngetProject(ctx: RequestContext) {\n  return ctx.get('project')\n}\n\\`\\`\\`\n\nUse \\`defineContextDecorator\\` (no Http prefix) only when the contributor must run across HTTP, WebSocket, queue, and cron transports — \\`Ctx\\` defaults to the smaller \\`ExecutionContext\\` surface (\\`get\\` / \\`set\\` / \\`requestId\\` only, no \\`req\\`).\n\n**Five precedence levels** (high → low):\n**method > class > module > adapter > global**\n\nSame-key collisions WITHIN a precedence level throw \\`DuplicateContributorError\\`. Across levels, the higher precedence silently overrides — a feature, not a bug, but debug it by giving resolvers distinguishable return values.\n\n**Boot-time validation**:\n- Cycles in \\`dependsOn\\` → \\`ContributorCycleError\\`.\n- \\`dependsOn\\` referring to an unknown key → \\`MissingContributorError\\`.\n- Both errors fail boot, not first request.\n\n**Critical rules — all stem from the same shared-via-ALS instance model**:\n- Every per-request stage (middleware → contributors → handler) gets its OWN \\`RequestContext\\` instance, but they all read/write the SAME \\`AsyncLocalStorage\\`-backed bag.\n- **\\`resolve\\` and \\`onError\\` must RETURN the value** — the runner writes it via \\`ctx.set(key, value)\\`. Direct property assignment (\\`ctx.tenant = …\\`) sticks to one instance only and the handler instance never sees it.\n- \\`ctx.set('tenant', x)\\` then \\`ctx.get('tenant')\\` works across instances. \\`ctx.req.headers[...]\\` works (the underlying node request is shared). Note it is a node \\`IncomingMessage\\` on Fastify and h3, not an \\`express.Request\\`.\n- Services with no \\`ctx\\` reference: \\`getRequestValue('tenant')\\` returns \\`MetaValue<'tenant'> | undefined\\` (typed via the augmented \\`ContextMeta\\`). For \\`requestId\\` use \\`getRequestStore()\\`.\n- **No \\`setRequestValue\\` — writes flow through \\`ctx.set\\` or a contributor's return value.** Avoids \"spooky action at a distance\" where any service can pollute the per-request bag.\n\n**Error matrix**:\n- \\`optional: true\\` — \\`resolve\\` throws → key left unset; downstream sees \\`ctx.get(key) === undefined\\`.\n- \\`optional: false\\` (default) + \\`onError\\` — return a fallback value to write; return \\`undefined\\` to skip; throw to forward to the request error handler.\n- \\`optional: false\\` + no \\`onError\\` — throw propagates straight to the request error handler.\n\n**Don't use this for**: response short-circuit, stream mutation, or pre-route-matching work — keep \\`@Middleware()\\` for those.\n\n**Red flags**:\n- \\`ctx.get('key')!\\` — the non-null assertion compiles even when the producing decorator isn't on the route. Use \\`ctx.require('key')\\`.\n- \\`contributors: [LoadX]\\` at a module / adapter / bootstrap site — those take registrations: \\`LoadX.registration\\` or \\`LoadX.with({ ... }).registration\\`.\n- A \\`paramDefaults\\` value that every call site overrides (\\`action: 'settings:read'\\`) — drop it and let the compiler require the field at each site.\n- \\`defineContextDecorator<'k', Deps, Params>(spec)\\` positional form for a parameterised contributor — use \\`.withParams<Params>()(spec)\\` or \\`deps\\` inference is lost.\n- \\`ctx.tenant = x\\` instead of returning the value from \\`resolve\\` — sticks to one instance only.\n- Reaching for \\`defineAugmentation\\` — deprecated, and it never affected types. The \\`declare module\\` block alone is what makes \\`ctx.get('tenant')\\` typed.\n- Plugin / adapter authors using bare keys (\\`'state'\\`) instead of namespaced (\\`'@my-plugin/state'\\`) — collides with adopter keys.\n- \\`getRequestValue<string>('traceId')\\` — generic is the **key** type, not value type.`,\n    },\n    {\n      slug: 'guard-vs-middleware-vs-contributor',\n      frontmatterName: 'kickjs-guard-vs-middleware-vs-contributor',\n      description:\n        'Use when adding auth checks, request-scoped values, or anything \"before the handler\" — picks between a guard, a middleware, and a context contributor.',\n      body: `**KickJS has no guard primitive.** There is no \\`@Guard\\`, no \\`canActivate\\`, no guard\nclass to implement. A guard IS a middleware — the word only names a convention\nand a directory. If you are porting NestJS habits, this is the first thing to\nunlearn.\n\n| | Guard | Middleware | Context contributor |\n|---|---|---|---|\n| What it is | a middleware, by convention | a middleware | a declarative value producer |\n| Signature | \\`(ctx, next)\\` | \\`(ctx, next)\\` on \\`@Middleware()\\`, \\`(req, res, next)\\` in \\`bootstrap({ middleware })\\` | \\`resolve(ctx, deps)\\` returning a value |\n| Can end the request | yes | yes | **no** |\n| Runs | in the middleware stage | in the middleware stage | after ALL middleware |\n| Attached by | \\`@Middleware(fn)\\` | \\`@Middleware(fn)\\` or \\`bootstrap({ middleware })\\` | \\`@LoadX\\`, or a registration at module / adapter / bootstrap level |\n| Generator | \\`kick g guard <name>\\` | \\`kick g middleware <name>\\` | \\`kick g contributor <name>\\` |\n| Lands in | \\`src/guards/<name>.guard.ts\\` | \\`src/middleware/<name>.middleware.ts\\` | \\`src/contributors/<name>.contributor.ts\\` |\n\nAdd \\`-m <module>\\` to any of those generators to place the file inside a module\ninstead of the app-level directory.\n\n**Choosing**: does the thing ever need to STOP the request?\n- Yes, and it is authorization → guard.\n- Yes, anything else (rate limit, body rewrite, response stream, work before route matching) → middleware.\n- No, it only computes a value the handler or a service reads off \\`ctx\\` → contributor. Typed, ordered, boot-validated, and it cannot silently swallow the request.\n\n**Ordering — guards run BEFORE contributors.** Every runtime does the same\nthing: run \\`entry.middlewares\\` in order, bail if the response was written,\nthen run the contributor pipeline, then the handler. So:\n\n\\`\\`\\`ts\n// WRONG — tenant is always undefined here.\nexport async function tenantGuard(ctx: RequestContext, next: () => void) {\n  const tenant = ctx.get('tenant') // contributors have not run yet\n  if (!tenant) return ctx.problem.forbidden()\n  next()\n}\n\\`\\`\\`\n\nA guard that needs a resolved value must resolve it itself, or the check\nbelongs in the contributor's own \\`resolve\\` (throw from there and the request\nerror handler takes over).\n\n**Write responses with \\`ctx.*\\`, never \\`ctx.res\\`.** \\`ctx.res\\` is the ENGINE-NATIVE\nresponse object, so \\`ctx.res.status(401).json(...)\\` only works on Express —\n\\`FastifyReply\\` has no \\`.json()\\` and h3's event has no \\`.status()\\`. Use\n\\`ctx.problem.unauthorized({ detail })\\` (RFC 9457) or \\`ctx.json(body, status)\\`;\nthose work on all four runtimes.\n\n**Guard shape**:\n\n\\`\\`\\`ts\nimport type { RequestContext } from '@forinda/kickjs'\n\nexport async function adminGuard(ctx: RequestContext, next: () => void): Promise<void> {\n  const user = ctx.session?.user // requires the session middleware\n  if (!user) {\n    ctx.problem.unauthorized({ detail: 'Not signed in' })\n    return // do NOT call next()\n  }\n  if (user.role !== 'admin') {\n    ctx.problem.forbidden({ detail: 'Admin only' })\n    return\n  }\n  next()\n}\n\\`\\`\\`\n\n\\`\\`\\`ts\n@Middleware(adminGuard)\n@Get('/admin/stats')\nstats(ctx: RequestContext) { ... }\n\\`\\`\\`\n\nRole checks that are purely declarative (\\`@Public()\\`, \\`@Roles('admin')\\`,\n\\`@Can(...)\\`) come from \\`@forinda/kickjs-auth\\` and need its adapter mounted.\nHand-write a guard only for logic those don't express.\n\n**Red flags**:\n- \\`class AdminGuard implements CanActivate\\` / \\`@UseGuards()\\` — NestJS, not KickJS. Export a \\`(ctx, next)\\` function and attach with \\`@Middleware()\\`.\n- A guard calling \\`next()\\` AND writing a response — pick one; writing then continuing double-sends.\n- A guard reading \\`ctx.get(...)\\` for a contributor-produced key — contributors have not run yet.\n- \\`ctx.res.status(403).json(...)\\` in a guard — Express-only. Use \\`ctx.problem.forbidden()\\`.\n- A \"guard\" that only sets a value and always calls \\`next()\\` — that is a contributor wearing a guard's name.\n- Passing a \\`(ctx, next)\\` guard to \\`bootstrap({ middleware })\\` — global middleware is connect-style \\`(req, res, next)\\`. Mount guards per-route with \\`@Middleware()\\`.\n`,\n    },\n    {\n      slug: 'query-parsing-list-endpoint',\n      frontmatterName: 'kickjs-query-parsing-list-endpoint',\n      description:\n        'Use when adding a paginated/filterable list route — emit ctx.qs + ctx.paginate with an allow-list.',\n      body: `**Canonical list endpoint**:\n\n\\`\\`\\`ts\n@Get('/')\nasync list(ctx: Ctx<KickRoutes.TodoController['list']>) {\n  const parsed = ctx.qs({\n    filterable: ['status', 'priority', 'assigneeId'], // allow-list, MUST be set\n    sortable: ['createdAt', 'updatedAt', 'priority'],\n    searchColumns: ['title', 'description'], // free-text search targets\n  })\n\n  return ctx.paginate(async () => {\n    const { data, total } = await this.service.list(parsed)\n    return { data, total }\n  }, parsed)\n}\n\\`\\`\\`\n\n**Operator format** (fixed): \\`?filter=field:op:value\\` where \\`op ∈ eq | neq | gt | gte | lt | lte | between | in | contains | starts | ends\\`. Sort is \\`?sort=field:asc|desc\\`. Only the first two colons are delimiters, so timestamps work (\\`createdAt:gt:2026-01-01T00:00:00Z\\`).\n\n**Drizzle adopters** — pass a \\`DrizzleQueryParamsConfig\\` with column refs:\n\n\\`\\`\\`ts\nconst TASK_QUERY_CONFIG = {\n  filterable: { status: tasks.status, priority: tasks.priority },\n  sortable: { createdAt: tasks.createdAt },\n  searchColumns: [tasks.title, tasks.description],\n}\nconst parsed = ctx.qs(TASK_QUERY_CONFIG)\n\\`\\`\\`\n\n**ORM-agnostic builders** — implement \\`QueryBuilderAdapter<TResult, TConfig>\\` with \\`build(parsed, config)\\`. The Drizzle + Prisma adapters live here.\n\n**Red flags**:\n- Reading \\`req.query.status\\` directly — bypasses the allow-list; opens unbounded filtering. Use \\`ctx.qs({ filterable })\\`.\n- Omitting \\`filterable\\` / \\`sortable\\` allow-list — every client-supplied filter is **silently dropped** (security default, but looks like a bug).\n- Hand-building the pagination meta in the controller — inconsistent response shape across endpoints. Always use \\`ctx.paginate()\\`.\n- Returning a bare array from a list endpoint when pagination is implied — breaks the \\`PaginatedResponse<T>\\` contract.\n- Mixing string \\`searchable\\` config with column \\`searchColumns\\` (Drizzle) — silently no-ops.\n\n**Nuances**:\n- \\`limit\\` is capped at 100 server-side; \\`q\\` (search) is truncated to 200 chars. Don't re-validate client-side.\n- Sort direction defaults to \\`asc\\` when omitted (\\`?sort=createdAt\\` ≡ \\`?sort=createdAt:asc\\`).`,\n    },\n    {\n      slug: 'use-asset-manager',\n      frontmatterName: 'kickjs-use-asset-manager',\n      description:\n        'Use when code reads template files / JSON fixtures via fs.readFile + path arithmetic — switch to assets.<ns>.<key>() and the kick.config.ts assetMap.',\n      body: `**Configure** \\`kick.config.ts\\`:\n\n\\`\\`\\`ts\nexport default defineConfig({\n  assetMap: {\n    mails: { src: 'src/templates/mails' },\n    reports: { src: 'src/templates/reports', glob: '**/*.{ejs,html}' },\n  },\n})\n\\`\\`\\`\n\n**Consume** via the typed Proxy — no \\`__dirname\\` arithmetic, dev/prod paths handled:\n\n\\`\\`\\`ts\nimport { assets } from '@forinda/kickjs'\n\nconst html = await assets.mails.welcome() // typed: tsc errors on bad key\n\\`\\`\\`\n\n**Class-field decorator** (lazy getter, swappable in tests):\n\n\\`\\`\\`ts\nclass WelcomeMailService {\n  @Asset('mails/welcome') private welcomeTemplate!: () => Promise<string>\n\n  async send(to: string) {\n    const body = await this.welcomeTemplate()\n  }\n}\n\\`\\`\\`\n\n**Dynamic dispatch** (CMS templates, codegen) — \\`resolveAsset(ns, key)\\` throws \\`UnknownAssetError\\` with \\`{ namespace, key }\\` fields when the key is missing.\n\n**Test fixtures** — swap via env override + cache clear:\n\n\\`\\`\\`ts\nbeforeEach(() => {\n  process.env.KICK_ASSETS_ROOT = path.resolve('__fixtures__/assets')\n  clearAssetCache()\n})\nafterEach(() => {\n  delete process.env.KICK_ASSETS_ROOT\n  clearAssetCache()\n})\n\\`\\`\\`\n\n**Red flags**:\n- Hand-rolled \\`process.env.NODE_ENV === 'production' ? join(__dirname, '../templates') : join(__dirname, 'templates')\\` — exactly what the asset manager replaces.\n- \\`keys: 'strip'\\` setting in \\`assetMap.<ns>\\` when basenames may collide — silent last-walk-wins data loss. Default \\`'auto'\\` keeps extensions only for colliding groups.\n- Non-default Vite \\`outDir\\` without mirroring in \\`kick.config.ts\\` — manifest writes at \\`dist/.kickjs-assets.json\\` but the resolver can't find it. Mirror via \\`build.outDir\\`.\n- Forgetting to re-run \\`kick typegen\\` after adding files — \\`assets.mails.newTemplate\\` is a tsc error even though the file ships. \\`kick dev\\` does this on-change; one-shot CI builds need \\`kick build\\` (or \\`kick build:assets\\` for manifest-only).\n- Same-name \\`welcome.ejs\\` + \\`welcome/login.ejs\\` — directory wins in the typed surface; the \\`.ejs\\` file still copies but isn't addressable.\n\n**Nuances**:\n- Resolution pipeline (cached): \\`KICK_ASSETS_ROOT\\` env override > built manifest at \\`build.outDir\\` / \\`dist\\` / \\`build\\` / \\`out\\` > dev-fallback in-memory walk. Manifest presence = \"running from built dist.\"\n- Dev-mode glob matcher is a lite implementation — \\`**/*\\`, \\`**/*.ext\\`, \\`**/*.{a,b}\\` are guaranteed; exotic globs warn-once and accept everything. Run \\`kick build:assets\\` to exercise the real glob engine.`,\n    },\n    {\n      slug: 'cli-commands-cheatsheet',\n      frontmatterName: 'kickjs-cli-commands-cheatsheet',\n      description:\n        'Use as a quick reference for the most common kick CLI workflows — scaffolding, dev/build/start, generation, inspection.',\n      body: `**Top commands**:\n- \\`kick new <name>\\` — start a new project (prompts for template / repo / pm).\n- \\`kick dev\\` — local dev server with Vite HMR.\n- \\`kick build\\` — production bundle via Vite.\n- \\`kick start\\` — run the built artifact (\\`NODE_ENV=production\\` auto-set).\n- \\`kick g module <name>\\` — add a feature module; structure follows \\`pattern\\` in \\`kick.config.ts\\`.\n- \\`kick g scaffold <Name> <field:type>...\\` — full CRUD module from field definitions.\n- \\`kick g guard <name>\\` / \\`kick g middleware <name>\\` / \\`kick g contributor <name>\\` — the three \"before the handler\" shapes. A guard is a middleware by convention, NOT a separate primitive.\n- \\`kick add <pkg>\\` — install optional packages (auto-resolves peer deps + package manager).\n- \\`kick g --list\\` — list every available generator (built-ins + plugin-shipped).\n- \\`kick info\\` — environment / version dump for bug reports.\n- \\`kick inspect\\` — introspect a running app: routes, middleware, adapters, DI graph.\n\n**Useful flag combos**:\n\n\\`\\`\\`bash\nkick new my-api --yes                                  # CI-safe: minimal + inmemory, no prompts\nkick new my-api -t ddd --pm ${pm} --no-git --install   # Fully scriptable DDD scaffold\nkick new . --yes --force                               # Scaffold into current dir, clear existing files\nkick g scaffold Post title:string body:text:optional   # Shell-safe optional field syntax\nkick g agents -f --only skills                         # Refresh just the skills after upgrade\nkick add queue:bullmq                                  # Package + peer deps (bullmq + ioredis) in one shot\nkick inspect --port 4000 --json                        # Machine-readable route/adapter dump\nkick g config --force --repo postgres                  # Drop a kick.config.ts into a legacy project\n\\`\\`\\`\n\n**Lesser-known, high-value**:\n- \\`kick inspect --watch\\` — live route/middleware/adapter table that re-renders on hot reload; faster than re-curling \\`/_debug\\`.\n- \\`kick g agents -f\\` — regenerates \\`CLAUDE.md\\` (root) and \\`.agents/AGENTS.md\\` / \\`GEMINI.md\\` / \\`COPILOT.md\\` + every \\`.agents/skills/<slug>/SKILL.md\\` from the current CLI templates.\n- \\`kick dev:debug\\` — same flags as \\`kick dev\\` but opens a Node inspector port for IDE attach.\n- \\`kick list --all\\` (alias \\`kick ls --all\\`) — full optional-package catalog at this CLI version.\n- \\`kick typegen --watch\\` — standalone typegen watcher when \\`kick dev\\` isn't running.\n- \\`kick check\\` — preflight gate (typecheck + lint + format) before commit.\n- \\`kick codemod\\` — automated AST-level migration between framework versions.\n\n**Red flags**:\n- Using globally-installed \\`@forinda/kickjs-cli\\` while contributing to the monorepo — \\`pnpm link --global\\` from \\`packages/cli\\` so generators match the framework.\n- Writing \\`\"name:type?\"\\` for optional scaffold fields — \\`?\\` is a shell glob in bash/zsh; use \\`name:type:optional\\`.\n- Running \\`kick new <name> --yes\\` in a non-empty directory expecting it to wipe — \\`--yes\\` aborts without \\`--force\\`; pair them when destruction is intended.\n- Skipping \\`kick g config\\` on a legacy project then wondering why generators ignore \\`modules.dir\\` / \\`modules.repo\\`.\n- Editing \\`kick.config.ts\\` with deprecated top-level \\`modulesDir\\` / \\`defaultRepo\\` / \\`schemaDir\\` / \\`pluralize\\` instead of the nested \\`modules\\` block.`,\n    },\n    {\n      slug: 'docs-lookup',\n      frontmatterName: 'kickjs-docs-lookup',\n      description:\n        'Use FIRST when unsure about any KickJS API, option, or behaviour — before guessing from memory or inferring from surrounding code.',\n      body: `These skills are deliberately short — they cover the traps, not the whole API\nsurface. When the answer is not in one of them, read the docs rather than\ninferring it from nearby code: a wrong guess about a framework API compiles\nfine and fails at runtime.\n\n**Where to look**\n\n| Question | Page |\n| --- | --- |\n| Anything — start here | https://kickjs.app/ |\n| Controllers, routing, \\`ctx\\` helpers | https://kickjs.app/guide/controllers |\n| DI, tokens, scopes | https://kickjs.app/guide/dependency-injection |\n| Modules and mounting | https://kickjs.app/guide/modules |\n| Adapters, plugins, lifecycle hooks | https://kickjs.app/guide/adapters |\n| Context Contributors | https://kickjs.app/guide/context-decorators |\n| Env, \\`ConfigService\\`, \\`@Value\\` | https://kickjs.app/guide/configuration |\n| Middleware and guards | https://kickjs.app/guide/middleware |\n| Testing (\\`createTestApp\\`) | https://kickjs.app/guide/testing |\n| Typegen and generated types | https://kickjs.app/guide/typegen |\n| HMR and the dev server | https://kickjs.app/guide/hmr |\n\n**Local, and usually faster**\n\n- \\`kick explain \"<error message>\"\\` — matches known failures and gives the fix.\n  Pipe a failing run in: \\`${pm} test 2>&1 | kick explain\\`.\n- \\`kick doctor\\` — checks this project's wiring.\n- \\`kick inspect\\` — the live route / adapter table.\n- \\`.kickjs/types/\\` — generated types are ground truth for what exists.\n- \\`node_modules/@forinda/kickjs/dist/*.d.mts\\` — the real signature when a doc\n  page and the code disagree.\n\n**Rule**: if you would be guessing, look it up. If a doc page contradicts the\ninstalled \\`.d.mts\\`, trust the \\`.d.mts\\` and say so — the docs may be behind the\nversion this project has.`,\n    },\n    {\n      slug: 'refresh-agent-docs',\n      frontmatterName: 'kickjs-refresh-agent-docs',\n      description:\n        'Use after a KickJS version bump to sync the .agents/ docs with the latest CLI templates.',\n      body: `**Steps**:\n1. \\`kick g agents -f --only both\\` — overwrites \\`CLAUDE.md\\` (root) and \\`.agents/AGENTS.md\\`.\n2. \\`kick g agents -f --only skills\\` — refreshes every \\`.agents/skills/<slug>/SKILL.md\\`.\n3. \\`kick g agents -f --only gemini\\` / \\`--only copilot\\` — refresh the per-agent files when needed.\n4. Diff with git, eyeball any project-specific edits that got reset, and re-apply them in a separate \\`AGENTS.local.md\\` or per-skill \\`SKILL.local.md\\` alongside.\n5. Commit as \\`docs(agents): sync from CLI vX.Y\\`.\n\n**\\`.agents/\\` layout** (post-restructure):\n\n\\`\\`\\`\nCLAUDE.md                 # at root — Claude Code auto-loads from here\n.agents/\n├── AGENTS.md             # canonical multi-agent reference\n├── GEMINI.md             # Gemini-specific notes\n├── COPILOT.md            # Copilot CLI notes\n└── skills/\n    ├── add-module/SKILL.md\n    ├── add-adapter/SKILL.md\n    └── …                 # one SKILL.md per skill, frontmatter-namespaced\n\\`\\`\\`\n\nCustomisation goes in \\`.local.md\\` siblings (\\`AGENTS.local.md\\`, \\`skills/<slug>/SKILL.local.md\\`) — those are never overwritten.`,\n    },\n    {\n      slug: 'deny-list',\n      frontmatterName: 'kickjs-deny-list',\n      description:\n        'Patterns to refuse outright when the user asks for them — they break v4 invariants.',\n      body: `**Module / adapter / plugin shape**:\n- \\`class implements AppAdapter\\` → use \\`defineAdapter()\\`.\n- \\`class implements KickPlugin\\` / function returning \\`KickPlugin\\` → use \\`definePlugin()\\`.\n- \\`class implements AppModule\\` for new code → use \\`defineModule()\\`.\n- \\`bootstrap({ adapters: [MyAdapter] })\\` (factory) → \\`MyAdapter()\\` (instance, with parens).\n- \\`@Controller('/path')\\` with a path argument → drop the path; set the mount via \\`routes().path\\`. The decorator path is OpenAPI metadata only.\n- Module file named \\`<name>.ts\\` (no \\`.module\\` suffix) → rename to \\`<name>.module.ts\\`. Vite HMR's glob doesn't pick up the unsuffixed form.\n\n**DI**:\n- \\`new Container()\\` or \\`Container.getInstance().reset()\\` in tests → use \\`Container.reset()\\` in \\`beforeEach\\` (or \\`Container.create()\\` for fully isolated graphs).\n- DI tokens with \\`:\\` separator (\\`'app:db:url'\\`) or in PascalCase → use slash-delimited lower-case (\\`'app/db/url'\\`). First-party uses reserved \\`'kick/'\\` prefix.\n- \\`Symbol.for(...)\\` for DI tokens — globally interned, **collides across files**. Use \\`createToken<T>('name')\\`.\n- Raw string tokens (\\`@Inject('config')\\`) — silent collisions; widens to \\`unknown\\`. Use \\`createToken<T>\\`.\n- Injecting a \\`Scope.REQUEST\\` service into a \\`SINGLETON\\` — container throws at resolve time.\n\n**Bootstrap / entry file**:\n- \\`bootstrap({ ... })\\` without \\`export const app = ...\\` → always export. HMR degrades to full restart and \\`createTestApp\\` loses the handle.\n- \\`bootstrap({ register: ... })\\` — that option doesn't exist. Use an inline plugin in \\`plugins\\`.\n\n**Middleware**:\n- Using \\`(ctx, next)\\` for global middleware in \\`bootstrap({ middleware })\\` — global middleware uses raw Express \\`(req, res, next)\\`. Wrong signature throws \"Cannot read properties of undefined\".\n- Using \\`(req, res, next)\\` for an \\`@Middleware()\\` decorator — those use \\`(ctx, next)\\`.\n- \\`@Middleware()\\` whose only output is \\`ctx.set('x', v)\\` — should be a context decorator (typed, ordered, testable).\n\n**Context contributors**:\n- \\`ctx.tenant = x\\` from a contributor — only sticks to one \\`RequestContext\\` instance. **Return the value** so the runner writes it via \\`ctx.set(key, value)\\`.\n- Omitting the \\`declare module '@forinda/kickjs'\\` block — without it \\`ctx.get('tenant')\\` is \\`unknown\\`. (\\`defineAugmentation\\` is deprecated and was never a substitute for it.)\n- \\`getRequestValue<string>('traceId')\\` — generic is the **key** type, not value type.\n\n**Env / config**:\n- \\`@Value('NEW_KEY')\\` without the key in the Zod schema — silent fallback to raw \\`process.env\\`, no coercion.\n- \\`resetEnvCache()\\` outside tests — drops the registered schema.\n\n**List endpoints**:\n- Reading \\`req.query.status\\` directly — bypasses the allow-list. Use \\`ctx.qs({ filterable })\\`.\n- Returning a bare array from a list endpoint — breaks the \\`PaginatedResponse<T>\\` contract. Use \\`ctx.paginate()\\`.\n\n**Assets**:\n- Hand-rolled \\`__dirname\\` arithmetic for template paths — use \\`assets.<ns>.<key>()\\` and add the namespace to \\`kick.config.ts assetMap\\`.`,\n    },\n  ]\n\n  return skills\n}\n\nexport function generateKickJsSkillFiles(\n  name: string,\n  _template: ProjectTemplate,\n  pm: string,\n): KickJsSkillFile[] {\n  const banner = `<!-- Generated by \\`kick g agents\\` for ${name}. Edits are overwritten on the next refresh; keep customisation in a SKILL.local.md alongside. -->`\n\n  const skills = buildSkills(pm)\n\n  return skills.map((skill) => ({\n    slug: skill.slug,\n    content: `---\nname: ${skill.frontmatterName}\ndescription: ${skill.description}\n---\n\n${banner}\n\n${skill.body}\n`,\n  }))\n}\n\n/**\n * @deprecated Kept only for back-compat with adopters who programmatically\n * import this function from `@forinda/kickjs-cli`. The CLI itself no\n * longer calls it — `kick g agents` emits per-skill SKILL.md files via\n * {@link generateKickJsSkillFiles}. Will be removed in a future minor.\n */\nexport function generateGemini(name: string, _template: ProjectTemplate, _pm: string): string {\n  return `# GEMINI.md — ${name}\n\n**Read \\`./AGENTS.md\\` first.** It is the canonical, multi-agent\nreference for this project — every convention, structure, decorator\npattern, env wiring rule, generator usage. This file is a thin\nGemini-specific layer; when the two disagree on anything substantive,\ntreat \\`AGENTS.md\\` as authoritative and flag the discrepancy.\n\n## Why this file\n\nGemini CLI auto-loads \\`GEMINI.md\\` when it lives alongside the\nagent-context files. Keeping it in \\`.agents/\\` next to \\`AGENTS.md\\`\nmeans Gemini reads the same shared prose as Codex / Cursor / Copilot\nwithout us copy-pasting.\n\n## Gemini-specific notes\n\n- **Skills activation** — Gemini activates skills via\n  \\`activate_skill\\` (its native MCP-style tool); the equivalent on\n  Claude Code is the \\`Skill\\` tool. Cross-reference the\n  \\`kickjs-skills.md\\` index for the available triggers.\n- **Tool naming** — Gemini's tool names differ from Claude Code's\n  (e.g. \\`read_file\\` vs \\`Read\\`, \\`run_terminal_command\\` vs\n  \\`Bash\\`). The shared prose in \\`AGENTS.md\\` describes intents, not\n  tool names; consult Gemini's docs for the concrete invocation.\n- **File ops** — Gemini's file edits are sandboxed; large refactors\n  may need explicit confirmation. Prefer the smallest-possible-edit\n  pattern.\n\n## Refreshing this file\n\n\\`kick g agents --only gemini -f\\` regenerates this file from the\nCLI template. Hand-edited content is overwritten — keep customisation\nin \\`.agents/GEMINI.local.md\\`.\n`\n}\n\n/**\n * Render the GitHub Copilot CLI agent file emitted at\n * `.agents/COPILOT.md`. Same pattern as `generateGemini` — thin\n * pointer to `.agents/AGENTS.md` with notes specific to Copilot\n * CLI's tool surface and conventions.\n */\nexport function generateCopilot(name: string, _template: ProjectTemplate, _pm: string): string {\n  return `# COPILOT.md — ${name}\n\n**Read \\`./AGENTS.md\\` first.** It is the canonical, multi-agent\nreference for this project — every convention, structure, decorator\npattern, env wiring rule, generator usage. This file is a thin\nCopilot-specific layer; when the two disagree on anything substantive,\ntreat \\`AGENTS.md\\` as authoritative and flag the discrepancy.\n\n## Why this file\n\nGitHub Copilot CLI auto-loads \\`COPILOT.md\\` when it lives alongside\nthe agent-context files. Keeping it in \\`.agents/\\` next to\n\\`AGENTS.md\\` means Copilot reads the same shared prose as\nCodex / Cursor / Gemini / Claude Code without copy-pasting.\n\n## Copilot-specific notes\n\n- **Skills** — Copilot CLI auto-discovers skills from installed\n  plugins; cross-reference \\`kickjs-skills.md\\` for available\n  triggers in this project.\n- **Tool naming** — Copilot's tool names differ from Claude Code's\n  (\\`edit\\` vs \\`Edit\\`, \\`shell\\` vs \\`Bash\\`, etc.). The shared\n  prose in \\`AGENTS.md\\` describes intents, not tool names; consult\n  Copilot's docs for the concrete invocation.\n- **Confirmation flows** — Copilot CLI surfaces destructive\n  operations through an explicit approval gate. Stage edits with\n  short, focused diffs so each one is easy to review at the prompt.\n\n## Refreshing this file\n\n\\`kick g agents --only copilot -f\\` regenerates this file from the\nCLI template. Hand-edited content is overwritten — keep customisation\nin \\`.agents/COPILOT.local.md\\`.\n`\n}\n"],"mappings":"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"}