@aventara/cli 1.0.0-rc.1 → 1.0.0-rc.11

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/CHANGELOG.md CHANGED
@@ -1,5 +1,266 @@
1
1
  # @aventara/cli
2
2
 
3
+ ## 1.0.0-rc.11
4
+
5
+ ### Patch Changes
6
+
7
+ - 6d8b589: The agent skill's `reference/errors.md` (written by `aventara new`, `aventara init` and `aventara skill`) now carries
8
+ `@aventara/core`'s current error reference: `COMPILER_RESERVED_RESOURCE_NAME` names `all`, the member beside the
9
+ Resources on `serverClient` (and Next.js's `avClient`).
10
+ - e5e98e6: The docs moved to https://aventara.razor34.dev/framework. Every `docs` link in `AvErrorCatalog` (and
11
+ `ERRORS.md`), and every docs link `aventara new`, `aventara init` and `aventara skill` write into the scaffold and the
12
+ agent skill, now point there instead of https://aventara-framework.vercel.app.
13
+ - fb20833: The agent skill `aventara new`, `aventara init` and `aventara skill` write now teaches rc.11's features. A new
14
+ `reference/client.md` covers calls made together going out as one `POST /_all`, `avClient.all` (strict, or
15
+ `settle: true`), aborting one call or a whole `all`, `avLazy`, `grouping: false`, `all` in server code
16
+ (`framework.serverClient.all`, Next.js `avClient.all`), `limits.maxAll` and `limits.maxAllConcurrency`, and the
17
+ `/_all` body and streamed answer for a client written by hand. `reference/config.md` adds caching reads:
18
+ `cache({ for, maxAge })` with `for` written first, where the stage may go, which level wins, the three audiences, and
19
+ `avCache` beside React's `cache`. SKILL.md gains two rules and a stage row for these, and points to
20
+ `@aventara/access`'s own skill when that package is installed.
21
+ - 0b2f077: The Next.js scaffold's `src/aventara/config.ts` starts with `import "server-only"`, as `src/aventara/server.ts` does, so
22
+ a Client Component that imports the configuration by mistake fails `next build` instead of bundling server code for the
23
+ browser.
24
+ - 2dd7e44: The agent skill teaches writing only what changes behaviour: no option at its default value (a limit, `grouping: true`,
25
+ `agent.extends: "client"`, the root's `exposed: true`), no key or wrapper that repeats a built-in, no type annotation
26
+ the inference already gives. `cache({ for, maxAge })` still writes `for`, even the default `"user"`. Its examples drop
27
+ the root's `exposed: true` and the agent layer's `extends: "client"`.
28
+
29
+ The scaffold follows the same rule: `aventara new` and `aventara init` no longer write `exposed: true` in
30
+ `aventara.config.ts` (NestJS) or `src/aventara/config.ts` (Next.js). The root exposes everything by default, as the
31
+ comment above it says.
32
+
33
+ ## 1.0.0-rc.10
34
+
35
+ ### Patch Changes
36
+
37
+ - 82afc5e: The scaffolded configuration's `diagnostics` sink logs `String(error)` when an error's `stack` is empty or missing,
38
+ instead of an empty `raw error` line.
39
+
40
+ `aventara` prints a defect as `String(error)` when its `stack` is empty or missing, instead of a blank or `undefined`
41
+ line.
42
+
43
+ - 09585dd: The agent skill's configuration reference covers `managedElsewhere`: a model whose table another service owns, and
44
+ the Prisma 7 external-tables setup that keeps `prisma migrate` off it.
45
+ - 04bb39a: `engines.node` is now `^22.23.4 || >=24.22.1`, the Node security releases of 2026-10-20 (CVE-2026-105481,
46
+ CVE-2026-105482, CVE-2026-105483, CVE-2026-106069, CVE-2026-106072, CVE-2026-106073, CVE-2026-106074,
47
+ CVE-2026-111497). The bins refuse an older Node in one sentence naming that range.
48
+ - 4f0fd29: The Prisma 7 adapter's peer floor is now `^7.10.1` (`prisma`, `@prisma/client`, `@prisma/adapter-pg`,
49
+ `@prisma/adapter-better-sqlite3`). `prisma` 7.10.0 pins `mysql2` 3.15.3 (GHSA-3f6p-5ww8-9rcr, GHSA-rgwj-5xj2-c3m3)
50
+ and, through `@prisma/config`, `deepmerge-ts` 7.1.5 (GHSA-ggr8-5vv4-36mx); 7.10.1 pins `mysql2` 3.24.4 and
51
+ `deepmerge-ts` 8.0.2. `aventara new` and `aventara init` install Prisma at the floor, so new projects get 7.10.1, and
52
+ `aventara init` refuses a project whose Prisma is below it.
53
+ - 10341d5: The Next.js scaffold's `src/prisma.ts` keeps one PrismaClient per generated schema: after `aventara:prepare` regenerates
54
+ the client, the next call makes a new one and disconnects the old one, so `next dev` needs no restart.
55
+ - 88263a1: Startup checks, tightened:
56
+
57
+ - An `mcp.authorization.servers` entry with a query or a fragment is refused for https URLs too, not only for loopback
58
+ http ones: an authorization server's issuer has neither (RFC 8414).
59
+ - A `client.resources` or `agent.resources` entry for a Resource managed elsewhere is refused (`COMPILER_UNKNOWN_RESOURCE`):
60
+ those layers never have the Resource, so nothing configured there would run. Configure it at the root or in
61
+ `application`.
62
+
63
+ - 88263a1: Documentation: `$access.can([])` answers `[]`, not a refusal; the MCP README states the query and fragment rule for
64
+ every authorization server.
65
+
66
+ ## 1.0.0-rc.9
67
+
68
+ ### Patch Changes
69
+
70
+ - a0bb05e: The agent skill that `aventara new`, `aventara init` and `aventara skill` write has a new section, "Calling the API over
71
+ HTTP", with a working curl example: the operation path uses the model's name as written in the Prisma schema
72
+ (`/api/_resources/User/create/one`), every request sends the `Aventara-Protocol-Version: 1` and
73
+ `Aventara-Contract-Hash` headers (the hash comes from `GET /api/_contract`), and a create's body is `{ "data": … }`. It
74
+ lists the answers each mistake gets. The printed next steps point to it. To refresh the skill in an existing
75
+ project, run `aventara skill`.
76
+ - 8c40b81: `aventara new` and `aventara init` now scaffold Next.js apps.
77
+
78
+ - `aventara new <name> --host next` runs `create-next-app@latest` (TypeScript, the App Router under `src/`, the `@/*`
79
+ alias, no install of its own), then the same `init` steps, then the install. create-next-app asks its own questions
80
+ on your terminal; with `--yes` it takes its defaults. Its own flags go after `--`, as they are:
81
+ `aventara new my-app --host next --yes -- --tailwind`. `--skip-git` becomes its `--disable-git`. Without a terminal,
82
+ `--yes` is required. `--host` defaults to `nest`: a NestJS project is scaffolded exactly as before.
83
+ - `aventara init` tells the host by `package.json`: `@nestjs/core` is NestJS 12, `next` is Next.js 16, and a project
84
+ that depends on both or neither is refused in one sentence, with nothing written. A Next.js app needs `src/app/`
85
+ and the `@/*` → `./src/*` path in `tsconfig.json`, and no ORM yet.
86
+ - In a Next.js app, init writes `src/aventara/config.ts`, `src/aventara/adapter.ts`, `src/aventara/server.ts`
87
+ (`Aventara()`, exporting `handlers`, `avClient`, `avApp` and `ready`), `src/app/api/[...aventara]/route.ts`,
88
+ `src/instrumentation.ts` (awaiting `ready()` on the Node.js runtime) and `src/prisma.ts`, with Prisma's schema and
89
+ config. `aventara:prepare` ends with `aventara-build --client` and runs on `postinstall` and `prebuild`; the files it
90
+ generates (`src/aventara/generated/`, `src/aventara/client.ts`, `src/aventara/universal.ts`) are added to
91
+ `.gitignore`. An instrumentation file of your own is never replaced: the lines to add are printed.
92
+ - Each host package now declares its project layout in its manifest (`"aventara": { "host": … }`). The CLI scaffolds
93
+ from it and `aventara-build` reads its paths from it, so the two always agree.
94
+
95
+ - 501b832: `aventara new --host next` and `aventara init` in a Next.js app add `serverExternalPackages: ["@aventara/core",
96
+ "@aventara/prisma7-adapter"]` to `next.config.ts`, so Node.js loads them once per server process: every route and
97
+ page shares one core, one Framework and one Prisma client. The line goes into create-next-app's config, or any config
98
+ whose `const nextConfig = {` object has no `serverExternalPackages`; an app with no config gets a `next.config.ts`. A
99
+ config that already names `serverExternalPackages`, or is written another way, is never changed, even with `--yes`:
100
+ the line to add is printed, with a warning. The agent skill's Next.js section says to keep it.
101
+ - The agent skill's Next.js section says what a page that calls `avClient` or `avApp` needs under Cache Components
102
+ (create-next-app's default): the calling component inside `<Suspense>` (or a `loading.tsx`), `"use cache"` on the
103
+ function that makes the call, or `export const instant = false`.
104
+
105
+ ## 1.0.0-rc.8
106
+
107
+ 1.0.0-rc.5, rc.6 and rc.7 were tagged but never published; 1.0.0-rc.8 contains everything listed under them and the changes below.
108
+
109
+ ## 1.0.0-rc.7
110
+
111
+ 1.0.0-rc.5 and 1.0.0-rc.6 were tagged but never published; 1.0.0-rc.7 contains everything listed under them and the changes below.
112
+
113
+ ## 1.0.0-rc.6
114
+
115
+ 1.0.0-rc.5 was tagged but never published. 1.0.0-rc.6 contains everything listed under 1.0.0-rc.5 and the fix below.
116
+
117
+ ## 1.0.0-rc.5
118
+
119
+ ## 1.0.0-rc.4
120
+
121
+ ### Patch Changes
122
+
123
+ - 7c3b65f: Build-time Contracts for serverless and edge cold starts.
124
+
125
+ - New package `@aventara/build`, bin `aventara-build`, a development dependency. It runs `src/aventara.config.ts` and
126
+ `src/aventara.adapter.ts` without a database client, compiles the Contracts with the project's `@aventara/core` and
127
+ writes `src/generated/aventara/contracts.generated.ts` (`aventaraContracts`), which a serverless or edge entry passes
128
+ to `createFramework` as `prebuilt`. A configuration that startup would refuse fails the build with the same
129
+ `CONFIG_…`/`COMPILER_…` diagnostics. `aventara-build --check` writes nothing and exits 1 when the file is missing or
130
+ stale, naming the Resources that changed.
131
+ - `@aventara/prisma7-adapter`: `describePrismaAdapter({ discovery, provider, driver })` states the adapter's passive
132
+ facts (the model, the driver's transaction capability, the referential actions, the computed fields) with no client.
133
+ `createPrismaAdapter({ ...description, client })` builds the adapter from the same facts, and still checks the client
134
+ against the discovery artifact.
135
+ - `@aventara/cli`: the scaffold's `src/aventara.config.ts` exports the configuration as a plain value
136
+ (`export const aventaraConfig = { … } as const`) with no `adapter`. A new `src/aventara.adapter.ts` default-exports
137
+ `describePrismaAdapter(…)`, and `app.module.ts` joins the two:
138
+ `config: { ...aventaraConfig, adapter: await createPrismaAdapter({ ...adapter, client: prisma }) }`. The Nest server
139
+ still compiles its Contracts at startup and passes no `prebuilt`. `aventara:prepare` ends with `&& aventara-build`,
140
+ and `@aventara/build` is an exact development dependency.
141
+
142
+ - 2b1b17e: `aventara-build`'s files no longer land inside a Prisma client generated into `src/generated`.
143
+
144
+ When `aventara init` reuses a project whose Prisma client is generated into `src/generated`, it already puts the
145
+ discovery artifact in `src/aventara/`, because `prisma generate` deletes every file in its output directory that it did
146
+ not write. `aventara-build` still wrote its three files to `src/generated/aventara/`, so each `prisma generate` deleted
147
+ them and the project stopped compiling until the next `aventara:prepare`. Now all of Aventara's generated files are
148
+ in one place.
149
+
150
+ - `@aventara/build`: `aventara-build` writes `resources.generated.ts`, `computed-fields.generated.ts` and
151
+ `contracts.generated.ts` to the directory the configuration imports `aventaraResources` from, so the tree is always
152
+ written where the configuration reads it. A configuration that imports no tree keeps `src/generated/aventara/`.
153
+ The files of a project whose client is generated anywhere else are the same bytes, in the same place.
154
+ - `@aventara/prisma7-adapter`: with `--config`, the artifact imports the computed fields from its sibling,
155
+ `./computed-fields.generated`, wherever `--out` puts it. `--config` is still required for that import and the step
156
+ still checks that the file exists, but the step no longer uses its location. A scaffold's artifact is unchanged.
157
+ - `@aventara/cli`: in that project, `src/aventara.config.ts` imports the tree from `./aventara/resources.generated`,
158
+ and `.gitignore` gets the one `/src/aventara/` line that covers all four files (no separate
159
+ `/src/generated/aventara/contracts.generated.ts` line). The agent skill says where the generated files are in
160
+ both cases.
161
+
162
+ - 99169d2: Policy engines, reads first. `createFramework` takes an optional root `policy: { engine, principal }`: an engine that
163
+ answers three questions (`can`, `scopeOf`, `fieldsOf`, each now or as a promise), and a function that derives a
164
+ request's principal from its `ctx.$state`. Core never imports an engine; one satisfies `AvPolicyEngine` by its shape,
165
+ and a scope or grant is a fragment of Aventara's own `where` (`AvPolicyWhere`).
166
+
167
+ - Client and agent requests are checked (an MCP tool call is an agent request). An application call is checked only
168
+ when it names a principal: `framework.application.Note.find.many(args, { as: user })`. A call a stage makes through
169
+ `ctx` never is.
170
+ - Before any guard, `can` and the fields the request names or receives (`fieldsOf`); a refusal is `403 A4002`. At the
171
+ adapter call, after every developer stage, the read scope is ANDed into the root `where`, every to-many include and
172
+ its `$count`, and every relation filter, at every level. A to-one include of a row out of scope refuses the request;
173
+ it is never nulled.
174
+ - Governed fields (the engine's `governed` list) are left out of every default projection and carry `governed: true`
175
+ in the Contracts. Name one to get it: `select: ["$defaults", "email"]`, where `$defaults` is the level's default
176
+ projection. It is refused where a returned row does not grant it, and a filter or sort by it is checked before the
177
+ query runs, so it cannot reveal values the caller may not read.
178
+ - The engine's `governed` and `paths` lists are checked against the Core Contract at startup. A rule's paths are lists
179
+ of segments, as other paths in core are: `["Note", "campaign", "members", "some", "userId", "equals"]`.
180
+ - Writes are checked as well; see the policy writes entry.
181
+
182
+ Without `policy`, nothing changes: the Contracts and their hashes are the same bytes.
183
+
184
+ - 154e440: Policy engines check writes. Every create, update, delete and upsert a client or agent makes (or an application call
185
+ made `{ as }` a principal) is now checked by the configuration's `policy`, where before it was refused.
186
+
187
+ - The fields a write sends are held to `fieldsOf({ access: "write" })` before any guard; a field outside it answers
188
+ `403 A4002`. A field writable on some rows only is checked against every row an update reaches, and against the
189
+ row a create inserts, after the insert and inside its transaction.
190
+ - A create asks `can({ action: "create", row })` about each new row on its final data. Its rules can look rows up
191
+ through `exists`, which runs inside the write's transaction, so a plan that creates a campaign and then its first
192
+ note sees the campaign.
193
+ - An update or delete acts only on rows the caller may both change (`scopeOf` for the action) and read. A single-row
194
+ one that matches nothing answers `A4002` when the caller can read the row, and `A2003` when it cannot, so the
195
+ answer does not reveal that the row exists. A `many` or `count` one answers for the caller's rows only.
196
+ - An update that moves a row out of what the caller reads is rolled back with `A4002`. So is one that fails an `after`
197
+ condition: inside the transaction core asks `can({ action: "update", row })` about each changed row of every
198
+ checked update. The engine's new `afterChecks` member (`{ Note: ["update"] }`) names the updates whose grants carry
199
+ such a condition, which are the ones refused where there is no interactive transaction.
200
+ - Where the operation's `transactionsStyle` is `"interactive"`, a checked write runs in a transaction of its own. Where
201
+ it is `"none"` (Cloudflare D1), a write that can only be checked after it runs is refused before it runs; every other
202
+ write runs, a create looking up before it inserts, and an unlisted update without the after check.
203
+ - Nested writes (a relation directive in a write's data) are refused under a policy for now.
204
+
205
+ `afterChecks` is checked against the Core Contract at startup and changes no Contract and no prebuilt fingerprint.
206
+
207
+ - 3813207: The Resource tree and the computed fields come from `aventara-build`.
208
+
209
+ - `@aventara/build`: before it compiles the Contracts, `aventara-build` writes two more files under
210
+ `src/generated/aventara/`. `resources.generated.ts` exports `aventaraResources`: every `defineResource(…)` result
211
+ that the files `src/resources/**/*.resource.ts` export, found by its type (never run), one `resources` tree per
212
+ layer, written as the plain spreads you wrote by hand (`root` always, `application`, `client` and `agent` when some
213
+ Resource has a block for them). Two definitions of one Resource stop the build, naming both. Imports are spelled as
214
+ the project spells its own. `computed-fields.generated.ts` exports `computedFields` and its type `AvComputedFields`:
215
+ which fields the configuration's write compute fills, read off its type after the tree exists, so a fresh install is
216
+ typed right on its first `aventara:prepare`. `--check` covers all three files. `typescript` (`>=5.7.0 <7`) is now a
217
+ peer dependency.
218
+ - `@aventara/prisma7-adapter`: the generate step no longer reads the configuration. With `--config`, the discovery
219
+ artifact imports `computedFields` and `AvComputedFields` from the file `aventara-build` writes beside the
220
+ configuration (`generated/aventara/computed-fields.generated.ts`); a `--config` file that does not exist is still
221
+ refused. `readConfigComputedFields`, `AvPrismaConfigReaderError` and `ConfigComputedFieldsReading` are removed from
222
+ `@aventara/prisma7-adapter/generate`, as are `PrismaGenerateToolchain.readComputedFields` and
223
+ `PrismaGenerateResult.computedFields`.
224
+ - `@aventara/cli`: the scaffold's `src/aventara.config.ts` takes its Resources from the tree,
225
+ `resources: aventaraResources.root`, so a new Resource file needs no configuration edit; the agent skill says so.
226
+
227
+ ## 1.0.0-rc.3
228
+
229
+ ### Patch Changes
230
+
231
+ - b38034d: A refusal that quotes a failed child's output (`npm install`, `nest new`) ends with that output as the child wrote it.
232
+ It printed a period of its own after the child's last line (`npm ERR! the registry said no.`).
233
+
234
+ ## 1.0.0-rc.2
235
+
236
+ ### Patch Changes
237
+
238
+ - `aventara init`'s refusal of a TypeScript 7 project names the supported range: "use TypeScript 5.7 to 6" (it said
239
+ "use TypeScript 6 or 5"). The Prisma adapter's `typescript` peer range starts at 5.7.0 now.
240
+ - An agent skill for your AI coding agent. `aventara new` and `aventara init` write `.claude/skills/aventara/`:
241
+ `SKILL.md` (the Agent Skills format Claude Code reads: when to use it, and one rule per task) and
242
+ `reference/config.md`, `reference/stages.md`, `reference/recipes.md` and `reference/errors.md` (`@aventara/core`'s
243
+ `ERRORS.md`), for the Aventara version they install. They also add a short Aventara section to `AGENTS.md`, between
244
+ `<!-- aventara:start -->` and `<!-- aventara:end -->`, for agents that read `AGENTS.md`: an existing `AGENTS.md`
245
+ keeps everything else, and `CLAUDE.md` is never written.
246
+ - `aventara skill` refreshes those files for the `@aventara/core` installed in the project (its version and its
247
+ `ERRORS.md`; it runs none of the project's packages). It rewrites the skill files it wrote, keeps one you changed
248
+ and says so (`--force` replaces it), and replaces only the marked section of `AGENTS.md`.
249
+ - `aventara new` and `aventara init` write an `aventara:prepare` script that also passes
250
+ `--config src/aventara.config.ts`, so the generated types know which fields your configuration computes: a
251
+ variant's guards, pipes and filters may leave exactly those out of a create. A project set up before keeps working;
252
+ add the flag to its script to get the precise types.
253
+ - The agent skill says that a `Date` or bytes value a stage is told is that stage's own copy, so changing it in place
254
+ changes nothing another stage sees, what is written or what the caller receives; and that a `compute.read` stage with
255
+ no `dependsOn` computes from the same inputs for every row, so its value usually belongs in response metadata or
256
+ `ctx.$state`. In rc.1 it said neither.
257
+ - The agent skill says that a `compute.read` stage is told the row frozen: it returns its field's value, and writing
258
+ into `record` answers `A3000`. Its error reference lists a nested write that writes its relation back (`A2004`,
259
+ `V1012`).
260
+ - The agent skill says that a computed value its field's `format` refuses (a relative path for `format: "url"`)
261
+ answers `A3000`, as a value of the wrong type does.
262
+ - Released with the other Aventara packages, and `aventara new` and `aventara init` install them at 1.0.0-rc.2.
263
+
3
264
  ## 1.0.0-rc.1
4
265
 
5
266
  ### Patch Changes
@@ -65,7 +326,6 @@
65
326
  nullable: false,
66
327
  list: false,
67
328
  lifecycle: ["VIRTUAL"],
68
- format: "url",
69
329
  },
70
330
  pipelines: {
71
331
  compute: {
package/README.md CHANGED
@@ -1,11 +1,13 @@
1
1
  # `@aventara/cli`
2
2
 
3
- The `aventara` command: it scaffolds an Aventara server on NestJS 12.
3
+ The `aventara` command: it scaffolds an Aventara server on NestJS 12 or Next.js 16.
4
4
 
5
5
  ```bash
6
6
  npm i -g @aventara/cli@rc # or run it once: npx @aventara/cli@rc <command>
7
7
  aventara new my-api # a new NestJS project with Aventara
8
- aventara init # Aventara added to the NestJS 12 project in this directory
8
+ aventara new my-app --host next # a new Next.js app with Aventara (create-next-app, then init)
9
+ aventara init # Aventara added to the NestJS 12 or Next.js 16 project in this directory
10
+ aventara skill # refresh the agent skill for the installed @aventara/core
9
11
  ```
10
12
 
11
13
  It is run once, globally or through `npx`; it is not a dependency of the projects it writes. The frontend's side
@@ -22,16 +24,29 @@ without `.env` (it is in `.gitignore`). No commit is made, and one line says why
22
24
  `user.name`/`user.email`, or when the directory is already inside a git repository (a monorepo: commit it there).
23
25
  `--skip-git` makes no repository and no commit.
24
26
 
27
+ ### `aventara new <name> --host next`
28
+
29
+ Runs `create-next-app@latest <name> --ts --app --src-dir --import-alias "@/*" --use-<npm|pnpm> --skip-install`, then
30
+ `aventara init`'s pipeline over the new app, then the install. create-next-app asks its own questions on your terminal;
31
+ with `--yes` it takes its defaults instead (and is given `--yes` too), which is also what a run with no terminal needs.
32
+ Its own flags go after `--`, as they are: `aventara new my-app --host next --yes -- --tailwind --eslint`. `--skip-git`
33
+ becomes its `--disable-git`. `--host` defaults to `nest`.
34
+
25
35
  ## `aventara init`
26
36
 
27
- Runs inside an existing NestJS 12 project. It refuses a directory with no `package.json`, another Nest major,
37
+ Runs inside an existing NestJS 12 or Next.js 16 project, telling them apart by `package.json`: `@nestjs/core` is
38
+ NestJS, `next` is Next.js, and a project depending on both or neither is refused in one sentence. A Next.js app must use
39
+ the App Router under `src/app/` and map `@/*` to `./src/*` in `tsconfig.json` (as create-next-app writes it), and have
40
+ no ORM yet. The rest of this section is NestJS's; a Next.js app gets [its own files](#what-it-writes-in-a-nextjs-app).
41
+
42
+ In a NestJS project, it refuses another Nest major,
28
43
  TypeScript 7, a yarn-only lockfile, or a project already initialized.
29
44
 
30
45
  In a project with no ORM yet, the ORM and the database are asked (or taken from the flags), and everything below is
31
46
  written.
32
47
 
33
48
  In a project that already uses Prisma, the installed Prisma must be one an Aventara adapter supports, or the run is
34
- refused in one sentence with nothing written. Today that is Prisma 7 (`^7.10.0`) on SQLite or PostgreSQL, with a driver
49
+ refused in one sentence with nothing written. Today that is Prisma 7 (`^7.10.1`) on SQLite or PostgreSQL, with a driver
35
50
  adapter and the `prisma-client` generator. Your schema, Prisma config and service are reused and never written, and
36
51
  your `.env` only gains a `CORS_ORIGINS` line at its end when it has none. Init finds the class extending `PrismaClient`
37
52
  and the module exporting it, or asks.
@@ -45,6 +60,7 @@ possible answer is shown, not asked.
45
60
  | Flag | Question | Default |
46
61
  |---|---|---|
47
62
  | `<name>` (`new` only) | The project directory. | required |
63
+ | `--host <nest\|next>` (`new` only) | The framework to build on; `init` reads it from `package.json`. Not asked. | `nest` |
48
64
  | `--orm <alias>` | The ORM, as an adapter's alias: `prisma7` (Prisma 7, `@aventara/prisma7-adapter`). `--help` lists the aliases that exist. | the only one there is |
49
65
  | `--db <provider>` | The database: the adapter's providers (`sqlite`, `postgresql`). | `sqlite` |
50
66
  | `--package-manager <npm\|pnpm>` | The package manager. | the lockfile's, else the one that launched the CLI, else npm |
@@ -54,6 +70,7 @@ possible answer is shown, not asked.
54
70
  | `--skip-git` (`new`) | Passed to `nest new`. | |
55
71
  | `-y`, `--yes` | Accept every unanswered default, and replace existing content that differs. | |
56
72
  | `--verbose` | Show the output of `nest new` and the install as they run. | |
73
+ | `-- <args>` (`new --host next`) | Passed to create-next-app as they are, after its own. | |
57
74
 
58
75
  While it works, each step is shown on stderr, such as `[3/4] Installing dependencies (npm install)`. On a terminal it
59
76
  has a spinner and the seconds so far; in a pipe, in CI (`CI`) or with `NO_COLOR` it is one plain line per step
@@ -77,6 +94,30 @@ when you confirm, or with `--yes`; where nobody can be asked, the run stops and
77
94
  | `package.json`: `@aventara/*` at this CLI's version, `prisma`, `@prisma/client` and the driver at `7.10.0`; `aventara:prepare`, run by `postinstall` and by `prebuild`, `prestart`, `prestart:dev` and `prestart:debug`, and the `.env` on the start scripts and `test:e2e` (`--env-file`, `--env-file-if-exists`) | you |
78
95
  | `pnpm-workspace.yaml` (pnpm only): `allowBuilds` for Prisma's and SQLite's install scripts | you |
79
96
  | `src/generated/prisma/**`, `src/generated/aventara/discovery.artifact.ts` | generated by `aventara:prepare` (run on every install, build and start, so a schema change needs only a restart); never edit |
97
+ | `.claude/skills/aventara/` (`SKILL.md`, `reference/*.md`, `.aventara-skill.json`): the agent skill your AI coding agent reads | Aventara's: `aventara skill` refreshes it, and keeps a file you changed unless `--force` |
98
+ | `AGENTS.md`: an Aventara section between `<!-- aventara:start -->` and `<!-- aventara:end -->`, appended to an existing file | you, except the marked section |
99
+
100
+ ### What it writes in a Next.js app
101
+
102
+ Everything Aventara is in one folder, `src/aventara/`, at the paths `@aventara/next` declares and `aventara-build`
103
+ reads.
104
+
105
+ | Path | Owner afterwards |
106
+ |---|---|
107
+ | `prisma/schema.prisma`, `prisma.config.ts` | you (as in a NestJS project) |
108
+ | `src/prisma.ts`: `prisma()`, the app's one Prisma client with the driver adapter, made on first use and kept across `next dev` reloads | you |
109
+ | `src/aventara/config.ts`: `aventaraConfig`, as in a NestJS project, logging through `console.error` | you |
110
+ | `src/aventara/adapter.ts`: the adapter's description | you |
111
+ | `src/aventara/server.ts`: `Aventara({ ...aventaraConfig, adapter, prebuilt, state })` exporting `handlers`, `avClient`, `avApp` and `ready`; `@/aventara/server` | you |
112
+ | `src/app/api/[...aventara]/route.ts`: every method of `handlers` | you |
113
+ | `src/instrumentation.ts`: awaits `ready()` on the Node.js runtime, so a bad configuration stops `next start`. An instrumentation file of yours is never replaced, even with `--yes`: the lines to add are printed | you |
114
+ | `next.config.ts`: `serverExternalPackages: ["@aventara/core", "@aventara/prisma7-adapter"]` added to its configuration object, so Node.js loads them once per server process (one core and one Prisma client for every route and page). Added to create-next-app's config, or to any whose `const nextConfig = {` object has no `serverExternalPackages`; written as a new `next.config.ts` when the app has none. A config that already names `serverExternalPackages`, or is written another way, is never changed, even with `--yes`: the line to add is printed | you |
115
+ | `package.json`: `@aventara/core`, `@aventara/next`, the adapter and `@aventara/build` at this CLI's version, `server-only`, Prisma at `7.10.0`; `aventara:prepare` (ending in `aventara-build --client`), run by `postinstall` and `prebuild` | you |
116
+ | `.env` (`DATABASE_URL`), `.gitignore` (`/src/generated/`, `/dev.db*`, `/src/aventara/generated/`, `/src/aventara/client.ts`, `/src/aventara/universal.ts`, `.env`) | you |
117
+ | `src/aventara/client.ts`, `src/aventara/universal.ts`, `src/aventara/generated/` | generated by `aventara:prepare`; never edit |
118
+
119
+ No CORS (the browser calls the same origin), no Pages Router, no proxy, and no MCP route: an `mcp` endpoint you add on
120
+ Next.js needs `authorization`. Next steps: `npx prisma db push`, then `npm run dev`.
80
121
 
81
122
  ### Next steps it prints
82
123
 
@@ -120,15 +161,23 @@ lower-cased or pluralized.
120
161
  Results are read-only. A list result is a `readonly` array, so type it `readonly User[]`:
121
162
  `const users: readonly User[] = await avClient.User.find.many({});`.
122
163
 
164
+ ## `aventara skill`
165
+
166
+ Writes the agent skill for the `@aventara/core` installed in the project in this directory: its version, and its
167
+ `ERRORS.md` as `reference/errors.md`. It reads those files and runs none of the project's packages. A skill file it
168
+ wrote before is replaced; one you changed is kept, with a warning, unless you pass `--force`. In `AGENTS.md` only the
169
+ text between the Aventara markers is replaced (or the section appended), and `CLAUDE.md` is never written. Run it with
170
+ the CLI at your `@aventara/core` version: `npx @aventara/cli@<version> skill`.
171
+
123
172
  ## Supported
124
173
 
125
174
  - NestJS 12.
126
- - Node `^22.18.0 || >=24.2.0`. On any other Node the bin refuses in one sentence naming that range. On Node 22 use
175
+ - Node `^22.23.4 || >=24.22.1`. On any other Node the bin refuses in one sentence naming that range. On Node 22 use
127
176
  npm ≥ 11, because Node 22's bundled npm 10 cannot install Nest 12's own scaffold. A CommonJS project's jest e2e needs
128
177
  Node ≥ 24.9, which is Nest's and Jest's limit.
129
178
  - npm and pnpm. Yarn is not supported.
130
179
  - ESM and CommonJS projects.
131
- - Prisma 7 (`^7.10.0`) on SQLite and PostgreSQL.
180
+ - Prisma 7 (`^7.10.1`) on SQLite and PostgreSQL.
132
181
 
133
182
  The ORMs, majors, databases and drivers on offer are generated from the Aventara adapter packages that exist
134
183
  (`src/catalog/adapter.catalog.generated.ts`), never listed by hand, so a future `@aventara/prisma8-adapter` appears
@@ -1,7 +1,7 @@
1
1
  export class AvConflictsNotConfirmedError extends Error {
2
2
  name = "AvConflictsNotConfirmedError";
3
3
  }
4
- export function conflictWarning(conflicts) {
4
+ function conflictWarning(conflicts) {
5
5
  return `${conflicts.join(", ")} already ${conflicts.length === 1 ? "has" : "have"} other content, and initializing will replace ${conflicts.length === 1 ? "it" : "them"}`;
6
6
  }
7
7
  export async function confirmConflicts(conflicts, consent) {
@@ -9,7 +9,7 @@ export const ADAPTER_CATALOG = [
9
9
  "package": "@prisma/client",
10
10
  "major": 7
11
11
  },
12
- "range": "^7.10.0",
12
+ "range": "^7.10.1",
13
13
  "familyPackages": [
14
14
  "prisma",
15
15
  "@prisma/client",
@@ -0,0 +1,10 @@
1
+ import { HOST_CATALOG } from "./host.catalog.generated.js";
2
+ import { lowestMajorOf } from "./range.reader.js";
3
+ export const HOSTS = HOST_CATALOG;
4
+ export const DEFAULT_HOST = "nest";
5
+ export function hostOf(alias) {
6
+ return HOST_CATALOG.find((entry) => entry.alias === alias);
7
+ }
8
+ export function frameworkMajorOf(host) {
9
+ return lowestMajorOf(host.framework.range);
10
+ }
@@ -0,0 +1,32 @@
1
+ export const HOST_CATALOG = [
2
+ {
3
+ "alias": "nest",
4
+ "label": "NestJS",
5
+ "package": "@aventara/nest",
6
+ "framework": {
7
+ "package": "@nestjs/core",
8
+ "range": "^12.0.0"
9
+ },
10
+ "layout": {
11
+ "config": "src/aventara.config",
12
+ "adapter": "src/aventara.adapter",
13
+ "generated": "src/generated/aventara"
14
+ }
15
+ },
16
+ {
17
+ "alias": "next",
18
+ "label": "Next.js",
19
+ "package": "@aventara/next",
20
+ "framework": {
21
+ "package": "next",
22
+ "range": ">=16.4 <17"
23
+ },
24
+ "layout": {
25
+ "config": "src/aventara/config",
26
+ "adapter": "src/aventara/adapter",
27
+ "generated": "src/aventara/generated",
28
+ "client": "src/aventara/client.ts",
29
+ "universal": "src/aventara/universal.ts"
30
+ }
31
+ }
32
+ ];
package/dist/cli.js CHANGED
@@ -6,6 +6,7 @@ import { AvProjectRefusedError } from "./project/project.inspector.js";
6
6
  import { runCommand } from "./run/command.runner.js";
7
7
  import { AvInstallFailedError, runInit } from "./run/init.orchestrator.js";
8
8
  import { runNew } from "./run/new.orchestrator.js";
9
+ import { AvSkillRefusedError, runSkill } from "./run/skill.orchestrator.js";
9
10
  import { progressModeOf } from "./run/step.reporter.js";
10
11
  import { AvUnansweredQuestionsError, } from "./wizard/answer.resolver.js";
11
12
  import { AvWizardCancelledError, createReadlinePrompter, } from "./wizard/readline.prompter.js";
@@ -18,6 +19,7 @@ const REFUSALS = [
18
19
  AvProjectRefusedError,
19
20
  AvConflictsNotConfirmedError,
20
21
  AvInstallFailedError,
22
+ AvSkillRefusedError,
21
23
  ];
22
24
  const MANIFEST = new URL("../package.json", import.meta.url);
23
25
  function ownVersion() {
@@ -38,6 +40,14 @@ export async function runCli(argv, io) {
38
40
  io.stdout(`${ownVersion()}\n`);
39
41
  return 0;
40
42
  }
43
+ if (command.command === "skill") {
44
+ return runSkill(command, {
45
+ directory: io.cwd,
46
+ stdout: io.stdout,
47
+ stderr: io.stderr,
48
+ cliVersion: ownVersion(),
49
+ });
50
+ }
41
51
  if (command.command === "init") {
42
52
  return await runInit(command, {
43
53
  directory: io.cwd,
@@ -65,10 +75,13 @@ export async function runCli(argv, io) {
65
75
  }
66
76
  catch (error) {
67
77
  if (REFUSALS.some((refusal) => error instanceof refusal)) {
68
- io.stderr(`aventara: ${error.message}.\n`);
78
+ const { message } = error;
79
+ io.stderr(message.includes("\n")
80
+ ? `aventara: ${message.trimEnd()}\n`
81
+ : `aventara: ${message}.\n`);
69
82
  return 1;
70
83
  }
71
- io.stderr(`${String(error instanceof Error ? error.stack : error)}\n`);
84
+ io.stderr(`${(error instanceof Error && error.stack) || String(error)}\n`);
72
85
  return 1;
73
86
  }
74
87
  }