prisma-next 0.7.0-dev.5 → 0.7.0-dev.7

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.
@@ -1,6 +1,6 @@
1
1
  import { t as CliStructuredError } from "./cli-errors-D3_sMh2K.mjs";
2
2
  import { i as formatErrorOutput, r as formatErrorJson, t as TerminalUI } from "./terminal-ui-C_hFNbAn.mjs";
3
- import { i as renderInitOutro, n as buildNextSteps, r as formatInitJson, t as InitOutputSchema } from "./output-B16Kefzx.mjs";
3
+ import { i as renderInitOutro, n as buildNextSteps, r as formatInitJson, t as InitOutputSchema } from "./output-BVj6a971.mjs";
4
4
  import { createRequire } from "node:module";
5
5
  import { basename, dirname, extname, isAbsolute, join, normalize } from "pathe";
6
6
  import * as clack from "@clack/prompts";
@@ -9,159 +9,6 @@ import { execFile } from "node:child_process";
9
9
  import { promisify } from "node:util";
10
10
  import { detect, getUserAgent } from "package-manager-detector/detect";
11
11
  import { applyEdits, modify, parse, printParseErrorCode } from "jsonc-parser";
12
- //#region src/commands/init/detect-package-manager.ts
13
- const KNOWN = new Set([
14
- "pnpm",
15
- "npm",
16
- "yarn",
17
- "bun",
18
- "deno"
19
- ]);
20
- /**
21
- * Resolves the package manager `init` should drive for `add` / `install`
22
- * commands. Tries, in order:
23
- *
24
- * 1. **`detect()`** — walks up from `cwd` looking for a lockfile, the
25
- * `packageManager` field, the `devEngines.packageManager` field, or
26
- * install metadata. This is the right answer whenever the user is
27
- * anywhere inside an existing project, including a deep workspace
28
- * subdirectory.
29
- *
30
- * 2. **`getUserAgent()`** — parses `npm_config_user_agent`, the env var
31
- * every PM sets when it spawns a script. This catches the
32
- * bare-directory case where there's no project to walk up to but the
33
- * user invoked us via `pnpm dlx prisma-next init` / `bunx
34
- * prisma-next init` / `yarn dlx …`. Same signal used by every
35
- * `create-*` tool in the ecosystem (`create-vite`, `create-next-app`,
36
- * `create-astro`, `@antfu/ni`, …).
37
- *
38
- * 3. **`npm`** — final fallback. Always present alongside Node.
39
- */
40
- async function detectPackageManager(cwd) {
41
- const detected = await detect({ cwd });
42
- if (detected && KNOWN.has(detected.name)) return detected.name;
43
- const userAgent = getUserAgent();
44
- if (userAgent !== null && KNOWN.has(userAgent)) return userAgent;
45
- return "npm";
46
- }
47
- function hasProjectManifest(cwd) {
48
- return existsSync(join(cwd, "package.json")) || existsSync(join(cwd, "deno.json")) || existsSync(join(cwd, "deno.jsonc"));
49
- }
50
- function formatRunCommand(pm, bin, args) {
51
- if (pm === "npm") return `npx ${bin} ${args}`;
52
- if (pm === "deno") return `deno run npm:${bin} ${args}`;
53
- return `${pm} ${bin} ${args}`;
54
- }
55
- function formatAddArgs(pm, packages) {
56
- if (pm === "deno") return ["add", ...packages.map((p) => `npm:${p}`)];
57
- return ["add", ...packages];
58
- }
59
- function formatAddDevArgs(pm, packages) {
60
- if (pm === "deno") return [
61
- "add",
62
- "--dev",
63
- ...packages.map((p) => `npm:${p}`)
64
- ];
65
- return [
66
- "add",
67
- "-D",
68
- ...packages
69
- ];
70
- }
71
- //#endregion
72
- //#region src/commands/init/detect-pnpm-catalog.ts
73
- /**
74
- * Walks up from `baseDir` looking for `pnpm-workspace.yaml`, then scans
75
- * its top-level `catalog:` block for entries that match any of `packages`.
76
- *
77
- * Implements FR7.3 / Spec Decision 8 (honour-and-warn): when `init` runs
78
- * inside a pnpm workspace whose catalog overrides one of the packages it
79
- * installs, surface a structured warning so the user knows the catalog
80
- * version (not the published `latest`) is what ended up in their
81
- * `node_modules`. pnpm itself does this silently; the warning closes the
82
- * "looks fine, must be wrong version six months later" gap.
83
- *
84
- * Notes / scope:
85
- *
86
- * - We only inspect the unnamed top-level `catalog:` block. pnpm also
87
- * supports `catalogs:` (plural — *named* catalogs referenced via
88
- * `catalog:foo` specifiers); those don't apply to a vanilla
89
- * `pnpm add prisma-next` invocation, so we skip them.
90
- * - We don't validate YAML syntax exhaustively. The file format pnpm
91
- * ships is line-oriented and well-known; a minimal regex is more
92
- * robust than depending on a YAML parser for one warning.
93
- * - We don't compare against the registry's `latest` — pnpm uses the
94
- * catalog version regardless, so the warning fires whenever a match
95
- * exists. The user-facing copy explains how to opt out.
96
- */
97
- function detectPnpmCatalogOverrides(baseDir, packages) {
98
- const workspaceFile = findNearestPnpmWorkspaceFile(baseDir);
99
- if (workspaceFile === null) return null;
100
- const catalog = extractCatalogBlock(readFileSync(workspaceFile, "utf-8"));
101
- if (catalog === null) return {
102
- workspaceFile,
103
- entries: []
104
- };
105
- const wanted = new Set(packages);
106
- const entries = [];
107
- for (const [name, version] of catalog) if (wanted.has(name)) entries.push({
108
- name,
109
- version
110
- });
111
- return {
112
- workspaceFile,
113
- entries
114
- };
115
- }
116
- function findNearestPnpmWorkspaceFile(baseDir) {
117
- let dir = baseDir;
118
- let prev = "";
119
- while (dir !== prev) {
120
- const candidate = join(dir, "pnpm-workspace.yaml");
121
- if (existsSync(candidate)) return candidate;
122
- prev = dir;
123
- dir = dirname(dir);
124
- }
125
- return null;
126
- }
127
- /**
128
- * Returns the entries inside the top-level `catalog:` block as `[name, version]`
129
- * pairs in document order, or `null` when no `catalog:` block exists.
130
- *
131
- * The parser is intentionally minimal: it reads line-by-line, locates the
132
- * top-level `catalog:` line (no leading whitespace), then collects every
133
- * subsequent indented line of the form `<key>: <value>` until the next
134
- * top-level key (or end of file). Quotes around `<key>` and `<value>`
135
- * are stripped; comments (`#…`) are ignored.
136
- */
137
- function extractCatalogBlock(contents) {
138
- const lines = contents.split(/\r?\n/);
139
- const startIdx = lines.findIndex((line) => /^catalog\s*:\s*$/.test(line));
140
- if (startIdx === -1) return null;
141
- const entries = [];
142
- for (let i = startIdx + 1; i < lines.length; i++) {
143
- const raw = lines[i] ?? "";
144
- if (raw.trim() === "" || /^\s*#/.test(raw)) continue;
145
- if (!/^\s/.test(raw)) break;
146
- const match = raw.match(/^\s+(?:'([^']+)'|"([^"]+)"|([^:\s'"]+))\s*:\s*(.*?)\s*(?:#.*)?$/);
147
- if (!match) continue;
148
- const name = match[1] ?? match[2] ?? match[3];
149
- if (name === void 0) continue;
150
- const version = stripQuotes((match[4] ?? "").trim());
151
- if (version === "") continue;
152
- entries.push([name, version]);
153
- }
154
- return entries;
155
- }
156
- function stripQuotes(value) {
157
- if (value.length >= 2) {
158
- const first = value[0];
159
- const last = value[value.length - 1];
160
- if (first === "\"" && last === "\"" || first === "'" && last === "'") return value.slice(1, -1);
161
- }
162
- return value;
163
- }
164
- //#endregion
165
12
  //#region src/commands/init/errors.ts
166
13
  /**
167
14
  * Re-init in non-interactive mode without `--force`. Distinct from the
@@ -364,6 +211,296 @@ function errorInitEmitFailed(options) {
364
211
  }
365
212
  });
366
213
  }
214
+ /**
215
+ * The project-level agent-skill install (`npx skills add
216
+ * @prisma-next/agent-skill`) failed after a successful dependency
217
+ * install + emit. The project's scaffold remains on disk; the user
218
+ * can either fix the underlying issue (network, registry, PATH) and
219
+ * run the install command manually, or re-run `init --no-skill` to
220
+ * proceed without the skill.
221
+ *
222
+ * Non-rolling-back, matching the existing install/emit failure
223
+ * semantics. Maps to exit code `6 = SKILL_INSTALL_FAILED`.
224
+ */
225
+ function errorInitSkillInstallFailed(options) {
226
+ return new CliStructuredError("5013", "Failed to install @prisma-next/agent-skill", {
227
+ domain: "CLI",
228
+ why: `\`${options.skillInstallCommand}\` exited with an error: ${options.cause}`,
229
+ fix: `Either:
230
+ - 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}`,
231
+ docsUrl: "https://prisma-next.dev/docs/cli/init#agent-skill",
232
+ meta: {
233
+ filesWritten: options.filesWritten,
234
+ skillInstallCommand: options.skillInstallCommand,
235
+ cause: options.cause
236
+ }
237
+ });
238
+ }
239
+ //#endregion
240
+ //#region src/commands/init/agent-skill-install.ts
241
+ const exec = promisify(execFile);
242
+ /**
243
+ * The npm package the agent-skill install dispatches to. Version-locked
244
+ * to Prisma Next via the consumer project's `package.json`; the install
245
+ * subprocess picks up whatever version is resolvable at install time.
246
+ *
247
+ * The skill is **always** installed at the project level — never the
248
+ * user level — precisely so the skill version tracks the project's
249
+ * Prisma Next version. A user-level (global) install of an
250
+ * agent-skills CLI package would have to pick a single version for
251
+ * every project on the host, which breaks the version-locking invariant
252
+ * the rest of the framework relies on (skills, CLI, runtime, and
253
+ * extension packs all ship at the same version per release).
254
+ */
255
+ const AGENT_SKILL_PACKAGE = "@prisma-next/agent-skill";
256
+ /**
257
+ * The skill-install command, formatted for the project's detected
258
+ * package manager. `npx`/`pnpm dlx`/`bunx` are interchangeable to the
259
+ * user; we pick the variant that matches the rest of the install step
260
+ * so a single project consistently uses one runner.
261
+ *
262
+ * `--all` auto-selects every skill in the cluster and every detected
263
+ * agent runtime, skipping the multi-select prompts the `skills` CLI
264
+ * shows by default. A non-interactive scaffold step cannot present
265
+ * prompts, and the cluster is designed to be installed as a unit (the
266
+ * router skill routes between the workflow-scoped siblings). Users who
267
+ * want a narrower install run `npx skills add @prisma-next/agent-skill`
268
+ * themselves after `init` with the flags they want.
269
+ *
270
+ * Exported for unit tests so the per-PM dispatch can be asserted
271
+ * without a live subprocess.
272
+ */
273
+ function formatSkillInstallCommand(pm) {
274
+ const args = [
275
+ "skills",
276
+ "add",
277
+ AGENT_SKILL_PACKAGE,
278
+ "--all"
279
+ ];
280
+ switch (pm) {
281
+ case "pnpm": return `pnpm dlx ${args.join(" ")}`;
282
+ case "yarn": return `yarn dlx ${args.join(" ")}`;
283
+ case "bun": return `bunx ${args.join(" ")}`;
284
+ case "deno": return `deno run -A npm:${args.join(" ")}`;
285
+ case "npm": return `npx ${args.join(" ")}`;
286
+ }
287
+ }
288
+ /**
289
+ * Parse the project-pm-formatted command into an exec call. The
290
+ * format-then-parse split keeps the user-facing command string the same
291
+ * as the surface the structured error advertises, so a user who copies
292
+ * the error's `fix` line gets the same invocation that init just
293
+ * attempted.
294
+ */
295
+ function commandToExec(command) {
296
+ const tokens = command.split(/\s+/);
297
+ return {
298
+ file: tokens[0] ?? "npx",
299
+ args: tokens.slice(1)
300
+ };
301
+ }
302
+ /**
303
+ * Runs the project-level skill install. Returns `{ ok: true, command }`
304
+ * on success; throws a structured `errorInitSkillInstallFailed` on
305
+ * failure. The throw is intentionally fatal — project-level skill
306
+ * install is unconditional (modulo `--no-skill`) and the user opted
307
+ * into Prisma Next by running `init`. A silent skip would defeat the
308
+ * onboarding-to-zero contract.
309
+ */
310
+ async function runProjectLevelSkillInstall(ctx) {
311
+ const command = formatSkillInstallCommand(ctx.pm);
312
+ const { file, args } = commandToExec(command);
313
+ try {
314
+ await exec(file, args, { cwd: ctx.baseDir });
315
+ return {
316
+ ok: true,
317
+ command
318
+ };
319
+ } catch (err) {
320
+ throw errorInitSkillInstallFailed({
321
+ skillInstallCommand: command,
322
+ filesWritten: ctx.filesWritten,
323
+ cause: redactSecrets$1(readChildStderr$1(err)) || (err instanceof Error ? err.message : String(err))
324
+ });
325
+ }
326
+ }
327
+ function readChildStderr$1(err) {
328
+ if (err instanceof Error && "stderr" in err) return String(err.stderr ?? "");
329
+ return "";
330
+ }
331
+ /**
332
+ * Strips credentials from a `scheme://user:pass@host/...` URL anywhere
333
+ * in `stderr`. Package-manager stderr regularly contains credentialed
334
+ * registry URLs (private npm registries, GitHub Packages tokens), and
335
+ * those bubble into the structured `errorInitSkillInstallFailed`
336
+ * envelope, which ends up in logs and CI output. Redact at the
337
+ * boundary so we never re-emit a secret.
338
+ *
339
+ * Exported for unit tests.
340
+ */
341
+ function redactSecrets$1(stderr) {
342
+ if (!stderr) return stderr;
343
+ return stderr.replace(/([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)([^/@\s]+)@/g, "$1***@");
344
+ }
345
+ /**
346
+ * Hand-rolled skill stub path that init must not leave behind. Removed
347
+ * on every init run so a project's `.agents/skills/prisma-next/` does
348
+ * not shadow the published `@prisma-next/agent-skill` package.
349
+ */
350
+ const LEGACY_SKILL_FILE = ".agents/skills/prisma-next/SKILL.md";
351
+ //#endregion
352
+ //#region src/commands/init/detect-package-manager.ts
353
+ const KNOWN = new Set([
354
+ "pnpm",
355
+ "npm",
356
+ "yarn",
357
+ "bun",
358
+ "deno"
359
+ ]);
360
+ /**
361
+ * Resolves the package manager `init` should drive for `add` / `install`
362
+ * commands. Tries, in order:
363
+ *
364
+ * 1. **`detect()`** — walks up from `cwd` looking for a lockfile, the
365
+ * `packageManager` field, the `devEngines.packageManager` field, or
366
+ * install metadata. This is the right answer whenever the user is
367
+ * anywhere inside an existing project, including a deep workspace
368
+ * subdirectory.
369
+ *
370
+ * 2. **`getUserAgent()`** — parses `npm_config_user_agent`, the env var
371
+ * every PM sets when it spawns a script. This catches the
372
+ * bare-directory case where there's no project to walk up to but the
373
+ * user invoked us via `pnpm dlx prisma-next init` / `bunx
374
+ * prisma-next init` / `yarn dlx …`. Same signal used by every
375
+ * `create-*` tool in the ecosystem (`create-vite`, `create-next-app`,
376
+ * `create-astro`, `@antfu/ni`, …).
377
+ *
378
+ * 3. **`npm`** — final fallback. Always present alongside Node.
379
+ */
380
+ async function detectPackageManager(cwd) {
381
+ const detected = await detect({ cwd });
382
+ if (detected && KNOWN.has(detected.name)) return detected.name;
383
+ const userAgent = getUserAgent();
384
+ if (userAgent !== null && KNOWN.has(userAgent)) return userAgent;
385
+ return "npm";
386
+ }
387
+ function hasProjectManifest(cwd) {
388
+ return existsSync(join(cwd, "package.json")) || existsSync(join(cwd, "deno.json")) || existsSync(join(cwd, "deno.jsonc"));
389
+ }
390
+ function formatRunCommand(pm, bin, args) {
391
+ if (pm === "npm") return `npx ${bin} ${args}`;
392
+ if (pm === "deno") return `deno run npm:${bin} ${args}`;
393
+ return `${pm} ${bin} ${args}`;
394
+ }
395
+ function formatAddArgs(pm, packages) {
396
+ if (pm === "deno") return ["add", ...packages.map((p) => `npm:${p}`)];
397
+ return ["add", ...packages];
398
+ }
399
+ function formatAddDevArgs(pm, packages) {
400
+ if (pm === "deno") return [
401
+ "add",
402
+ "--dev",
403
+ ...packages.map((p) => `npm:${p}`)
404
+ ];
405
+ return [
406
+ "add",
407
+ "-D",
408
+ ...packages
409
+ ];
410
+ }
411
+ //#endregion
412
+ //#region src/commands/init/detect-pnpm-catalog.ts
413
+ /**
414
+ * Walks up from `baseDir` looking for `pnpm-workspace.yaml`, then scans
415
+ * its top-level `catalog:` block for entries that match any of `packages`.
416
+ *
417
+ * Implements FR7.3 / Spec Decision 8 (honour-and-warn): when `init` runs
418
+ * inside a pnpm workspace whose catalog overrides one of the packages it
419
+ * installs, surface a structured warning so the user knows the catalog
420
+ * version (not the published `latest`) is what ended up in their
421
+ * `node_modules`. pnpm itself does this silently; the warning closes the
422
+ * "looks fine, must be wrong version six months later" gap.
423
+ *
424
+ * Notes / scope:
425
+ *
426
+ * - We only inspect the unnamed top-level `catalog:` block. pnpm also
427
+ * supports `catalogs:` (plural — *named* catalogs referenced via
428
+ * `catalog:foo` specifiers); those don't apply to a vanilla
429
+ * `pnpm add prisma-next` invocation, so we skip them.
430
+ * - We don't validate YAML syntax exhaustively. The file format pnpm
431
+ * ships is line-oriented and well-known; a minimal regex is more
432
+ * robust than depending on a YAML parser for one warning.
433
+ * - We don't compare against the registry's `latest` — pnpm uses the
434
+ * catalog version regardless, so the warning fires whenever a match
435
+ * exists. The user-facing copy explains how to opt out.
436
+ */
437
+ function detectPnpmCatalogOverrides(baseDir, packages) {
438
+ const workspaceFile = findNearestPnpmWorkspaceFile(baseDir);
439
+ if (workspaceFile === null) return null;
440
+ const catalog = extractCatalogBlock(readFileSync(workspaceFile, "utf-8"));
441
+ if (catalog === null) return {
442
+ workspaceFile,
443
+ entries: []
444
+ };
445
+ const wanted = new Set(packages);
446
+ const entries = [];
447
+ for (const [name, version] of catalog) if (wanted.has(name)) entries.push({
448
+ name,
449
+ version
450
+ });
451
+ return {
452
+ workspaceFile,
453
+ entries
454
+ };
455
+ }
456
+ function findNearestPnpmWorkspaceFile(baseDir) {
457
+ let dir = baseDir;
458
+ let prev = "";
459
+ while (dir !== prev) {
460
+ const candidate = join(dir, "pnpm-workspace.yaml");
461
+ if (existsSync(candidate)) return candidate;
462
+ prev = dir;
463
+ dir = dirname(dir);
464
+ }
465
+ return null;
466
+ }
467
+ /**
468
+ * Returns the entries inside the top-level `catalog:` block as `[name, version]`
469
+ * pairs in document order, or `null` when no `catalog:` block exists.
470
+ *
471
+ * The parser is intentionally minimal: it reads line-by-line, locates the
472
+ * top-level `catalog:` line (no leading whitespace), then collects every
473
+ * subsequent indented line of the form `<key>: <value>` until the next
474
+ * top-level key (or end of file). Quotes around `<key>` and `<value>`
475
+ * are stripped; comments (`#…`) are ignored.
476
+ */
477
+ function extractCatalogBlock(contents) {
478
+ const lines = contents.split(/\r?\n/);
479
+ const startIdx = lines.findIndex((line) => /^catalog\s*:\s*$/.test(line));
480
+ if (startIdx === -1) return null;
481
+ const entries = [];
482
+ for (let i = startIdx + 1; i < lines.length; i++) {
483
+ const raw = lines[i] ?? "";
484
+ if (raw.trim() === "" || /^\s*#/.test(raw)) continue;
485
+ if (!/^\s/.test(raw)) break;
486
+ const match = raw.match(/^\s+(?:'([^']+)'|"([^"]+)"|([^:\s'"]+))\s*:\s*(.*?)\s*(?:#.*)?$/);
487
+ if (!match) continue;
488
+ const name = match[1] ?? match[2] ?? match[3];
489
+ if (name === void 0) continue;
490
+ const version = stripQuotes((match[4] ?? "").trim());
491
+ if (version === "") continue;
492
+ entries.push([name, version]);
493
+ }
494
+ return entries;
495
+ }
496
+ function stripQuotes(value) {
497
+ if (value.length >= 2) {
498
+ const first = value[0];
499
+ const last = value[value.length - 1];
500
+ if (first === "\"" && last === "\"" || first === "'" && last === "'") return value.slice(1, -1);
501
+ }
502
+ return value;
503
+ }
367
504
  //#endregion
368
505
  //#region src/commands/init/hygiene-gitattributes.ts
369
506
  /**
@@ -885,6 +1022,7 @@ async function resolveInitInputs(ctx) {
885
1022
  canPrompt,
886
1023
  autoAcceptPrompts
887
1024
  });
1025
+ const installProjectSkill = options.skill !== false;
888
1026
  return {
889
1027
  target: finalTarget,
890
1028
  authoring: finalAuthoring,
@@ -894,7 +1032,8 @@ async function resolveInitInputs(ctx) {
894
1032
  probeDb: Boolean(options.probeDb),
895
1033
  strictProbe: Boolean(options.strictProbe),
896
1034
  reinit,
897
- removePreviousFacade
1035
+ removePreviousFacade,
1036
+ installProjectSkill
898
1037
  };
899
1038
  }
900
1039
  async function resolveWriteEnv(opts) {
@@ -1305,47 +1444,6 @@ function removeDependency(existing, depName) {
1305
1444
  return `${JSON.stringify(parsed, null, 2)}${trailingNewline}`;
1306
1445
  }
1307
1446
  //#endregion
1308
- //#region src/commands/init/templates/render.ts
1309
- function renderTemplate(templateFile, variableNames, vars) {
1310
- let result = readFileSync(join(import.meta.dirname, templateFile), "utf-8");
1311
- for (const key of variableNames) {
1312
- const value = vars[key];
1313
- if (value === void 0) throw new Error(`Template variable '${key}' is not defined`);
1314
- result = result.replaceAll(`{{${key}}}`, value);
1315
- }
1316
- return result;
1317
- }
1318
- //#endregion
1319
- //#region src/commands/init/templates/agent-skill.ts
1320
- const variables$1 = [
1321
- "schemaPath",
1322
- "schemaDir",
1323
- "dbImportPath",
1324
- "pkgRun",
1325
- "authoringLabel"
1326
- ];
1327
- /**
1328
- * Renders the per-project agent skill (FR5.2). The skill template is
1329
- * target-specific (Postgres vs Mongo query syntax differs); the authoring
1330
- * style enters via:
1331
- *
1332
- * - `schemaPath` — already routed through {@link agentSkillMd}'s caller
1333
- * (the AC says a TS-authoring scaffold must reference `prisma/contract.ts`).
1334
- * - `authoringLabel` — a short human-readable note (`PSL` / `TypeScript`)
1335
- * the skill template uses when describing the contract file.
1336
- */
1337
- function agentSkillMd(target, authoring, schemaPath, pkgRun) {
1338
- const schemaDir = dirname(schemaPath);
1339
- const vars = {
1340
- schemaPath,
1341
- schemaDir,
1342
- dbImportPath: `./${schemaDir}/db`,
1343
- pkgRun,
1344
- authoringLabel: authoring === "typescript" ? "TypeScript" : "PSL"
1345
- };
1346
- return renderTemplate(`agent-skill-${target}.md`, variables$1, vars);
1347
- }
1348
- //#endregion
1349
1447
  //#region src/commands/init/templates/env.ts
1350
1448
  /**
1351
1449
  * The minimum supported server version for each target (FR8.1). The
@@ -1417,6 +1515,17 @@ function envFileContent(target) {
1417
1515
  return envPlaceholderBody(target);
1418
1516
  }
1419
1517
  //#endregion
1518
+ //#region src/commands/init/templates/render.ts
1519
+ function renderTemplate(templateFile, variableNames, vars) {
1520
+ let result = readFileSync(join(import.meta.dirname, templateFile), "utf-8");
1521
+ for (const key of variableNames) {
1522
+ const value = vars[key];
1523
+ if (value === void 0) throw new Error(`Template variable '${key}' is not defined`);
1524
+ result = result.replaceAll(`{{${key}}}`, value);
1525
+ }
1526
+ return result;
1527
+ }
1528
+ //#endregion
1420
1529
  //#region src/commands/init/templates/quick-reference.ts
1421
1530
  const variables = [
1422
1531
  "schemaPath",
@@ -1656,16 +1765,13 @@ async function runInit(baseDir, runOptions) {
1656
1765
  path: "prisma-next.md",
1657
1766
  content: quickReferenceMd(inputs.target, inputs.authoring, inputs.schemaPath, pkgRun)
1658
1767
  },
1659
- {
1660
- path: ".agents/skills/prisma-next/SKILL.md",
1661
- content: agentSkillMd(inputs.target, inputs.authoring, inputs.schemaPath, pkgRun)
1662
- },
1663
1768
  {
1664
1769
  path: ".env.example",
1665
1770
  content: envExampleContent(inputs.target)
1666
1771
  }
1667
1772
  ];
1668
1773
  const filesToDelete = inputs.reinit ? [...findStaleArtefacts(baseDir, schemaDir)] : [];
1774
+ if (existsSync(join(baseDir, ".agents/skills/prisma-next/SKILL.md"))) filesToDelete.push(LEGACY_SKILL_FILE);
1669
1775
  if (inputs.writeEnv) if (!existsSync(join(baseDir, ".env"))) filesToWrite.push({
1670
1776
  path: ".env",
1671
1777
  content: envFileContent(inputs.target)
@@ -1810,6 +1916,25 @@ async function runInit(baseDir, runOptions) {
1810
1916
  filesWritten
1811
1917
  }));
1812
1918
  }
1919
+ const manualProjectSkillCommand = formatSkillInstallCommand(install.effectivePm);
1920
+ if (!inputs.installProjectSkill) warnings.push(`Skipped @prisma-next/agent-skill install (--no-skill). To install later, run \`${manualProjectSkillCommand}\` in this project.`);
1921
+ else if (install.skipped) warnings.push(`Skipped @prisma-next/agent-skill install because --no-install was passed. Once you run install manually, register the skill with \`${manualProjectSkillCommand}\`.`);
1922
+ else {
1923
+ const spinner = ui.spinner();
1924
+ spinner.start("Registering @prisma-next/agent-skill with the agent runtime...");
1925
+ try {
1926
+ const project = await runProjectLevelSkillInstall({
1927
+ baseDir,
1928
+ pm: install.effectivePm,
1929
+ filesWritten
1930
+ });
1931
+ spinner.stop(`Registered @prisma-next/agent-skill (project level) — ran \`${project.command}\``);
1932
+ } catch (error) {
1933
+ spinner.stop("Agent-skill install failed");
1934
+ if (CliStructuredError.is(error)) return emitError(ui, flags, error);
1935
+ throw error;
1936
+ }
1937
+ }
1813
1938
  const output = {
1814
1939
  ok: true,
1815
1940
  target: inputs.target === "mongo" ? "mongodb" : "postgres",
@@ -1887,6 +2012,7 @@ function exitCodeForError(error) {
1887
2012
  case "5007": return 4;
1888
2013
  case "5008": return 5;
1889
2014
  case "5009": return 1;
2015
+ case "5013": return 6;
1890
2016
  default: return 1;
1891
2017
  }
1892
2018
  }
@@ -1958,7 +2084,8 @@ async function runInstall(ctx) {
1958
2084
  skipped: true,
1959
2085
  deps: [],
1960
2086
  devDeps: [],
1961
- warnings: catalogWarnings
2087
+ warnings: catalogWarnings,
2088
+ effectivePm: pm
1962
2089
  };
1963
2090
  }
1964
2091
  const exec = promisify(execFile);
@@ -1976,7 +2103,8 @@ async function runInstall(ctx) {
1976
2103
  skipped: false,
1977
2104
  deps,
1978
2105
  devDeps,
1979
- warnings: catalogWarnings
2106
+ warnings: catalogWarnings,
2107
+ effectivePm: pm
1980
2108
  };
1981
2109
  } catch (err) {
1982
2110
  const stderrText = redactSecrets(readChildStderr(err));
@@ -1994,7 +2122,8 @@ async function runInstall(ctx) {
1994
2122
  "Falling back to `npm install` so init can complete.",
1995
2123
  stderrText ? ` pnpm error: ${stderrText.trim().split("\n")[0]}` : "",
1996
2124
  "Once the offending package republishes a clean version, re-run `pnpm install` to switch back."
1997
- ].filter(Boolean).join("\n")]
2125
+ ].filter(Boolean).join("\n")],
2126
+ effectivePm: "npm"
1998
2127
  };
1999
2128
  } catch (npmErr) {
2000
2129
  spinner.stop("Installation failed");
@@ -2153,4 +2282,4 @@ function sanitisePackageName(raw) {
2153
2282
  //#endregion
2154
2283
  export { runInit };
2155
2284
 
2156
- //# sourceMappingURL=init-CRbEuP9W.mjs.map
2285
+ //# sourceMappingURL=init-B-k3a1Qw.mjs.map