@prisma/cli 8.0.0-rc.15-dev.109 → 8.0.0-rc.15-dev.110

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 (2) hide show
  1. package/dist/cli.js +114 -53
  2. package/package.json +8 -8
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from "node:module";
3
3
  import process$1 from "node:process";
4
- import { SERVICE_TOKEN_ENV_VAR, claimedExpiresAt, claimedIdentity, createCli, credentialWorkspaceId, credentialWorkspaceMismatchError, credentialsRequiredError, defineCommand, defineCommandFamily, defineConfigSection, defineSessionCommand, detectCI, emptyServiceTokenError, flag, loadConfig, noSessionForWorkspaceError, positional, readActiveAccessToken, telemetryCommandGroup } from "@prisma/cli-engine";
4
+ import { SERVICE_TOKEN_ENV_VAR, claimedExpiresAt, claimedIdentity, createCli, credentialWorkspaceId, credentialWorkspaceMismatchError, credentialsRequiredError, defineCommand, defineCommandFamily, defineConfigSection, defineSessionCommand, detectCI, emptyServiceTokenError, flag, loadConfig, noSessionForWorkspaceError, positional, readActiveAccessToken, realpathOr, resolveSectionOverChain, telemetryCommandGroup } from "@prisma/cli-engine";
5
5
  import { createComposerFamily } from "@prisma/composer-cli/family";
6
6
  import { ormCommandFamily } from "@prisma/orm-toolchain/cli";
7
7
  import { CliStructuredError, notOk, ok } from "@prisma/cli-engine/protocol";
@@ -16,7 +16,7 @@ import events from "node:events";
16
16
  import http from "node:http";
17
17
  import readline from "node:readline/promises";
18
18
  import open from "open";
19
- import { existsSync, fstatSync, readFileSync, statSync } from "node:fs";
19
+ import { fstatSync, readFileSync, statSync } from "node:fs";
20
20
  import { PnpmTool, YarnTool } from "@manypkg/tools";
21
21
  import { Result, TaggedError, UnhandledException, matchError } from "better-result";
22
22
  import { execFile, fork, spawn } from "node:child_process";
@@ -2212,6 +2212,28 @@ async function isFile(target) {
2212
2212
  }
2213
2213
  }
2214
2214
  //#endregion
2215
+ //#region src/lib/version.ts
2216
+ const requireFromHere = createRequire(import.meta.url);
2217
+ /** The bundled entry sits one directory below the package root
2218
+ * (`dist/cli.js`); this source file sits two below (`src/lib/`). Both
2219
+ * are tried, nearest first, so the same code serves either. */
2220
+ const PACKAGE_JSON_CANDIDATES = ["../package.json", "../../package.json"];
2221
+ function readPackageMetadata() {
2222
+ for (const candidate of PACKAGE_JSON_CANDIDATES) try {
2223
+ const metadata = requireFromHere(candidate);
2224
+ if (metadata.version) return metadata;
2225
+ } catch {}
2226
+ return {};
2227
+ }
2228
+ function getCliVersion() {
2229
+ const pkg = readPackageMetadata();
2230
+ if (!pkg.version) throw new Error("CLI version metadata is missing from the installed package: the bundled package.json could not be read or did not contain a version field. Reinstall the CLI from the npm registry, or check your install path is intact.");
2231
+ return pkg.version;
2232
+ }
2233
+ function getCliName() {
2234
+ return CLI_NAME;
2235
+ }
2236
+ //#endregion
2215
2237
  //#region src/commands/skills/config.ts
2216
2238
  const DEFAULT = {
2217
2239
  check: true,
@@ -2288,31 +2310,34 @@ function validateAgents(raw) {
2288
2310
  agents
2289
2311
  };
2290
2312
  }
2313
+ /** The disk loader bound the way the bin's Runtime binds it, for
2314
+ * callers with no Runtime in scope (the post-login tip). */
2315
+ function projectConfigLoader(cwd) {
2316
+ return (configPath) => loadConfig(cwd, configPath, getCliVersion());
2317
+ }
2291
2318
  /**
2292
- * The validated skills section of an already-loaded config, or null
2293
- * when the section does not validate. Used by code that runs outside a
2294
- * command handler (the staleness check, the post-login tip), which has
2295
- * no ctx.config.
2319
+ * The project's skills settings, resolved per key over the discovered
2320
+ * config chain exactly as the skills commands resolve them, so callers
2321
+ * that run outside a command handler (the staleness check, the
2322
+ * post-login tip) agree with the commands on the governing config from
2323
+ * any directory. `load` is Runtime.loadConfig wherever a Runtime is in
2324
+ * scope, so a host-supplied loader governs these reads too. Chain
2325
+ * discovery is stat-only until a file exists, so a project without a
2326
+ * config never pays a TypeScript transpile.
2296
2327
  *
2297
- * Null deliberately collapses "no config" and "config invalid": both
2298
- * callers fall back to the default agent set, so a broken config never
2299
- * silences the check. The commands that consume the config surface the
2300
- * validation error themselves.
2328
+ * Null deliberately collapses "no config" and "config broken or
2329
+ * invalid": both callers fall back to the default agent set, so a
2330
+ * broken config never silences the check. The commands that consume
2331
+ * the config surface the error themselves.
2301
2332
  */
2302
- function readSkillsConfig(loaded) {
2303
- const section = skillsConfigSection.validate(loaded.sections[SKILLS_CONFIG_SECTION_NAME]);
2333
+ async function readProjectSkillsConfig(load, configPath) {
2334
+ const loaded = await load(configPath);
2335
+ if (loaded.diagnostics.some((entry) => entry.diagnostic.severity === "error") || loaded.files.length === 0) return null;
2336
+ const resolved = resolveSectionOverChain(skillsConfigSection, loaded.files);
2337
+ if (!resolved.ok) return null;
2338
+ const section = skillsConfigSection.validate(resolved.value, resolved.provenance);
2304
2339
  return section.ok ? section.value : null;
2305
2340
  }
2306
- /**
2307
- * The project's skills settings from prisma.config.ts, or null when no
2308
- * config file exists — decided with one stat, so a project without a
2309
- * config never pays the file's TypeScript transpile — or the section
2310
- * does not validate.
2311
- */
2312
- async function readProjectSkillsConfig(cwd, configPath) {
2313
- if (!existsSync(configPath === void 0 ? path.join(cwd, "prisma.config.ts") : path.resolve(cwd, configPath))) return null;
2314
- return readSkillsConfig(await loadConfig(cwd, configPath));
2315
- }
2316
2341
  const skillsConfigSection = defineConfigSection({
2317
2342
  name: SKILLS_CONFIG_SECTION_NAME,
2318
2343
  validate: (raw) => {
@@ -2369,7 +2394,7 @@ const SKILLS_SYNC_ARGS = ["skills", "sync"];
2369
2394
  async function resolveAgentSetupTipCommand(ctx) {
2370
2395
  if (ctx.env.CI) return null;
2371
2396
  try {
2372
- const config = await readProjectSkillsConfig(ctx.cwd);
2397
+ const config = await readProjectSkillsConfig(projectConfigLoader(ctx.cwd), ctx.configPath);
2373
2398
  if (config !== null && !config.check) return null;
2374
2399
  const status = await readSkillsStatus(ctx.cwd, {
2375
2400
  orphans: false,
@@ -5053,28 +5078,6 @@ function unreadableBodyDetail(error) {
5053
5078
  return isTimeout(error) ? TIMEOUT_DETAIL : "The feedback service response could not be read.";
5054
5079
  }
5055
5080
  //#endregion
5056
- //#region src/lib/version.ts
5057
- const requireFromHere = createRequire(import.meta.url);
5058
- /** The bundled entry sits one directory below the package root
5059
- * (`dist/cli.js`); this source file sits two below (`src/lib/`). Both
5060
- * are tried, nearest first, so the same code serves either. */
5061
- const PACKAGE_JSON_CANDIDATES = ["../package.json", "../../package.json"];
5062
- function readPackageMetadata() {
5063
- for (const candidate of PACKAGE_JSON_CANDIDATES) try {
5064
- const metadata = requireFromHere(candidate);
5065
- if (metadata.version) return metadata;
5066
- } catch {}
5067
- return {};
5068
- }
5069
- function getCliVersion() {
5070
- const pkg = readPackageMetadata();
5071
- if (!pkg.version) throw new Error("CLI version metadata is missing from the installed package: the bundled package.json could not be read or did not contain a version field. Reinstall the CLI from the npm registry, or check your install path is intact.");
5072
- return pkg.version;
5073
- }
5074
- function getCliName() {
5075
- return CLI_NAME;
5076
- }
5077
- //#endregion
5078
5081
  //#region src/commands/feedback.ts
5079
5082
  const DEFAULT_FEEDBACK_ENDPOINT = "https://hiieirp2pwqnjvq9axzyg6d0.fra.prisma.build/feedback";
5080
5083
  const MAX_MESSAGE_LENGTH = 4e3;
@@ -6272,6 +6275,39 @@ async function syncSkillsStep(cwd, agents, checkEnabledByConfig) {
6272
6275
  };
6273
6276
  }
6274
6277
  }
6278
+ /** Whether some file on the resolved chain sits in a strict ancestor
6279
+ * directory of cwd. A config in cwd itself does not count, and neither
6280
+ * does one reached sideways (--config to a file elsewhere) — the spec
6281
+ * defers only to an ancestor config. The chain is the one the needs
6282
+ * check loaded before the handler ran, so init's own scaffold never
6283
+ * counts either. Realpath'd on both sides so symlinked layouts compare
6284
+ * like with like. */
6285
+ function governedByAncestorConfig(files, cwd) {
6286
+ const here = realpathOr(cwd);
6287
+ return files.some((file) => {
6288
+ const relative = path.relative(realpathOr(path.dirname(file.path)), here);
6289
+ return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative);
6290
+ });
6291
+ }
6292
+ const ANCESTOR_SKIPPED_POSTINSTALL = {
6293
+ report: {
6294
+ outcome: "skipped",
6295
+ reason: "governing-config",
6296
+ script: null,
6297
+ dependency: "skipped"
6298
+ },
6299
+ lines: [summary("info", "Skipped the postinstall hook and the prisma dev dependency: another prisma.config.ts already governs this directory, so both belong at the repository root. Pass --postinstall to add them here anyway.")],
6300
+ diagnostics: []
6301
+ };
6302
+ const ANCESTOR_SKIPPED_SKILLS = {
6303
+ report: {
6304
+ outcome: "skipped",
6305
+ reason: "governing-config",
6306
+ sync: null
6307
+ },
6308
+ lines: [summary("info", "Skipped the skills sync: another prisma.config.ts already governs this directory, so the skills belong at the repository root. Pass --skills with your agents to sync them here anyway.")],
6309
+ diagnostics: []
6310
+ };
6275
6311
  const SKIPPED_POSTINSTALL = {
6276
6312
  report: {
6277
6313
  outcome: "skipped",
@@ -6327,6 +6363,11 @@ function parseSkillsFlag(raw, configured) {
6327
6363
  agents
6328
6364
  };
6329
6365
  }
6366
+ async function postinstallStep(flag, deferToAncestor, cwd) {
6367
+ if (flag === false) return SKIPPED_POSTINSTALL;
6368
+ if (deferToAncestor && flag === void 0) return ANCESTOR_SKIPPED_POSTINSTALL;
6369
+ return addPostinstallHook(cwd);
6370
+ }
6330
6371
  function initPresentations(result, postinstall, config, skills) {
6331
6372
  return {
6332
6373
  json: () => result,
@@ -6345,7 +6386,7 @@ function initPresentations(result, postinstall, config, skills) {
6345
6386
  const initCommand = defineCommand({
6346
6387
  help: {
6347
6388
  summary: "Prepare this repository for Prisma: config file, dev dependency, AI-agent skills",
6348
- description: "Runs locally and calls no platform API. Adds a postinstall script to package.json that keeps the Prisma agent skills in sync on every install, adds prisma to devDependencies at this CLI's exact version when no dependency field declares it, scaffolds a prisma.config.ts recording which agents to install skills for, then syncs the skills once now. Everything lands in the current directory; a prisma.config.ts or postinstall script that already exists is never edited. Rerunning is safe: each step reports what is already done.",
6389
+ description: "Runs locally and calls no platform API. Adds a postinstall script to package.json that keeps the Prisma agent skills in sync on every install, adds prisma to devDependencies at this CLI's exact version when no dependency field declares it, scaffolds a prisma.config.ts recording which agents to install skills for, then syncs the skills once now. Everything lands in the current directory; a prisma.config.ts or postinstall script that already exists is never edited. Rerunning is safe: each step reports what is already done. In a directory another prisma.config.ts already governs, init writes only the prisma.config.ts scaffold — the postinstall hook, the prisma dev dependency, and the skills sync belong at the repository root and are skipped unless --postinstall or --skills asks for them here.",
6349
6390
  examples: [
6350
6391
  "init",
6351
6392
  "init --skills=claude,cursor",
@@ -6364,9 +6405,13 @@ const initCommand = defineCommand({
6364
6405
  handler: async (args, ctx) => {
6365
6406
  const skillsFlag = parseSkillsFlag(args.flags.skills, ctx.config.agents);
6366
6407
  if (skillsFlag.kind === "invalid") return notOk(skillsFlag.error);
6367
- const postinstall = args.flags.postinstall === false ? SKIPPED_POSTINSTALL : await addPostinstallHook(ctx.cwd);
6408
+ const deferToAncestor = governedByAncestorConfig(ctx.configFiles, ctx.cwd);
6409
+ const postinstall = await postinstallStep(args.flags.postinstall, deferToAncestor, ctx.cwd);
6368
6410
  const config = await scaffoldConfigStep(ctx.cwd, skillsFlag.kind === "skip" ? [] : skillsFlag.agents, ctx.config.agentsConfigured);
6369
- const skills = skillsFlag.kind === "skip" ? SKIPPED_SKILLS : await syncSkillsStep(ctx.cwd, skillsFlag.agents, ctx.config.check);
6411
+ let skills;
6412
+ if (skillsFlag.kind === "skip") skills = SKIPPED_SKILLS;
6413
+ else if (deferToAncestor && args.flags.skills === void 0) skills = ANCESTOR_SKIPPED_SKILLS;
6414
+ else skills = await syncSkillsStep(ctx.cwd, skillsFlag.agents, ctx.config.check);
6370
6415
  const result = {
6371
6416
  postinstall: postinstall.report,
6372
6417
  config: config.report,
@@ -14482,6 +14527,21 @@ function outputStreamsShareDevice() {
14482
14527
  return;
14483
14528
  }
14484
14529
  }
14530
+ /** One chain discovery and transpile per config path per process: a
14531
+ * command's needs check and the skills staleness check both load the
14532
+ * config, and the process is single-shot, so nothing invalidates. The
14533
+ * promise is cached, not the value, so concurrent calls coalesce. */
14534
+ function memoizedConfigLoader(proc) {
14535
+ const loads = /* @__PURE__ */ new Map();
14536
+ return (configPath) => {
14537
+ let load = loads.get(configPath);
14538
+ if (load === void 0) {
14539
+ load = loadConfig(proc.cwd(), configPath, getCliVersion());
14540
+ loads.set(configPath, load);
14541
+ }
14542
+ return load;
14543
+ };
14544
+ }
14485
14545
  async function assembleRuntime(proc) {
14486
14546
  const stdin = {
14487
14547
  setRawMode: proc.stdin.isTTY === true && proc.stdin.setRawMode !== void 0 ? (enabled) => {
@@ -14515,7 +14575,7 @@ async function assembleRuntime(proc) {
14515
14575
  outputStreamsShareDevice: outputStreamsShareDevice(),
14516
14576
  exit: (code) => proc.exit(code),
14517
14577
  onSignal: makeOnSignal(proc),
14518
- loadConfig: (configPath) => loadConfig(proc.cwd(), configPath, getCliVersion()),
14578
+ loadConfig: memoizedConfigLoader(proc),
14519
14579
  credentialManager: new FileCredentialManager({
14520
14580
  env: proc.env,
14521
14581
  fetchWorkspaceName: fetchWorkspaceName(apiBaseUrl),
@@ -14554,7 +14614,7 @@ async function maybeWriteSkillsStaleNotice(runtime) {
14554
14614
  checkDisabled: false
14555
14615
  });
14556
14616
  if (status.upToDate) return;
14557
- const config = await readProjectSkillsConfig(runtime.cwd, configPathFromArgv(runtime.argv));
14617
+ const config = await readProjectSkillsConfig(runtime.loadConfig, configPathFromArgv(runtime.argv));
14558
14618
  if (config !== null && !config.check) return;
14559
14619
  const agents = config?.agents ?? DEFAULT_AGENTS;
14560
14620
  if (agents.length === 0) return;
@@ -14631,8 +14691,8 @@ function isSuppressedByInvocation(runtime) {
14631
14691
  function isFormat(tokens, format) {
14632
14692
  return tokens.some((token, index) => token === `--format=${format}` || token === "--format" && tokens[index + 1] === format);
14633
14693
  }
14634
- /** The file an explicit --config names, so the check reads the same
14635
- * config the command did. Discovery is otherwise cwd-only. */
14694
+ /** The file an explicit --config names, so the check anchors the same
14695
+ * chain the command did. Discovery otherwise anchors at cwd. */
14636
14696
  function configPathFromArgv(argv) {
14637
14697
  const tokens = flagTokens(argv);
14638
14698
  for (let index = 0; index < tokens.length; index += 1) {
@@ -14863,7 +14923,8 @@ async function main(proc, buildCliForRun = buildCli) {
14863
14923
  argv: proc.argv.slice(2),
14864
14924
  cwd: proc.cwd(),
14865
14925
  stdout: proc.stdout,
14866
- stderr: proc.stderr
14926
+ stderr: proc.stderr,
14927
+ loadConfig: runtime.loadConfig
14867
14928
  });
14868
14929
  return exitCode;
14869
14930
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/cli",
3
- "version": "8.0.0-rc.15-dev.109",
3
+ "version": "8.0.0-rc.15-dev.110",
4
4
  "description": "Command-line interface for the Prisma Developer Platform.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -40,11 +40,11 @@
40
40
  "license": "Apache-2.0",
41
41
  "dependencies": {
42
42
  "@manypkg/tools": "^2.1.2",
43
- "@prisma/cli-engine": "0.4.0",
44
- "@prisma/composer-cli": "0.20.0-dev.6",
43
+ "@prisma/cli-engine": "0.5.0",
44
+ "@prisma/composer-cli": "0.21.0-dev.1",
45
45
  "@prisma/compute-sdk": "0.42.0",
46
46
  "@prisma/management-api-sdk": "1.69.0",
47
- "@prisma/orm-toolchain": "8.0.0-rc.11-dev.22",
47
+ "@prisma/orm-toolchain": "8.0.0-rc.11-dev.37",
48
48
  "@vercel/detect-agent": "^1.2.3",
49
49
  "better-result": "^2.9.2",
50
50
  "cross-spawn": "^7.0.6",
@@ -53,11 +53,11 @@
53
53
  "open": "^11.0.0"
54
54
  },
55
55
  "devDependencies": {
56
- "@prisma/composer": "0.20.0-dev.6",
56
+ "@prisma/composer": "0.21.0-dev.1",
57
57
  "@prisma/credentials-store": "^7.8.0",
58
- "@repo/cli-conformance": "8.0.0-rc.15-dev.109",
59
- "@repo/cli-telemetry": "8.0.0-rc.15-dev.109",
60
- "@repo/tsconfig": "8.0.0-rc.15-dev.109",
58
+ "@repo/cli-conformance": "8.0.0-rc.15-dev.110",
59
+ "@repo/cli-telemetry": "8.0.0-rc.15-dev.110",
60
+ "@repo/tsconfig": "8.0.0-rc.15-dev.110",
61
61
  "@types/node": "^22.19.19",
62
62
  "@types/cross-spawn": "^6.0.6",
63
63
  "tsdown": "^0.21.10",