@prisma/cli 8.0.0-rc.13-dev.95 → 8.0.0-rc.13-dev.96

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 +51 -19
  2. package/package.json +7 -7
package/dist/cli.js CHANGED
@@ -9,7 +9,7 @@ import { AuthError, createManagementApiClient, createManagementApiSdk } from "@p
9
9
  import os from "node:os";
10
10
  import path from "node:path";
11
11
  import { randomBytes, randomUUID } from "node:crypto";
12
- import fs, { mkdir, readFile, readdir, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
12
+ import fs, { mkdir, readFile, readdir, rename, rm, rmdir, stat, unlink, writeFile } from "node:fs/promises";
13
13
  import { mkdir as mkdir$1, readFile as readFile$1, writeFile as writeFile$1 } from "fs/promises";
14
14
  import path$1 from "path";
15
15
  import events from "node:events";
@@ -2045,9 +2045,14 @@ async function hasPackageJsonWorkspaces(root) {
2045
2045
  }
2046
2046
  //#endregion
2047
2047
  //#region src/lib/skills/status.ts
2048
+ /** Reads every skill the installed source packages ship and the state
2049
+ * of each copy in the configured agents' directories, plus the copies
2050
+ * the next sync will remove. */
2048
2051
  async function readSkillsStatus(cwd, options) {
2049
2052
  const projectRoot = path.resolve(cwd);
2050
- const dirs = agentSkillDirs(options?.agents ?? DEFAULT_AGENTS);
2053
+ const agents = options?.agents ?? DEFAULT_AGENTS;
2054
+ const dirs = agentSkillDirs(agents);
2055
+ const unconfiguredDirs = agentSkillDirs(KNOWN_AGENTS.filter((agent) => !agents.includes(agent)));
2051
2056
  const checkDisabled = options?.checkDisabled ?? await readSkillsCheckDisabled(projectRoot);
2052
2057
  const packages = await findInstalledSourcePackages(projectRoot);
2053
2058
  const sources = await collectSkillSources(packages);
@@ -2059,7 +2064,7 @@ async function readSkillsStatus(cwd, options) {
2059
2064
  checkDisabled,
2060
2065
  packages,
2061
2066
  skills,
2062
- orphans: options?.orphans === false ? [] : await findOrphanedSkills(projectRoot, dirs, new Set(sources.keys())),
2067
+ orphans: options?.orphans === false ? [] : await findOrphanedSkills(projectRoot, dirs, new Set(sources.keys()), unconfiguredDirs),
2063
2068
  upToDate: skills.every((skill) => skill.upToDate)
2064
2069
  };
2065
2070
  }
@@ -2145,16 +2150,25 @@ async function missingFromDisk(target) {
2145
2150
  }
2146
2151
  /**
2147
2152
  * Copies in the harness directories that this CLI installed — their
2148
- * SKILL.md names an allowlisted package as its `library` — and that no
2149
- * installed package still provides. A skill from anywhere else is
2150
- * someone else's file and is never touched.
2153
+ * SKILL.md names an allowlisted package as its `library` — and that
2154
+ * nothing wants any more: in a configured directory, one no installed
2155
+ * package still provides; in the directory of an agent the config no
2156
+ * longer names, every one. A skill from anywhere else is someone
2157
+ * else's file and is never touched.
2151
2158
  */
2152
- async function findOrphanedSkills(projectRoot, dirs, provided) {
2159
+ async function findOrphanedSkills(projectRoot, dirs, provided, unconfiguredDirs = []) {
2153
2160
  const orphans = /* @__PURE__ */ new Map();
2154
- for (const dir of dirs) {
2161
+ const scan = [...dirs.map((dir) => ({
2162
+ dir,
2163
+ wanted: provided
2164
+ })), ...unconfiguredDirs.map((dir) => ({
2165
+ dir,
2166
+ wanted: /* @__PURE__ */ new Set()
2167
+ }))];
2168
+ for (const { dir, wanted } of scan) {
2155
2169
  const harnessDir = path.join(projectRoot, dir);
2156
2170
  for (const skill of await skillDirectories(harnessDir)) {
2157
- if (provided.has(skill)) continue;
2171
+ if (wanted.has(skill)) continue;
2158
2172
  const stamp = await readSkillStamp(path.join(harnessDir, skill, "SKILL.md"));
2159
2173
  if (stamp?.library === null || stamp === null) continue;
2160
2174
  if (!isSkillSourcePackage(stamp.library)) continue;
@@ -5527,11 +5541,12 @@ const gitDisconnectCommand = defineCommand({
5527
5541
  //#region src/lib/skills/sync.ts
5528
5542
  /**
5529
5543
  * Brings the harness skill directories in line with the installed
5530
- * source packages: copies each skill tree whose stamp does not match
5531
- * the package it came from, and removes copies whose source package is
5532
- * gone. A target directory that exists but is not this CLI's copy is
5533
- * refused, never replaced. Doing nothing is the normal outcome and is
5534
- * not an error.
5544
+ * source packages and the configured agents: copies each skill tree
5545
+ * whose stamp does not match the package it came from, and removes
5546
+ * copies whose source package is gone or whose agent the config no
5547
+ * longer names. A target directory that exists but is not this CLI's
5548
+ * copy is refused, never replaced. Doing nothing is the normal outcome
5549
+ * and is not an error.
5535
5550
  */
5536
5551
  async function syncSkills(status) {
5537
5552
  const synced = [];
@@ -5555,10 +5570,13 @@ async function syncSkills(status) {
5555
5570
  }
5556
5571
  const pruned = [];
5557
5572
  for (const orphan of status.orphans) {
5558
- for (const dir of orphan.dirs) await rm(path.join(status.projectRoot, dir, orphan.skill), {
5559
- recursive: true,
5560
- force: true
5561
- });
5573
+ for (const dir of orphan.dirs) {
5574
+ await rm(path.join(status.projectRoot, dir, orphan.skill), {
5575
+ recursive: true,
5576
+ force: true
5577
+ });
5578
+ await removeEmptyHarnessDirs(status.projectRoot, dir);
5579
+ }
5562
5580
  pruned.push({
5563
5581
  skill: orphan.skill,
5564
5582
  library: orphan.library,
@@ -5575,6 +5593,20 @@ async function syncSkills(status) {
5575
5593
  checkDisabled: status.checkDisabled
5576
5594
  };
5577
5595
  }
5596
+ /**
5597
+ * A harness directory this CLI emptied by removing its last copy is
5598
+ * removed too, and so is its parent (`.claude/skills`, then `.claude`),
5599
+ * so opting an agent out leaves nothing behind. `rmdir` refuses a
5600
+ * directory holding anything else, which is exactly the user's file
5601
+ * that must stay.
5602
+ */
5603
+ async function removeEmptyHarnessDirs(projectRoot, dir) {
5604
+ for (let current = dir; current !== "." && current !== ""; current = path.dirname(current)) try {
5605
+ await rmdir(path.join(projectRoot, current));
5606
+ } catch {
5607
+ return;
5608
+ }
5609
+ }
5578
5610
  const OLD_CLI_GITIGNORE = /^\*\r?\n?$/;
5579
5611
  async function removeOldCliGitignore(file) {
5580
5612
  let content;
@@ -5778,7 +5810,7 @@ function bothSwitchesError() {
5778
5810
  const skillsSyncCommand = defineCommand({
5779
5811
  help: {
5780
5812
  summary: "Copy the AI-agent instruction files (skills) from installed Prisma packages into this project",
5781
- description: "Agent skills are instruction files that teach AI coding agents (Claude Code, Cursor, and others) how to use the installed Prisma packages. They ship inside the packages themselves, so they always describe the version in use. Sync copies them into the skill directories the agent harnesses read, and removes copies whose package is gone. It does nothing, and exits 0, when everything is already current.",
5813
+ description: "Agent skills are instruction files that teach AI coding agents (Claude Code, Cursor, and others) how to use the installed Prisma packages. They ship inside the packages themselves, so they always describe the version in use. Sync copies them into the skill directories of the agents that skills.agents in prisma.config.ts names (every known agent when unset), and removes copies whose package is gone or whose agent is no longer named there — agents: [] removes them all. It does nothing, and exits 0, when everything is already current.",
5782
5814
  examples: ["skills sync", "skills sync --disable"]
5783
5815
  },
5784
5816
  needs: { config: skillsConfigSection },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma/cli",
3
- "version": "8.0.0-rc.13-dev.95",
3
+ "version": "8.0.0-rc.13-dev.96",
4
4
  "description": "Command-line interface for the Prisma Developer Platform.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -41,10 +41,10 @@
41
41
  "dependencies": {
42
42
  "@manypkg/tools": "^2.1.2",
43
43
  "@prisma/cli-engine": "0.3.0",
44
- "@prisma/composer-cli": "0.17.0-dev.2",
44
+ "@prisma/composer-cli": "0.17.0-dev.4",
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.9-dev.1",
47
+ "@prisma/orm-toolchain": "8.0.0-rc.9-dev.2",
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.17.0-dev.2",
56
+ "@prisma/composer": "0.17.0-dev.4",
57
57
  "@prisma/credentials-store": "^7.8.0",
58
- "@repo/cli-conformance": "8.0.0-rc.13-dev.95",
59
- "@repo/cli-telemetry": "8.0.0-rc.13-dev.95",
60
- "@repo/tsconfig": "8.0.0-rc.13-dev.95",
58
+ "@repo/cli-conformance": "8.0.0-rc.13-dev.96",
59
+ "@repo/cli-telemetry": "8.0.0-rc.13-dev.96",
60
+ "@repo/tsconfig": "8.0.0-rc.13-dev.96",
61
61
  "@types/node": "^22.19.19",
62
62
  "@types/cross-spawn": "^6.0.6",
63
63
  "tsdown": "^0.21.10",