prisma-next 0.9.0 → 0.10.0-dev.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.
Files changed (54) hide show
  1. package/dist/cli.mjs +154 -10
  2. package/dist/cli.mjs.map +1 -1
  3. package/dist/{command-helpers-D3vL5yi8.mjs → command-helpers-Dvgul7UA.mjs} +3 -3
  4. package/dist/command-helpers-Dvgul7UA.mjs.map +1 -0
  5. package/dist/commands/contract-emit.mjs +1 -1
  6. package/dist/commands/contract-infer.mjs +1 -1
  7. package/dist/commands/db-init.mjs +4 -4
  8. package/dist/commands/db-schema.mjs +4 -4
  9. package/dist/commands/db-sign.mjs +3 -3
  10. package/dist/commands/db-update.mjs +4 -4
  11. package/dist/commands/db-verify.mjs +1 -1
  12. package/dist/commands/migrate.mjs +3 -3
  13. package/dist/commands/migration-check.mjs +1 -1
  14. package/dist/commands/migration-graph.mjs +2 -2
  15. package/dist/commands/migration-list.mjs +2 -2
  16. package/dist/commands/migration-log.mjs +2 -2
  17. package/dist/commands/migration-new.mjs +2 -2
  18. package/dist/commands/migration-plan.mjs +1 -1
  19. package/dist/commands/migration-show.mjs +3 -3
  20. package/dist/commands/migration-status.mjs +3 -3
  21. package/dist/commands/ref.mjs +2 -2
  22. package/dist/{contract-emit-C3STUIBg.mjs → contract-emit-BDBzHlaC.mjs} +4 -4
  23. package/dist/{contract-emit-C3STUIBg.mjs.map → contract-emit-BDBzHlaC.mjs.map} +1 -1
  24. package/dist/{contract-infer-Cnj8G1E2.mjs → contract-infer-Dm8pBZMR.mjs} +4 -4
  25. package/dist/{contract-infer-Cnj8G1E2.mjs.map → contract-infer-Dm8pBZMR.mjs.map} +1 -1
  26. package/dist/{db-verify-D7cyH_zz.mjs → db-verify-CW8DR5Ei.mjs} +4 -4
  27. package/dist/{db-verify-D7cyH_zz.mjs.map → db-verify-CW8DR5Ei.mjs.map} +1 -1
  28. package/dist/{errors-Cw6kyTyV.mjs → errors-BYAXmyRJ.mjs} +2 -2
  29. package/dist/{errors-Cw6kyTyV.mjs.map → errors-BYAXmyRJ.mjs.map} +1 -1
  30. package/dist/exports/index.mjs +2 -2
  31. package/dist/global-flags-DGmw6Kqg.d.mts.map +1 -1
  32. package/dist/{init-eh2z5Tl6.mjs → init-CxS9eqbQ.mjs} +435 -373
  33. package/dist/init-CxS9eqbQ.mjs.map +1 -0
  34. package/dist/{inspect-live-schema-CWLK_lgs.mjs → inspect-live-schema-iETRZ_59.mjs} +2 -2
  35. package/dist/{inspect-live-schema-CWLK_lgs.mjs.map → inspect-live-schema-iETRZ_59.mjs.map} +1 -1
  36. package/dist/is-ci-YyvQBBke.mjs +44 -0
  37. package/dist/is-ci-YyvQBBke.mjs.map +1 -0
  38. package/dist/{migration-command-scaffold-CmXXC1UZ.mjs → migration-command-scaffold-BlgVj_Pn.mjs} +2 -2
  39. package/dist/{migration-command-scaffold-CmXXC1UZ.mjs.map → migration-command-scaffold-BlgVj_Pn.mjs.map} +1 -1
  40. package/dist/{migration-plan-CHyUlBV0.mjs → migration-plan-BSzcWsvm.mjs} +3 -3
  41. package/dist/{migration-plan-CHyUlBV0.mjs.map → migration-plan-BSzcWsvm.mjs.map} +1 -1
  42. package/dist/{migrations-DyUf5lTt.mjs → migrations-CgANWI0w.mjs} +2 -2
  43. package/dist/{migrations-DyUf5lTt.mjs.map → migrations-CgANWI0w.mjs.map} +1 -1
  44. package/dist/quick-reference-mongo.md +1 -1
  45. package/dist/quick-reference-postgres.md +1 -1
  46. package/dist/{result-handler-Bm_6dDYg.mjs → result-handler-CG3vVoKf.mjs} +2 -2
  47. package/dist/{result-handler-Bm_6dDYg.mjs.map → result-handler-CG3vVoKf.mjs.map} +1 -1
  48. package/dist/{verify-D7ypCCe6.mjs → verify-nlzO0uIY.mjs} +2 -2
  49. package/dist/{verify-D7ypCCe6.mjs.map → verify-nlzO0uIY.mjs.map} +1 -1
  50. package/package.json +12 -10
  51. package/dist/command-helpers-D3vL5yi8.mjs.map +0 -1
  52. package/dist/helpers-eqdN8tH6.mjs +0 -25
  53. package/dist/helpers-eqdN8tH6.mjs.map +0 -1
  54. package/dist/init-eh2z5Tl6.mjs.map +0 -1
@@ -1,5 +1,6 @@
1
1
  import { t as CliStructuredError } from "./cli-errors-CF60g2cG.mjs";
2
- import { n as formatErrorOutput, t as formatErrorJson } from "./errors-Cw6kyTyV.mjs";
2
+ import { t as isCI } from "./is-ci-YyvQBBke.mjs";
3
+ import { n as formatErrorOutput, t as formatErrorJson } from "./errors-BYAXmyRJ.mjs";
3
4
  import { t as TerminalUI } from "./terminal-ui-XtOQsqe9.mjs";
4
5
  import { t as version } from "./cli.mjs";
5
6
  import { i as renderInitOutro, n as buildNextSteps, r as formatInitJson, t as InitOutputSchema } from "./output-B60Gw5fu.mjs";
@@ -7,10 +8,164 @@ import { createRequire } from "node:module";
7
8
  import { basename, dirname, extname, isAbsolute, join, normalize } from "pathe";
8
9
  import * as clack from "@clack/prompts";
9
10
  import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
11
+ import { readUserConfig, resolveGating, writeUserConfig } from "@prisma-next/cli-telemetry";
10
12
  import { execFile } from "node:child_process";
11
13
  import { promisify } from "node:util";
12
14
  import { detect, getUserAgent } from "package-manager-detector/detect";
13
15
  import { applyEdits, modify, parse, printParseErrorCode } from "jsonc-parser";
16
+ //#region src/commands/init/detect-package-manager.ts
17
+ const KNOWN = new Set([
18
+ "pnpm",
19
+ "npm",
20
+ "yarn",
21
+ "bun",
22
+ "deno"
23
+ ]);
24
+ /**
25
+ * Resolves the package manager `init` should drive for `add` / `install`
26
+ * commands. Tries, in order:
27
+ *
28
+ * 1. **`detect()`** — walks up from `cwd` looking for a lockfile, the
29
+ * `packageManager` field, the `devEngines.packageManager` field, or
30
+ * install metadata. This is the right answer whenever the user is
31
+ * anywhere inside an existing project, including a deep workspace
32
+ * subdirectory.
33
+ *
34
+ * 2. **`getUserAgent()`** — parses `npm_config_user_agent`, the env var
35
+ * every PM sets when it spawns a script. This catches the
36
+ * bare-directory case where there's no project to walk up to but the
37
+ * user invoked us via `pnpm dlx prisma-next init` / `bunx
38
+ * prisma-next init` / `yarn dlx …`. Same signal used by every
39
+ * `create-*` tool in the ecosystem (`create-vite`, `create-next-app`,
40
+ * `create-astro`, `@antfu/ni`, …).
41
+ *
42
+ * 3. **`npm`** — final fallback. Always present alongside Node.
43
+ */
44
+ async function detectPackageManager(cwd) {
45
+ const detected = await detect({ cwd });
46
+ if (detected && KNOWN.has(detected.name)) return detected.name;
47
+ const userAgent = getUserAgent();
48
+ if (userAgent !== null && KNOWN.has(userAgent)) return userAgent;
49
+ return "npm";
50
+ }
51
+ function hasProjectManifest(cwd) {
52
+ return existsSync(join(cwd, "package.json")) || existsSync(join(cwd, "deno.json")) || existsSync(join(cwd, "deno.jsonc"));
53
+ }
54
+ function formatRunCommand(pm, bin, args) {
55
+ if (pm === "npm") return `npx ${bin} ${args}`;
56
+ if (pm === "deno") return `deno run npm:${bin} ${args}`;
57
+ return `${pm} ${bin} ${args}`;
58
+ }
59
+ function formatAddArgs(pm, packages) {
60
+ if (pm === "deno") return ["add", ...packages.map((p) => `npm:${p}`)];
61
+ return ["add", ...packages];
62
+ }
63
+ function formatAddDevArgs(pm, packages) {
64
+ if (pm === "deno") return [
65
+ "add",
66
+ "--dev",
67
+ ...packages.map((p) => `npm:${p}`)
68
+ ];
69
+ return [
70
+ "add",
71
+ "-D",
72
+ ...packages
73
+ ];
74
+ }
75
+ //#endregion
76
+ //#region src/commands/init/detect-pnpm-catalog.ts
77
+ /**
78
+ * Walks up from `baseDir` looking for `pnpm-workspace.yaml`, then scans
79
+ * its top-level `catalog:` block for entries that match any of `packages`.
80
+ *
81
+ * Implements FR7.3 / Spec Decision 8 (honour-and-warn): when `init` runs
82
+ * inside a pnpm workspace whose catalog overrides one of the packages it
83
+ * installs, surface a structured warning so the user knows the catalog
84
+ * version (not the published `latest`) is what ended up in their
85
+ * `node_modules`. pnpm itself does this silently; the warning closes the
86
+ * "looks fine, must be wrong version six months later" gap.
87
+ *
88
+ * Notes / scope:
89
+ *
90
+ * - We only inspect the unnamed top-level `catalog:` block. pnpm also
91
+ * supports `catalogs:` (plural — *named* catalogs referenced via
92
+ * `catalog:foo` specifiers); those don't apply to a vanilla
93
+ * `pnpm add prisma-next` invocation, so we skip them.
94
+ * - We don't validate YAML syntax exhaustively. The file format pnpm
95
+ * ships is line-oriented and well-known; a minimal regex is more
96
+ * robust than depending on a YAML parser for one warning.
97
+ * - We don't compare against the registry's `latest` — pnpm uses the
98
+ * catalog version regardless, so the warning fires whenever a match
99
+ * exists. The user-facing copy explains how to opt out.
100
+ */
101
+ function detectPnpmCatalogOverrides(baseDir, packages) {
102
+ const workspaceFile = findNearestPnpmWorkspaceFile(baseDir);
103
+ if (workspaceFile === null) return null;
104
+ const catalog = extractCatalogBlock(readFileSync(workspaceFile, "utf-8"));
105
+ if (catalog === null) return {
106
+ workspaceFile,
107
+ entries: []
108
+ };
109
+ const wanted = new Set(packages);
110
+ const entries = [];
111
+ for (const [name, version] of catalog) if (wanted.has(name)) entries.push({
112
+ name,
113
+ version
114
+ });
115
+ return {
116
+ workspaceFile,
117
+ entries
118
+ };
119
+ }
120
+ function findNearestPnpmWorkspaceFile(baseDir) {
121
+ let dir = baseDir;
122
+ let prev = "";
123
+ while (dir !== prev) {
124
+ const candidate = join(dir, "pnpm-workspace.yaml");
125
+ if (existsSync(candidate)) return candidate;
126
+ prev = dir;
127
+ dir = dirname(dir);
128
+ }
129
+ return null;
130
+ }
131
+ /**
132
+ * Returns the entries inside the top-level `catalog:` block as `[name, version]`
133
+ * pairs in document order, or `null` when no `catalog:` block exists.
134
+ *
135
+ * The parser is intentionally minimal: it reads line-by-line, locates the
136
+ * top-level `catalog:` line (no leading whitespace), then collects every
137
+ * subsequent indented line of the form `<key>: <value>` until the next
138
+ * top-level key (or end of file). Quotes around `<key>` and `<value>`
139
+ * are stripped; comments (`#…`) are ignored.
140
+ */
141
+ function extractCatalogBlock(contents) {
142
+ const lines = contents.split(/\r?\n/);
143
+ const startIdx = lines.findIndex((line) => /^catalog\s*:\s*$/.test(line));
144
+ if (startIdx === -1) return null;
145
+ const entries = [];
146
+ for (let i = startIdx + 1; i < lines.length; i++) {
147
+ const raw = lines[i] ?? "";
148
+ if (raw.trim() === "" || /^\s*#/.test(raw)) continue;
149
+ if (!/^\s/.test(raw)) break;
150
+ const match = raw.match(/^\s+(?:'([^']+)'|"([^"]+)"|([^:\s'"]+))\s*:\s*(.*?)\s*(?:#.*)?$/);
151
+ if (!match) continue;
152
+ const name = match[1] ?? match[2] ?? match[3];
153
+ if (name === void 0) continue;
154
+ const version = stripQuotes((match[4] ?? "").trim());
155
+ if (version === "") continue;
156
+ entries.push([name, version]);
157
+ }
158
+ return entries;
159
+ }
160
+ function stripQuotes(value) {
161
+ if (value.length >= 2) {
162
+ const first = value[0];
163
+ const last = value[value.length - 1];
164
+ if (first === "\"" && last === "\"" || first === "'" && last === "'") return value.slice(1, -1);
165
+ }
166
+ return value;
167
+ }
168
+ //#endregion
14
169
  //#region src/commands/init/errors.ts
15
170
  /**
16
171
  * Re-init in non-interactive mode without `--force`. Distinct from the
@@ -206,367 +361,37 @@ function errorInitEmitFailed(options) {
206
361
  domain: "CLI",
207
362
  why: `\`prisma-next contract emit\` failed: ${options.cause}`,
208
363
  fix: `Inspect your contract file, fix the underlying issue, then re-run \`${options.emitCommand}\`. Pass \`-v\` for the full error envelope.`,
209
- docsUrl: "https://prisma-next.dev/docs/cli/contract-emit",
210
- meta: {
211
- filesWritten: options.filesWritten,
212
- cause: options.cause
213
- }
214
- });
215
- }
216
- /**
217
- * The project-level agent-skill install (`npx skills add
218
- * prisma/prisma-next#v<version>`) failed after a successful dependency
219
- * install + emit. The project's scaffold remains on disk; the user
220
- * can either fix the underlying issue (network, registry, PATH) and
221
- * run the install command manually, or re-run `init --no-skill` to
222
- * proceed without the skill.
223
- *
224
- * Non-rolling-back, matching the existing install/emit failure
225
- * semantics. Maps to exit code `6 = SKILL_INSTALL_FAILED`.
226
- */
227
- function errorInitSkillInstallFailed(options) {
228
- return new CliStructuredError("5013", "Failed to install Prisma Next skills", {
229
- domain: "CLI",
230
- why: `\`${options.skillInstallCommand}\` exited with an error: ${options.cause}`,
231
- fix: `Either:
232
- - Re-run \`prisma-next init --no-skill${options.filesWritten.length > 0 ? " --force" : ""}\` to skip the skill install for this run, or\n - Fix the underlying issue (network, npm registry, \`npx skills\` on PATH) and install manually:\n ${options.skillInstallCommand}`,
233
- docsUrl: "https://prisma-next.dev/docs/cli/init#agent-skill",
234
- meta: {
235
- filesWritten: options.filesWritten,
236
- skillInstallCommand: options.skillInstallCommand,
237
- cause: options.cause
238
- }
239
- });
240
- }
241
- //#endregion
242
- //#region src/commands/init/agent-skill-install.ts
243
- const exec = promisify(execFile);
244
- /**
245
- * Default base for the GitHub-URL form `<owner>/<repo>` consumed by
246
- * upstream `skills add`. Each `SkillSource` joins this base with its
247
- * own subpath (and optional `#ref` for version-pinned clusters).
248
- */
249
- const DEFAULT_AGENT_SKILL_BASE = "prisma/prisma-next";
250
- const DEFAULT_AGENT_SKILL_SOURCES = [
251
- {
252
- subpath: "skills",
253
- ref: "cli",
254
- description: "usage skills (version-locked to installed Prisma Next)"
255
- },
256
- {
257
- subpath: "skills/upgrade",
258
- ref: null,
259
- description: "upgrade skill (always tracks `main`)"
260
- },
261
- {
262
- subpath: "skills/extension-author",
263
- ref: null,
264
- description: "extension-author skill (always tracks `main`)"
265
- }
266
- ];
267
- /**
268
- * Test-only escape hatch for pinning the install base to a local
269
- * checkout. Production runs leave this unset, so installs always use
270
- * `DEFAULT_AGENT_SKILL_BASE`.
271
- *
272
- * When set to an absolute filesystem path (typical for tests), the
273
- * `#ref` fragment is dropped — local-path mode in upstream's CLI does
274
- * not accept refs, and the local clone has whatever content the test
275
- * checked into it anyway. When set to anything else (e.g. a fork name
276
- * `myuser/prisma-next`), the ref policy is preserved.
277
- */
278
- function resolveAgentSkillBase() {
279
- const override = process.env["PRISMA_NEXT_SKILLS_BASE"]?.trim();
280
- return override && override.length > 0 ? override : DEFAULT_AGENT_SKILL_BASE;
281
- }
282
- function isLocalPath(base) {
283
- return base.startsWith("/") || /^[a-zA-Z]:[\\/]/.test(base);
284
- }
285
- /**
286
- * Build the `<base>/<subpath>[#ref]` URL the `skills` CLI will
287
- * resolve. Exported for unit tests so the per-source format can be
288
- * asserted without going through the full install loop.
289
- */
290
- function formatSkillSourceUrl(source) {
291
- const base = resolveAgentSkillBase();
292
- const url = `${base}/${source.subpath}`;
293
- if (source.ref === null) return url;
294
- if (isLocalPath(base)) return url;
295
- if (source.ref === "cli") return `${url}#v${version}`;
296
- return url;
297
- }
298
- /**
299
- * The skill-install command for one source, formatted for the
300
- * project's detected package manager. `npx`/`pnpm dlx`/`bunx` are
301
- * interchangeable to the user; we pick the variant that matches the
302
- * rest of the install step so a single project consistently uses one
303
- * runner.
304
- *
305
- * `--all` auto-selects every skill in the cluster and every detected
306
- * agent runtime, skipping the multi-select prompts the `skills` CLI
307
- * shows by default. A non-interactive scaffold step cannot present
308
- * prompts.
309
- *
310
- * Exported for unit tests so the per-PM dispatch can be asserted
311
- * without a live subprocess.
312
- */
313
- function formatSkillInstallCommand(pm, source) {
314
- return formatPackageManagerCommand(pm, [
315
- "skills@latest",
316
- "add",
317
- formatSkillSourceUrl(source),
318
- "--all"
319
- ]);
320
- }
321
- /**
322
- * `skills add --all` should cover Claude Code, but upstream currently skips
323
- * project-local Claude symlinks when `.claude/` does not already exist. Run
324
- * the explicit Claude Code install as well so fresh projects get
325
- * `.claude/skills` without asking users to create that folder first.
326
- */
327
- function formatClaudeSkillInstallCommand(pm, source) {
328
- return formatPackageManagerCommand(pm, [
329
- "skills@latest",
330
- "add",
331
- formatSkillSourceUrl(source),
332
- "--agent",
333
- "claude-code",
334
- "--skill",
335
- "'*'",
336
- "-y"
337
- ]);
338
- }
339
- function formatPackageManagerCommand(pm, args) {
340
- switch (pm) {
341
- case "pnpm": return `pnpm dlx ${args.join(" ")}`;
342
- case "yarn": return `yarn dlx ${args.join(" ")}`;
343
- case "bun": return `bunx ${args.join(" ")}`;
344
- case "deno": return `deno run -A npm:${args.join(" ")}`;
345
- case "npm": return `npx ${args.join(" ")}`;
346
- }
347
- }
348
- /**
349
- * Parse the project-pm-formatted command into an exec call. The
350
- * format-then-parse split keeps the user-facing command string the same
351
- * as the surface the structured error advertises, so a user who copies
352
- * the error's `fix` line gets the same invocation that init just
353
- * attempted. Single quotes are preserved in the display form so `*` is
354
- * safe to copy into a shell, then stripped before `execFile`.
355
- */
356
- function commandToExec(command) {
357
- const tokens = (command.match(/'[^']*'|\S+/g) ?? []).map((token) => token.startsWith("'") && token.endsWith("'") ? token.slice(1, -1) : token);
358
- return {
359
- file: tokens[0] ?? "npx",
360
- args: tokens.slice(1)
361
- };
362
- }
363
- /**
364
- * Runs the project-level skill install for every source in
365
- * `DEFAULT_AGENT_SKILL_SOURCES`, in order. Returns
366
- * `{ ok: true, commands }` on success; throws a structured
367
- * `errorInitSkillInstallFailed` on the first failure (subsequent
368
- * sources are not attempted — the user opted into Prisma Next by
369
- * running `init` and a partial install would leave the project in an
370
- * ambiguous state). The throw is intentionally fatal — project-level
371
- * skill install is unconditional (modulo `--no-skill`).
372
- */
373
- async function runProjectLevelSkillInstall(ctx) {
374
- const commands = [];
375
- const installCommands = DEFAULT_AGENT_SKILL_SOURCES.flatMap((source) => [formatSkillInstallCommand(ctx.pm, source), formatClaudeSkillInstallCommand(ctx.pm, source)]);
376
- for (const command of installCommands) {
377
- const { file, args } = commandToExec(command);
378
- try {
379
- await exec(file, args, { cwd: ctx.baseDir });
380
- commands.push(command);
381
- } catch (err) {
382
- throw errorInitSkillInstallFailed({
383
- skillInstallCommand: command,
384
- filesWritten: ctx.filesWritten,
385
- cause: redactSecrets$1(readChildStderr$1(err)) || (err instanceof Error ? err.message : String(err))
386
- });
387
- }
388
- }
389
- return {
390
- ok: true,
391
- commands
392
- };
393
- }
394
- function readChildStderr$1(err) {
395
- if (err instanceof Error && "stderr" in err) return String(err.stderr ?? "");
396
- return "";
397
- }
398
- /**
399
- * Strips credentials from a `scheme://user:pass@host/...` URL anywhere
400
- * in `stderr`. Package-manager stderr regularly contains credentialed
401
- * registry URLs (private npm registries, GitHub Packages tokens), and
402
- * those bubble into the structured `errorInitSkillInstallFailed`
403
- * envelope, which ends up in logs and CI output. Redact at the
404
- * boundary so we never re-emit a secret.
405
- *
406
- * Exported for unit tests.
407
- */
408
- function redactSecrets$1(stderr) {
409
- if (!stderr) return stderr;
410
- return stderr.replace(/([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)([^/@\s]+)@/g, "$1***@");
411
- }
412
- /**
413
- * Hand-rolled skill stub path that init must not leave behind. Removed
414
- * on every init run so a project's `.agents/skills/prisma-next/` does
415
- * not shadow the installed Prisma Next skill cluster.
416
- */
417
- const LEGACY_SKILL_FILE = ".agents/skills/prisma-next/SKILL.md";
418
- //#endregion
419
- //#region src/commands/init/detect-package-manager.ts
420
- const KNOWN = new Set([
421
- "pnpm",
422
- "npm",
423
- "yarn",
424
- "bun",
425
- "deno"
426
- ]);
427
- /**
428
- * Resolves the package manager `init` should drive for `add` / `install`
429
- * commands. Tries, in order:
430
- *
431
- * 1. **`detect()`** — walks up from `cwd` looking for a lockfile, the
432
- * `packageManager` field, the `devEngines.packageManager` field, or
433
- * install metadata. This is the right answer whenever the user is
434
- * anywhere inside an existing project, including a deep workspace
435
- * subdirectory.
436
- *
437
- * 2. **`getUserAgent()`** — parses `npm_config_user_agent`, the env var
438
- * every PM sets when it spawns a script. This catches the
439
- * bare-directory case where there's no project to walk up to but the
440
- * user invoked us via `pnpm dlx prisma-next init` / `bunx
441
- * prisma-next init` / `yarn dlx …`. Same signal used by every
442
- * `create-*` tool in the ecosystem (`create-vite`, `create-next-app`,
443
- * `create-astro`, `@antfu/ni`, …).
444
- *
445
- * 3. **`npm`** — final fallback. Always present alongside Node.
446
- */
447
- async function detectPackageManager(cwd) {
448
- const detected = await detect({ cwd });
449
- if (detected && KNOWN.has(detected.name)) return detected.name;
450
- const userAgent = getUserAgent();
451
- if (userAgent !== null && KNOWN.has(userAgent)) return userAgent;
452
- return "npm";
453
- }
454
- function hasProjectManifest(cwd) {
455
- return existsSync(join(cwd, "package.json")) || existsSync(join(cwd, "deno.json")) || existsSync(join(cwd, "deno.jsonc"));
456
- }
457
- function formatRunCommand(pm, bin, args) {
458
- if (pm === "npm") return `npx ${bin} ${args}`;
459
- if (pm === "deno") return `deno run npm:${bin} ${args}`;
460
- return `${pm} ${bin} ${args}`;
461
- }
462
- function formatAddArgs(pm, packages) {
463
- if (pm === "deno") return ["add", ...packages.map((p) => `npm:${p}`)];
464
- return ["add", ...packages];
465
- }
466
- function formatAddDevArgs(pm, packages) {
467
- if (pm === "deno") return [
468
- "add",
469
- "--dev",
470
- ...packages.map((p) => `npm:${p}`)
471
- ];
472
- return [
473
- "add",
474
- "-D",
475
- ...packages
476
- ];
477
- }
478
- //#endregion
479
- //#region src/commands/init/detect-pnpm-catalog.ts
480
- /**
481
- * Walks up from `baseDir` looking for `pnpm-workspace.yaml`, then scans
482
- * its top-level `catalog:` block for entries that match any of `packages`.
483
- *
484
- * Implements FR7.3 / Spec Decision 8 (honour-and-warn): when `init` runs
485
- * inside a pnpm workspace whose catalog overrides one of the packages it
486
- * installs, surface a structured warning so the user knows the catalog
487
- * version (not the published `latest`) is what ended up in their
488
- * `node_modules`. pnpm itself does this silently; the warning closes the
489
- * "looks fine, must be wrong version six months later" gap.
490
- *
491
- * Notes / scope:
492
- *
493
- * - We only inspect the unnamed top-level `catalog:` block. pnpm also
494
- * supports `catalogs:` (plural — *named* catalogs referenced via
495
- * `catalog:foo` specifiers); those don't apply to a vanilla
496
- * `pnpm add prisma-next` invocation, so we skip them.
497
- * - We don't validate YAML syntax exhaustively. The file format pnpm
498
- * ships is line-oriented and well-known; a minimal regex is more
499
- * robust than depending on a YAML parser for one warning.
500
- * - We don't compare against the registry's `latest` — pnpm uses the
501
- * catalog version regardless, so the warning fires whenever a match
502
- * exists. The user-facing copy explains how to opt out.
503
- */
504
- function detectPnpmCatalogOverrides(baseDir, packages) {
505
- const workspaceFile = findNearestPnpmWorkspaceFile(baseDir);
506
- if (workspaceFile === null) return null;
507
- const catalog = extractCatalogBlock(readFileSync(workspaceFile, "utf-8"));
508
- if (catalog === null) return {
509
- workspaceFile,
510
- entries: []
511
- };
512
- const wanted = new Set(packages);
513
- const entries = [];
514
- for (const [name, version] of catalog) if (wanted.has(name)) entries.push({
515
- name,
516
- version
364
+ docsUrl: "https://prisma-next.dev/docs/cli/contract-emit",
365
+ meta: {
366
+ filesWritten: options.filesWritten,
367
+ cause: options.cause
368
+ }
517
369
  });
518
- return {
519
- workspaceFile,
520
- entries
521
- };
522
- }
523
- function findNearestPnpmWorkspaceFile(baseDir) {
524
- let dir = baseDir;
525
- let prev = "";
526
- while (dir !== prev) {
527
- const candidate = join(dir, "pnpm-workspace.yaml");
528
- if (existsSync(candidate)) return candidate;
529
- prev = dir;
530
- dir = dirname(dir);
531
- }
532
- return null;
533
370
  }
534
371
  /**
535
- * Returns the entries inside the top-level `catalog:` block as `[name, version]`
536
- * pairs in document order, or `null` when no `catalog:` block exists.
372
+ * The project-level skills install (`npx skills add
373
+ * prisma/prisma-next#v<version>`) failed after a successful dependency
374
+ * install + emit. The project's scaffold remains on disk; the user
375
+ * can either fix the underlying issue (network, registry, PATH) and
376
+ * run the install command manually, or re-run `init --no-skill` to
377
+ * proceed without the skill.
537
378
  *
538
- * The parser is intentionally minimal: it reads line-by-line, locates the
539
- * top-level `catalog:` line (no leading whitespace), then collects every
540
- * subsequent indented line of the form `<key>: <value>` until the next
541
- * top-level key (or end of file). Quotes around `<key>` and `<value>`
542
- * are stripped; comments (`#…`) are ignored.
379
+ * Non-rolling-back, matching the existing install/emit failure
380
+ * semantics. Maps to exit code `6 = SKILL_INSTALL_FAILED`.
543
381
  */
544
- function extractCatalogBlock(contents) {
545
- const lines = contents.split(/\r?\n/);
546
- const startIdx = lines.findIndex((line) => /^catalog\s*:\s*$/.test(line));
547
- if (startIdx === -1) return null;
548
- const entries = [];
549
- for (let i = startIdx + 1; i < lines.length; i++) {
550
- const raw = lines[i] ?? "";
551
- if (raw.trim() === "" || /^\s*#/.test(raw)) continue;
552
- if (!/^\s/.test(raw)) break;
553
- const match = raw.match(/^\s+(?:'([^']+)'|"([^"]+)"|([^:\s'"]+))\s*:\s*(.*?)\s*(?:#.*)?$/);
554
- if (!match) continue;
555
- const name = match[1] ?? match[2] ?? match[3];
556
- if (name === void 0) continue;
557
- const version = stripQuotes((match[4] ?? "").trim());
558
- if (version === "") continue;
559
- entries.push([name, version]);
560
- }
561
- return entries;
562
- }
563
- function stripQuotes(value) {
564
- if (value.length >= 2) {
565
- const first = value[0];
566
- const last = value[value.length - 1];
567
- if (first === "\"" && last === "\"" || first === "'" && last === "'") return value.slice(1, -1);
568
- }
569
- return value;
382
+ function errorInitSkillInstallFailed(options) {
383
+ return new CliStructuredError("5013", "Failed to install Prisma Next skills", {
384
+ domain: "CLI",
385
+ why: `\`${options.skillInstallCommand}\` exited with an error: ${options.cause}`,
386
+ fix: `Either:
387
+ - Re-run \`prisma-next init --no-skill${options.filesWritten.length > 0 ? " --force" : ""}\` to skip the skill install for this run, or\n - Fix the underlying issue (network, npm registry, \`npx skills\` on PATH) and install manually:\n ${options.skillInstallCommand}`,
388
+ docsUrl: "https://prisma-next.dev/docs/cli/init#skills",
389
+ meta: {
390
+ filesWritten: options.filesWritten,
391
+ skillInstallCommand: options.skillInstallCommand,
392
+ cause: options.cause
393
+ }
394
+ });
570
395
  }
571
396
  //#endregion
572
397
  //#region src/commands/init/hygiene-gitattributes.ts
@@ -814,18 +639,20 @@ function schemaSample(target, authoring) {
814
639
  function schemaSamplePslPostgres() {
815
640
  return `\`\`\`prisma
816
641
  model User {
817
- id Int @id @default(autoincrement())
818
- email String @unique
819
- name String?
642
+ id Int @id @default(autoincrement())
643
+ email String @unique
644
+ username String?
645
+ name String?
820
646
  }
821
647
  \`\`\``;
822
648
  }
823
649
  function schemaSamplePslMongo() {
824
650
  return `\`\`\`prisma
825
651
  model User {
826
- id ObjectId @id @map("_id")
827
- email String @unique
828
- name String?
652
+ id ObjectId @id @map("_id")
653
+ email String @unique
654
+ username String?
655
+ name String?
829
656
  @@map("users")
830
657
  }
831
658
  \`\`\``;
@@ -844,6 +671,7 @@ export const contract = defineContract(
844
671
  fields: {
845
672
  id: field.id.uuidv7(),
846
673
  email: field.text().unique(),
674
+ username: field.text().optional(),
847
675
  name: field.text().optional(),
848
676
  },
849
677
  }),
@@ -867,6 +695,7 @@ export const contract = defineContract(
867
695
  fields: {
868
696
  _id: field.objectId(),
869
697
  email: field.string(),
698
+ username: field.string().optional(),
870
699
  name: field.string().optional(),
871
700
  },
872
701
  }),
@@ -881,6 +710,7 @@ function starterSchemaPslPostgres() {
881
710
  model User {
882
711
  id Int @id @default(autoincrement())
883
712
  email String @unique
713
+ username String?
884
714
  name String?
885
715
  posts Post[]
886
716
  createdAt DateTime @default(now())
@@ -902,10 +732,11 @@ function starterSchemaPslMongo() {
902
732
  return `// use prisma-next
903
733
 
904
734
  model User {
905
- id ObjectId @id @map("_id")
906
- email String @unique
907
- name String?
908
- posts Post[]
735
+ id ObjectId @id @map("_id")
736
+ email String @unique
737
+ username String?
738
+ name String?
739
+ posts Post[]
909
740
  @@map("users")
910
741
  }
911
742
 
@@ -932,6 +763,7 @@ export const contract = defineContract(
932
763
  fields: {
933
764
  id: field.id.uuidv7(),
934
765
  email: field.text().unique(),
766
+ username: field.text().optional(),
935
767
  name: field.text().optional(),
936
768
  createdAt: field.temporal.createdAt(),
937
769
  updatedAt: field.temporal.updatedAt(),
@@ -973,6 +805,7 @@ export const contract = defineContract(
973
805
  fields: {
974
806
  _id: field.objectId(),
975
807
  email: field.string(),
808
+ username: field.string().optional(),
976
809
  name: field.string().optional(),
977
810
  },
978
811
  relations: {
@@ -1042,6 +875,11 @@ const AUTHORING_VALUES = new Map([
1042
875
  ["typescript", "typescript"],
1043
876
  ["ts", "typescript"]
1044
877
  ]);
878
+ const TELEMETRY_CONSENT_MESSAGE = [
879
+ "Help us prioritize features by sharing anonymous CLI usage data?",
880
+ "The telemetry implementation is open source and fully transparent.",
881
+ "(packages/1-framework/3-tooling/cli-telemetry and apps/telemetry-backend)."
882
+ ].join(" ");
1045
883
  /**
1046
884
  * Resolves every required input for `runInit`. In interactive mode, missing
1047
885
  * inputs are prompted via clack; in non-interactive mode, missing required
@@ -1089,6 +927,10 @@ async function resolveInitInputs(ctx) {
1089
927
  canPrompt,
1090
928
  autoAcceptPrompts
1091
929
  });
930
+ const enableTelemetry = await resolveTelemetryConsent({
931
+ canPrompt,
932
+ autoAcceptPrompts
933
+ });
1092
934
  const installProjectSkill = options.skill !== false;
1093
935
  return {
1094
936
  target: finalTarget,
@@ -1100,9 +942,49 @@ async function resolveInitInputs(ctx) {
1100
942
  strictProbe: Boolean(options.strictProbe),
1101
943
  reinit,
1102
944
  removePreviousFacade,
945
+ enableTelemetry,
1103
946
  installProjectSkill
1104
947
  };
1105
948
  }
949
+ /**
950
+ * The interactive telemetry consent prompt. Shown as the last
951
+ * question of the `init` sequence iff:
952
+ * 1. `canPrompt === true` (interactive stdin / stdout combo),
953
+ * 2. `autoAcceptPrompts === false` (the user did not pass `--yes`),
954
+ * 3. neither telemetry env opt-out is active,
955
+ * 4. the process is not running in CI,
956
+ * 5. the stored `enableTelemetry` value is `undefined` (the user
957
+ * has never been asked, or skipped the prompt previously).
958
+ *
959
+ * Outside that intersection the function returns `null` and leaves the
960
+ * stored preference untouched. Inside it, the user's answer is
961
+ * persisted via `writeUserConfig({ enableTelemetry })` before this
962
+ * function returns; on an affirmative answer `writeUserConfig`
963
+ * generates and stores the v4 `installationId` in the same write.
964
+ *
965
+ * The wording names CLI usage data and points to the open-source
966
+ * client/backend paths. Default value is `true` to match precedent
967
+ * and to make the consent answer a single keystroke once it's been
968
+ * disclosed.
969
+ */
970
+ async function resolveTelemetryConsent(opts) {
971
+ if (!opts.canPrompt || opts.autoAcceptPrompts || isCI()) return null;
972
+ const config = readUserConfig();
973
+ const gating = resolveGating({
974
+ env: process.env,
975
+ config
976
+ });
977
+ if (!gating.enabled && gating.reason === "env-override") return null;
978
+ if (config.enableTelemetry !== void 0) return null;
979
+ const result = await clack.confirm({
980
+ message: TELEMETRY_CONSENT_MESSAGE,
981
+ initialValue: true,
982
+ output: process.stderr
983
+ });
984
+ if (clack.isCancel(result)) throw errorInitUserAborted();
985
+ writeUserConfig({ enableTelemetry: Boolean(result) });
986
+ return Boolean(result);
987
+ }
1106
988
  async function resolveWriteEnv(opts) {
1107
989
  if (opts.flag !== void 0) return Boolean(opts.flag);
1108
990
  if (!opts.canPrompt || opts.autoAcceptPrompts) return false;
@@ -1511,6 +1393,183 @@ function removeDependency(existing, depName) {
1511
1393
  return `${JSON.stringify(parsed, null, 2)}${trailingNewline}`;
1512
1394
  }
1513
1395
  //#endregion
1396
+ //#region src/commands/init/skill-install.ts
1397
+ const exec = promisify(execFile);
1398
+ /**
1399
+ * Default base for the GitHub-URL form `<owner>/<repo>` consumed by
1400
+ * upstream `skills add`. Each `SkillSource` joins this base with its
1401
+ * own subpath (and optional `#ref` for version-pinned clusters).
1402
+ */
1403
+ const DEFAULT_SKILL_BASE = "prisma/prisma-next";
1404
+ const DEFAULT_SKILL_SOURCES = [
1405
+ {
1406
+ subpath: "skills",
1407
+ ref: "cli",
1408
+ description: "usage skills (version-locked to installed Prisma Next)"
1409
+ },
1410
+ {
1411
+ subpath: "skills/upgrade",
1412
+ ref: null,
1413
+ description: "upgrade skill (always tracks `main`)"
1414
+ },
1415
+ {
1416
+ subpath: "skills/extension-author",
1417
+ ref: null,
1418
+ description: "extension-author skill (always tracks `main`)"
1419
+ }
1420
+ ];
1421
+ /**
1422
+ * Test-only escape hatch for pinning the install base to a local
1423
+ * checkout. Production runs leave this unset, so installs always use
1424
+ * `DEFAULT_SKILL_BASE`.
1425
+ *
1426
+ * When set to an absolute filesystem path (typical for tests), the
1427
+ * `#ref` fragment is dropped — local-path mode in upstream's CLI does
1428
+ * not accept refs, and the local clone has whatever content the test
1429
+ * checked into it anyway. When set to anything else (e.g. a fork name
1430
+ * `myuser/prisma-next`), the ref policy is preserved.
1431
+ */
1432
+ function resolveAgentSkillBase() {
1433
+ const override = process.env["PRISMA_NEXT_SKILLS_BASE"]?.trim();
1434
+ return override && override.length > 0 ? override : DEFAULT_SKILL_BASE;
1435
+ }
1436
+ function isLocalPath(base) {
1437
+ return base.startsWith("/") || /^[a-zA-Z]:[\\/]/.test(base);
1438
+ }
1439
+ /**
1440
+ * Build the `<base>/<subpath>[#ref]` URL the `skills` CLI will
1441
+ * resolve. Exported for unit tests so the per-source format can be
1442
+ * asserted without going through the full install loop.
1443
+ */
1444
+ function formatSkillSourceUrl(source) {
1445
+ const base = resolveAgentSkillBase();
1446
+ const url = `${base}/${source.subpath}`;
1447
+ if (source.ref === null) return url;
1448
+ if (isLocalPath(base)) return url;
1449
+ if (source.ref === "cli") return `${url}#v${version}`;
1450
+ return url;
1451
+ }
1452
+ /**
1453
+ * The skill-install command for one source, formatted for the
1454
+ * project's detected package manager. `npx`/`pnpm dlx`/`bunx` are
1455
+ * interchangeable to the user; we pick the variant that matches the
1456
+ * rest of the install step so a single project consistently uses one
1457
+ * runner.
1458
+ *
1459
+ * `--all` auto-selects every skill in the cluster and every detected
1460
+ * agent runtime, skipping the multi-select prompts the `skills` CLI
1461
+ * shows by default. A non-interactive scaffold step cannot present
1462
+ * prompts.
1463
+ *
1464
+ * Exported for unit tests so the per-PM dispatch can be asserted
1465
+ * without a live subprocess.
1466
+ */
1467
+ function formatSkillInstallCommand(pm, source) {
1468
+ return formatPackageManagerCommand(pm, [
1469
+ "skills@latest",
1470
+ "add",
1471
+ formatSkillSourceUrl(source),
1472
+ "--all"
1473
+ ]);
1474
+ }
1475
+ /**
1476
+ * `skills add --all` should cover Claude Code, but upstream currently skips
1477
+ * project-local Claude symlinks when `.claude/` does not already exist. Run
1478
+ * the explicit Claude Code install as well so fresh projects get
1479
+ * `.claude/skills` without asking users to create that folder first.
1480
+ */
1481
+ function formatClaudeSkillInstallCommand(pm, source) {
1482
+ return formatPackageManagerCommand(pm, [
1483
+ "skills@latest",
1484
+ "add",
1485
+ formatSkillSourceUrl(source),
1486
+ "--agent",
1487
+ "claude-code",
1488
+ "--skill",
1489
+ "'*'",
1490
+ "-y"
1491
+ ]);
1492
+ }
1493
+ function formatPackageManagerCommand(pm, args) {
1494
+ switch (pm) {
1495
+ case "pnpm": return `pnpm dlx ${args.join(" ")}`;
1496
+ case "yarn": return `yarn dlx ${args.join(" ")}`;
1497
+ case "bun": return `bunx ${args.join(" ")}`;
1498
+ case "deno": return `deno run -A npm:${args.join(" ")}`;
1499
+ case "npm": return `npx ${args.join(" ")}`;
1500
+ }
1501
+ }
1502
+ /**
1503
+ * Parse the project-pm-formatted command into an exec call. The
1504
+ * format-then-parse split keeps the user-facing command string the same
1505
+ * as the surface the structured error advertises, so a user who copies
1506
+ * the error's `fix` line gets the same invocation that init just
1507
+ * attempted. Single quotes are preserved in the display form so `*` is
1508
+ * safe to copy into a shell, then stripped before `execFile`.
1509
+ */
1510
+ function commandToExec(command) {
1511
+ const tokens = (command.match(/'[^']*'|\S+/g) ?? []).map((token) => token.startsWith("'") && token.endsWith("'") ? token.slice(1, -1) : token);
1512
+ return {
1513
+ file: tokens[0] ?? "npx",
1514
+ args: tokens.slice(1)
1515
+ };
1516
+ }
1517
+ /**
1518
+ * Runs the project-level skill install for every source in
1519
+ * `DEFAULT_SKILL_SOURCES`, in order. Returns
1520
+ * `{ ok: true, commands }` on success; throws a structured
1521
+ * `errorInitSkillInstallFailed` on the first failure (subsequent
1522
+ * sources are not attempted — the user opted into Prisma Next by
1523
+ * running `init` and a partial install would leave the project in an
1524
+ * ambiguous state). The throw is intentionally fatal — project-level
1525
+ * skill install is unconditional (modulo `--no-skill`).
1526
+ */
1527
+ async function runProjectLevelSkillInstall(ctx) {
1528
+ const commands = [];
1529
+ const installCommands = DEFAULT_SKILL_SOURCES.flatMap((source) => [formatSkillInstallCommand(ctx.pm, source), formatClaudeSkillInstallCommand(ctx.pm, source)]);
1530
+ for (const command of installCommands) {
1531
+ const { file, args } = commandToExec(command);
1532
+ try {
1533
+ await exec(file, args, { cwd: ctx.baseDir });
1534
+ commands.push(command);
1535
+ } catch (err) {
1536
+ throw errorInitSkillInstallFailed({
1537
+ skillInstallCommand: command,
1538
+ filesWritten: ctx.filesWritten,
1539
+ cause: redactSecrets$1(readChildStderr$1(err)) || (err instanceof Error ? err.message : String(err))
1540
+ });
1541
+ }
1542
+ }
1543
+ return {
1544
+ ok: true,
1545
+ commands
1546
+ };
1547
+ }
1548
+ function readChildStderr$1(err) {
1549
+ if (err instanceof Error && "stderr" in err) return String(err.stderr ?? "");
1550
+ return "";
1551
+ }
1552
+ /**
1553
+ * Strips credentials from a `scheme://user:pass@host/...` URL anywhere
1554
+ * in `stderr`. Package-manager stderr regularly contains credentialed
1555
+ * registry URLs (private npm registries, GitHub Packages tokens), and
1556
+ * those bubble into the structured `errorInitSkillInstallFailed`
1557
+ * envelope, which ends up in logs and CI output. Redact at the
1558
+ * boundary so we never re-emit a secret.
1559
+ *
1560
+ * Exported for unit tests.
1561
+ */
1562
+ function redactSecrets$1(stderr) {
1563
+ if (!stderr) return stderr;
1564
+ return stderr.replace(/([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)([^/@\s]+)@/g, "$1***@");
1565
+ }
1566
+ /**
1567
+ * Hand-rolled skill stub path that init must not leave behind. Removed
1568
+ * on every init run so a project's `.agents/skills/prisma-next/` does
1569
+ * not shadow the installed Prisma Next skill cluster.
1570
+ */
1571
+ const LEGACY_SKILL_FILE = ".agents/skills/prisma-next/SKILL.md";
1572
+ //#endregion
1514
1573
  //#region src/commands/init/templates/env.ts
1515
1574
  /**
1516
1575
  * The minimum supported server version for each target (FR8.1). The
@@ -1782,7 +1841,7 @@ function mergeTypesArray(existing) {
1782
1841
  * structured CLI errors raised at every phase (input resolution, install,
1783
1842
  * emit) and renders them via the same UI surface as success output
1784
1843
  * (`--json` to stdout, human to stderr). Exit codes follow the documented
1785
- * stable set in `./exit-codes.ts` (FR1.6) and the
1844
+ * stable set in `./exit-codes.ts` and the
1786
1845
  * [Style Guide § Exit Codes](../../../../../../../docs/CLI%20Style%20Guide.md#exit-codes).
1787
1846
  *
1788
1847
  * Layered for testability: the action handler in `./index.ts` is
@@ -1790,7 +1849,7 @@ function mergeTypesArray(existing) {
1790
1849
  * function does no flag parsing of its own.
1791
1850
  */
1792
1851
  async function runInit(baseDir, runOptions) {
1793
- const { options, flags, canPrompt, probeOverrides } = runOptions;
1852
+ const { options, flags, canPrompt, probeOverrides, afterFirstTelemetryConsent } = runOptions;
1794
1853
  const ui = new TerminalUI({
1795
1854
  color: flags.color,
1796
1855
  interactive: flags.interactive
@@ -1811,6 +1870,9 @@ async function runInit(baseDir, runOptions) {
1811
1870
  if (CliStructuredError.is(error)) return emitError(ui, flags, error);
1812
1871
  throw error;
1813
1872
  }
1873
+ if (inputs.enableTelemetry === true && afterFirstTelemetryConsent !== void 0) try {
1874
+ await afterFirstTelemetryConsent(inputs);
1875
+ } catch {}
1814
1876
  const pm = await detectPackageManager(baseDir);
1815
1877
  const pkgRun = formatRunCommand(pm, "prisma-next", "").trimEnd();
1816
1878
  const schemaDir = dirname(inputs.schemaPath);
@@ -1983,10 +2045,10 @@ async function runInit(baseDir, runOptions) {
1983
2045
  filesWritten
1984
2046
  }));
1985
2047
  }
1986
- const manualProjectSkillSummary = DEFAULT_AGENT_SKILL_SOURCES.flatMap((source) => [formatSkillInstallCommand(install.effectivePm, source), formatClaudeSkillInstallCommand(install.effectivePm, source)]).map((c) => `\`${c}\``).join(" && ");
2048
+ const manualProjectSkillSummary = DEFAULT_SKILL_SOURCES.flatMap((source) => [formatSkillInstallCommand(install.effectivePm, source), formatClaudeSkillInstallCommand(install.effectivePm, source)]).map((c) => `\`${c}\``).join(" && ");
1987
2049
  let skillRegistered = false;
1988
- if (!inputs.installProjectSkill) warnings.push(`Skipped Prisma Next agent-skill install (--no-skill). To install the skills later, run: ${manualProjectSkillSummary}`);
1989
- else if (install.skipped) warnings.push(`Skipped Prisma Next agent-skill install because --no-install was passed. After you run install manually, install the skills with: ${manualProjectSkillSummary}`);
2050
+ if (!inputs.installProjectSkill) warnings.push(`Skipped Prisma Next skills install (--no-skill). To install the skills later, run: ${manualProjectSkillSummary}`);
2051
+ else if (install.skipped) warnings.push(`Skipped Prisma Next skills install because --no-install was passed. After you run install manually, install the skills with: ${manualProjectSkillSummary}`);
1990
2052
  else {
1991
2053
  const spinner = ui.spinner();
1992
2054
  spinner.start("Registering Prisma Next skills with the agent runtime...");
@@ -2352,4 +2414,4 @@ function sanitisePackageName(raw) {
2352
2414
  //#endregion
2353
2415
  export { runInit };
2354
2416
 
2355
- //# sourceMappingURL=init-eh2z5Tl6.mjs.map
2417
+ //# sourceMappingURL=init-CxS9eqbQ.mjs.map