@prisma/cli 3.0.0-beta.2 → 3.0.0-beta.20

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 (87) hide show
  1. package/README.md +5 -16
  2. package/dist/adapters/git.js +8 -3
  3. package/dist/adapters/local-state.js +26 -7
  4. package/dist/adapters/mock-api.js +81 -2
  5. package/dist/adapters/token-storage.js +344 -25
  6. package/dist/cli.js +18 -3
  7. package/dist/cli2.js +12 -4
  8. package/dist/commands/agent/index.js +60 -0
  9. package/dist/commands/app/index.js +90 -61
  10. package/dist/commands/auth/index.js +55 -2
  11. package/dist/commands/branch/index.js +2 -27
  12. package/dist/commands/build/index.js +29 -0
  13. package/dist/commands/database/index.js +159 -0
  14. package/dist/commands/env.js +8 -4
  15. package/dist/commands/git/index.js +1 -1
  16. package/dist/commands/project/index.js +1 -1
  17. package/dist/controllers/agent.js +228 -0
  18. package/dist/controllers/app-env-api.js +54 -0
  19. package/dist/controllers/app-env-file.js +181 -0
  20. package/dist/controllers/app-env.js +286 -131
  21. package/dist/controllers/app.js +849 -309
  22. package/dist/controllers/auth.js +255 -11
  23. package/dist/controllers/branch.js +78 -48
  24. package/dist/controllers/build.js +88 -0
  25. package/dist/controllers/database.js +318 -0
  26. package/dist/controllers/project.js +156 -87
  27. package/dist/controllers/select-prompt-port.js +1 -0
  28. package/dist/lib/agent/cli-command.js +17 -0
  29. package/dist/lib/agent/constants.js +12 -0
  30. package/dist/lib/agent/package-manager.js +99 -0
  31. package/dist/lib/agent/setup-status.js +83 -0
  32. package/dist/lib/app/app-interaction.js +5 -0
  33. package/dist/lib/app/{preview-provider.js → app-provider.js} +220 -104
  34. package/dist/lib/app/branch-database-api.js +102 -0
  35. package/dist/lib/app/branch-database-deploy.js +326 -0
  36. package/dist/lib/app/branch-database.js +216 -0
  37. package/dist/lib/app/build-settings.js +93 -0
  38. package/dist/lib/app/build.js +82 -0
  39. package/dist/lib/app/bun-project.js +15 -9
  40. package/dist/lib/app/compute-config.js +145 -0
  41. package/dist/lib/app/deploy-plan.js +59 -0
  42. package/dist/lib/app/{preview-progress.js → deploy-progress.js} +12 -12
  43. package/dist/lib/app/env-config.js +1 -1
  44. package/dist/lib/app/env-file.js +82 -0
  45. package/dist/lib/app/env-vars.js +28 -2
  46. package/dist/lib/app/local-dev.js +8 -49
  47. package/dist/lib/app/production-deploy-gate.js +162 -0
  48. package/dist/lib/app/read-branch.js +30 -0
  49. package/dist/lib/auth/auth-ops.js +38 -23
  50. package/dist/lib/auth/guard.js +6 -2
  51. package/dist/lib/auth/login.js +117 -15
  52. package/dist/lib/database/provider.js +167 -0
  53. package/dist/lib/diagnostics.js +15 -0
  54. package/dist/lib/fs/home-path.js +24 -0
  55. package/dist/lib/git/local-branch.js +53 -0
  56. package/dist/lib/git/local-status.js +57 -0
  57. package/dist/lib/project/interactive-setup.js +2 -1
  58. package/dist/lib/project/local-pin.js +183 -34
  59. package/dist/lib/project/resolution.js +206 -50
  60. package/dist/lib/project/setup.js +64 -18
  61. package/dist/output/patterns.js +1 -1
  62. package/dist/presenters/agent.js +74 -0
  63. package/dist/presenters/app-env.js +149 -14
  64. package/dist/presenters/app.js +187 -26
  65. package/dist/presenters/auth.js +99 -2
  66. package/dist/presenters/branch.js +37 -102
  67. package/dist/presenters/database.js +274 -0
  68. package/dist/presenters/project.js +44 -26
  69. package/dist/presenters/verbose-context.js +64 -0
  70. package/dist/shell/cli-command.js +12 -0
  71. package/dist/shell/command-arguments.js +7 -1
  72. package/dist/shell/command-meta.js +243 -15
  73. package/dist/shell/command-runner.js +60 -21
  74. package/dist/shell/diagnostics-output.js +57 -0
  75. package/dist/shell/errors.js +61 -1
  76. package/dist/shell/help.js +31 -20
  77. package/dist/shell/output.js +10 -1
  78. package/dist/shell/prompt.js +7 -3
  79. package/dist/shell/runtime.js +10 -6
  80. package/dist/shell/ui.js +42 -3
  81. package/dist/shell/update-check.js +247 -0
  82. package/dist/use-cases/auth.js +68 -1
  83. package/dist/use-cases/branch.js +20 -68
  84. package/dist/use-cases/create-cli-gateways.js +2 -17
  85. package/package.json +27 -10
  86. package/dist/lib/app/preview-build.js +0 -284
  87. package/dist/lib/app/preview-interaction.js +0 -5
@@ -0,0 +1,29 @@
1
+ import { attachCommandDescriptor } from "../../shell/command-meta.js";
2
+ import { addCompactGlobalFlags, addGlobalFlags } from "../../shell/global-flags.js";
3
+ import { configureRuntimeCommand } from "../../shell/runtime.js";
4
+ import { runStreamingCommand } from "../../shell/command-runner.js";
5
+ import { runBuildLogs } from "../../controllers/build.js";
6
+ import { Command, Option } from "commander";
7
+ //#region src/commands/build/index.ts
8
+ function createBuildCommand(runtime) {
9
+ const build = attachCommandDescriptor(configureRuntimeCommand(new Command("build"), runtime), "build");
10
+ addCompactGlobalFlags(build);
11
+ build.addCommand(createLogsCommand(runtime));
12
+ return build;
13
+ }
14
+ function createLogsCommand(runtime) {
15
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("logs"), runtime), "build.logs");
16
+ command.argument("<buildId>", "Build id from a git-push or Console deploy").addOption(new Option("--follow", "Keep the connection open and stream new logs as the build runs")).addOption(new Option("--cursor <cursor>", "Resume from a prior terminal cursor"));
17
+ addGlobalFlags(command);
18
+ command.action(async (buildId, options) => {
19
+ const follow = options.follow;
20
+ const cursor = options.cursor;
21
+ await runStreamingCommand(runtime, "build.logs", options, (context) => runBuildLogs(context, buildId, {
22
+ follow,
23
+ cursor
24
+ }), { emitJsonSuccessEvent: false });
25
+ });
26
+ return command;
27
+ }
28
+ //#endregion
29
+ export { createBuildCommand };
@@ -0,0 +1,159 @@
1
+ import { attachCommandDescriptor } from "../../shell/command-meta.js";
2
+ import { addCompactGlobalFlags, addGlobalFlags } from "../../shell/global-flags.js";
3
+ import { configureRuntimeCommand } from "../../shell/runtime.js";
4
+ import { runCommand } from "../../shell/command-runner.js";
5
+ import { runDatabaseConnectionCreate, runDatabaseConnectionList, runDatabaseConnectionRemove, runDatabaseCreate, runDatabaseList, runDatabaseRemove, runDatabaseShow } from "../../controllers/database.js";
6
+ import { renderDatabaseConnectionCreate, renderDatabaseConnectionCreateStdout, renderDatabaseConnectionList, renderDatabaseConnectionRemove, renderDatabaseCreate, renderDatabaseCreateStdout, renderDatabaseList, renderDatabaseRemove, renderDatabaseShow, serializeDatabaseConnectionCreate, serializeDatabaseConnectionList, serializeDatabaseConnectionRemove, serializeDatabaseCreate, serializeDatabaseList, serializeDatabaseRemove, serializeDatabaseShow } from "../../presenters/database.js";
7
+ import { Command, Option } from "commander";
8
+ //#region src/commands/database/index.ts
9
+ function createDatabaseCommand(runtime) {
10
+ const database = attachCommandDescriptor(configureRuntimeCommand(new Command("database"), runtime), "database");
11
+ addCompactGlobalFlags(database);
12
+ database.addCommand(createDatabaseListCommand(runtime));
13
+ database.addCommand(createDatabaseShowCommand(runtime));
14
+ database.addCommand(createDatabaseCreateCommand(runtime));
15
+ database.addCommand(createDatabaseRemoveCommand(runtime));
16
+ database.addCommand(createDatabaseConnectionCommand(runtime));
17
+ return database;
18
+ }
19
+ function addProjectAndBranchOptions(command) {
20
+ return command.addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--branch <git-name>", "Branch git name"));
21
+ }
22
+ function createDatabaseListCommand(runtime) {
23
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("list"), runtime), "database.list");
24
+ addProjectAndBranchOptions(command);
25
+ addGlobalFlags(command);
26
+ command.action(async (options) => {
27
+ const projectRef = options.project;
28
+ const branchName = options.branch;
29
+ await runCommand(runtime, "database.list", options, (context) => runDatabaseList(context, {
30
+ projectRef,
31
+ branchName
32
+ }), {
33
+ renderHuman: (context, descriptor, result) => renderDatabaseList(context, descriptor, result),
34
+ renderJson: (result) => serializeDatabaseList(result)
35
+ });
36
+ });
37
+ return command;
38
+ }
39
+ function createDatabaseShowCommand(runtime) {
40
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("show"), runtime), "database.show");
41
+ command.argument("<database>", "Database id or name");
42
+ addProjectAndBranchOptions(command);
43
+ addGlobalFlags(command);
44
+ command.action(async (databaseRef, options) => {
45
+ const projectRef = options.project;
46
+ const branchName = options.branch;
47
+ await runCommand(runtime, "database.show", options, (context) => runDatabaseShow(context, databaseRef, {
48
+ projectRef,
49
+ branchName
50
+ }), {
51
+ renderHuman: (context, descriptor, result) => renderDatabaseShow(context, descriptor, result),
52
+ renderJson: (result) => serializeDatabaseShow(result)
53
+ });
54
+ });
55
+ return command;
56
+ }
57
+ function createDatabaseCreateCommand(runtime) {
58
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("create"), runtime), "database.create");
59
+ command.argument("<name>", "Database name").addOption(new Option("--region <region>", "Prisma Postgres region id"));
60
+ addProjectAndBranchOptions(command);
61
+ addGlobalFlags(command);
62
+ command.action(async (name, options) => {
63
+ const projectRef = options.project;
64
+ const branchName = options.branch;
65
+ const region = options.region;
66
+ await runCommand(runtime, "database.create", options, (context) => runDatabaseCreate(context, name, {
67
+ projectRef,
68
+ branchName,
69
+ region
70
+ }), {
71
+ renderStdout: (context, descriptor, result) => renderDatabaseCreateStdout(context, descriptor, result),
72
+ renderHuman: (context, descriptor, result) => renderDatabaseCreate(context, descriptor, result),
73
+ renderJson: (result) => serializeDatabaseCreate(result)
74
+ });
75
+ });
76
+ return command;
77
+ }
78
+ function createDatabaseRemoveCommand(runtime) {
79
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("remove"), runtime), "database.remove");
80
+ command.argument("<database>", "Database id or name").addOption(new Option("--confirm <database-id>", "Exact database id required to remove"));
81
+ addProjectAndBranchOptions(command);
82
+ addGlobalFlags(command);
83
+ command.action(async (databaseRef, options) => {
84
+ const projectRef = options.project;
85
+ const branchName = options.branch;
86
+ const confirm = options.confirm;
87
+ await runCommand(runtime, "database.remove", options, (context) => runDatabaseRemove(context, databaseRef, {
88
+ projectRef,
89
+ branchName,
90
+ confirm
91
+ }), {
92
+ renderHuman: (context, descriptor, result) => renderDatabaseRemove(context, descriptor, result),
93
+ renderJson: (result) => serializeDatabaseRemove(result)
94
+ });
95
+ });
96
+ return command;
97
+ }
98
+ function createDatabaseConnectionCommand(runtime) {
99
+ const connection = attachCommandDescriptor(configureRuntimeCommand(new Command("connection"), runtime), "database.connection");
100
+ addCompactGlobalFlags(connection);
101
+ connection.addCommand(createDatabaseConnectionListCommand(runtime));
102
+ connection.addCommand(createDatabaseConnectionCreateCommand(runtime));
103
+ connection.addCommand(createDatabaseConnectionRemoveCommand(runtime));
104
+ return connection;
105
+ }
106
+ function createDatabaseConnectionListCommand(runtime) {
107
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("list"), runtime), "database.connection.list");
108
+ command.argument("<database>", "Database id or name");
109
+ addProjectAndBranchOptions(command);
110
+ addGlobalFlags(command);
111
+ command.action(async (databaseRef, options) => {
112
+ const projectRef = options.project;
113
+ const branchName = options.branch;
114
+ await runCommand(runtime, "database.connection.list", options, (context) => runDatabaseConnectionList(context, databaseRef, {
115
+ projectRef,
116
+ branchName
117
+ }), {
118
+ renderHuman: (context, descriptor, result) => renderDatabaseConnectionList(context, descriptor, result),
119
+ renderJson: (result) => serializeDatabaseConnectionList(result)
120
+ });
121
+ });
122
+ return command;
123
+ }
124
+ function createDatabaseConnectionCreateCommand(runtime) {
125
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("create"), runtime), "database.connection.create");
126
+ command.argument("<database>", "Database id or name").addOption(new Option("--name <name>", "Connection name"));
127
+ addProjectAndBranchOptions(command);
128
+ addGlobalFlags(command);
129
+ command.action(async (databaseRef, options) => {
130
+ const projectRef = options.project;
131
+ const branchName = options.branch;
132
+ const name = options.name;
133
+ await runCommand(runtime, "database.connection.create", options, (context) => runDatabaseConnectionCreate(context, databaseRef, {
134
+ projectRef,
135
+ branchName,
136
+ name
137
+ }), {
138
+ renderStdout: (context, descriptor, result) => renderDatabaseConnectionCreateStdout(context, descriptor, result),
139
+ renderHuman: (context, descriptor, result) => renderDatabaseConnectionCreate(context, descriptor, result),
140
+ renderJson: (result) => serializeDatabaseConnectionCreate(result)
141
+ });
142
+ });
143
+ return command;
144
+ }
145
+ function createDatabaseConnectionRemoveCommand(runtime) {
146
+ const command = attachCommandDescriptor(configureRuntimeCommand(new Command("remove"), runtime), "database.connection.remove");
147
+ command.argument("<connection>", "Connection id").addOption(new Option("--confirm <connection-id>", "Exact connection id required to remove"));
148
+ addGlobalFlags(command);
149
+ command.action(async (connectionRef, options) => {
150
+ const confirm = options.confirm;
151
+ await runCommand(runtime, "database.connection.remove", options, (context) => runDatabaseConnectionRemove(context, connectionRef, { confirm }), {
152
+ renderHuman: (context, descriptor, result) => renderDatabaseConnectionRemove(context, descriptor, result),
153
+ renderJson: (result) => serializeDatabaseConnectionRemove(result)
154
+ });
155
+ });
156
+ return command;
157
+ }
158
+ //#endregion
159
+ export { createDatabaseCommand };
@@ -17,16 +17,18 @@ function createEnvCommand(runtime) {
17
17
  }
18
18
  function createEnvAddCommand(runtime) {
19
19
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("add"), runtime), "project.env.add");
20
- command.argument("<assignment>", "Variable assignment as KEY=VALUE or KEY from the current environment").addOption(new Option("--role <role>", "Project template scope (production or preview)").choices(["production", "preview"])).addOption(new Option("--branch <git-name>", "Preview branch override scope")).addOption(new Option("--project <id-or-name>", "Project id or name"));
20
+ command.argument("[assignment]", "Variable assignment as KEY=VALUE or KEY from the current environment").addOption(new Option("--file <path>", "Read KEY=VALUE assignments from a dotenv file")).addOption(new Option("--role <role>", "Project template scope (production or preview)").choices(["production", "preview"])).addOption(new Option("--branch <git-name>", "Preview branch override scope")).addOption(new Option("--project <id-or-name>", "Project id or name"));
21
21
  addGlobalFlags(command);
22
22
  command.action(async (assignment, options) => {
23
23
  const roleName = options.role;
24
24
  const branchName = options.branch;
25
25
  const projectRef = options.project;
26
+ const filePath = options.file;
26
27
  await runCommand(runtime, "project.env.add", options, (context) => runEnvAdd(context, assignment, {
27
28
  roleName,
28
29
  branchName,
29
- projectRef
30
+ projectRef,
31
+ filePath
30
32
  }), {
31
33
  renderHuman: (context, descriptor, result) => renderEnvAdd(context, descriptor, result),
32
34
  renderJson: (result) => serializeEnvAdd(result)
@@ -36,16 +38,18 @@ function createEnvAddCommand(runtime) {
36
38
  }
37
39
  function createEnvUpdateCommand(runtime) {
38
40
  const command = attachCommandDescriptor(configureRuntimeCommand(new Command("update"), runtime), "project.env.update");
39
- command.argument("<assignment>", "Variable assignment as KEY=VALUE or KEY from the current environment").addOption(new Option("--role <role>", "Project template scope (production or preview)").choices(["production", "preview"])).addOption(new Option("--branch <git-name>", "Preview branch override scope")).addOption(new Option("--project <id-or-name>", "Project id or name"));
41
+ command.argument("[assignment]", "Variable assignment as KEY=VALUE or KEY from the current environment").addOption(new Option("--file <path>", "Read KEY=VALUE assignments from a dotenv file")).addOption(new Option("--role <role>", "Project template scope (production or preview)").choices(["production", "preview"])).addOption(new Option("--branch <git-name>", "Preview branch override scope")).addOption(new Option("--project <id-or-name>", "Project id or name"));
40
42
  addGlobalFlags(command);
41
43
  command.action(async (assignment, options) => {
42
44
  const roleName = options.role;
43
45
  const branchName = options.branch;
44
46
  const projectRef = options.project;
47
+ const filePath = options.file;
45
48
  await runCommand(runtime, "project.env.update", options, (context) => runEnvUpdate(context, assignment, {
46
49
  roleName,
47
50
  branchName,
48
- projectRef
51
+ projectRef,
52
+ filePath
49
53
  }), {
50
54
  renderHuman: (context, descriptor, result) => renderEnvUpdate(context, descriptor, result),
51
55
  renderJson: (result) => serializeEnvUpdate(result)
@@ -1,8 +1,8 @@
1
1
  import { attachCommandDescriptor } from "../../shell/command-meta.js";
2
2
  import { addCompactGlobalFlags, addGlobalFlags } from "../../shell/global-flags.js";
3
3
  import { configureRuntimeCommand } from "../../shell/runtime.js";
4
- import { runGitConnect, runGitDisconnect } from "../../controllers/project.js";
5
4
  import { runCommand } from "../../shell/command-runner.js";
5
+ import { runGitConnect, runGitDisconnect } from "../../controllers/project.js";
6
6
  import { renderGitConnect, renderGitDisconnect } from "../../presenters/project.js";
7
7
  import { Command } from "commander";
8
8
  //#region src/commands/git/index.ts
@@ -1,8 +1,8 @@
1
1
  import { attachCommandDescriptor } from "../../shell/command-meta.js";
2
2
  import { addCompactGlobalFlags, addGlobalFlags } from "../../shell/global-flags.js";
3
3
  import { configureRuntimeCommand } from "../../shell/runtime.js";
4
- import { runProjectCreate, runProjectLink, runProjectList, runProjectShow } from "../../controllers/project.js";
5
4
  import { runCommand } from "../../shell/command-runner.js";
5
+ import { runProjectCreate, runProjectLink, runProjectList, runProjectShow } from "../../controllers/project.js";
6
6
  import { renderProjectList, renderProjectSetup, renderProjectShow, serializeProjectList, serializeProjectSetup, serializeProjectShow } from "../../presenters/project.js";
7
7
  import { createEnvCommand } from "../env.js";
8
8
  import { Command } from "commander";
@@ -0,0 +1,228 @@
1
+ import { resolveSkillsPackageRunner } from "../lib/agent/package-manager.js";
2
+ import { resolvePrismaCliPackageCommand } from "../lib/agent/cli-command.js";
3
+ import { DEFAULT_PRISMA_AGENT_SKILLS, DEFAULT_PRISMA_AGENT_TARGETS, PRISMA_AGENT_INSTALL_ARGS, PRISMA_AGENT_STATUS_ARGS, PRISMA_SKILLS_SOURCE, SKILLS_CLI_PACKAGE } from "../lib/agent/constants.js";
4
+ import { readPrismaAgentSetupStatus, resolvePrismaAgentSetupCwd } from "../lib/agent/setup-status.js";
5
+ import { formatShellCommand } from "../shell/command-arguments.js";
6
+ import { CliError } from "../shell/errors.js";
7
+ import { execa } from "execa";
8
+ //#region src/controllers/agent.ts
9
+ async function runAgentInstall(context, options, operation = "install", runOptions = {}) {
10
+ const dryRun = options.dryRun === true;
11
+ const cwd = await resolvePrismaAgentSetupCwd({
12
+ cwd: runOptions.cwd ?? context.runtime.cwd,
13
+ signal: context.runtime.signal
14
+ });
15
+ const skills = await installSkills(context, {
16
+ command: await buildSkillsInstallCommand(context, options, cwd),
17
+ cwd,
18
+ dryRun
19
+ });
20
+ const nextSteps = await resolveAgentInstallNextSteps(context, {
21
+ cwd,
22
+ dryRun,
23
+ global: options.global === true
24
+ });
25
+ return {
26
+ command: `agent.${operation}`,
27
+ result: {
28
+ operation,
29
+ skills
30
+ },
31
+ warnings: [],
32
+ nextSteps
33
+ };
34
+ }
35
+ async function resolveAgentInstallNextSteps(context, options) {
36
+ if (options.dryRun) return [];
37
+ return [`Run ${await resolvePrismaCliPackageCommand({
38
+ cwd: options.cwd,
39
+ signal: context.runtime.signal,
40
+ args: options.global ? [...PRISMA_AGENT_STATUS_ARGS, "--global"] : PRISMA_AGENT_STATUS_ARGS
41
+ })} to verify the installed Prisma skills.`];
42
+ }
43
+ async function runAgentStatus(context, options = {}) {
44
+ const statusScope = options.global ? "global" : "project";
45
+ const cwd = await resolvePrismaAgentSetupCwd({
46
+ cwd: context.runtime.cwd,
47
+ signal: context.runtime.signal
48
+ });
49
+ const status = await readPrismaAgentSetupStatus({
50
+ cwd,
51
+ stateStore: context.stateStore,
52
+ signal: context.runtime.signal
53
+ });
54
+ const installCommand = await resolvePrismaCliPackageCommand({
55
+ cwd,
56
+ signal: context.runtime.signal,
57
+ args: options.global ? [...PRISMA_AGENT_INSTALL_ARGS, "--global"] : PRISMA_AGENT_INSTALL_ARGS
58
+ });
59
+ const skillsList = await listInstalledPrismaSkills(context, cwd, statusScope);
60
+ const skillsInstalled = skillsList.status === "ok" ? skillsList.skills.length > 0 : statusScope === "project" && status.skillsInstalled;
61
+ const warnings = skillsList.status === "ok" ? [] : [statusScope === "project" ? `Could not read installed skills with ${formatShellCommand(skillsList.command)}: ${skillsList.message}. Falling back to ${status.skillsLockPath}.` : `Could not read globally installed skills with ${formatShellCommand(skillsList.command)}: ${skillsList.message}.`];
62
+ const statusSource = resolveStatusSource(skillsList, statusScope);
63
+ return {
64
+ command: "agent.status",
65
+ result: {
66
+ skills: skillsList.status === "ok" ? skillsList.skills : [],
67
+ skillsListCommand: skillsList.command,
68
+ statusScope,
69
+ skillsLockPath: status.skillsLockPath,
70
+ skillsLockInstalled: status.skillsInstalled,
71
+ skillsInstalled,
72
+ statusSource,
73
+ promptDismissedAt: status.promptDismissedAt
74
+ },
75
+ warnings,
76
+ nextSteps: skillsInstalled ? [] : [`Run ${installCommand} to install or refresh Prisma skills.`]
77
+ };
78
+ }
79
+ async function buildSkillsInstallCommand(context, options, cwd) {
80
+ const command = [
81
+ ...await resolveSkillsPackageRunner({
82
+ cwd,
83
+ signal: context.runtime.signal
84
+ }),
85
+ SKILLS_CLI_PACKAGE,
86
+ "add",
87
+ PRISMA_SKILLS_SOURCE
88
+ ];
89
+ const skills = options.skill && options.skill.length > 0 ? options.skill : DEFAULT_PRISMA_AGENT_SKILLS;
90
+ const agents = resolveTargetAgents(options);
91
+ for (const skill of skills) command.push("--skill", skill);
92
+ for (const agent of agents) command.push("--agent", agent);
93
+ if (options.global) command.push("--global");
94
+ if (options.copy || process.platform === "win32") command.push("--copy");
95
+ command.push("--yes");
96
+ return command;
97
+ }
98
+ function resolveTargetAgents(options) {
99
+ if (options.allAgents) return ["*"];
100
+ if (options.agent && options.agent.length > 0) return options.agent;
101
+ return DEFAULT_PRISMA_AGENT_TARGETS;
102
+ }
103
+ async function installSkills(context, options) {
104
+ if (options.dryRun) return {
105
+ status: "would-install",
106
+ command: options.command
107
+ };
108
+ await runChildProcess(context, options.command, options.cwd);
109
+ return {
110
+ status: "installed",
111
+ command: options.command
112
+ };
113
+ }
114
+ async function listInstalledPrismaSkills(context, cwd, scope) {
115
+ const command = [
116
+ ...await resolveSkillsPackageRunner({
117
+ cwd,
118
+ signal: context.runtime.signal
119
+ }),
120
+ SKILLS_CLI_PACKAGE,
121
+ "list",
122
+ ...scope === "global" ? ["-g"] : [],
123
+ "--json"
124
+ ];
125
+ try {
126
+ const { stdout } = await runChildProcessCapture(context, command, cwd);
127
+ return {
128
+ status: "ok",
129
+ command,
130
+ skills: parseSkillsListOutput(stdout).filter((skill) => isPrismaSkillName(skill.name))
131
+ };
132
+ } catch (error) {
133
+ if (isAbortError(error) || context.runtime.signal.aborted) throw error;
134
+ return {
135
+ status: "failed",
136
+ command,
137
+ message: error instanceof Error ? error.message : String(error)
138
+ };
139
+ }
140
+ }
141
+ async function runChildProcess(context, command, cwd) {
142
+ const [executable, args] = splitCommand(command);
143
+ try {
144
+ await execa(executable, args, {
145
+ cwd,
146
+ env: context.runtime.env,
147
+ cancelSignal: context.runtime.signal,
148
+ stdin: "ignore"
149
+ });
150
+ } catch (error) {
151
+ if (isAbortError(error)) throw error;
152
+ throw skillsInstallFailed(command, exitCodeFromError(error), error);
153
+ }
154
+ }
155
+ async function runChildProcessCapture(context, command, cwd) {
156
+ const [executable, args] = splitCommand(command);
157
+ const result = await execa(executable, args, {
158
+ cwd,
159
+ env: context.runtime.env,
160
+ cancelSignal: context.runtime.signal,
161
+ stdin: "ignore"
162
+ });
163
+ return {
164
+ stdout: result.stdout ?? "",
165
+ stderr: result.stderr ?? ""
166
+ };
167
+ }
168
+ function splitCommand(command) {
169
+ const [executable, ...args] = command;
170
+ if (!executable) throw new Error("Cannot run an empty command.");
171
+ return [executable, args];
172
+ }
173
+ function isAbortError(error) {
174
+ return error instanceof Error && error.name === "AbortError" || isObject(error) && error.isCanceled === true;
175
+ }
176
+ function exitCodeFromError(error) {
177
+ if (!isObject(error) || typeof error.exitCode !== "number") return null;
178
+ return error.exitCode;
179
+ }
180
+ function isObject(value) {
181
+ return typeof value === "object" && value !== null;
182
+ }
183
+ function resolveStatusSource(skillsList, statusScope) {
184
+ if (skillsList.status === "ok") return "skills-cli";
185
+ return statusScope === "project" ? "skills-lock" : "unavailable";
186
+ }
187
+ function parseSkillsListOutput(output) {
188
+ const parsed = JSON.parse(output);
189
+ if (!Array.isArray(parsed)) throw new Error("skills list did not return a JSON array");
190
+ return parsed.flatMap((item) => {
191
+ const skill = parseInstalledSkill(item);
192
+ return skill ? [skill] : [];
193
+ });
194
+ }
195
+ function parseInstalledSkill(value) {
196
+ if (typeof value !== "object" || value === null) return null;
197
+ const candidate = value;
198
+ if (typeof candidate.name !== "string" || typeof candidate.path !== "string" || typeof candidate.scope !== "string" || !Array.isArray(candidate.agents)) return null;
199
+ return {
200
+ name: candidate.name,
201
+ path: candidate.path,
202
+ scope: candidate.scope,
203
+ agents: candidate.agents.filter((agent) => typeof agent === "string")
204
+ };
205
+ }
206
+ function isPrismaSkillName(name) {
207
+ return name === "prisma" || name.startsWith("prisma-");
208
+ }
209
+ function skillsInstallFailed(command, code, error) {
210
+ const commandText = formatShellCommand(command);
211
+ return new CliError({
212
+ code: "AGENT_SKILLS_INSTALL_FAILED",
213
+ domain: "cli",
214
+ summary: "Prisma skills install failed",
215
+ why: `The skills installer exited with code ${code ?? "unknown"}.`,
216
+ fix: "Run the command below to retry the installer directly.",
217
+ debug: formatErrorDebug(error),
218
+ exitCode: 1,
219
+ nextSteps: [commandText]
220
+ });
221
+ }
222
+ function formatErrorDebug(error) {
223
+ if (error instanceof Error) return error.stack ?? error.message;
224
+ if (error === void 0) return;
225
+ return String(error);
226
+ }
227
+ //#endregion
228
+ export { runAgentInstall, runAgentStatus };
@@ -0,0 +1,54 @@
1
+ import { CliError, authRequiredError } from "../shell/errors.js";
2
+ //#region src/controllers/app-env-api.ts
3
+ async function findVariableByNaturalKey(client, projectId, key, resolved, signal) {
4
+ const { data, error, response } = await client.GET("/v1/environment-variables", {
5
+ params: { query: {
6
+ projectId,
7
+ class: resolved.apiTarget.class,
8
+ key
9
+ } },
10
+ signal
11
+ });
12
+ if (error || !data) throw apiCallError(`Failed to look up ${key}`, response, error);
13
+ return data.data.filter((row) => rowMatchesExactScope(row, resolved))[0] ?? null;
14
+ }
15
+ function toMetadata(row, requestedScope) {
16
+ const rowScope = row.branchId === null ? {
17
+ kind: "role",
18
+ role: row.class
19
+ } : requestedScope;
20
+ return {
21
+ id: row.id,
22
+ key: row.key,
23
+ scope: rowScope,
24
+ source: formatDescriptorLabel(rowScope),
25
+ isManagedBySystem: row.isManagedBySystem,
26
+ updatedAt: row.updatedAt
27
+ };
28
+ }
29
+ function rowMatchesExactScope(row, resolved) {
30
+ return row.class === resolved.apiTarget.class && row.branchId === resolved.apiTarget.branchId;
31
+ }
32
+ function apiCallError(summary, response, error) {
33
+ const status = response?.status ?? 0;
34
+ const apiCode = error?.error?.code;
35
+ const apiMessage = error?.error?.message;
36
+ const apiHint = error?.error?.hint;
37
+ if (status === 401 || status === 403) return authRequiredError(["prisma auth login"]);
38
+ return new CliError({
39
+ code: apiCode ?? "ENV_API_ERROR",
40
+ domain: "app",
41
+ summary,
42
+ why: apiMessage ?? `The Management API returned status ${status || "unknown"}.`,
43
+ fix: apiHint ?? "Re-run with --trace for the underlying API response details.",
44
+ exitCode: 1,
45
+ nextSteps: []
46
+ });
47
+ }
48
+ function formatDescriptorLabel(scope) {
49
+ if (scope.kind === "role") return scope.role ?? "unknown";
50
+ if (scope.kind === "overview") return "overview";
51
+ return `branch:${scope.branchName ?? scope.branchId ?? "unknown"}`;
52
+ }
53
+ //#endregion
54
+ export { apiCallError, findVariableByNaturalKey, toMetadata };