@forinda/kickjs-cli 8.8.0 → 8.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/{agent-docs-BsXKM5QH.mjs → agent-docs-DUB-1Z6Q.mjs} +34 -13
  2. package/dist/{agent-docs-BsXKM5QH.mjs.map → agent-docs-DUB-1Z6Q.mjs.map} +1 -1
  3. package/dist/{agent-docs-DQksWOe5.mjs → agent-docs-bVMPt2m5.mjs} +33 -12
  4. package/dist/{build-Bnd_mk4h.mjs → build-C30mBgw6.mjs} +3 -3
  5. package/dist/{build-Bnd_mk4h.mjs.map → build-C30mBgw6.mjs.map} +1 -1
  6. package/dist/{build-DPUojF2G.mjs → build-xQXbdDpw.mjs} +2 -2
  7. package/dist/{builtins-BEBO5upe.mjs → builtins-CtpLZ4FY.mjs} +2 -2
  8. package/dist/{builtins-CJTP3xQj.mjs → builtins-DiWfXc-D.mjs} +115 -101
  9. package/dist/cli.mjs +2 -2
  10. package/dist/{config-ty1Nc3PN.mjs → config-YvIngROH.mjs} +2 -2
  11. package/dist/{config-F9g6CNDA.mjs → config-ZHuFjsKI.mjs} +3 -3
  12. package/dist/config-ZHuFjsKI.mjs.map +1 -0
  13. package/dist/{doctor-C8TAKn1d.mjs → doctor-CnsnRW7T.mjs} +4 -4
  14. package/dist/{doctor-C8TAKn1d.mjs.map → doctor-CnsnRW7T.mjs.map} +1 -1
  15. package/dist/{fs-BGHl3dHm.mjs → fs-Bm2St4gk.mjs} +1 -1
  16. package/dist/{fs-BB3QxPj8.mjs → fs-BvGbbHY0.mjs} +2 -2
  17. package/dist/{fs-BB3QxPj8.mjs.map → fs-BvGbbHY0.mjs.map} +1 -1
  18. package/dist/fullstack-B0g06sSQ.mjs +96 -0
  19. package/dist/fullstack-B0g06sSQ.mjs.map +1 -0
  20. package/dist/fullstack-CZ9XQYk-.mjs +95 -0
  21. package/dist/index.d.mts +6 -0
  22. package/dist/index.d.mts.map +1 -1
  23. package/dist/index.mjs +2 -2
  24. package/dist/{plugin-C4Dl_s4-.mjs → plugin-BfdvW6_r.mjs} +2 -2
  25. package/dist/{plugin-Y7BoYk1K.mjs → plugin-Bs0soxrU.mjs} +2 -2
  26. package/dist/{project-3LsfnPLE.mjs → project-B_qDdkYQ.mjs} +89 -23
  27. package/dist/project-B_qDdkYQ.mjs.map +1 -0
  28. package/dist/{project-BIq7_Fzk.mjs → project-Bp-KfBNb.mjs} +88 -22
  29. package/dist/{project-root-CFrn6ftT.mjs → project-root-B9BrO1na.mjs} +3 -3
  30. package/dist/{project-root-CFrn6ftT.mjs.map → project-root-B9BrO1na.mjs.map} +1 -1
  31. package/dist/{project-root-BDRPMlb9.mjs → project-root-LYOxQHXp.mjs} +2 -2
  32. package/dist/{prompts-BJTp1w0l.mjs → prompts-BEAqcbPT.mjs} +2 -2
  33. package/dist/{prompts-BJTp1w0l.mjs.map → prompts-BEAqcbPT.mjs.map} +1 -1
  34. package/dist/{rolldown-runtime-OACgOwtl.mjs → rolldown-runtime-Da-NDvKz.mjs} +1 -1
  35. package/dist/{run-plugins-2DJy76gx.mjs → run-plugins-0AfIgIsZ.mjs} +89 -75
  36. package/dist/run-plugins-0AfIgIsZ.mjs.map +1 -0
  37. package/dist/{typegen-BBzX2LDz.mjs → typegen-BzgWveE_.mjs} +5 -5
  38. package/dist/{typegen-BBzX2LDz.mjs.map → typegen-BzgWveE_.mjs.map} +1 -1
  39. package/dist/{typegen-COAIhZZ4.mjs → typegen-up-UkaNc.mjs} +4 -4
  40. package/dist/{types-gy6PkRFW.mjs → types-ChFFRT8E.mjs} +1 -1
  41. package/package.json +3 -3
  42. package/templates/base/files/src/serverless.ts +6 -0
  43. package/templates/host-config/files/netlify.toml +1 -1
  44. package/templates/template-inertia/files/src/index.ts +4 -2
  45. package/templates/template-inertia/files/vite.client.config.ts +14 -3
  46. package/templates/template-inertia/files/vite.config.ts +9 -5
  47. package/dist/config-F9g6CNDA.mjs.map +0 -1
  48. package/dist/fullstack-D25STbVk.mjs +0 -95
  49. package/dist/fullstack-DWcfo-zl.mjs +0 -96
  50. package/dist/fullstack-DWcfo-zl.mjs.map +0 -1
  51. package/dist/project-3LsfnPLE.mjs.map +0 -1
  52. package/dist/run-plugins-2DJy76gx.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @forinda/kickjs-cli v8.8.0
2
+ * @forinda/kickjs-cli v8.9.0
3
3
  *
4
4
  * Copyright (c) Felix Orinda
5
5
  *
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import{t as e}from"./rolldown-runtime-OACgOwtl.mjs";import{r as t}from"./fs-BB3QxPj8.mjs";import{t as n}from"./prompts-BJTp1w0l.mjs";import{o as r}from"./config-F9g6CNDA.mjs";import{join as i}from"node:path";import{existsSync as a,readFileSync as o}from"node:fs";function s(e,t,n){return`# CLAUDE.md — ${e}
11
+ import{t as e}from"./rolldown-runtime-Da-NDvKz.mjs";import{r as t}from"./fs-BvGbbHY0.mjs";import{t as n}from"./prompts-BEAqcbPT.mjs";import{o as r}from"./config-ZHuFjsKI.mjs";import{join as i}from"node:path";import{existsSync as a,readFileSync as o}from"node:fs";function s(e,t,n){return`# CLAUDE.md — ${e}
12
12
 
13
13
  **Read \`./.agents/AGENTS.md\` first.** It is the canonical, multi-agent
14
14
  reference for this project (Claude, Copilot, Codex, Gemini, etc.) —
@@ -675,27 +675,45 @@ kick g config --force --repo postgres # Drop a kick.config.ts i
675
675
  - Writing \`"name:type?"\` for optional scaffold fields — \`?\` is a shell glob in bash/zsh; use \`name:type:optional\`.
676
676
  - Running \`kick new <name> --yes\` in a non-empty directory expecting it to wipe — \`--yes\` aborts without \`--force\`; pair them when destruction is intended.
677
677
  - Skipping \`kick g config\` on a legacy project then wondering why generators ignore \`modules.dir\` / \`modules.repo\`.
678
- - Editing \`kick.config.ts\` with deprecated top-level \`modulesDir\` / \`defaultRepo\` / \`schemaDir\` / \`pluralize\` instead of the nested \`modules\` block.`},{slug:`route-flags`,frontmatterName:`kickjs-route-flags`,description:`Use when a fact about a route (public, CSRF-exempt, unmetered, expose as a tool) has to be read by auth, CSRF, rate limiting, OpenAPI or MCP — instead of repeating it as paths in each consumer.`,body:"A route flag is a named, inheritable fact about a route. It carries no\nbehaviour: it records something every consumer can read, so \"this endpoint is\nopen\" is declared once instead of restated as an auth contributor, a\n`csrf ignorePaths` entry and a `rateLimit skipPaths` entry — two of which are\npathname strings that cannot express `/users/:id`.\n\n**Steps**:\n1. Declare it once, in its own module:\n ```ts\n import { defineRouteFlag } from '@forinda/kickjs'\n\n export const Public = defineRouteFlag('auth.public')\n export const Limit = defineRouteFlag<{ rpm: number }>('rate.limit')\n ```\n2. Apply it. A class flag is inherited by every route under it; `.off` on a\n method removes it:\n ```ts\n @Public // every route below inherits it\n @Controller()\n export class WebhooksController {\n @Get('/health')\n health(ctx: RequestContext) {} // public\n\n @Public.off // the method wins\n @Post('/admin')\n admin(ctx: RequestContext) {} // not public\n\n @Limit({ rpm: 10 }) // flags can carry a value\n @Post('/login')\n login(ctx: RequestContext) {}\n }\n ```\n3. Read it from the consumer that already exists, rather than a new one.\n **Where a consumer is mounted decides how it reads flags** — everything\n after route matching gets `ctx.route`; anything before it does not:\n\n | Consumer | Mounted at | Reads flags by |\n | --- | --- | --- |\n | Handler | the route itself | `ctx.route?.flags.has('auth.public')` |\n | Guard / `@Middleware()` | `@Middleware(fn)` on a method or controller class | `ctx.route`, or the built-ins' `exemptWhen` |\n | `csrfGuard()` / `rateLimitGuard()` | same — `@Middleware()`, class or method | `exemptWhen: 'csrf.exempt'` |\n | Contributor | method > class > module `contributors()` > adapter `contributors()` > `bootstrap({ contributors })` | `skipWhen` / `onlyWhen` on the registration |\n | Global middleware (`rateLimit()`) | `bootstrap({ middlewares: [...] })` — runs **before** matching | the route policy table (`bindRoutePolicy`); `ctx.route` is `undefined` here |\n | Adapter middleware | `AppAdapter.middleware()`, phase `beforeGlobal` … `afterRoutes` | the policy table — the handler is Express-style `(req, res, next)`, so there is no `ctx` in any phase |\n | OpenAPI | `SwaggerAdapter({ publicFlag: 'auth.public' })` | read once at startup, not per request |\n | MCP / AI tools | `McpAdapter({ exposeWhen: 'mcp.tool', hideWhen: 'mcp.hidden' })` | read once at startup |\n\n The contributor row is the one that buys the most: those five levels mean a\n plugin's contributor can be skipped on one route (`skipWhen`) without\n forking it, and a method-level registration beats the adapter's.\n\n4. Run `kick typegen`. It writes the `KickRouteFlags` augmentation, so flag\n names autocomplete and a typo fails `tsc` instead of silently never matching.\n\n**Red flags**:\n- Writing `@Public(false)` to remove a flag — removal is `@Public.off`. A\n resolved flag is present or absent; `false` is a legitimate *value* for a\n flag declared `boolean`, and a presence check would still answer `true`.\n- A new consumer growing its own `skipPaths` / `ignorePaths` list — that is\n the duplication flags exist to remove, and path strings break on params and\n on any `apiPrefix` change.\n- `@Public.off` on a route that never inherited the flag — a no-op, and\n usually a sign the expected class-level flag is not there.\n- Reading `ctx.route` in global middleware — it is `undefined` before a route\n is matched (steps 1-6 of the pipeline). Move the check into a guard mounted\n with `@Middleware()`, or read the policy table.\n- Inventing a flag name per consumer (`auth.open`, `public`, `isPublic`). The\n framework names none of them; pick one name per fact and reuse it."},{slug:`cli-plugin`,frontmatterName:`kickjs-cli-plugin`,description:`Use when adding a kick <name> command, a kick g <name> generator, or a typegen emitter to this project or a package it ships.`,body:"A CLI plugin contributes commands, generators and typegen emitters to the\n`kick` CLI. Every built-in command ships as one, so the contract is the same\none the framework uses.\n\n**Steps**:\n1. Write the plugin. All four contribution kinds are optional:\n ```ts\n // kick-tool.ts\n import { defineCliPlugin } from '@forinda/kickjs-cli'\n\n export const toolPlugin = (options: { watch?: boolean } = {}) =>\n defineCliPlugin({\n // Stable id, unique across plugins — it names the plugin in conflict errors.\n name: 'my-tool',\n // Declarative: same shape as kick.config.ts `commands`.\n commands: [{ name: 'db:migrate', description: 'Apply migrations', steps: 'node ./scripts/migrate.js' }],\n // Programmatic: full commander API, when you need options or subcommands.\n register(program, ctx) {\n program\n .command('my-tool')\n .description('Do the thing')\n .option('--watch', 'Watch mode')\n .action(async () => {\n ctx.log(`running in ${ctx.projectRoot}`)\n // ctx.config is the loaded kick.config.ts\n })\n },\n })\n ```\n2. Register it in `kick.config.ts`:\n ```ts\n import { toolPlugin } from './kick-tool'\n\n export default defineConfig({ plugins: [toolPlugin()] })\n ```\n3. Check it is loaded, per contribution kind: `kick --help` lists a command,\n `kick g --list` lists a generator, `kick typegen` runs an emitter. A\n plugin that fails to load takes the whole CLI down with a conflict error,\n so silence here means the config never referenced it.\n\n**Which kind to use**: `commands` for a shell one-liner, `register` for\noptions / subcommands / async work, `generators` (`defineGenerator`) for\n`kick g <name>` scaffolders, `typegens` for a file under `.kickjs/types/`.\n\n**Red flags**:\n- Confusing this with a runtime plugin: `defineCliPlugin` (from\n `@forinda/kickjs-cli`) extends the CLI; `definePlugin` (from\n `@forinda/kickjs`) hooks the running app. They share nothing.\n- Claiming a command name a built-in owns (`build:netlify`, `typegen`,\n `generate`) — duplicate declarative names are a startup conflict, and\n `register` has no conflict detection at all, so it silently loses. Namespace\n your own (`my-tool:build`).\n- Doing real work inside `register` — it runs at CLI startup for every\n command, so it must only register. Put the work in the action.\n- Importing heavy dependencies at module scope. `await import()` them inside\n the action, so an unrelated `kick dev` does not pay for them."},{slug:`deploy`,frontmatterName:`kickjs-deploy`,description:`Use when deploying this app — Netlify, Vercel or Cloudflare Workers — or when an API route returns the SPA shell, the platform build fails, or the function is missing from a deploy.`,body:`**Netlify and Vercel** run the app as a Node function; the CLI builds both:
678
+ - Editing \`kick.config.ts\` with deprecated top-level \`modulesDir\` / \`defaultRepo\` / \`schemaDir\` / \`pluralize\` instead of the nested \`modules\` block.`},{slug:`route-flags`,frontmatterName:`kickjs-route-flags`,description:`Use when a fact about a route (public, CSRF-exempt, unmetered, expose as a tool) has to be read by auth, CSRF, rate limiting, OpenAPI or MCP — instead of repeating it as paths in each consumer.`,body:"A route flag is a named, inheritable fact about a route. It carries no\nbehaviour: it records something every consumer can read, so \"this endpoint is\nopen\" is declared once instead of restated as an auth contributor, a\n`csrf ignorePaths` entry and a `rateLimit skipPaths` entry — two of which are\npathname strings that cannot express `/users/:id`.\n\n**Steps**:\n1. Declare it once, in its own module:\n ```ts\n import { defineRouteFlag } from '@forinda/kickjs'\n\n export const Public = defineRouteFlag('auth.public')\n export const Limit = defineRouteFlag<{ rpm: number }>('rate.limit')\n ```\n2. Apply it. A class flag is inherited by every route under it; `.off` on a\n method removes it:\n ```ts\n @Public // every route below inherits it\n @Controller()\n export class WebhooksController {\n @Get('/health')\n health(ctx: RequestContext) {} // public\n\n @Public.off // the method wins\n @Post('/admin')\n admin(ctx: RequestContext) {} // not public\n\n @Limit({ rpm: 10 }) // flags can carry a value\n @Post('/login')\n login(ctx: RequestContext) {}\n }\n ```\n3. Read it from the consumer that already exists, rather than a new one.\n **Where a consumer is mounted decides how it reads flags** — everything\n after route matching gets `ctx.route`; anything before it does not:\n\n | Consumer | Mounted at | Reads flags by |\n | --- | --- | --- |\n | Handler | the route itself | `ctx.route?.flags.has('auth.public')` |\n | Guard / `@Middleware()` | `@Middleware(fn)` on a method or controller class | `ctx.route`, or the built-ins' `exemptWhen` |\n | `csrfGuard()` / `rateLimitGuard()` | same — `@Middleware()`, class or method | `exemptWhen: 'csrf.exempt'` |\n | Contributor | method > class > module `contributors()` > adapter `contributors()` > `bootstrap({ contributors })` | `skipWhen` / `onlyWhen` on the registration |\n | Global middleware (`rateLimit()`) | `bootstrap({ middlewares: [...] })` — runs **before** matching | the route policy table (`bindRoutePolicy`); `ctx.route` is `undefined` here |\n | Adapter middleware | `AppAdapter.middleware()`, phase `beforeGlobal` … `afterRoutes` | the policy table — the handler is Express-style `(req, res, next)`, so there is no `ctx` in any phase |\n | OpenAPI | `SwaggerAdapter({ publicFlag: 'auth.public' })` | read once at startup, not per request |\n | MCP / AI tools | `McpAdapter({ exposeWhen: 'mcp.tool', hideWhen: 'mcp.hidden' })` | read once at startup |\n\n The contributor row is the one that buys the most: those five levels mean a\n plugin's contributor can be skipped on one route (`skipWhen`) without\n forking it, and a method-level registration beats the adapter's.\n\n4. Run `kick typegen`. It writes the `KickRouteFlags` augmentation, so flag\n names autocomplete and a typo fails `tsc` instead of silently never matching.\n\n**Red flags**:\n- Writing `@Public(false)` to remove a flag — removal is `@Public.off`. A\n resolved flag is present or absent; `false` is a legitimate *value* for a\n flag declared `boolean`, and a presence check would still answer `true`.\n- A new consumer growing its own `skipPaths` / `ignorePaths` list — that is\n the duplication flags exist to remove, and path strings break on params and\n on any `apiPrefix` change.\n- `@Public.off` on a route that never inherited the flag — a no-op, and\n usually a sign the expected class-level flag is not there.\n- Reading `ctx.route` in global middleware — it is `undefined` before a route\n is matched (steps 1-6 of the pipeline). Move the check into a guard mounted\n with `@Middleware()`, or read the policy table.\n- Inventing a flag name per consumer (`auth.open`, `public`, `isPublic`). The\n framework names none of them; pick one name per fact and reuse it."},{slug:`cli-plugin`,frontmatterName:`kickjs-cli-plugin`,description:`Use when adding a kick <name> command, a kick g <name> generator, or a typegen emitter to this project or a package it ships.`,body:"A CLI plugin contributes commands, generators and typegen emitters to the\n`kick` CLI. Every built-in command ships as one, so the contract is the same\none the framework uses.\n\n**Steps**:\n1. Write the plugin. All four contribution kinds are optional:\n ```ts\n // kick-tool.ts\n import { defineCliPlugin } from '@forinda/kickjs-cli'\n\n export const toolPlugin = (options: { watch?: boolean } = {}) =>\n defineCliPlugin({\n // Stable id, unique across plugins — it names the plugin in conflict errors.\n name: 'my-tool',\n // Declarative: same shape as kick.config.ts `commands`.\n commands: [{ name: 'db:migrate', description: 'Apply migrations', steps: 'node ./scripts/migrate.js' }],\n // Programmatic: full commander API, when you need options or subcommands.\n register(program, ctx) {\n program\n .command('my-tool')\n .description('Do the thing')\n .option('--watch', 'Watch mode')\n .action(async () => {\n ctx.log(`running in ${ctx.projectRoot}`)\n // ctx.config is the loaded kick.config.ts\n })\n },\n })\n ```\n2. Register it in `kick.config.ts`:\n ```ts\n import { toolPlugin } from './kick-tool'\n\n export default defineConfig({ plugins: [toolPlugin()] })\n ```\n3. Check it is loaded, per contribution kind: `kick --help` lists a command,\n `kick g --list` lists a generator, `kick typegen` runs an emitter. A\n plugin that fails to load takes the whole CLI down with a conflict error,\n so silence here means the config never referenced it.\n\n**Which kind to use**: `commands` for a shell one-liner, `register` for\noptions / subcommands / async work, `generators` (`defineGenerator`) for\n`kick g <name>` scaffolders, `typegens` for a file under `.kickjs/types/`.\n\n**Red flags**:\n- Confusing this with a runtime plugin: `defineCliPlugin` (from\n `@forinda/kickjs-cli`) extends the CLI; `definePlugin` (from\n `@forinda/kickjs`) hooks the running app. They share nothing.\n- Claiming a command name a built-in owns (`build:netlify`, `typegen`,\n `generate`) — duplicate declarative names are a startup conflict, and\n `register` has no conflict detection at all, so it silently loses. Namespace\n your own (`my-tool:build`).\n- Doing real work inside `register` — it runs at CLI startup for every\n command, so it must only register. Put the work in the action.\n- Importing heavy dependencies at module scope. `await import()` them inside\n the action, so an unrelated `kick dev` does not pay for them."},{slug:`deploy`,frontmatterName:`kickjs-deploy`,description:`Use when deploying this app — a Node host or Docker, Netlify, Vercel or Cloudflare Workers — or when an API route returns the SPA shell, the platform build fails, or the function is missing from a deploy.`,body:`**A Node host or a container** runs the long-running server. The project
679
+ ships a \`Dockerfile\`; without Docker:
680
+
681
+ \`\`\`bash
682
+ ${e} run build && NODE_ENV=production node dist/index.js
683
+ \`\`\`
684
+
685
+ Start it with \`node\`, not \`kick start\`: the CLI is a dev dependency, gone
686
+ after a production install. The image installs from the lockfile, so commit it.
687
+
688
+ **Netlify and Vercel** run the app as a Node function; the CLI builds both:
679
689
 
680
690
  \`\`\`bash
681
691
  ${e} run build:netlify # → .netlify/v1/functions/api.mjs
682
692
  ${e} run build:vercel # → .vercel/output (Build Output API v3)
683
693
  \`\`\`
684
694
 
685
- Both bundle \`src/serverless.ts\` (\`createHandler\`), which is a second entry
686
- beside \`src/index.ts\` — the long-running server. Keep the shared options in
687
- one module both import, so they cannot drift.
695
+ Both bundle \`src/serverless.ts\`:
696
+ \`createHandler(() => import('./index'))\` serves the app \`src/index.ts\`
697
+ describes — its \`bootstrap()\` call builds the app without listening — so
698
+ there is one set of options. Add middleware and adapters to \`src/index.ts\`
699
+ as usual.
688
700
 
689
701
  Settings are detected from the layout: a workspace member beside a \`web\`
690
- package publishes \`web/dist\` and routes \`/api/*\`; a standalone API takes
691
- every path. Override in \`kick.config.ts\`:
702
+ package publishes \`web/dist\` and routes \`/api/*\`; an Inertia app publishes
703
+ \`dist/client\`, packages the asset manifest and SSR bundle with the function,
704
+ and lets it take every other path; a standalone API takes every path.
705
+ Override in \`kick.config.ts\`:
692
706
 
693
707
  \`\`\`ts
694
708
  export default defineConfig({
695
- deploy: { apiPath: '/api', staticDir: '../web/dist' },
709
+ deploy: { apiPath: '/api', staticDir: '../web/dist', include: ['data/geo.json'] },
696
710
  })
697
711
  \`\`\`
698
712
 
713
+ \`include\` lists files the app reads at runtime; they are packaged with the
714
+ function. Memory does not survive between function instances: keep sessions in
715
+ \`session({ store: 'cookie' })\` or a shared store, and data in a database.
716
+
699
717
  **Cloudflare Workers** is a different entry, not a third flag on this one.
700
718
  Workers have no \`node:http\`, so \`createHandler\` cannot run there; use the
701
719
  web entry over h3 v2:
@@ -734,14 +752,17 @@ plugins. Serve static files from Workers Assets or a separate deploy.
734
752
  **Red flags**:
735
753
  - An \`/api/*\` route returning \`index.html\` on Netlify — the function is not
736
754
  routed. Check the deploy summary says a function was deployed, keep
737
- \`preferStatic\` out of its config, and leave Netlify's **Package directory**
738
- unset so it reads the function at the repo root.
755
+ \`preferStatic\` out of a fullstack function's config, and leave Netlify's
756
+ **Package directory** unset so it reads the function at the repo root.
757
+ - Validation errors or flash messages that vanish on Netlify / Vercel — the
758
+ session lives in one instance's memory. Use \`session({ store: 'cookie' })\`.
739
759
  - Committing \`.netlify/\` or \`.vercel/\` — both are build output.
740
760
  - A frontend that builds somewhere other than \`web/dist\` and only one of
741
761
  \`deploy.staticDir\`, \`SpaAdapter({ clientDir })\` and netlify.toml's
742
762
  \`publish\` updated. All three name that directory.
743
763
  - Pointing a platform at \`src/index.ts\` — it calls \`bootstrap()\`, which
744
- listens on a port and registers signal handlers inside the function.
764
+ listens on a port and registers signal handlers inside the function. The
765
+ platform entry is \`src/serverless.ts\`.
745
766
  - Expecting \`kick build\` alone to produce a deployable function; it builds
746
767
  the server. Run the target command after it.`},{slug:`docs-lookup`,frontmatterName:`kickjs-docs-lookup`,description:`Use FIRST when unsure about any KickJS API, option, or behaviour — before guessing from memory or inferring from surrounding code.`,body:`These skills are deliberately short — they cover the traps, not the whole API
747
768
  surface. When the answer is not in one of them, read the docs rather than
@@ -852,4 +873,4 @@ Codex / Cursor / Gemini / Claude Code without copy-pasting.
852
873
  CLI template. Hand-edited content is overwritten — keep customisation
853
874
  in \`.agents/COPILOT.local.md\`.
854
875
  `}var p=/* @__PURE__ */ e({generateAgentDocs:()=>b});const m=`.agents`,h=/* @__PURE__ */ new Set([`rest`,`minimal`,`fullstack`,`inertia`]);function g(e,t){if(t)return t;try{let t=JSON.parse(o(i(e,`package.json`),`utf-8`));if(t.name)return t.name.replace(/^@[^/]+\//,``)}catch{}return e.split(`/`).findLast(Boolean)??`app`}function _(e,t){if(t)return t;try{let t=JSON.parse(o(i(e,`package.json`),`utf-8`));if(t.packageManager)return t.packageManager.split(`@`)[0]}catch{}return`pnpm`}async function v(e){try{return(await r(e))?.modules?.style===`class`?`class`:`define`}catch{return`define`}}async function y(e,t){if(t)return t;try{let t=(await r(e))?.pattern;if(t&&h.has(t))return t}catch{}return`rest`}async function b(e){let r=e.only??`all`,o=g(e.outDir,e.name),l=_(e.outDir,e.pm),p=await y(e.outDir,e.template),h=await v(e.outDir),b=r===`agents`||r===`both`||r===`all`,x=r===`claude`||r===`both`||r===`all`,S=r===`skills`||r===`all`,C=r===`gemini`||r===`all`,w=r===`copilot`||r===`all`,T=[];if(b&&T.push({file:i(e.outDir,m,`AGENTS.md`),render:()=>c(o,p,l)}),x&&T.push({file:i(e.outDir,`CLAUDE.md`),render:()=>s(o,p,l)}),S)for(let t of u(o,p,l,h))T.push({file:i(e.outDir,m,`skills`,t.slug,`SKILL.md`),render:()=>t.content});C&&T.push({file:i(e.outDir,m,`GEMINI.md`),render:()=>d(o,p,l)}),w&&T.push({file:i(e.outDir,m,`COPILOT.md`),render:()=>f(o,p,l)});let E=[];for(let{file:r,render:i}of T)a(r)&&!e.force&&!await n({message:`${r.replace(e.outDir+`/`,``)} already exists. Overwrite?`,initialValue:!1})?console.log(` Skipped — existing ${r.replace(e.outDir+`/`,``)} preserved.`):(await t(r,i()),E.push(r));return E}export{b as n,p as t};
855
- //# sourceMappingURL=agent-docs-BsXKM5QH.mjs.map
876
+ //# sourceMappingURL=agent-docs-DUB-1Z6Q.mjs.map