@forinda/kickjs-cli 8.10.0 → 8.10.2
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.
- package/README.md +2 -0
- package/dist/{agent-docs-CvBsLoE4.mjs → agent-docs-As_KjQBC.mjs} +67 -23
- package/dist/{agent-docs-CmPrfpaP.mjs → agent-docs-ZgfnGL-j.mjs} +65 -21
- package/dist/agent-docs-ZgfnGL-j.mjs.map +1 -0
- package/dist/{build-Snjzr08O.mjs → build-BfC9Kkt-.mjs} +2 -2
- package/dist/{build-Dr7_JT3S.mjs → build-BuBCsnzr.mjs} +3 -3
- package/dist/{build-Dr7_JT3S.mjs.map → build-BuBCsnzr.mjs.map} +1 -1
- package/dist/{builtins-BTPvizzK.mjs → builtins-397XZB9_.mjs} +137 -150
- package/dist/{builtins-MG6t5uS3.mjs → builtins-DXASTS7y.mjs} +2 -2
- package/dist/cli.mjs +2 -2
- package/dist/config-Ck9aQVpE.mjs +12 -0
- package/dist/config-CsOfUFfq.mjs +13 -0
- package/dist/config-CsOfUFfq.mjs.map +1 -0
- package/dist/{doctor-C-VSGhJ6.mjs → doctor-DGWvBOvj.mjs} +35 -40
- package/dist/doctor-DGWvBOvj.mjs.map +1 -0
- package/dist/fullstack-BqYdhTDI.mjs +100 -0
- package/dist/fullstack-BqYdhTDI.mjs.map +1 -0
- package/dist/fullstack-x16HfCRz.mjs +99 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/package-manager--IUl91nq.mjs +11 -0
- package/dist/package-manager-DBmD5nSr.mjs +12 -0
- package/dist/package-manager-DBmD5nSr.mjs.map +1 -0
- package/dist/{plugin-BpfANLIW.mjs → plugin-Dh0LYWl5.mjs} +2 -2
- package/dist/{plugin-E910l1_e.mjs → plugin-HazJu53p.mjs} +2 -2
- package/dist/project-C98JovY4.mjs +115 -0
- package/dist/project-C98JovY4.mjs.map +1 -0
- package/dist/project-TbTVQCnh.mjs +114 -0
- package/dist/{project-root-D74lbi2U.mjs → project-root-DGKTJDH3.mjs} +2 -2
- package/dist/{project-root-DO7MsZOq.mjs → project-root-DlgCWwc_.mjs} +3 -3
- package/dist/{project-root-DO7MsZOq.mjs.map → project-root-DlgCWwc_.mjs.map} +1 -1
- package/dist/{prompts-DKR7UZkc.mjs → prompts-D4nwf5mP.mjs} +2 -2
- package/dist/{prompts-DKR7UZkc.mjs.map → prompts-D4nwf5mP.mjs.map} +1 -1
- package/dist/{rolldown-runtime-vT0bVE76.mjs → rolldown-runtime-7c5UUG6D.mjs} +1 -1
- package/dist/{run-plugins-BXNfws9R.mjs → run-plugins-Dx-QENlm.mjs} +99 -107
- package/dist/run-plugins-Dx-QENlm.mjs.map +1 -0
- package/dist/{typegen-BmyEoY3Z.mjs → typegen-DJQ6WBwr.mjs} +4 -4
- package/dist/{typegen-B90QMhV8.mjs → typegen-DSaawXaQ.mjs} +5 -5
- package/dist/{typegen-B90QMhV8.mjs.map → typegen-DSaawXaQ.mjs.map} +1 -1
- package/dist/{types-C2QNIHnD.mjs → types-CtrnAiNl.mjs} +1 -1
- package/package.json +2 -2
- package/templates/base/files/README.md +17 -15
- package/templates/base/files/kick.config.ts +1 -1
- package/templates/template-inertia/files/src/client/app.css +1 -1
- package/templates/template-inertia/files/vite.client.config.ts +1 -1
- package/dist/agent-docs-CmPrfpaP.mjs.map +0 -1
- package/dist/config-B7ZUrOl6.mjs +0 -13
- package/dist/config-B7ZUrOl6.mjs.map +0 -1
- package/dist/config-DO4J2xgV.mjs +0 -12
- package/dist/doctor-C-VSGhJ6.mjs.map +0 -1
- package/dist/fs-CT9PRuSw.mjs +0 -11
- package/dist/fs-gRPNbfZO.mjs +0 -12
- package/dist/fs-gRPNbfZO.mjs.map +0 -1
- package/dist/fullstack-CTB1yuCK.mjs +0 -95
- package/dist/fullstack-bVcLaFbj.mjs +0 -96
- package/dist/fullstack-bVcLaFbj.mjs.map +0 -1
- package/dist/project-BAmOMd-l.mjs +0 -113
- package/dist/project-D7x753R7.mjs +0 -114
- package/dist/project-D7x753R7.mjs.map +0 -1
- package/dist/run-plugins-BXNfws9R.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -13,6 +13,8 @@ npx @forinda/kickjs-cli new my-api
|
|
|
13
13
|
|
|
14
14
|
## Commands
|
|
15
15
|
|
|
16
|
+
The CLI is a dev dependency, so in a shell run it through your package manager — `npx kick dev`, `pnpm exec kick dev`, `yarn kick dev`, `bunx kick dev` — or through the project's scripts (`npm run dev`). A bare `kick` needs a global install.
|
|
17
|
+
|
|
16
18
|
```bash
|
|
17
19
|
kick new <name> # Scaffold a new KickJS project
|
|
18
20
|
kick dev # Start dev server with Vite HMR
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v8.10.
|
|
2
|
+
* @forinda/kickjs-cli v8.10.2
|
|
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-
|
|
11
|
+
import{t as e}from"./rolldown-runtime-7c5UUG6D.mjs";import{o as t,r as n,u as r}from"./config-Ck9aQVpE.mjs";import{n as i,o as a}from"./package-manager--IUl91nq.mjs";import{existsSync as o,readFileSync as s}from"node:fs";import{join as c}from"node:path";import*as l from"@clack/prompts";import u from"picocolors";const d={GET:u.green,POST:u.cyan,PUT:u.yellow,PATCH:u.magenta,DELETE:u.red};function f(e){return(d[e]??u.dim)(e.padEnd(7))}function p(e){let t=`[${e}]`.padEnd(10);switch(e){case`CRITICAL`:return u.red(t);case`WARNING`:return u.yellow(t);case`INFO`:return u.blue(u.dim(t));default:return t}}u.green(`✓`),u.red(`✖`),u.yellow(`⚠`),u.blue(`ℹ`);function m(e){l.intro(u.bgCyan(u.black(` ${e} `)))}function h(e){l.outro(e)}function g(e){l.isCancel(e)&&(l.cancel(`Operation cancelled.`),process.exit(0))}async function _(e){let t=await l.text(e);return g(t),t}async function v(e){let t=await l.select(e);return g(t),t}async function y(e){let t=await l.multiselect(e);return g(t),t}async function b(e){let t=await l.confirm(e);return g(t),t}function x(){return l.spinner()}const S=l.log;function C(e,t){let n=e;return t===`fullstack`&&n!==`pnpm`?`${r(n,`dev:server`)} + ${r(n,`dev:web`)}`:r(n,`dev`)}function w(e,t,i){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.) —
|
|
@@ -56,14 +56,17 @@ prose.
|
|
|
56
56
|
## Quick reference (full version in .agents/AGENTS.md)
|
|
57
57
|
|
|
58
58
|
\`\`\`bash
|
|
59
|
-
${
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
${
|
|
63
|
-
kick typecheck
|
|
64
|
-
kick format
|
|
59
|
+
${i} install
|
|
60
|
+
${C(i,t)} # Dev server with HMR + typegen
|
|
61
|
+
${r(i,`build`)} && ${r(i,`start`)} # Production
|
|
62
|
+
${r(i,`test`)} # Vitest
|
|
63
|
+
${t===`fullstack`?r(i,`typecheck`):`${n(i,`kick`)} typecheck`} # tsc/tsgo, whichever the project has
|
|
64
|
+
${t===`fullstack`?r(i,`format`):`${n(i,`kick`)} format`} # oxfmt
|
|
65
65
|
\`\`\`
|
|
66
66
|
|
|
67
|
+
\`kick\` is this project's dev dependency, not a global command: every \`kick …\`
|
|
68
|
+
in these docs runs as \`${n(i,`kick`)} …\` in a shell.
|
|
69
|
+
|
|
67
70
|
## v4 framework reminders
|
|
68
71
|
|
|
69
72
|
When generating or modifying code in this project, stay aligned with the v4 conventions documented in \`.agents/AGENTS.md\`:
|
|
@@ -83,7 +86,7 @@ When generating or modifying code in this project, stay aligned with the v4 conv
|
|
|
83
86
|
- **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.
|
|
84
87
|
|
|
85
88
|
For everything else (controllers, services, modules, RequestContext API, generators, CLI commands, package additions, env wiring, troubleshooting) → \`.agents/AGENTS.md\`.
|
|
86
|
-
`}function
|
|
89
|
+
`}function T(e,t,i){return`# AGENTS.md — AI Agent Guide for ${e}
|
|
87
90
|
|
|
88
91
|
This guide is the **canonical, multi-agent reference** for this KickJS
|
|
89
92
|
application — Claude, Copilot, Codex, Gemini, etc. all read it first.
|
|
@@ -92,13 +95,18 @@ add tool-specific affordances on top.
|
|
|
92
95
|
|
|
93
96
|
## Before You Start
|
|
94
97
|
|
|
95
|
-
1. Run \`${
|
|
96
|
-
2. Run \`
|
|
98
|
+
1. Run \`${i} install\` to install dependencies
|
|
99
|
+
2. Run \`${C(i,t)}\` to verify the app starts
|
|
100
|
+
|
|
101
|
+
\`kick\` is this project's dev dependency, not a global command: every \`kick …\`
|
|
102
|
+
below runs as \`${n(i,`kick`)} …\` in a shell.${t===`fullstack`?`
|
|
97
103
|
|
|
98
104
|
## Fullstack workspace layout
|
|
99
105
|
|
|
100
106
|
This is a WORKSPACE root — the KickJS API lives in \`server/\`, the typed web
|
|
101
|
-
app in \`web/\`. Run both with \`${
|
|
107
|
+
app in \`web/\`. Run both with \`${C(i,t)}\`. From this root,
|
|
108
|
+
\`${r(i,`test`)}\`, \`${r(i,`typecheck`)}\` and \`${r(i,`format`)}\` reach into
|
|
109
|
+
\`server/\` (and \`web/\` for typecheck).
|
|
102
110
|
|
|
103
111
|
The type loop (do not break it):
|
|
104
112
|
1. \`server/\` handlers RETURN their payloads → \`kick typegen\` emits
|
|
@@ -112,8 +120,8 @@ The type loop (do not break it):
|
|
|
112
120
|
relative \`/api/v1\` (Vite proxies it in dev) unless \`VITE_API_URL\` points at
|
|
113
121
|
an API on another origin.
|
|
114
122
|
|
|
115
|
-
Rules: kick commands (\`kick g\`, \`kick typegen\`, \`kick dev\`)
|
|
116
|
-
\`server
|
|
123
|
+
Rules: kick commands (\`kick g\`, \`kick typegen\`, \`kick dev\`, \`kick typecheck\`)
|
|
124
|
+
run in \`server/\` — the root has no \`kick.config.ts\`; never import server runtime code into \`web/\` (the d.ts bridge is
|
|
117
125
|
type-only); prefer return-value handlers so responses stay inferable.`:``}
|
|
118
126
|
3. Read the [KickJS documentation](https://kickjs.app/) for framework details
|
|
119
127
|
|
|
@@ -358,7 +366,7 @@ See the **\`kickjs-write-controller-test\`** skill for the canonical test — it
|
|
|
358
366
|
carries the call shape, the DI reset, and the env side-effect import, each of
|
|
359
367
|
which has its own failure mode.
|
|
360
368
|
|
|
361
|
-
Run with \`${
|
|
369
|
+
Run with \`${i} run test\` (\`test:watch\` for watch mode).
|
|
362
370
|
|
|
363
371
|
## Environment Variables
|
|
364
372
|
|
|
@@ -493,7 +501,7 @@ page and lists the local tools (\`kick explain\`, \`kick doctor\`, \`kick inspec
|
|
|
493
501
|
|
|
494
502
|
Start at <https://kickjs.app/>.
|
|
495
503
|
|
|
496
|
-
`}function
|
|
504
|
+
`}function E(e,t=`define`){let i=t===`class`?`UserModule`:`UserModule()`;return[{slug:`add-module`,frontmatterName:`kickjs-add-module`,description:`Use when the user asks to add a new feature module (controller + service + repo + DTOs).`,body:`**Trigger phrases**: "add a users module", "scaffold tasks", "new feature for X".
|
|
497
505
|
|
|
498
506
|
**Steps**:
|
|
499
507
|
1. Run \`kick g module <name>\` (use plural form if the project pluralizes — check \`kick.config.ts\`).
|
|
@@ -567,7 +575,7 @@ describe('UserController', () => {
|
|
|
567
575
|
// configured with. Pass \`runtime\` to \`createTestApp\` to match production.
|
|
568
576
|
const { app } = await createTestApp({
|
|
569
577
|
// Matches this project's \`modules.style\`.
|
|
570
|
-
modules: [${
|
|
578
|
+
modules: [${i}],
|
|
571
579
|
})
|
|
572
580
|
const res = await request(app.handle.bind(app)).get('/api/v1/users')
|
|
573
581
|
expect(res.status).toBe(200)
|
|
@@ -597,7 +605,43 @@ async create(ctx: Ctx<KickRoutes.TodoController['create']>) {
|
|
|
597
605
|
|
|
598
606
|
**Nuances**:
|
|
599
607
|
- \`@Inject\` and \`@Autowired\` are interchangeable — same runtime, same types; pick by readability.
|
|
600
|
-
- \`@Value('MISSING_KEY')\` with no default **throws on property access**, not at construction — tests that exercise the getter will surface the missing-env issue.`},{slug:`env-wiring-check`,frontmatterName:`kickjs-env-wiring-check`,description:`Use when ConfigService.get('SOME_KEY') returns undefined or @Value silently falls back to process.env.`,body
|
|
608
|
+
- \`@Value('MISSING_KEY')\` with no default **throws on property access**, not at construction — tests that exercise the getter will surface the missing-env issue.`},{slug:`env-wiring-check`,frontmatterName:`kickjs-env-wiring-check`,description:`Use when ConfigService.get('SOME_KEY') returns undefined or @Value silently falls back to process.env.`,body:`**Fastest path**: \`kick explain "ConfigService.get('MY_KEY') returned undefined"\` —
|
|
609
|
+
pipe a failing run straight in if you prefer (\`${r(e,`test`)} 2>&1 | ${n(e,`kick`)} explain\`). It
|
|
610
|
+
distinguishes the entry-file cause from the test-file one, which is the step most
|
|
611
|
+
people lose time on. The manual checks below are the same reasoning.
|
|
612
|
+
|
|
613
|
+
**Diagnosis (in order)**:
|
|
614
|
+
1. Open \`src/index.ts\`. The **first non-\`reflect-metadata\`** import MUST be \`import './config'\`.
|
|
615
|
+
2. 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:
|
|
616
|
+
\`\`\`ts
|
|
617
|
+
import { loadEnvFromSchema } from '@forinda/kickjs/config'
|
|
618
|
+
import { fromZod } from '@forinda/kickjs-schema/zod'
|
|
619
|
+
const envSchema = fromZod(z.object({ DATABASE_URL: z.url() }))
|
|
620
|
+
export const env = loadEnvFromSchema(envSchema)
|
|
621
|
+
\`\`\`
|
|
622
|
+
3. The new key MUST be declared in the 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 its parsing and defaults.
|
|
623
|
+
4. 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.
|
|
624
|
+
|
|
625
|
+
5. **In a test?** \`createTestApp\` never loads \`src/index.ts\`, so the entry's
|
|
626
|
+
\`import './config'\` never runs no matter how correct it is. The test file
|
|
627
|
+
must import it itself:
|
|
628
|
+
\`\`\`ts
|
|
629
|
+
import '@/config'
|
|
630
|
+
\`\`\`
|
|
631
|
+
Symptom is identical to the missing-entry-import case, and step 1 will look
|
|
632
|
+
fine, which is what makes it slow to spot.
|
|
633
|
+
|
|
634
|
+
**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.
|
|
635
|
+
|
|
636
|
+
**\`reloadEnv\` vs \`resetEnvCache\`** — distinct, frequently mixed up:
|
|
637
|
+
- \`reloadEnv()\` — re-reads \`process.env\` against the **already registered** schema. Use in HMR plugins after \`.env\` file changes. Schema survives.
|
|
638
|
+
- \`resetEnvCache()\` — drops the registered schema entirely. **Test-only.** Calling it between dev requests drops the project's keys.
|
|
639
|
+
|
|
640
|
+
**Nuances**:
|
|
641
|
+
- \`dotenv\` is an **optional peer dep** in v5+ — projects upgrading from older versions may need to add it explicitly.
|
|
642
|
+
- For HMR-friendly \`.env\` edits, add \`envWatchPlugin()\` to \`vite.config.ts\` — calls \`reloadEnv()\` automatically.
|
|
643
|
+
|
|
644
|
+
**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\`.`},{slug:`bootstrap-export`,frontmatterName:`kickjs-bootstrap-export`,description:`Use when HMR is silently doing full restarts on every save, or createTestApp can't find the app handle.`,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."},{slug:`thin-entry-file`,frontmatterName:`kickjs-thin-entry-file`,description:`Use when src/index.ts is accumulating module/middleware/plugin/adapter literals.`,body:`**Refactor target**:
|
|
601
645
|
|
|
602
646
|
\`\`\`ts
|
|
603
647
|
// src/modules/index.ts — fluent chain (default for \`modules.style: 'define'\`)
|
|
@@ -793,7 +837,7 @@ fine and fails at runtime.
|
|
|
793
837
|
**Local, and usually faster**
|
|
794
838
|
|
|
795
839
|
- \`kick explain "<error message>"\` — matches known failures and gives the fix.
|
|
796
|
-
Pipe a failing run in: \`${e}
|
|
840
|
+
Pipe a failing run in: \`${r(e,`test`)} 2>&1 | ${n(e,`kick`)} explain\`.
|
|
797
841
|
- \`kick doctor\` — checks this project's wiring.
|
|
798
842
|
- \`kick inspect\` — the live route / adapter table.
|
|
799
843
|
- \`.kickjs/types/\` — generated types are ground truth for what exists.
|
|
@@ -802,7 +846,7 @@ fine and fails at runtime.
|
|
|
802
846
|
|
|
803
847
|
**Rule**: if you would be guessing, look it up. If a doc page contradicts the
|
|
804
848
|
installed \`.d.mts\`, trust the \`.d.mts\` and say so — the docs may be behind the
|
|
805
|
-
version this project has.`},{slug:`refresh-agent-docs`,frontmatterName:`kickjs-refresh-agent-docs`,description:`Use after a KickJS version bump to sync the .agents/ docs with the latest CLI templates.`,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."},{slug:`deny-list`,frontmatterName:`kickjs-deny-list`,description:`Patterns to refuse outright when the user asks for them — they break v4 invariants.`,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 → `@Controller()`, with the prefix in `routes().path`.\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({ middlewares })` — 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`.\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`."}]}function
|
|
849
|
+
version this project has.`},{slug:`refresh-agent-docs`,frontmatterName:`kickjs-refresh-agent-docs`,description:`Use after a KickJS version bump to sync the .agents/ docs with the latest CLI templates.`,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."},{slug:`deny-list`,frontmatterName:`kickjs-deny-list`,description:`Patterns to refuse outright when the user asks for them — they break v4 invariants.`,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 → `@Controller()`, with the prefix in `routes().path`.\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({ middlewares })` — 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`.\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`."}]}function D(e,t,n,r=`define`){let i=`<!-- Generated by \`kick g agents\` for ${e}. Edits are overwritten on the next refresh; keep customisation in a SKILL.local.md alongside. -->`;return E(n,r).map(e=>({slug:e.slug,content:`---
|
|
806
850
|
name: ${e.frontmatterName}
|
|
807
851
|
description: ${e.description}
|
|
808
852
|
---
|
|
@@ -810,7 +854,7 @@ description: ${e.description}
|
|
|
810
854
|
${i}
|
|
811
855
|
|
|
812
856
|
${e.body}
|
|
813
|
-
`}))}function
|
|
857
|
+
`}))}function O(e,t,n){return`# GEMINI.md — ${e}
|
|
814
858
|
|
|
815
859
|
**Read \`./AGENTS.md\` first.** It is the canonical, multi-agent
|
|
816
860
|
reference for this project — every convention, structure, decorator
|
|
@@ -844,7 +888,7 @@ without us copy-pasting.
|
|
|
844
888
|
\`kick g agents --only gemini -f\` regenerates this file from the
|
|
845
889
|
CLI template. Hand-edited content is overwritten — keep customisation
|
|
846
890
|
in \`.agents/GEMINI.local.md\`.
|
|
847
|
-
`}function
|
|
891
|
+
`}function k(e,t,n){return`# COPILOT.md — ${e}
|
|
848
892
|
|
|
849
893
|
**Read \`./AGENTS.md\` first.** It is the canonical, multi-agent
|
|
850
894
|
reference for this project — every convention, structure, decorator
|
|
@@ -877,4 +921,4 @@ Codex / Cursor / Gemini / Claude Code without copy-pasting.
|
|
|
877
921
|
\`kick g agents --only copilot -f\` regenerates this file from the
|
|
878
922
|
CLI template. Hand-edited content is overwritten — keep customisation
|
|
879
923
|
in \`.agents/COPILOT.local.md\`.
|
|
880
|
-
`}var
|
|
924
|
+
`}var A=/* @__PURE__ */ e({generateAgentDocs:()=>I});const j=`.agents`,M=/* @__PURE__ */ new Set([`rest`,`minimal`,`fullstack`,`inertia`]);function N(e,t){if(t)return t;try{let t=JSON.parse(s(c(e,`package.json`),`utf-8`));if(t.name)return t.name.replace(/^@[^/]+\//,``)}catch{}return e.split(`/`).findLast(Boolean)??`app`}async function P(e){try{return(await t(e))?.modules?.style===`class`?`class`:`define`}catch{return`define`}}async function F(e,n){if(n)return n;try{let n=(await t(e))?.pattern;if(n&&M.has(n))return n}catch{}return`rest`}async function I(e){let t=e.only??`all`,n=N(e.outDir,e.name),r=await i(e.pm,e.outDir),s=await F(e.outDir,e.template),l=await P(e.outDir),u=t===`agents`||t===`both`||t===`all`,d=t===`claude`||t===`both`||t===`all`,f=t===`skills`||t===`all`,p=t===`gemini`||t===`all`,m=t===`copilot`||t===`all`,h=[];if(u&&h.push({file:c(e.outDir,j,`AGENTS.md`),render:()=>T(n,s,r)}),d&&h.push({file:c(e.outDir,`CLAUDE.md`),render:()=>w(n,s,r)}),f)for(let t of D(n,s,r,l))h.push({file:c(e.outDir,j,`skills`,t.slug,`SKILL.md`),render:()=>t.content});p&&h.push({file:c(e.outDir,j,`GEMINI.md`),render:()=>O(n,s,r)}),m&&h.push({file:c(e.outDir,j,`COPILOT.md`),render:()=>k(n,s,r)});let g=[];for(let{file:t,render:n}of h)o(t)&&!e.force&&!await b({message:`${t.replace(e.outDir+`/`,``)} already exists. Overwrite?`,initialValue:!1})?console.log(` Skipped — existing ${t.replace(e.outDir+`/`,``)} preserved.`):(await a(t,n()),g.push(t));return g}export{S as a,v as c,f as d,u as f,m as i,x as l,I as n,y as o,p,b as r,h as s,A as t,_ as u};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @forinda/kickjs-cli v8.10.
|
|
2
|
+
* @forinda/kickjs-cli v8.10.2
|
|
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-
|
|
11
|
+
import{t as e}from"./rolldown-runtime-7c5UUG6D.mjs";import{n as t,o as n}from"./package-manager-DBmD5nSr.mjs";import{t as r}from"./prompts-D4nwf5mP.mjs";import{d as i,i as a,s as o}from"./config-CsOfUFfq.mjs";import{join as s}from"node:path";import{existsSync as c,readFileSync as l}from"node:fs";function u(e,t){let n=e;return t===`fullstack`&&n!==`pnpm`?`${i(n,`dev:server`)} + ${i(n,`dev:web`)}`:i(n,`dev`)}function d(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.) —
|
|
@@ -56,14 +56,17 @@ prose.
|
|
|
56
56
|
## Quick reference (full version in .agents/AGENTS.md)
|
|
57
57
|
|
|
58
58
|
\`\`\`bash
|
|
59
|
-
${n} install
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
${n}
|
|
63
|
-
kick typecheck
|
|
64
|
-
kick format
|
|
59
|
+
${n} install
|
|
60
|
+
${u(n,t)} # Dev server with HMR + typegen
|
|
61
|
+
${i(n,`build`)} && ${i(n,`start`)} # Production
|
|
62
|
+
${i(n,`test`)} # Vitest
|
|
63
|
+
${t===`fullstack`?i(n,`typecheck`):`${a(n,`kick`)} typecheck`} # tsc/tsgo, whichever the project has
|
|
64
|
+
${t===`fullstack`?i(n,`format`):`${a(n,`kick`)} format`} # oxfmt
|
|
65
65
|
\`\`\`
|
|
66
66
|
|
|
67
|
+
\`kick\` is this project's dev dependency, not a global command: every \`kick …\`
|
|
68
|
+
in these docs runs as \`${a(n,`kick`)} …\` in a shell.
|
|
69
|
+
|
|
67
70
|
## v4 framework reminders
|
|
68
71
|
|
|
69
72
|
When generating or modifying code in this project, stay aligned with the v4 conventions documented in \`.agents/AGENTS.md\`:
|
|
@@ -83,7 +86,7 @@ When generating or modifying code in this project, stay aligned with the v4 conv
|
|
|
83
86
|
- **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.
|
|
84
87
|
|
|
85
88
|
For everything else (controllers, services, modules, RequestContext API, generators, CLI commands, package additions, env wiring, troubleshooting) → \`.agents/AGENTS.md\`.
|
|
86
|
-
`}function
|
|
89
|
+
`}function f(e,t,n){return`# AGENTS.md — AI Agent Guide for ${e}
|
|
87
90
|
|
|
88
91
|
This guide is the **canonical, multi-agent reference** for this KickJS
|
|
89
92
|
application — Claude, Copilot, Codex, Gemini, etc. all read it first.
|
|
@@ -93,12 +96,17 @@ add tool-specific affordances on top.
|
|
|
93
96
|
## Before You Start
|
|
94
97
|
|
|
95
98
|
1. Run \`${n} install\` to install dependencies
|
|
96
|
-
2. Run \`
|
|
99
|
+
2. Run \`${u(n,t)}\` to verify the app starts
|
|
100
|
+
|
|
101
|
+
\`kick\` is this project's dev dependency, not a global command: every \`kick …\`
|
|
102
|
+
below runs as \`${a(n,`kick`)} …\` in a shell.${t===`fullstack`?`
|
|
97
103
|
|
|
98
104
|
## Fullstack workspace layout
|
|
99
105
|
|
|
100
106
|
This is a WORKSPACE root — the KickJS API lives in \`server/\`, the typed web
|
|
101
|
-
app in \`web/\`. Run both with \`${n
|
|
107
|
+
app in \`web/\`. Run both with \`${u(n,t)}\`. From this root,
|
|
108
|
+
\`${i(n,`test`)}\`, \`${i(n,`typecheck`)}\` and \`${i(n,`format`)}\` reach into
|
|
109
|
+
\`server/\` (and \`web/\` for typecheck).
|
|
102
110
|
|
|
103
111
|
The type loop (do not break it):
|
|
104
112
|
1. \`server/\` handlers RETURN their payloads → \`kick typegen\` emits
|
|
@@ -112,8 +120,8 @@ The type loop (do not break it):
|
|
|
112
120
|
relative \`/api/v1\` (Vite proxies it in dev) unless \`VITE_API_URL\` points at
|
|
113
121
|
an API on another origin.
|
|
114
122
|
|
|
115
|
-
Rules: kick commands (\`kick g\`, \`kick typegen\`, \`kick dev\`)
|
|
116
|
-
\`server
|
|
123
|
+
Rules: kick commands (\`kick g\`, \`kick typegen\`, \`kick dev\`, \`kick typecheck\`)
|
|
124
|
+
run in \`server/\` — the root has no \`kick.config.ts\`; never import server runtime code into \`web/\` (the d.ts bridge is
|
|
117
125
|
type-only); prefer return-value handlers so responses stay inferable.`:``}
|
|
118
126
|
3. Read the [KickJS documentation](https://kickjs.app/) for framework details
|
|
119
127
|
|
|
@@ -493,7 +501,7 @@ page and lists the local tools (\`kick explain\`, \`kick doctor\`, \`kick inspec
|
|
|
493
501
|
|
|
494
502
|
Start at <https://kickjs.app/>.
|
|
495
503
|
|
|
496
|
-
`}function
|
|
504
|
+
`}function p(e,t=`define`){let n=t===`class`?`UserModule`:`UserModule()`;return[{slug:`add-module`,frontmatterName:`kickjs-add-module`,description:`Use when the user asks to add a new feature module (controller + service + repo + DTOs).`,body:`**Trigger phrases**: "add a users module", "scaffold tasks", "new feature for X".
|
|
497
505
|
|
|
498
506
|
**Steps**:
|
|
499
507
|
1. Run \`kick g module <name>\` (use plural form if the project pluralizes — check \`kick.config.ts\`).
|
|
@@ -597,7 +605,43 @@ async create(ctx: Ctx<KickRoutes.TodoController['create']>) {
|
|
|
597
605
|
|
|
598
606
|
**Nuances**:
|
|
599
607
|
- \`@Inject\` and \`@Autowired\` are interchangeable — same runtime, same types; pick by readability.
|
|
600
|
-
- \`@Value('MISSING_KEY')\` with no default **throws on property access**, not at construction — tests that exercise the getter will surface the missing-env issue.`},{slug:`env-wiring-check`,frontmatterName:`kickjs-env-wiring-check`,description:`Use when ConfigService.get('SOME_KEY') returns undefined or @Value silently falls back to process.env.`,body
|
|
608
|
+
- \`@Value('MISSING_KEY')\` with no default **throws on property access**, not at construction — tests that exercise the getter will surface the missing-env issue.`},{slug:`env-wiring-check`,frontmatterName:`kickjs-env-wiring-check`,description:`Use when ConfigService.get('SOME_KEY') returns undefined or @Value silently falls back to process.env.`,body:`**Fastest path**: \`kick explain "ConfigService.get('MY_KEY') returned undefined"\` —
|
|
609
|
+
pipe a failing run straight in if you prefer (\`${i(e,`test`)} 2>&1 | ${a(e,`kick`)} explain\`). It
|
|
610
|
+
distinguishes the entry-file cause from the test-file one, which is the step most
|
|
611
|
+
people lose time on. The manual checks below are the same reasoning.
|
|
612
|
+
|
|
613
|
+
**Diagnosis (in order)**:
|
|
614
|
+
1. Open \`src/index.ts\`. The **first non-\`reflect-metadata\`** import MUST be \`import './config'\`.
|
|
615
|
+
2. 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:
|
|
616
|
+
\`\`\`ts
|
|
617
|
+
import { loadEnvFromSchema } from '@forinda/kickjs/config'
|
|
618
|
+
import { fromZod } from '@forinda/kickjs-schema/zod'
|
|
619
|
+
const envSchema = fromZod(z.object({ DATABASE_URL: z.url() }))
|
|
620
|
+
export const env = loadEnvFromSchema(envSchema)
|
|
621
|
+
\`\`\`
|
|
622
|
+
3. The new key MUST be declared in the 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 its parsing and defaults.
|
|
623
|
+
4. 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.
|
|
624
|
+
|
|
625
|
+
5. **In a test?** \`createTestApp\` never loads \`src/index.ts\`, so the entry's
|
|
626
|
+
\`import './config'\` never runs no matter how correct it is. The test file
|
|
627
|
+
must import it itself:
|
|
628
|
+
\`\`\`ts
|
|
629
|
+
import '@/config'
|
|
630
|
+
\`\`\`
|
|
631
|
+
Symptom is identical to the missing-entry-import case, and step 1 will look
|
|
632
|
+
fine, which is what makes it slow to spot.
|
|
633
|
+
|
|
634
|
+
**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.
|
|
635
|
+
|
|
636
|
+
**\`reloadEnv\` vs \`resetEnvCache\`** — distinct, frequently mixed up:
|
|
637
|
+
- \`reloadEnv()\` — re-reads \`process.env\` against the **already registered** schema. Use in HMR plugins after \`.env\` file changes. Schema survives.
|
|
638
|
+
- \`resetEnvCache()\` — drops the registered schema entirely. **Test-only.** Calling it between dev requests drops the project's keys.
|
|
639
|
+
|
|
640
|
+
**Nuances**:
|
|
641
|
+
- \`dotenv\` is an **optional peer dep** in v5+ — projects upgrading from older versions may need to add it explicitly.
|
|
642
|
+
- For HMR-friendly \`.env\` edits, add \`envWatchPlugin()\` to \`vite.config.ts\` — calls \`reloadEnv()\` automatically.
|
|
643
|
+
|
|
644
|
+
**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\`.`},{slug:`bootstrap-export`,frontmatterName:`kickjs-bootstrap-export`,description:`Use when HMR is silently doing full restarts on every save, or createTestApp can't find the app handle.`,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."},{slug:`thin-entry-file`,frontmatterName:`kickjs-thin-entry-file`,description:`Use when src/index.ts is accumulating module/middleware/plugin/adapter literals.`,body:`**Refactor target**:
|
|
601
645
|
|
|
602
646
|
\`\`\`ts
|
|
603
647
|
// src/modules/index.ts — fluent chain (default for \`modules.style: 'define'\`)
|
|
@@ -793,7 +837,7 @@ fine and fails at runtime.
|
|
|
793
837
|
**Local, and usually faster**
|
|
794
838
|
|
|
795
839
|
- \`kick explain "<error message>"\` — matches known failures and gives the fix.
|
|
796
|
-
Pipe a failing run in: \`${e}
|
|
840
|
+
Pipe a failing run in: \`${i(e,`test`)} 2>&1 | ${a(e,`kick`)} explain\`.
|
|
797
841
|
- \`kick doctor\` — checks this project's wiring.
|
|
798
842
|
- \`kick inspect\` — the live route / adapter table.
|
|
799
843
|
- \`.kickjs/types/\` — generated types are ground truth for what exists.
|
|
@@ -802,7 +846,7 @@ fine and fails at runtime.
|
|
|
802
846
|
|
|
803
847
|
**Rule**: if you would be guessing, look it up. If a doc page contradicts the
|
|
804
848
|
installed \`.d.mts\`, trust the \`.d.mts\` and say so — the docs may be behind the
|
|
805
|
-
version this project has.`},{slug:`refresh-agent-docs`,frontmatterName:`kickjs-refresh-agent-docs`,description:`Use after a KickJS version bump to sync the .agents/ docs with the latest CLI templates.`,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."},{slug:`deny-list`,frontmatterName:`kickjs-deny-list`,description:`Patterns to refuse outright when the user asks for them — they break v4 invariants.`,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 → `@Controller()`, with the prefix in `routes().path`.\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({ middlewares })` — 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`.\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`."}]}function
|
|
849
|
+
version this project has.`},{slug:`refresh-agent-docs`,frontmatterName:`kickjs-refresh-agent-docs`,description:`Use after a KickJS version bump to sync the .agents/ docs with the latest CLI templates.`,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."},{slug:`deny-list`,frontmatterName:`kickjs-deny-list`,description:`Patterns to refuse outright when the user asks for them — they break v4 invariants.`,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 → `@Controller()`, with the prefix in `routes().path`.\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({ middlewares })` — 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`.\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`."}]}function m(e,t,n,r=`define`){let i=`<!-- Generated by \`kick g agents\` for ${e}. Edits are overwritten on the next refresh; keep customisation in a SKILL.local.md alongside. -->`;return p(n,r).map(e=>({slug:e.slug,content:`---
|
|
806
850
|
name: ${e.frontmatterName}
|
|
807
851
|
description: ${e.description}
|
|
808
852
|
---
|
|
@@ -810,7 +854,7 @@ description: ${e.description}
|
|
|
810
854
|
${i}
|
|
811
855
|
|
|
812
856
|
${e.body}
|
|
813
|
-
`}))}function
|
|
857
|
+
`}))}function h(e,t,n){return`# GEMINI.md — ${e}
|
|
814
858
|
|
|
815
859
|
**Read \`./AGENTS.md\` first.** It is the canonical, multi-agent
|
|
816
860
|
reference for this project — every convention, structure, decorator
|
|
@@ -844,7 +888,7 @@ without us copy-pasting.
|
|
|
844
888
|
\`kick g agents --only gemini -f\` regenerates this file from the
|
|
845
889
|
CLI template. Hand-edited content is overwritten — keep customisation
|
|
846
890
|
in \`.agents/GEMINI.local.md\`.
|
|
847
|
-
`}function
|
|
891
|
+
`}function g(e,t,n){return`# COPILOT.md — ${e}
|
|
848
892
|
|
|
849
893
|
**Read \`./AGENTS.md\` first.** It is the canonical, multi-agent
|
|
850
894
|
reference for this project — every convention, structure, decorator
|
|
@@ -877,5 +921,5 @@ Codex / Cursor / Gemini / Claude Code without copy-pasting.
|
|
|
877
921
|
\`kick g agents --only copilot -f\` regenerates this file from the
|
|
878
922
|
CLI template. Hand-edited content is overwritten — keep customisation
|
|
879
923
|
in \`.agents/COPILOT.local.md\`.
|
|
880
|
-
`}var
|
|
881
|
-
//# sourceMappingURL=agent-docs-
|
|
924
|
+
`}var _=/* @__PURE__ */ e({generateAgentDocs:()=>C});const v=`.agents`,y=/* @__PURE__ */ new Set([`rest`,`minimal`,`fullstack`,`inertia`]);function b(e,t){if(t)return t;try{let t=JSON.parse(l(s(e,`package.json`),`utf-8`));if(t.name)return t.name.replace(/^@[^/]+\//,``)}catch{}return e.split(`/`).findLast(Boolean)??`app`}async function x(e){try{return(await o(e))?.modules?.style===`class`?`class`:`define`}catch{return`define`}}async function S(e,t){if(t)return t;try{let t=(await o(e))?.pattern;if(t&&y.has(t))return t}catch{}return`rest`}async function C(e){let i=e.only??`all`,a=b(e.outDir,e.name),o=await t(e.pm,e.outDir),l=await S(e.outDir,e.template),u=await x(e.outDir),p=i===`agents`||i===`both`||i===`all`,_=i===`claude`||i===`both`||i===`all`,y=i===`skills`||i===`all`,C=i===`gemini`||i===`all`,w=i===`copilot`||i===`all`,T=[];if(p&&T.push({file:s(e.outDir,v,`AGENTS.md`),render:()=>f(a,l,o)}),_&&T.push({file:s(e.outDir,`CLAUDE.md`),render:()=>d(a,l,o)}),y)for(let t of m(a,l,o,u))T.push({file:s(e.outDir,v,`skills`,t.slug,`SKILL.md`),render:()=>t.content});C&&T.push({file:s(e.outDir,v,`GEMINI.md`),render:()=>h(a,l,o)}),w&&T.push({file:s(e.outDir,v,`COPILOT.md`),render:()=>g(a,l,o)});let E=[];for(let{file:t,render:i}of T)c(t)&&!e.force&&!await r({message:`${t.replace(e.outDir+`/`,``)} already exists. Overwrite?`,initialValue:!1})?console.log(` Skipped — existing ${t.replace(e.outDir+`/`,``)} preserved.`):(await n(t,i()),E.push(t));return E}export{C as n,_ as t};
|
|
925
|
+
//# sourceMappingURL=agent-docs-ZgfnGL-j.mjs.map
|