prisma-next 0.7.0 → 0.8.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.
- package/README.md +1 -1
- package/dist/{cli-errors-D3_sMh2K.mjs → cli-errors-CF60g2cG.mjs} +40 -2
- package/dist/cli-errors-CF60g2cG.mjs.map +1 -0
- package/dist/cli.mjs +70 -21
- package/dist/cli.mjs.map +1 -1
- package/dist/{client-BCnP7cHo.mjs → client-XkUw4xD0.mjs} +17 -13
- package/dist/client-XkUw4xD0.mjs.map +1 -0
- package/dist/{command-helpers-BeZHkxV8.mjs → command-helpers-D3vL5yi8.mjs} +29 -6
- package/dist/command-helpers-D3vL5yi8.mjs.map +1 -0
- package/dist/commands/contract-emit.mjs +1 -1
- package/dist/commands/contract-infer.mjs +1 -1
- package/dist/commands/db-init.mjs +7 -7
- package/dist/commands/db-schema.mjs +5 -5
- package/dist/commands/db-sign.d.mts.map +1 -1
- package/dist/commands/db-sign.mjs +67 -25
- package/dist/commands/db-sign.mjs.map +1 -1
- package/dist/commands/db-update.d.mts.map +1 -1
- package/dist/commands/db-update.mjs +37 -9
- package/dist/commands/db-update.mjs.map +1 -1
- package/dist/commands/db-verify.mjs +1 -1
- package/dist/commands/migrate.d.mts +28 -0
- package/dist/commands/migrate.d.mts.map +1 -0
- package/dist/commands/{migration-apply.mjs → migrate.mjs} +54 -36
- package/dist/commands/migrate.mjs.map +1 -0
- package/dist/commands/migration-check.d.mts +18 -0
- package/dist/commands/migration-check.d.mts.map +1 -0
- package/dist/commands/migration-check.mjs +284 -0
- package/dist/commands/migration-check.mjs.map +1 -0
- package/dist/commands/migration-graph.d.mts +16 -0
- package/dist/commands/migration-graph.d.mts.map +1 -0
- package/dist/commands/migration-graph.mjs +141 -0
- package/dist/commands/migration-graph.mjs.map +1 -0
- package/dist/commands/migration-list.d.mts +20 -0
- package/dist/commands/migration-list.d.mts.map +1 -0
- package/dist/commands/migration-list.mjs +107 -0
- package/dist/commands/migration-list.mjs.map +1 -0
- package/dist/commands/migration-log.d.mts +21 -0
- package/dist/commands/migration-log.d.mts.map +1 -0
- package/dist/commands/migration-log.mjs +146 -0
- package/dist/commands/migration-log.mjs.map +1 -0
- package/dist/commands/migration-new.d.mts.map +1 -1
- package/dist/commands/migration-new.mjs +21 -20
- package/dist/commands/migration-new.mjs.map +1 -1
- package/dist/commands/migration-plan.d.mts +2 -2
- package/dist/commands/migration-plan.d.mts.map +1 -1
- package/dist/commands/migration-plan.mjs +1 -1
- package/dist/commands/migration-show.d.mts +1 -1
- package/dist/commands/migration-show.d.mts.map +1 -1
- package/dist/commands/migration-show.mjs +85 -47
- package/dist/commands/migration-show.mjs.map +1 -1
- package/dist/commands/migration-status.d.mts +3 -15
- package/dist/commands/migration-status.d.mts.map +1 -1
- package/dist/commands/migration-status.mjs +732 -1
- package/dist/commands/migration-status.mjs.map +1 -0
- package/dist/commands/ref.d.mts +34 -0
- package/dist/commands/ref.d.mts.map +1 -0
- package/dist/commands/{migration-ref.mjs → ref.mjs} +28 -57
- package/dist/commands/ref.mjs.map +1 -0
- package/dist/{contract-emit-B77TsJqf.mjs → contract-emit-CgoFk9AU.mjs} +8 -4
- package/dist/contract-emit-CgoFk9AU.mjs.map +1 -0
- package/dist/{contract-emit-9DBda5Ou.mjs → contract-emit-GpxW5RLe.mjs} +6 -6
- package/dist/{contract-emit-9DBda5Ou.mjs.map → contract-emit-GpxW5RLe.mjs.map} +1 -1
- package/dist/{contract-infer-ByxhPjpW.mjs → contract-infer-D8edZOCi.mjs} +5 -5
- package/dist/{contract-infer-ByxhPjpW.mjs.map → contract-infer-D8edZOCi.mjs.map} +1 -1
- package/dist/{contract-space-aggregate-loader-BrwKK6Q6.mjs → contract-space-aggregate-loader-D68YpuPR.mjs} +3 -3
- package/dist/{contract-space-aggregate-loader-BrwKK6Q6.mjs.map → contract-space-aggregate-loader-D68YpuPR.mjs.map} +1 -1
- package/dist/{db-verify-Czm5T-J4.mjs → db-verify-DtRB9iHJ.mjs} +7 -7
- package/dist/{db-verify-Czm5T-J4.mjs.map → db-verify-DtRB9iHJ.mjs.map} +1 -1
- package/dist/errors-Cw6kyTyV.mjs +56 -0
- package/dist/errors-Cw6kyTyV.mjs.map +1 -0
- package/dist/exports/control-api.d.mts +1 -1
- package/dist/exports/control-api.d.mts.map +1 -1
- package/dist/exports/control-api.mjs +2 -2
- package/dist/exports/index.mjs +1 -1
- package/dist/exports/init-output.mjs +1 -1
- package/dist/{framework-components-ChqVUxR-.mjs → framework-components-xFLFpZUO.mjs} +2 -2
- package/dist/{framework-components-ChqVUxR-.mjs.map → framework-components-xFLFpZUO.mjs.map} +1 -1
- package/dist/{global-flags-Icqpxk23.d.mts → global-flags-DGmw6Kqg.d.mts} +1 -1
- package/dist/{global-flags-Icqpxk23.d.mts.map → global-flags-DGmw6Kqg.d.mts.map} +1 -1
- package/dist/{migration-status-By9G5p2H.mjs → graph-render-eJDcLWny.mjs} +3 -692
- package/dist/graph-render-eJDcLWny.mjs.map +1 -0
- package/dist/{init-BRKnARU6.mjs → init-Dm0QZPUA.mjs} +412 -208
- package/dist/init-Dm0QZPUA.mjs.map +1 -0
- package/dist/{inspect-live-schema-DxdBd4Er.mjs → inspect-live-schema-CPPqCips.mjs} +4 -4
- package/dist/{inspect-live-schema-DxdBd4Er.mjs.map → inspect-live-schema-CPPqCips.mjs.map} +1 -1
- package/dist/migration-cli.mjs +1 -1
- package/dist/migration-cli.mjs.map +1 -1
- package/dist/{migration-command-scaffold-BdV8JYXV.mjs → migration-command-scaffold-B_ezTTwX.mjs} +4 -4
- package/dist/{migration-command-scaffold-BdV8JYXV.mjs.map → migration-command-scaffold-B_ezTTwX.mjs.map} +1 -1
- package/dist/{migration-plan-mRu5K81L.mjs → migration-plan-DWB-NTxH.mjs} +62 -30
- package/dist/migration-plan-DWB-NTxH.mjs.map +1 -0
- package/dist/migration-types-D2FW63pr.d.mts +15 -0
- package/dist/migration-types-D2FW63pr.d.mts.map +1 -0
- package/dist/{migrations-CTsyBXCA.mjs → migrations-DyUf5lTt.mjs} +2 -2
- package/dist/migrations-DyUf5lTt.mjs.map +1 -0
- package/dist/{output-B16Kefzx.mjs → output-B60Gw5fu.mjs} +12 -11
- package/dist/{output-B16Kefzx.mjs.map → output-B60Gw5fu.mjs.map} +1 -1
- package/dist/{result-handler-rmPVKIP2.mjs → result-handler-Bm_6dDYg.mjs} +2 -2
- package/dist/{result-handler-rmPVKIP2.mjs.map → result-handler-Bm_6dDYg.mjs.map} +1 -1
- package/dist/{terminal-ui-C_hFNbAn.mjs → terminal-ui-XtOQsqe9.mjs} +2 -54
- package/dist/terminal-ui-XtOQsqe9.mjs.map +1 -0
- package/dist/{types-LItU7E4l.d.mts → types-BS_wpjAY.d.mts} +2 -2
- package/dist/{types-LItU7E4l.d.mts.map → types-BS_wpjAY.d.mts.map} +1 -1
- package/dist/{verify-CiwNWM9N.mjs → verify-D7ypCCe6.mjs} +1 -1
- package/dist/{verify-CiwNWM9N.mjs.map → verify-D7ypCCe6.mjs.map} +1 -1
- package/package.json +11 -11
- package/dist/agent-skill-mongo.md +0 -138
- package/dist/agent-skill-postgres.md +0 -106
- package/dist/cli-errors-D3_sMh2K.mjs.map +0 -1
- package/dist/client-BCnP7cHo.mjs.map +0 -1
- package/dist/command-helpers-BeZHkxV8.mjs.map +0 -1
- package/dist/commands/migration-apply.d.mts +0 -51
- package/dist/commands/migration-apply.d.mts.map +0 -1
- package/dist/commands/migration-apply.mjs.map +0 -1
- package/dist/commands/migration-ref.d.mts +0 -45
- package/dist/commands/migration-ref.d.mts.map +0 -1
- package/dist/commands/migration-ref.mjs.map +0 -1
- package/dist/contract-emit-B77TsJqf.mjs.map +0 -1
- package/dist/init-BRKnARU6.mjs.map +0 -1
- package/dist/migration-plan-mRu5K81L.mjs.map +0 -1
- package/dist/migration-status-By9G5p2H.mjs.map +0 -1
- package/dist/migrations-CTsyBXCA.mjs.map +0 -1
- package/dist/terminal-ui-C_hFNbAn.mjs.map +0 -1
- /package/dist/{cli-errors-B9OBbled.d.mts → cli-errors-DdcjVLJV.d.mts} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { t as CliStructuredError } from "./cli-errors-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { t as CliStructuredError } from "./cli-errors-CF60g2cG.mjs";
|
|
2
|
+
import { n as formatErrorOutput, t as formatErrorJson } from "./errors-Cw6kyTyV.mjs";
|
|
3
|
+
import { t as TerminalUI } from "./terminal-ui-XtOQsqe9.mjs";
|
|
4
|
+
import { i as renderInitOutro, n as buildNextSteps, r as formatInitJson, t as InitOutputSchema } from "./output-B60Gw5fu.mjs";
|
|
4
5
|
import { createRequire } from "node:module";
|
|
5
6
|
import { basename, dirname, extname, isAbsolute, join, normalize } from "pathe";
|
|
6
7
|
import * as clack from "@clack/prompts";
|
|
@@ -9,158 +10,8 @@ import { execFile } from "node:child_process";
|
|
|
9
10
|
import { promisify } from "node:util";
|
|
10
11
|
import { detect, getUserAgent } from "package-manager-detector/detect";
|
|
11
12
|
import { applyEdits, modify, parse, printParseErrorCode } from "jsonc-parser";
|
|
12
|
-
//#region
|
|
13
|
-
|
|
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
|
-
}
|
|
13
|
+
//#region package.json
|
|
14
|
+
var version = "0.8.0-dev.10";
|
|
164
15
|
//#endregion
|
|
165
16
|
//#region src/commands/init/errors.ts
|
|
166
17
|
/**
|
|
@@ -364,6 +215,361 @@ function errorInitEmitFailed(options) {
|
|
|
364
215
|
}
|
|
365
216
|
});
|
|
366
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* The project-level agent-skill install (`npx skills add
|
|
220
|
+
* prisma/prisma-next#v<version>`) failed after a successful dependency
|
|
221
|
+
* install + emit. The project's scaffold remains on disk; the user
|
|
222
|
+
* can either fix the underlying issue (network, registry, PATH) and
|
|
223
|
+
* run the install command manually, or re-run `init --no-skill` to
|
|
224
|
+
* proceed without the skill.
|
|
225
|
+
*
|
|
226
|
+
* Non-rolling-back, matching the existing install/emit failure
|
|
227
|
+
* semantics. Maps to exit code `6 = SKILL_INSTALL_FAILED`.
|
|
228
|
+
*/
|
|
229
|
+
function errorInitSkillInstallFailed(options) {
|
|
230
|
+
return new CliStructuredError("5013", "Failed to install Prisma Next skills", {
|
|
231
|
+
domain: "CLI",
|
|
232
|
+
why: `\`${options.skillInstallCommand}\` exited with an error: ${options.cause}`,
|
|
233
|
+
fix: `Either:
|
|
234
|
+
- 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}`,
|
|
235
|
+
docsUrl: "https://prisma-next.dev/docs/cli/init#agent-skill",
|
|
236
|
+
meta: {
|
|
237
|
+
filesWritten: options.filesWritten,
|
|
238
|
+
skillInstallCommand: options.skillInstallCommand,
|
|
239
|
+
cause: options.cause
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
//#endregion
|
|
244
|
+
//#region src/commands/init/agent-skill-install.ts
|
|
245
|
+
const exec = promisify(execFile);
|
|
246
|
+
/**
|
|
247
|
+
* Default base for the GitHub-URL form `<owner>/<repo>` consumed by
|
|
248
|
+
* upstream `skills add`. Each `SkillSource` joins this base with its
|
|
249
|
+
* own subpath (and optional `#ref` for version-pinned clusters).
|
|
250
|
+
*/
|
|
251
|
+
const DEFAULT_AGENT_SKILL_BASE = "prisma/prisma-next";
|
|
252
|
+
const DEFAULT_AGENT_SKILL_SOURCES = [
|
|
253
|
+
{
|
|
254
|
+
subpath: "skills",
|
|
255
|
+
ref: "cli",
|
|
256
|
+
description: "usage skills (version-locked to installed Prisma Next)"
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
subpath: "skills/upgrade",
|
|
260
|
+
ref: null,
|
|
261
|
+
description: "upgrade skill (always tracks `main`)"
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
subpath: "skills/extension-author",
|
|
265
|
+
ref: null,
|
|
266
|
+
description: "extension-author skill (always tracks `main`)"
|
|
267
|
+
}
|
|
268
|
+
];
|
|
269
|
+
/**
|
|
270
|
+
* Test-only escape hatch for pinning the install base to a local
|
|
271
|
+
* checkout. Production runs leave this unset, so installs always use
|
|
272
|
+
* `DEFAULT_AGENT_SKILL_BASE`.
|
|
273
|
+
*
|
|
274
|
+
* When set to an absolute filesystem path (typical for tests), the
|
|
275
|
+
* `#ref` fragment is dropped — local-path mode in upstream's CLI does
|
|
276
|
+
* not accept refs, and the local clone has whatever content the test
|
|
277
|
+
* checked into it anyway. When set to anything else (e.g. a fork name
|
|
278
|
+
* `myuser/prisma-next`), the ref policy is preserved.
|
|
279
|
+
*/
|
|
280
|
+
function resolveAgentSkillBase() {
|
|
281
|
+
const override = process.env["PRISMA_NEXT_SKILLS_BASE"]?.trim();
|
|
282
|
+
return override && override.length > 0 ? override : DEFAULT_AGENT_SKILL_BASE;
|
|
283
|
+
}
|
|
284
|
+
function isLocalPath(base) {
|
|
285
|
+
return base.startsWith("/") || /^[a-zA-Z]:[\\/]/.test(base);
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Build the `<base>/<subpath>[#ref]` URL the `skills` CLI will
|
|
289
|
+
* resolve. Exported for unit tests so the per-source format can be
|
|
290
|
+
* asserted without going through the full install loop.
|
|
291
|
+
*/
|
|
292
|
+
function formatSkillSourceUrl(source) {
|
|
293
|
+
const base = resolveAgentSkillBase();
|
|
294
|
+
const url = `${base}/${source.subpath}`;
|
|
295
|
+
if (source.ref === null) return url;
|
|
296
|
+
if (isLocalPath(base)) return url;
|
|
297
|
+
if (source.ref === "cli") return `${url}#v${version}`;
|
|
298
|
+
return url;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* The skill-install command for one source, formatted for the
|
|
302
|
+
* project's detected package manager. `npx`/`pnpm dlx`/`bunx` are
|
|
303
|
+
* interchangeable to the user; we pick the variant that matches the
|
|
304
|
+
* rest of the install step so a single project consistently uses one
|
|
305
|
+
* runner.
|
|
306
|
+
*
|
|
307
|
+
* `--all` auto-selects every skill in the cluster and every detected
|
|
308
|
+
* agent runtime, skipping the multi-select prompts the `skills` CLI
|
|
309
|
+
* shows by default. A non-interactive scaffold step cannot present
|
|
310
|
+
* prompts.
|
|
311
|
+
*
|
|
312
|
+
* Exported for unit tests so the per-PM dispatch can be asserted
|
|
313
|
+
* without a live subprocess.
|
|
314
|
+
*/
|
|
315
|
+
function formatSkillInstallCommand(pm, source) {
|
|
316
|
+
return formatPackageManagerCommand(pm, [
|
|
317
|
+
"skills@latest",
|
|
318
|
+
"add",
|
|
319
|
+
formatSkillSourceUrl(source),
|
|
320
|
+
"--all"
|
|
321
|
+
]);
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* `skills add --all` should cover Claude Code, but upstream currently skips
|
|
325
|
+
* project-local Claude symlinks when `.claude/` does not already exist. Run
|
|
326
|
+
* the explicit Claude Code install as well so fresh projects get
|
|
327
|
+
* `.claude/skills` without asking users to create that folder first.
|
|
328
|
+
*/
|
|
329
|
+
function formatClaudeSkillInstallCommand(pm, source) {
|
|
330
|
+
return formatPackageManagerCommand(pm, [
|
|
331
|
+
"skills@latest",
|
|
332
|
+
"add",
|
|
333
|
+
formatSkillSourceUrl(source),
|
|
334
|
+
"--agent",
|
|
335
|
+
"claude-code",
|
|
336
|
+
"--skill",
|
|
337
|
+
"'*'",
|
|
338
|
+
"-y"
|
|
339
|
+
]);
|
|
340
|
+
}
|
|
341
|
+
function formatPackageManagerCommand(pm, args) {
|
|
342
|
+
switch (pm) {
|
|
343
|
+
case "pnpm": return `pnpm dlx ${args.join(" ")}`;
|
|
344
|
+
case "yarn": return `yarn dlx ${args.join(" ")}`;
|
|
345
|
+
case "bun": return `bunx ${args.join(" ")}`;
|
|
346
|
+
case "deno": return `deno run -A npm:${args.join(" ")}`;
|
|
347
|
+
case "npm": return `npx ${args.join(" ")}`;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Parse the project-pm-formatted command into an exec call. The
|
|
352
|
+
* format-then-parse split keeps the user-facing command string the same
|
|
353
|
+
* as the surface the structured error advertises, so a user who copies
|
|
354
|
+
* the error's `fix` line gets the same invocation that init just
|
|
355
|
+
* attempted. Single quotes are preserved in the display form so `*` is
|
|
356
|
+
* safe to copy into a shell, then stripped before `execFile`.
|
|
357
|
+
*/
|
|
358
|
+
function commandToExec(command) {
|
|
359
|
+
const tokens = (command.match(/'[^']*'|\S+/g) ?? []).map((token) => token.startsWith("'") && token.endsWith("'") ? token.slice(1, -1) : token);
|
|
360
|
+
return {
|
|
361
|
+
file: tokens[0] ?? "npx",
|
|
362
|
+
args: tokens.slice(1)
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Runs the project-level skill install for every source in
|
|
367
|
+
* `DEFAULT_AGENT_SKILL_SOURCES`, in order. Returns
|
|
368
|
+
* `{ ok: true, commands }` on success; throws a structured
|
|
369
|
+
* `errorInitSkillInstallFailed` on the first failure (subsequent
|
|
370
|
+
* sources are not attempted — the user opted into Prisma Next by
|
|
371
|
+
* running `init` and a partial install would leave the project in an
|
|
372
|
+
* ambiguous state). The throw is intentionally fatal — project-level
|
|
373
|
+
* skill install is unconditional (modulo `--no-skill`).
|
|
374
|
+
*/
|
|
375
|
+
async function runProjectLevelSkillInstall(ctx) {
|
|
376
|
+
const commands = [];
|
|
377
|
+
const installCommands = DEFAULT_AGENT_SKILL_SOURCES.flatMap((source) => [formatSkillInstallCommand(ctx.pm, source), formatClaudeSkillInstallCommand(ctx.pm, source)]);
|
|
378
|
+
for (const command of installCommands) {
|
|
379
|
+
const { file, args } = commandToExec(command);
|
|
380
|
+
try {
|
|
381
|
+
await exec(file, args, { cwd: ctx.baseDir });
|
|
382
|
+
commands.push(command);
|
|
383
|
+
} catch (err) {
|
|
384
|
+
throw errorInitSkillInstallFailed({
|
|
385
|
+
skillInstallCommand: command,
|
|
386
|
+
filesWritten: ctx.filesWritten,
|
|
387
|
+
cause: redactSecrets$1(readChildStderr$1(err)) || (err instanceof Error ? err.message : String(err))
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return {
|
|
392
|
+
ok: true,
|
|
393
|
+
commands
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
function readChildStderr$1(err) {
|
|
397
|
+
if (err instanceof Error && "stderr" in err) return String(err.stderr ?? "");
|
|
398
|
+
return "";
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Strips credentials from a `scheme://user:pass@host/...` URL anywhere
|
|
402
|
+
* in `stderr`. Package-manager stderr regularly contains credentialed
|
|
403
|
+
* registry URLs (private npm registries, GitHub Packages tokens), and
|
|
404
|
+
* those bubble into the structured `errorInitSkillInstallFailed`
|
|
405
|
+
* envelope, which ends up in logs and CI output. Redact at the
|
|
406
|
+
* boundary so we never re-emit a secret.
|
|
407
|
+
*
|
|
408
|
+
* Exported for unit tests.
|
|
409
|
+
*/
|
|
410
|
+
function redactSecrets$1(stderr) {
|
|
411
|
+
if (!stderr) return stderr;
|
|
412
|
+
return stderr.replace(/([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)([^/@\s]+)@/g, "$1***@");
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Hand-rolled skill stub path that init must not leave behind. Removed
|
|
416
|
+
* on every init run so a project's `.agents/skills/prisma-next/` does
|
|
417
|
+
* not shadow the installed Prisma Next skill cluster.
|
|
418
|
+
*/
|
|
419
|
+
const LEGACY_SKILL_FILE = ".agents/skills/prisma-next/SKILL.md";
|
|
420
|
+
//#endregion
|
|
421
|
+
//#region src/commands/init/detect-package-manager.ts
|
|
422
|
+
const KNOWN = new Set([
|
|
423
|
+
"pnpm",
|
|
424
|
+
"npm",
|
|
425
|
+
"yarn",
|
|
426
|
+
"bun",
|
|
427
|
+
"deno"
|
|
428
|
+
]);
|
|
429
|
+
/**
|
|
430
|
+
* Resolves the package manager `init` should drive for `add` / `install`
|
|
431
|
+
* commands. Tries, in order:
|
|
432
|
+
*
|
|
433
|
+
* 1. **`detect()`** — walks up from `cwd` looking for a lockfile, the
|
|
434
|
+
* `packageManager` field, the `devEngines.packageManager` field, or
|
|
435
|
+
* install metadata. This is the right answer whenever the user is
|
|
436
|
+
* anywhere inside an existing project, including a deep workspace
|
|
437
|
+
* subdirectory.
|
|
438
|
+
*
|
|
439
|
+
* 2. **`getUserAgent()`** — parses `npm_config_user_agent`, the env var
|
|
440
|
+
* every PM sets when it spawns a script. This catches the
|
|
441
|
+
* bare-directory case where there's no project to walk up to but the
|
|
442
|
+
* user invoked us via `pnpm dlx prisma-next init` / `bunx
|
|
443
|
+
* prisma-next init` / `yarn dlx …`. Same signal used by every
|
|
444
|
+
* `create-*` tool in the ecosystem (`create-vite`, `create-next-app`,
|
|
445
|
+
* `create-astro`, `@antfu/ni`, …).
|
|
446
|
+
*
|
|
447
|
+
* 3. **`npm`** — final fallback. Always present alongside Node.
|
|
448
|
+
*/
|
|
449
|
+
async function detectPackageManager(cwd) {
|
|
450
|
+
const detected = await detect({ cwd });
|
|
451
|
+
if (detected && KNOWN.has(detected.name)) return detected.name;
|
|
452
|
+
const userAgent = getUserAgent();
|
|
453
|
+
if (userAgent !== null && KNOWN.has(userAgent)) return userAgent;
|
|
454
|
+
return "npm";
|
|
455
|
+
}
|
|
456
|
+
function hasProjectManifest(cwd) {
|
|
457
|
+
return existsSync(join(cwd, "package.json")) || existsSync(join(cwd, "deno.json")) || existsSync(join(cwd, "deno.jsonc"));
|
|
458
|
+
}
|
|
459
|
+
function formatRunCommand(pm, bin, args) {
|
|
460
|
+
if (pm === "npm") return `npx ${bin} ${args}`;
|
|
461
|
+
if (pm === "deno") return `deno run npm:${bin} ${args}`;
|
|
462
|
+
return `${pm} ${bin} ${args}`;
|
|
463
|
+
}
|
|
464
|
+
function formatAddArgs(pm, packages) {
|
|
465
|
+
if (pm === "deno") return ["add", ...packages.map((p) => `npm:${p}`)];
|
|
466
|
+
return ["add", ...packages];
|
|
467
|
+
}
|
|
468
|
+
function formatAddDevArgs(pm, packages) {
|
|
469
|
+
if (pm === "deno") return [
|
|
470
|
+
"add",
|
|
471
|
+
"--dev",
|
|
472
|
+
...packages.map((p) => `npm:${p}`)
|
|
473
|
+
];
|
|
474
|
+
return [
|
|
475
|
+
"add",
|
|
476
|
+
"-D",
|
|
477
|
+
...packages
|
|
478
|
+
];
|
|
479
|
+
}
|
|
480
|
+
//#endregion
|
|
481
|
+
//#region src/commands/init/detect-pnpm-catalog.ts
|
|
482
|
+
/**
|
|
483
|
+
* Walks up from `baseDir` looking for `pnpm-workspace.yaml`, then scans
|
|
484
|
+
* its top-level `catalog:` block for entries that match any of `packages`.
|
|
485
|
+
*
|
|
486
|
+
* Implements FR7.3 / Spec Decision 8 (honour-and-warn): when `init` runs
|
|
487
|
+
* inside a pnpm workspace whose catalog overrides one of the packages it
|
|
488
|
+
* installs, surface a structured warning so the user knows the catalog
|
|
489
|
+
* version (not the published `latest`) is what ended up in their
|
|
490
|
+
* `node_modules`. pnpm itself does this silently; the warning closes the
|
|
491
|
+
* "looks fine, must be wrong version six months later" gap.
|
|
492
|
+
*
|
|
493
|
+
* Notes / scope:
|
|
494
|
+
*
|
|
495
|
+
* - We only inspect the unnamed top-level `catalog:` block. pnpm also
|
|
496
|
+
* supports `catalogs:` (plural — *named* catalogs referenced via
|
|
497
|
+
* `catalog:foo` specifiers); those don't apply to a vanilla
|
|
498
|
+
* `pnpm add prisma-next` invocation, so we skip them.
|
|
499
|
+
* - We don't validate YAML syntax exhaustively. The file format pnpm
|
|
500
|
+
* ships is line-oriented and well-known; a minimal regex is more
|
|
501
|
+
* robust than depending on a YAML parser for one warning.
|
|
502
|
+
* - We don't compare against the registry's `latest` — pnpm uses the
|
|
503
|
+
* catalog version regardless, so the warning fires whenever a match
|
|
504
|
+
* exists. The user-facing copy explains how to opt out.
|
|
505
|
+
*/
|
|
506
|
+
function detectPnpmCatalogOverrides(baseDir, packages) {
|
|
507
|
+
const workspaceFile = findNearestPnpmWorkspaceFile(baseDir);
|
|
508
|
+
if (workspaceFile === null) return null;
|
|
509
|
+
const catalog = extractCatalogBlock(readFileSync(workspaceFile, "utf-8"));
|
|
510
|
+
if (catalog === null) return {
|
|
511
|
+
workspaceFile,
|
|
512
|
+
entries: []
|
|
513
|
+
};
|
|
514
|
+
const wanted = new Set(packages);
|
|
515
|
+
const entries = [];
|
|
516
|
+
for (const [name, version] of catalog) if (wanted.has(name)) entries.push({
|
|
517
|
+
name,
|
|
518
|
+
version
|
|
519
|
+
});
|
|
520
|
+
return {
|
|
521
|
+
workspaceFile,
|
|
522
|
+
entries
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
function findNearestPnpmWorkspaceFile(baseDir) {
|
|
526
|
+
let dir = baseDir;
|
|
527
|
+
let prev = "";
|
|
528
|
+
while (dir !== prev) {
|
|
529
|
+
const candidate = join(dir, "pnpm-workspace.yaml");
|
|
530
|
+
if (existsSync(candidate)) return candidate;
|
|
531
|
+
prev = dir;
|
|
532
|
+
dir = dirname(dir);
|
|
533
|
+
}
|
|
534
|
+
return null;
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Returns the entries inside the top-level `catalog:` block as `[name, version]`
|
|
538
|
+
* pairs in document order, or `null` when no `catalog:` block exists.
|
|
539
|
+
*
|
|
540
|
+
* The parser is intentionally minimal: it reads line-by-line, locates the
|
|
541
|
+
* top-level `catalog:` line (no leading whitespace), then collects every
|
|
542
|
+
* subsequent indented line of the form `<key>: <value>` until the next
|
|
543
|
+
* top-level key (or end of file). Quotes around `<key>` and `<value>`
|
|
544
|
+
* are stripped; comments (`#…`) are ignored.
|
|
545
|
+
*/
|
|
546
|
+
function extractCatalogBlock(contents) {
|
|
547
|
+
const lines = contents.split(/\r?\n/);
|
|
548
|
+
const startIdx = lines.findIndex((line) => /^catalog\s*:\s*$/.test(line));
|
|
549
|
+
if (startIdx === -1) return null;
|
|
550
|
+
const entries = [];
|
|
551
|
+
for (let i = startIdx + 1; i < lines.length; i++) {
|
|
552
|
+
const raw = lines[i] ?? "";
|
|
553
|
+
if (raw.trim() === "" || /^\s*#/.test(raw)) continue;
|
|
554
|
+
if (!/^\s/.test(raw)) break;
|
|
555
|
+
const match = raw.match(/^\s+(?:'([^']+)'|"([^"]+)"|([^:\s'"]+))\s*:\s*(.*?)\s*(?:#.*)?$/);
|
|
556
|
+
if (!match) continue;
|
|
557
|
+
const name = match[1] ?? match[2] ?? match[3];
|
|
558
|
+
if (name === void 0) continue;
|
|
559
|
+
const version = stripQuotes((match[4] ?? "").trim());
|
|
560
|
+
if (version === "") continue;
|
|
561
|
+
entries.push([name, version]);
|
|
562
|
+
}
|
|
563
|
+
return entries;
|
|
564
|
+
}
|
|
565
|
+
function stripQuotes(value) {
|
|
566
|
+
if (value.length >= 2) {
|
|
567
|
+
const first = value[0];
|
|
568
|
+
const last = value[value.length - 1];
|
|
569
|
+
if (first === "\"" && last === "\"" || first === "'" && last === "'") return value.slice(1, -1);
|
|
570
|
+
}
|
|
571
|
+
return value;
|
|
572
|
+
}
|
|
367
573
|
//#endregion
|
|
368
574
|
//#region src/commands/init/hygiene-gitattributes.ts
|
|
369
575
|
/**
|
|
@@ -810,7 +1016,10 @@ function dbFile(target) {
|
|
|
810
1016
|
import type { Contract } from './contract.d';
|
|
811
1017
|
import contractJson from './contract.json' with { type: 'json' };
|
|
812
1018
|
|
|
813
|
-
export const db = postgres<Contract>({
|
|
1019
|
+
export const db = postgres<Contract>({
|
|
1020
|
+
contractJson,
|
|
1021
|
+
url: process.env['DATABASE_URL']!,
|
|
1022
|
+
});
|
|
814
1023
|
`;
|
|
815
1024
|
return `import mongo from '@prisma-next/mongo/runtime';
|
|
816
1025
|
import type { Contract } from './contract.d';
|
|
@@ -882,6 +1091,7 @@ async function resolveInitInputs(ctx) {
|
|
|
882
1091
|
canPrompt,
|
|
883
1092
|
autoAcceptPrompts
|
|
884
1093
|
});
|
|
1094
|
+
const installProjectSkill = options.skill !== false;
|
|
885
1095
|
return {
|
|
886
1096
|
target: finalTarget,
|
|
887
1097
|
authoring: finalAuthoring,
|
|
@@ -891,7 +1101,8 @@ async function resolveInitInputs(ctx) {
|
|
|
891
1101
|
probeDb: Boolean(options.probeDb),
|
|
892
1102
|
strictProbe: Boolean(options.strictProbe),
|
|
893
1103
|
reinit,
|
|
894
|
-
removePreviousFacade
|
|
1104
|
+
removePreviousFacade,
|
|
1105
|
+
installProjectSkill
|
|
895
1106
|
};
|
|
896
1107
|
}
|
|
897
1108
|
async function resolveWriteEnv(opts) {
|
|
@@ -1302,47 +1513,6 @@ function removeDependency(existing, depName) {
|
|
|
1302
1513
|
return `${JSON.stringify(parsed, null, 2)}${trailingNewline}`;
|
|
1303
1514
|
}
|
|
1304
1515
|
//#endregion
|
|
1305
|
-
//#region src/commands/init/templates/render.ts
|
|
1306
|
-
function renderTemplate(templateFile, variableNames, vars) {
|
|
1307
|
-
let result = readFileSync(join(import.meta.dirname, templateFile), "utf-8");
|
|
1308
|
-
for (const key of variableNames) {
|
|
1309
|
-
const value = vars[key];
|
|
1310
|
-
if (value === void 0) throw new Error(`Template variable '${key}' is not defined`);
|
|
1311
|
-
result = result.replaceAll(`{{${key}}}`, value);
|
|
1312
|
-
}
|
|
1313
|
-
return result;
|
|
1314
|
-
}
|
|
1315
|
-
//#endregion
|
|
1316
|
-
//#region src/commands/init/templates/agent-skill.ts
|
|
1317
|
-
const variables$1 = [
|
|
1318
|
-
"schemaPath",
|
|
1319
|
-
"schemaDir",
|
|
1320
|
-
"dbImportPath",
|
|
1321
|
-
"pkgRun",
|
|
1322
|
-
"authoringLabel"
|
|
1323
|
-
];
|
|
1324
|
-
/**
|
|
1325
|
-
* Renders the per-project agent skill (FR5.2). The skill template is
|
|
1326
|
-
* target-specific (Postgres vs Mongo query syntax differs); the authoring
|
|
1327
|
-
* style enters via:
|
|
1328
|
-
*
|
|
1329
|
-
* - `schemaPath` — already routed through {@link agentSkillMd}'s caller
|
|
1330
|
-
* (the AC says a TS-authoring scaffold must reference `prisma/contract.ts`).
|
|
1331
|
-
* - `authoringLabel` — a short human-readable note (`PSL` / `TypeScript`)
|
|
1332
|
-
* the skill template uses when describing the contract file.
|
|
1333
|
-
*/
|
|
1334
|
-
function agentSkillMd(target, authoring, schemaPath, pkgRun) {
|
|
1335
|
-
const schemaDir = dirname(schemaPath);
|
|
1336
|
-
const vars = {
|
|
1337
|
-
schemaPath,
|
|
1338
|
-
schemaDir,
|
|
1339
|
-
dbImportPath: `./${schemaDir}/db`,
|
|
1340
|
-
pkgRun,
|
|
1341
|
-
authoringLabel: authoring === "typescript" ? "TypeScript" : "PSL"
|
|
1342
|
-
};
|
|
1343
|
-
return renderTemplate(`agent-skill-${target}.md`, variables$1, vars);
|
|
1344
|
-
}
|
|
1345
|
-
//#endregion
|
|
1346
1516
|
//#region src/commands/init/templates/env.ts
|
|
1347
1517
|
/**
|
|
1348
1518
|
* The minimum supported server version for each target (FR8.1). The
|
|
@@ -1414,6 +1584,17 @@ function envFileContent(target) {
|
|
|
1414
1584
|
return envPlaceholderBody(target);
|
|
1415
1585
|
}
|
|
1416
1586
|
//#endregion
|
|
1587
|
+
//#region src/commands/init/templates/render.ts
|
|
1588
|
+
function renderTemplate(templateFile, variableNames, vars) {
|
|
1589
|
+
let result = readFileSync(join(import.meta.dirname, templateFile), "utf-8");
|
|
1590
|
+
for (const key of variableNames) {
|
|
1591
|
+
const value = vars[key];
|
|
1592
|
+
if (value === void 0) throw new Error(`Template variable '${key}' is not defined`);
|
|
1593
|
+
result = result.replaceAll(`{{${key}}}`, value);
|
|
1594
|
+
}
|
|
1595
|
+
return result;
|
|
1596
|
+
}
|
|
1597
|
+
//#endregion
|
|
1417
1598
|
//#region src/commands/init/templates/quick-reference.ts
|
|
1418
1599
|
const variables = [
|
|
1419
1600
|
"schemaPath",
|
|
@@ -1653,16 +1834,13 @@ async function runInit(baseDir, runOptions) {
|
|
|
1653
1834
|
path: "prisma-next.md",
|
|
1654
1835
|
content: quickReferenceMd(inputs.target, inputs.authoring, inputs.schemaPath, pkgRun)
|
|
1655
1836
|
},
|
|
1656
|
-
{
|
|
1657
|
-
path: ".agents/skills/prisma-next/SKILL.md",
|
|
1658
|
-
content: agentSkillMd(inputs.target, inputs.authoring, inputs.schemaPath, pkgRun)
|
|
1659
|
-
},
|
|
1660
1837
|
{
|
|
1661
1838
|
path: ".env.example",
|
|
1662
1839
|
content: envExampleContent(inputs.target)
|
|
1663
1840
|
}
|
|
1664
1841
|
];
|
|
1665
1842
|
const filesToDelete = inputs.reinit ? [...findStaleArtefacts(baseDir, schemaDir)] : [];
|
|
1843
|
+
if (existsSync(join(baseDir, ".agents/skills/prisma-next/SKILL.md"))) filesToDelete.push(LEGACY_SKILL_FILE);
|
|
1666
1844
|
if (inputs.writeEnv) if (!existsSync(join(baseDir, ".env"))) filesToWrite.push({
|
|
1667
1845
|
path: ".env",
|
|
1668
1846
|
content: envFileContent(inputs.target)
|
|
@@ -1807,6 +1985,27 @@ async function runInit(baseDir, runOptions) {
|
|
|
1807
1985
|
filesWritten
|
|
1808
1986
|
}));
|
|
1809
1987
|
}
|
|
1988
|
+
const manualProjectSkillSummary = DEFAULT_AGENT_SKILL_SOURCES.flatMap((source) => [formatSkillInstallCommand(install.effectivePm, source), formatClaudeSkillInstallCommand(install.effectivePm, source)]).map((c) => `\`${c}\``).join(" && ");
|
|
1989
|
+
let skillRegistered = false;
|
|
1990
|
+
if (!inputs.installProjectSkill) warnings.push(`Skipped Prisma Next agent-skill install (--no-skill). To install the skills later, run: ${manualProjectSkillSummary}`);
|
|
1991
|
+
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}`);
|
|
1992
|
+
else {
|
|
1993
|
+
const spinner = ui.spinner();
|
|
1994
|
+
spinner.start("Registering Prisma Next skills with the agent runtime...");
|
|
1995
|
+
try {
|
|
1996
|
+
const project = await runProjectLevelSkillInstall({
|
|
1997
|
+
baseDir,
|
|
1998
|
+
pm: install.effectivePm,
|
|
1999
|
+
filesWritten
|
|
2000
|
+
});
|
|
2001
|
+
spinner.stop(`Registered Prisma Next skills (project level) — ran ${project.commands.map((c) => `\`${c}\``).join(", ")}`);
|
|
2002
|
+
skillRegistered = true;
|
|
2003
|
+
} catch (error) {
|
|
2004
|
+
spinner.stop("Agent-skill install failed");
|
|
2005
|
+
if (CliStructuredError.is(error)) return emitError(ui, flags, error);
|
|
2006
|
+
throw error;
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
1810
2009
|
const output = {
|
|
1811
2010
|
ok: true,
|
|
1812
2011
|
target: inputs.target === "mongo" ? "mongodb" : "postgres",
|
|
@@ -1824,7 +2023,8 @@ async function runInit(baseDir, runOptions) {
|
|
|
1824
2023
|
target: inputs.target === "mongo" ? "mongodb" : "postgres",
|
|
1825
2024
|
contractEmitted,
|
|
1826
2025
|
emitCommand,
|
|
1827
|
-
schemaPath: inputs.schemaPath
|
|
2026
|
+
schemaPath: inputs.schemaPath,
|
|
2027
|
+
skillRegistered
|
|
1828
2028
|
}),
|
|
1829
2029
|
warnings
|
|
1830
2030
|
};
|
|
@@ -1884,6 +2084,7 @@ function exitCodeForError(error) {
|
|
|
1884
2084
|
case "5007": return 4;
|
|
1885
2085
|
case "5008": return 5;
|
|
1886
2086
|
case "5009": return 1;
|
|
2087
|
+
case "5013": return 6;
|
|
1887
2088
|
default: return 1;
|
|
1888
2089
|
}
|
|
1889
2090
|
}
|
|
@@ -1955,7 +2156,8 @@ async function runInstall(ctx) {
|
|
|
1955
2156
|
skipped: true,
|
|
1956
2157
|
deps: [],
|
|
1957
2158
|
devDeps: [],
|
|
1958
|
-
warnings: catalogWarnings
|
|
2159
|
+
warnings: catalogWarnings,
|
|
2160
|
+
effectivePm: pm
|
|
1959
2161
|
};
|
|
1960
2162
|
}
|
|
1961
2163
|
const exec = promisify(execFile);
|
|
@@ -1973,7 +2175,8 @@ async function runInstall(ctx) {
|
|
|
1973
2175
|
skipped: false,
|
|
1974
2176
|
deps,
|
|
1975
2177
|
devDeps,
|
|
1976
|
-
warnings: catalogWarnings
|
|
2178
|
+
warnings: catalogWarnings,
|
|
2179
|
+
effectivePm: pm
|
|
1977
2180
|
};
|
|
1978
2181
|
} catch (err) {
|
|
1979
2182
|
const stderrText = redactSecrets(readChildStderr(err));
|
|
@@ -1991,7 +2194,8 @@ async function runInstall(ctx) {
|
|
|
1991
2194
|
"Falling back to `npm install` so init can complete.",
|
|
1992
2195
|
stderrText ? ` pnpm error: ${stderrText.trim().split("\n")[0]}` : "",
|
|
1993
2196
|
"Once the offending package republishes a clean version, re-run `pnpm install` to switch back."
|
|
1994
|
-
].filter(Boolean).join("\n")]
|
|
2197
|
+
].filter(Boolean).join("\n")],
|
|
2198
|
+
effectivePm: "npm"
|
|
1995
2199
|
};
|
|
1996
2200
|
} catch (npmErr) {
|
|
1997
2201
|
spinner.stop("Installation failed");
|
|
@@ -2097,7 +2301,7 @@ async function runEmit(ctx) {
|
|
|
2097
2301
|
const spinner = ctx.ui.spinner();
|
|
2098
2302
|
spinner.start("Emitting contract...");
|
|
2099
2303
|
try {
|
|
2100
|
-
const { executeContractEmit } = await import("./contract-emit-
|
|
2304
|
+
const { executeContractEmit } = await import("./contract-emit-CgoFk9AU.mjs").then((n) => n.t);
|
|
2101
2305
|
await executeContractEmit({ configPath: join(ctx.baseDir, "prisma-next.config.ts") });
|
|
2102
2306
|
spinner.stop("Contract emitted");
|
|
2103
2307
|
} catch (err) {
|
|
@@ -2150,4 +2354,4 @@ function sanitisePackageName(raw) {
|
|
|
2150
2354
|
//#endregion
|
|
2151
2355
|
export { runInit };
|
|
2152
2356
|
|
|
2153
|
-
//# sourceMappingURL=init-
|
|
2357
|
+
//# sourceMappingURL=init-Dm0QZPUA.mjs.map
|