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

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,236 @@
1
1
  # @aventara/cli
2
2
 
3
+ ## 1.0.0-rc.10
4
+
5
+ ### Patch Changes
6
+
7
+ - 82afc5e: The scaffolded configuration's `diagnostics` sink logs `String(error)` when an error's `stack` is empty or missing,
8
+ instead of an empty `raw error` line.
9
+
10
+ `aventara` prints a defect as `String(error)` when its `stack` is empty or missing, instead of a blank or `undefined`
11
+ line.
12
+
13
+ - 09585dd: The agent skill's configuration reference covers `managedElsewhere`: a model whose table another service owns, and
14
+ the Prisma 7 external-tables setup that keeps `prisma migrate` off it.
15
+ - 04bb39a: `engines.node` is now `^22.23.4 || >=24.22.1`, the Node security releases of 2026-10-20 (CVE-2026-105481,
16
+ CVE-2026-105482, CVE-2026-105483, CVE-2026-106069, CVE-2026-106072, CVE-2026-106073, CVE-2026-106074,
17
+ CVE-2026-111497). The bins refuse an older Node in one sentence naming that range.
18
+ - 4f0fd29: The Prisma 7 adapter's peer floor is now `^7.10.1` (`prisma`, `@prisma/client`, `@prisma/adapter-pg`,
19
+ `@prisma/adapter-better-sqlite3`). `prisma` 7.10.0 pins `mysql2` 3.15.3 (GHSA-3f6p-5ww8-9rcr, GHSA-rgwj-5xj2-c3m3)
20
+ and, through `@prisma/config`, `deepmerge-ts` 7.1.5 (GHSA-ggr8-5vv4-36mx); 7.10.1 pins `mysql2` 3.24.4 and
21
+ `deepmerge-ts` 8.0.2. `aventara new` and `aventara init` install Prisma at the floor, so new projects get 7.10.1, and
22
+ `aventara init` refuses a project whose Prisma is below it.
23
+ - 10341d5: The Next.js scaffold's `src/prisma.ts` keeps one PrismaClient per generated schema: after `aventara:prepare` regenerates
24
+ the client, the next call makes a new one and disconnects the old one, so `next dev` needs no restart.
25
+ - 88263a1: Startup checks, tightened:
26
+
27
+ - An `mcp.authorization.servers` entry with a query or a fragment is refused for https URLs too, not only for loopback
28
+ http ones: an authorization server's issuer has neither (RFC 8414).
29
+ - A `client.resources` or `agent.resources` entry for a Resource managed elsewhere is refused (`COMPILER_UNKNOWN_RESOURCE`):
30
+ those layers never have the Resource, so nothing configured there would run. Configure it at the root or in
31
+ `application`.
32
+
33
+ - 88263a1: Documentation: `$access.can([])` answers `[]`, not a refusal; the MCP README states the query and fragment rule for
34
+ every authorization server.
35
+
36
+ ## 1.0.0-rc.9
37
+
38
+ ### Patch Changes
39
+
40
+ - a0bb05e: The agent skill that `aventara new`, `aventara init` and `aventara skill` write has a new section, "Calling the API over
41
+ HTTP", with a working curl example: the operation path uses the model's name as written in the Prisma schema
42
+ (`/api/_resources/User/create/one`), every request sends the `Aventara-Protocol-Version: 1` and
43
+ `Aventara-Contract-Hash` headers (the hash comes from `GET /api/_contract`), and a create's body is `{ "data": … }`. It
44
+ lists the answers each mistake gets. The printed next steps point to it. To refresh the skill in an existing
45
+ project, run `aventara skill`.
46
+ - 8c40b81: `aventara new` and `aventara init` now scaffold Next.js apps.
47
+
48
+ - `aventara new <name> --host next` runs `create-next-app@latest` (TypeScript, the App Router under `src/`, the `@/*`
49
+ alias, no install of its own), then the same `init` steps, then the install. create-next-app asks its own questions
50
+ on your terminal; with `--yes` it takes its defaults. Its own flags go after `--`, as they are:
51
+ `aventara new my-app --host next --yes -- --tailwind`. `--skip-git` becomes its `--disable-git`. Without a terminal,
52
+ `--yes` is required. `--host` defaults to `nest`: a NestJS project is scaffolded exactly as before.
53
+ - `aventara init` tells the host by `package.json`: `@nestjs/core` is NestJS 12, `next` is Next.js 16, and a project
54
+ that depends on both or neither is refused in one sentence, with nothing written. A Next.js app needs `src/app/`
55
+ and the `@/*` → `./src/*` path in `tsconfig.json`, and no ORM yet.
56
+ - In a Next.js app, init writes `src/aventara/config.ts`, `src/aventara/adapter.ts`, `src/aventara/server.ts`
57
+ (`Aventara()`, exporting `handlers`, `avClient`, `avApp` and `ready`), `src/app/api/[...aventara]/route.ts`,
58
+ `src/instrumentation.ts` (awaiting `ready()` on the Node.js runtime) and `src/prisma.ts`, with Prisma's schema and
59
+ config. `aventara:prepare` ends with `aventara-build --client` and runs on `postinstall` and `prebuild`; the files it
60
+ generates (`src/aventara/generated/`, `src/aventara/client.ts`, `src/aventara/universal.ts`) are added to
61
+ `.gitignore`. An instrumentation file of your own is never replaced: the lines to add are printed.
62
+ - Each host package now declares its project layout in its manifest (`"aventara": { "host": … }`). The CLI scaffolds
63
+ from it and `aventara-build` reads its paths from it, so the two always agree.
64
+
65
+ - 501b832: `aventara new --host next` and `aventara init` in a Next.js app add `serverExternalPackages: ["@aventara/core",
66
+ "@aventara/prisma7-adapter"]` to `next.config.ts`, so Node.js loads them once per server process: every route and
67
+ page shares one core, one Framework and one Prisma client. The line goes into create-next-app's config, or any config
68
+ whose `const nextConfig = {` object has no `serverExternalPackages`; an app with no config gets a `next.config.ts`. A
69
+ config that already names `serverExternalPackages`, or is written another way, is never changed, even with `--yes`:
70
+ the line to add is printed, with a warning. The agent skill's Next.js section says to keep it.
71
+ - The agent skill's Next.js section says what a page that calls `avClient` or `avApp` needs under Cache Components
72
+ (create-next-app's default): the calling component inside `<Suspense>` (or a `loading.tsx`), `"use cache"` on the
73
+ function that makes the call, or `export const instant = false`.
74
+
75
+ ## 1.0.0-rc.8
76
+
77
+ 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.
78
+
79
+ ## 1.0.0-rc.7
80
+
81
+ 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.
82
+
83
+ ## 1.0.0-rc.6
84
+
85
+ 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.
86
+
87
+ ## 1.0.0-rc.5
88
+
89
+ ## 1.0.0-rc.4
90
+
91
+ ### Patch Changes
92
+
93
+ - 7c3b65f: Build-time Contracts for serverless and edge cold starts.
94
+
95
+ - New package `@aventara/build`, bin `aventara-build`, a development dependency. It runs `src/aventara.config.ts` and
96
+ `src/aventara.adapter.ts` without a database client, compiles the Contracts with the project's `@aventara/core` and
97
+ writes `src/generated/aventara/contracts.generated.ts` (`aventaraContracts`), which a serverless or edge entry passes
98
+ to `createFramework` as `prebuilt`. A configuration that startup would refuse fails the build with the same
99
+ `CONFIG_…`/`COMPILER_…` diagnostics. `aventara-build --check` writes nothing and exits 1 when the file is missing or
100
+ stale, naming the Resources that changed.
101
+ - `@aventara/prisma7-adapter`: `describePrismaAdapter({ discovery, provider, driver })` states the adapter's passive
102
+ facts (the model, the driver's transaction capability, the referential actions, the computed fields) with no client.
103
+ `createPrismaAdapter({ ...description, client })` builds the adapter from the same facts, and still checks the client
104
+ against the discovery artifact.
105
+ - `@aventara/cli`: the scaffold's `src/aventara.config.ts` exports the configuration as a plain value
106
+ (`export const aventaraConfig = { … } as const`) with no `adapter`. A new `src/aventara.adapter.ts` default-exports
107
+ `describePrismaAdapter(…)`, and `app.module.ts` joins the two:
108
+ `config: { ...aventaraConfig, adapter: await createPrismaAdapter({ ...adapter, client: prisma }) }`. The Nest server
109
+ still compiles its Contracts at startup and passes no `prebuilt`. `aventara:prepare` ends with `&& aventara-build`,
110
+ and `@aventara/build` is an exact development dependency.
111
+
112
+ - 2b1b17e: `aventara-build`'s files no longer land inside a Prisma client generated into `src/generated`.
113
+
114
+ When `aventara init` reuses a project whose Prisma client is generated into `src/generated`, it already puts the
115
+ discovery artifact in `src/aventara/`, because `prisma generate` deletes every file in its output directory that it did
116
+ not write. `aventara-build` still wrote its three files to `src/generated/aventara/`, so each `prisma generate` deleted
117
+ them and the project stopped compiling until the next `aventara:prepare`. Now all of Aventara's generated files are
118
+ in one place.
119
+
120
+ - `@aventara/build`: `aventara-build` writes `resources.generated.ts`, `computed-fields.generated.ts` and
121
+ `contracts.generated.ts` to the directory the configuration imports `aventaraResources` from, so the tree is always
122
+ written where the configuration reads it. A configuration that imports no tree keeps `src/generated/aventara/`.
123
+ The files of a project whose client is generated anywhere else are the same bytes, in the same place.
124
+ - `@aventara/prisma7-adapter`: with `--config`, the artifact imports the computed fields from its sibling,
125
+ `./computed-fields.generated`, wherever `--out` puts it. `--config` is still required for that import and the step
126
+ still checks that the file exists, but the step no longer uses its location. A scaffold's artifact is unchanged.
127
+ - `@aventara/cli`: in that project, `src/aventara.config.ts` imports the tree from `./aventara/resources.generated`,
128
+ and `.gitignore` gets the one `/src/aventara/` line that covers all four files (no separate
129
+ `/src/generated/aventara/contracts.generated.ts` line). The agent skill says where the generated files are in
130
+ both cases.
131
+
132
+ - 99169d2: Policy engines, reads first. `createFramework` takes an optional root `policy: { engine, principal }`: an engine that
133
+ answers three questions (`can`, `scopeOf`, `fieldsOf`, each now or as a promise), and a function that derives a
134
+ request's principal from its `ctx.$state`. Core never imports an engine; one satisfies `AvPolicyEngine` by its shape,
135
+ and a scope or grant is a fragment of Aventara's own `where` (`AvPolicyWhere`).
136
+
137
+ - Client and agent requests are checked (an MCP tool call is an agent request). An application call is checked only
138
+ when it names a principal: `framework.application.Note.find.many(args, { as: user })`. A call a stage makes through
139
+ `ctx` never is.
140
+ - Before any guard, `can` and the fields the request names or receives (`fieldsOf`); a refusal is `403 A4002`. At the
141
+ adapter call, after every developer stage, the read scope is ANDed into the root `where`, every to-many include and
142
+ its `$count`, and every relation filter, at every level. A to-one include of a row out of scope refuses the request;
143
+ it is never nulled.
144
+ - Governed fields (the engine's `governed` list) are left out of every default projection and carry `governed: true`
145
+ in the Contracts. Name one to get it: `select: ["$defaults", "email"]`, where `$defaults` is the level's default
146
+ projection. It is refused where a returned row does not grant it, and a filter or sort by it is checked before the
147
+ query runs, so it cannot reveal values the caller may not read.
148
+ - The engine's `governed` and `paths` lists are checked against the Core Contract at startup. A rule's paths are lists
149
+ of segments, as other paths in core are: `["Note", "campaign", "members", "some", "userId", "equals"]`.
150
+ - Writes are checked as well; see the policy writes entry.
151
+
152
+ Without `policy`, nothing changes: the Contracts and their hashes are the same bytes.
153
+
154
+ - 154e440: Policy engines check writes. Every create, update, delete and upsert a client or agent makes (or an application call
155
+ made `{ as }` a principal) is now checked by the configuration's `policy`, where before it was refused.
156
+
157
+ - The fields a write sends are held to `fieldsOf({ access: "write" })` before any guard; a field outside it answers
158
+ `403 A4002`. A field writable on some rows only is checked against every row an update reaches, and against the
159
+ row a create inserts, after the insert and inside its transaction.
160
+ - A create asks `can({ action: "create", row })` about each new row on its final data. Its rules can look rows up
161
+ through `exists`, which runs inside the write's transaction, so a plan that creates a campaign and then its first
162
+ note sees the campaign.
163
+ - An update or delete acts only on rows the caller may both change (`scopeOf` for the action) and read. A single-row
164
+ one that matches nothing answers `A4002` when the caller can read the row, and `A2003` when it cannot, so the
165
+ answer does not reveal that the row exists. A `many` or `count` one answers for the caller's rows only.
166
+ - An update that moves a row out of what the caller reads is rolled back with `A4002`. So is one that fails an `after`
167
+ condition: inside the transaction core asks `can({ action: "update", row })` about each changed row of every
168
+ checked update. The engine's new `afterChecks` member (`{ Note: ["update"] }`) names the updates whose grants carry
169
+ such a condition, which are the ones refused where there is no interactive transaction.
170
+ - Where the operation's `transactionsStyle` is `"interactive"`, a checked write runs in a transaction of its own. Where
171
+ it is `"none"` (Cloudflare D1), a write that can only be checked after it runs is refused before it runs; every other
172
+ write runs, a create looking up before it inserts, and an unlisted update without the after check.
173
+ - Nested writes (a relation directive in a write's data) are refused under a policy for now.
174
+
175
+ `afterChecks` is checked against the Core Contract at startup and changes no Contract and no prebuilt fingerprint.
176
+
177
+ - 3813207: The Resource tree and the computed fields come from `aventara-build`.
178
+
179
+ - `@aventara/build`: before it compiles the Contracts, `aventara-build` writes two more files under
180
+ `src/generated/aventara/`. `resources.generated.ts` exports `aventaraResources`: every `defineResource(…)` result
181
+ that the files `src/resources/**/*.resource.ts` export, found by its type (never run), one `resources` tree per
182
+ layer, written as the plain spreads you wrote by hand (`root` always, `application`, `client` and `agent` when some
183
+ Resource has a block for them). Two definitions of one Resource stop the build, naming both. Imports are spelled as
184
+ the project spells its own. `computed-fields.generated.ts` exports `computedFields` and its type `AvComputedFields`:
185
+ which fields the configuration's write compute fills, read off its type after the tree exists, so a fresh install is
186
+ typed right on its first `aventara:prepare`. `--check` covers all three files. `typescript` (`>=5.7.0 <7`) is now a
187
+ peer dependency.
188
+ - `@aventara/prisma7-adapter`: the generate step no longer reads the configuration. With `--config`, the discovery
189
+ artifact imports `computedFields` and `AvComputedFields` from the file `aventara-build` writes beside the
190
+ configuration (`generated/aventara/computed-fields.generated.ts`); a `--config` file that does not exist is still
191
+ refused. `readConfigComputedFields`, `AvPrismaConfigReaderError` and `ConfigComputedFieldsReading` are removed from
192
+ `@aventara/prisma7-adapter/generate`, as are `PrismaGenerateToolchain.readComputedFields` and
193
+ `PrismaGenerateResult.computedFields`.
194
+ - `@aventara/cli`: the scaffold's `src/aventara.config.ts` takes its Resources from the tree,
195
+ `resources: aventaraResources.root`, so a new Resource file needs no configuration edit; the agent skill says so.
196
+
197
+ ## 1.0.0-rc.3
198
+
199
+ ### Patch Changes
200
+
201
+ - b38034d: A refusal that quotes a failed child's output (`npm install`, `nest new`) ends with that output as the child wrote it.
202
+ It printed a period of its own after the child's last line (`npm ERR! the registry said no.`).
203
+
204
+ ## 1.0.0-rc.2
205
+
206
+ ### Patch Changes
207
+
208
+ - `aventara init`'s refusal of a TypeScript 7 project names the supported range: "use TypeScript 5.7 to 6" (it said
209
+ "use TypeScript 6 or 5"). The Prisma adapter's `typescript` peer range starts at 5.7.0 now.
210
+ - An agent skill for your AI coding agent. `aventara new` and `aventara init` write `.claude/skills/aventara/`:
211
+ `SKILL.md` (the Agent Skills format Claude Code reads: when to use it, and one rule per task) and
212
+ `reference/config.md`, `reference/stages.md`, `reference/recipes.md` and `reference/errors.md` (`@aventara/core`'s
213
+ `ERRORS.md`), for the Aventara version they install. They also add a short Aventara section to `AGENTS.md`, between
214
+ `<!-- aventara:start -->` and `<!-- aventara:end -->`, for agents that read `AGENTS.md`: an existing `AGENTS.md`
215
+ keeps everything else, and `CLAUDE.md` is never written.
216
+ - `aventara skill` refreshes those files for the `@aventara/core` installed in the project (its version and its
217
+ `ERRORS.md`; it runs none of the project's packages). It rewrites the skill files it wrote, keeps one you changed
218
+ and says so (`--force` replaces it), and replaces only the marked section of `AGENTS.md`.
219
+ - `aventara new` and `aventara init` write an `aventara:prepare` script that also passes
220
+ `--config src/aventara.config.ts`, so the generated types know which fields your configuration computes: a
221
+ variant's guards, pipes and filters may leave exactly those out of a create. A project set up before keeps working;
222
+ add the flag to its script to get the precise types.
223
+ - 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
224
+ changes nothing another stage sees, what is written or what the caller receives; and that a `compute.read` stage with
225
+ no `dependsOn` computes from the same inputs for every row, so its value usually belongs in response metadata or
226
+ `ctx.$state`. In rc.1 it said neither.
227
+ - The agent skill says that a `compute.read` stage is told the row frozen: it returns its field's value, and writing
228
+ into `record` answers `A3000`. Its error reference lists a nested write that writes its relation back (`A2004`,
229
+ `V1012`).
230
+ - The agent skill says that a computed value its field's `format` refuses (a relative path for `format: "url"`)
231
+ answers `A3000`, as a value of the wrong type does.
232
+ - Released with the other Aventara packages, and `aventara new` and `aventara init` install them at 1.0.0-rc.2.
233
+
3
234
  ## 1.0.0-rc.1
4
235
 
5
236
  ### Patch Changes
@@ -65,7 +296,6 @@
65
296
  nullable: false,
66
297
  list: false,
67
298
  lifecycle: ["VIRTUAL"],
68
- format: "url",
69
299
  },
70
300
  pipelines: {
71
301
  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
  }