@prisma/cli 3.0.0-beta.17 → 3.0.0-beta.18
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/dist/adapters/local-state.js +14 -3
- package/dist/adapters/token-storage.js +1 -1
- package/dist/cli2.js +4 -2
- package/dist/commands/agent/index.js +60 -0
- package/dist/commands/app/index.js +5 -3
- package/dist/commands/auth/index.js +1 -1
- package/dist/commands/git/index.js +1 -1
- package/dist/commands/project/index.js +1 -1
- package/dist/controllers/agent.js +228 -0
- package/dist/controllers/app.js +156 -72
- package/dist/controllers/auth.js +38 -3
- package/dist/controllers/project.js +2 -2
- package/dist/controllers/select-prompt-port.js +1 -0
- package/dist/lib/agent/cli-command.js +17 -0
- package/dist/lib/agent/constants.js +12 -0
- package/dist/lib/agent/package-manager.js +99 -0
- package/dist/lib/agent/setup-status.js +83 -0
- package/dist/lib/app/branch-database-deploy.js +3 -2
- package/dist/lib/app/branch-database.js +2 -1
- package/dist/lib/app/build-settings.js +1 -1
- package/dist/lib/app/build.js +2 -2
- package/dist/lib/app/bun-project.js +1 -1
- package/dist/lib/app/compute-config.js +27 -29
- package/dist/lib/app/deploy-plan.js +1 -0
- package/dist/lib/app/env-file.js +1 -1
- package/dist/lib/app/local-dev.js +1 -1
- package/dist/lib/app/production-deploy-gate.js +2 -1
- package/dist/lib/auth/login.js +1 -1
- package/dist/lib/git/local-branch.js +1 -1
- package/dist/lib/project/interactive-setup.js +1 -0
- package/dist/lib/project/local-pin.js +1 -1
- package/dist/lib/project/resolution.js +2 -2
- package/dist/lib/project/setup.js +1 -1
- package/dist/presenters/agent.js +74 -0
- package/dist/presenters/auth.js +1 -1
- package/dist/presenters/project.js +1 -1
- package/dist/shell/cli-command.js +12 -0
- package/dist/shell/command-arguments.js +7 -1
- package/dist/shell/command-meta.js +72 -0
- package/dist/shell/command-runner.js +1 -1
- package/dist/shell/help.js +6 -5
- package/dist/shell/prompt.js +7 -3
- package/dist/shell/runtime.js +2 -2
- package/dist/shell/update-check.js +2 -2
- package/package.json +3 -2
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { PRISMA_SKILLS_LOCK_FILENAME } from "./constants.js";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { readFile, stat } from "node:fs/promises";
|
|
4
|
+
import { findComputeConfigDir } from "@prisma/compute-sdk/config";
|
|
5
|
+
//#region src/lib/agent/setup-status.ts
|
|
6
|
+
async function readPrismaAgentSetupStatus(options) {
|
|
7
|
+
const setupCwd = await resolvePrismaAgentSetupCwd(options);
|
|
8
|
+
const skillsLockPath = path.join(setupCwd, PRISMA_SKILLS_LOCK_FILENAME);
|
|
9
|
+
const [skillsInstalled, promptDismissedAt] = await Promise.all([hasPrismaSkillsLock(skillsLockPath, options.signal, options.requiredSkill), options.stateStore?.readAgentSetupPromptDismissedAt() ?? null]);
|
|
10
|
+
return {
|
|
11
|
+
skillsLockPath: path.basename(skillsLockPath),
|
|
12
|
+
skillsInstalled,
|
|
13
|
+
promptDismissedAt
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
async function resolvePrismaAgentSetupCwd(options) {
|
|
17
|
+
options.signal.throwIfAborted();
|
|
18
|
+
const configDir = await findComputeConfigDir(options.cwd, options.signal);
|
|
19
|
+
options.signal.throwIfAborted();
|
|
20
|
+
return configDir ?? options.cwd;
|
|
21
|
+
}
|
|
22
|
+
function isPrismaAgentSetupComplete(status) {
|
|
23
|
+
return status.skillsInstalled;
|
|
24
|
+
}
|
|
25
|
+
function shouldOfferPrismaAgentSetup(status) {
|
|
26
|
+
return !isPrismaAgentSetupComplete(status) && !status.promptDismissedAt;
|
|
27
|
+
}
|
|
28
|
+
async function isLikelyProjectDirectory(options) {
|
|
29
|
+
return (await Promise.all([
|
|
30
|
+
"package.json",
|
|
31
|
+
"prisma.compute.ts",
|
|
32
|
+
"prisma.config.ts",
|
|
33
|
+
".git"
|
|
34
|
+
].map((fileName) => pathExists(path.join(options.cwd, fileName), options.signal)))).some(Boolean);
|
|
35
|
+
}
|
|
36
|
+
async function hasPrismaSkillsLock(filePath, signal, requiredSkill) {
|
|
37
|
+
try {
|
|
38
|
+
const raw = await readFile(filePath, {
|
|
39
|
+
encoding: "utf8",
|
|
40
|
+
signal
|
|
41
|
+
});
|
|
42
|
+
return hasPrismaSkillsLockEntry(JSON.parse(raw), requiredSkill);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
if (isNotFoundError(error) || error instanceof SyntaxError) return false;
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function hasPrismaSkillsLockEntry(value, requiredSkill) {
|
|
49
|
+
if (!isRecord(value)) return false;
|
|
50
|
+
if (requiredSkill) return skillLockEntryUsesPrismaSource(readSkillLockEntries(value)[requiredSkill]);
|
|
51
|
+
if (readLegacySources(value).includes("prisma/skills")) return true;
|
|
52
|
+
return Object.values(readSkillLockEntries(value)).some(skillLockEntryUsesPrismaSource);
|
|
53
|
+
}
|
|
54
|
+
function readLegacySources(value) {
|
|
55
|
+
return Array.isArray(value.sources) ? value.sources.filter((source) => typeof source === "string") : [];
|
|
56
|
+
}
|
|
57
|
+
function readSkillLockEntries(value) {
|
|
58
|
+
return isRecord(value.skills) ? value.skills : {};
|
|
59
|
+
}
|
|
60
|
+
function skillLockEntryUsesPrismaSource(value) {
|
|
61
|
+
return isRecord(value) && value.source === "prisma/skills";
|
|
62
|
+
}
|
|
63
|
+
function isRecord(value) {
|
|
64
|
+
return typeof value === "object" && value !== null;
|
|
65
|
+
}
|
|
66
|
+
async function pathExists(filePath, signal) {
|
|
67
|
+
signal.throwIfAborted();
|
|
68
|
+
try {
|
|
69
|
+
await stat(filePath);
|
|
70
|
+
signal.throwIfAborted();
|
|
71
|
+
return true;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
if (signal.aborted) throw error;
|
|
74
|
+
if (isNotFoundError(error)) return false;
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function isNotFoundError(error) {
|
|
79
|
+
const code = error.code;
|
|
80
|
+
return code === "ENOENT" || code === "ENOTDIR";
|
|
81
|
+
}
|
|
82
|
+
//#endregion
|
|
83
|
+
export { isLikelyProjectDirectory, readPrismaAgentSetupStatus, resolvePrismaAgentSetupCwd, shouldOfferPrismaAgentSetup };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { formatCommandArgument } from "../../shell/command-arguments.js";
|
|
1
2
|
import { CliError, usageError } from "../../shell/errors.js";
|
|
2
|
-
import { confirmPrompt } from "../../shell/prompt.js";
|
|
3
3
|
import { renderSummaryLine } from "../../shell/ui.js";
|
|
4
4
|
import { canPrompt } from "../../shell/runtime.js";
|
|
5
|
-
import {
|
|
5
|
+
import { confirmPrompt } from "../../shell/prompt.js";
|
|
6
6
|
import "../project/setup.js";
|
|
7
7
|
import { hasBranchDatabaseSignal, inspectBranchDatabaseSignal } from "./branch-database.js";
|
|
8
8
|
import path from "node:path";
|
|
@@ -51,6 +51,7 @@ async function maybeSetupBranchDatabase(context, provider, projectId, branch, op
|
|
|
51
51
|
if (!await confirmPrompt({
|
|
52
52
|
input: context.runtime.stdin,
|
|
53
53
|
output: context.output.stderr,
|
|
54
|
+
signal: context.runtime.signal,
|
|
54
55
|
message: databasePromptMessage(branch),
|
|
55
56
|
initialValue: false
|
|
56
57
|
})) return emptyBranchDatabaseSetupOutcome();
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { access, readFile, readdir, stat } from "node:fs/promises";
|
|
2
1
|
import path from "node:path";
|
|
2
|
+
import { access, readFile, readdir, stat } from "node:fs/promises";
|
|
3
3
|
//#region src/lib/app/branch-database.ts
|
|
4
4
|
const SKIPPED_DIRECTORIES = new Set([
|
|
5
5
|
".git",
|
|
6
|
+
".agents",
|
|
6
7
|
".next",
|
|
7
8
|
".nuxt",
|
|
8
9
|
".output",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
1
|
import path from "node:path";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { resolveBuildSettings, resolveConfiguredBuildSettings } from "@prisma/compute-sdk";
|
|
4
4
|
//#region src/lib/app/build-settings.ts
|
|
5
5
|
/** Legacy build-settings file: no longer read or written, only detected for migration. */
|
package/dist/lib/app/build.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./build-settings.js";
|
|
2
|
-
import { FRAMEWORKS } from "@prisma/compute-sdk/config";
|
|
3
|
-
import "node:fs/promises";
|
|
4
2
|
import "node:path";
|
|
3
|
+
import "node:fs/promises";
|
|
4
|
+
import { FRAMEWORKS } from "@prisma/compute-sdk/config";
|
|
5
5
|
import { normalizeArtifactSymlinks, resolveBuildStrategy } from "@prisma/compute-sdk";
|
|
6
6
|
//#region src/lib/app/build.ts
|
|
7
7
|
const RESOLVED_APP_BUILD_TYPES = [...frameworkBuildTypesByLastOccurrence()];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { access, readFile } from "node:fs/promises";
|
|
2
1
|
import path from "node:path";
|
|
2
|
+
import { access, readFile } from "node:fs/promises";
|
|
3
3
|
//#region src/lib/app/bun-project.ts
|
|
4
4
|
async function readBunPackageJson(appPath, signal) {
|
|
5
5
|
const packageJsonPath = path.join(appPath, "package.json");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CliError } from "../../shell/errors.js";
|
|
2
|
-
import { COMPUTE_CONFIG_FILENAME, COMPUTE_CONFIG_FILENAME as COMPUTE_CONFIG_FILENAME$1, ComputeConfigTargetRequiredError, computeTargetAppDir, frameworkByKey, inferComputeTargetFromCwd, loadComputeConfig, selectComputeDeployTarget } from "@prisma/compute-sdk/config";
|
|
3
2
|
import path from "node:path";
|
|
3
|
+
import { COMPUTE_CONFIG_FILENAME, COMPUTE_CONFIG_FILENAME as COMPUTE_CONFIG_FILENAME$1, ComputeConfigTargetRequiredError, computeTargetAppDir, frameworkByKey, inferComputeTargetFromCwd, loadComputeConfig, selectComputeDeployTarget } from "@prisma/compute-sdk/config";
|
|
4
4
|
import { matchError } from "better-result";
|
|
5
5
|
//#region src/lib/app/compute-config.ts
|
|
6
6
|
/**
|
|
@@ -18,47 +18,45 @@ function computeFrameworkToBuildType(framework) {
|
|
|
18
18
|
function mergeComputeDeployInputs(options) {
|
|
19
19
|
const { cli, target, configFilename } = options;
|
|
20
20
|
const configAnnotation = `set by ${configFilename}`;
|
|
21
|
-
const framework = cli.framework
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
value: target.framework,
|
|
26
|
-
annotation: configAnnotation
|
|
27
|
-
} : void 0;
|
|
28
|
-
const entrypoint = cli.entrypoint ? {
|
|
29
|
-
value: cli.entrypoint,
|
|
30
|
-
annotation: "set by --entry"
|
|
31
|
-
} : target?.entry ? {
|
|
32
|
-
value: target.entry,
|
|
33
|
-
annotation: configAnnotation
|
|
34
|
-
} : void 0;
|
|
35
|
-
const httpPort = cli.httpPort ? {
|
|
36
|
-
value: cli.httpPort,
|
|
37
|
-
annotation: "set by --http-port"
|
|
38
|
-
} : target?.httpPort ? {
|
|
39
|
-
value: String(target.httpPort),
|
|
40
|
-
annotation: configAnnotation
|
|
41
|
-
} : void 0;
|
|
21
|
+
const framework = mergeStringInput(cli.framework, "set by --framework", target?.framework ?? void 0, configAnnotation);
|
|
22
|
+
const entrypoint = mergeStringInput(cli.entrypoint, "set by --entry", target?.entry ?? void 0, configAnnotation);
|
|
23
|
+
const httpPort = mergeStringInput(cli.httpPort, "set by --http-port", target?.httpPort ? String(target.httpPort) : void 0, configAnnotation);
|
|
24
|
+
const region = mergeStringInput(cli.region, "set by --region", target?.region ?? void 0, configAnnotation);
|
|
42
25
|
const cliEnvInputs = cli.envInputs && cli.envInputs.length > 0 ? cli.envInputs : void 0;
|
|
43
26
|
const configEnvInputs = target && target.envInputs.length > 0 ? target.envInputs : void 0;
|
|
44
27
|
const envInputs = cliEnvInputs ?? configEnvInputs;
|
|
45
|
-
const configAppName = target
|
|
46
|
-
value: target.name,
|
|
47
|
-
annotation: configAnnotation
|
|
48
|
-
} : target?.key ? {
|
|
49
|
-
value: target.key,
|
|
50
|
-
annotation: configAnnotation
|
|
51
|
-
} : void 0;
|
|
28
|
+
const configAppName = readConfigAppName(target, configAnnotation);
|
|
52
29
|
return {
|
|
53
30
|
framework,
|
|
54
31
|
entrypoint,
|
|
55
32
|
httpPort,
|
|
33
|
+
region,
|
|
56
34
|
envInputs,
|
|
57
35
|
envInputsFromConfig: !cliEnvInputs && configEnvInputs !== void 0,
|
|
58
36
|
configAppName,
|
|
59
37
|
appRoot: target?.root ?? void 0
|
|
60
38
|
};
|
|
61
39
|
}
|
|
40
|
+
function mergeStringInput(cliValue, cliAnnotation, configValue, configAnnotation) {
|
|
41
|
+
if (cliValue !== void 0) return {
|
|
42
|
+
value: cliValue,
|
|
43
|
+
annotation: cliAnnotation
|
|
44
|
+
};
|
|
45
|
+
if (configValue) return {
|
|
46
|
+
value: configValue,
|
|
47
|
+
annotation: configAnnotation
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function readConfigAppName(target, configAnnotation) {
|
|
51
|
+
if (target?.name) return {
|
|
52
|
+
value: target.name,
|
|
53
|
+
annotation: configAnnotation
|
|
54
|
+
};
|
|
55
|
+
if (target?.key) return {
|
|
56
|
+
value: target.key,
|
|
57
|
+
annotation: configAnnotation
|
|
58
|
+
};
|
|
59
|
+
}
|
|
62
60
|
/**
|
|
63
61
|
* Merges CLI inputs for the local `app build` and `app run` commands with a
|
|
64
62
|
* selected config target. Explicit flags win; `--build-type auto` is the
|
|
@@ -30,6 +30,7 @@ function perAppInputsForDeployAll(inputs) {
|
|
|
30
30
|
["--framework", inputs.framework],
|
|
31
31
|
["--entry", inputs.entrypoint],
|
|
32
32
|
["--http-port", inputs.httpPort],
|
|
33
|
+
["--region", inputs.region],
|
|
33
34
|
["--env", inputs.envAssignments?.length ? inputs.envAssignments : void 0],
|
|
34
35
|
[inputs.appIdEnvVar.name, inputs.appIdEnvVar.value]
|
|
35
36
|
].filter(([, value]) => value !== void 0).map(([flag]) => flag);
|
package/dist/lib/app/env-file.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { usageError } from "../../shell/errors.js";
|
|
2
2
|
import { validateKey } from "./env-config.js";
|
|
3
|
-
import { readFile } from "node:fs/promises";
|
|
4
3
|
import path from "node:path";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
5
|
import { parse } from "dotenv";
|
|
6
6
|
//#region src/lib/app/env-file.ts
|
|
7
7
|
const ASSIGNMENT_KEY_PATTERN = /^\s*(?:export\s+)?([^#=\s]+)\s*=/;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CliError } from "../../shell/errors.js";
|
|
2
|
-
import { confirmPrompt } from "../../shell/prompt.js";
|
|
3
2
|
import { canPrompt } from "../../shell/runtime.js";
|
|
3
|
+
import { confirmPrompt } from "../../shell/prompt.js";
|
|
4
4
|
//#region src/lib/app/production-deploy-gate.ts
|
|
5
5
|
async function enforceProductionDeployGate(context, provider, options) {
|
|
6
6
|
if (options.branchKind !== "production") return { firstProductionDeploy: false };
|
|
@@ -25,6 +25,7 @@ async function enforceProductionDeployGate(context, provider, options) {
|
|
|
25
25
|
if (!await confirmPrompt({
|
|
26
26
|
input: context.runtime.stdin,
|
|
27
27
|
output: context.output.stderr,
|
|
28
|
+
signal: context.runtime.signal,
|
|
28
29
|
message: "Deploy to production?",
|
|
29
30
|
initialValue: false
|
|
30
31
|
})) throw productionDeployCancelledError();
|
package/dist/lib/auth/login.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getApiBaseUrl } from "./client.js";
|
|
2
2
|
import { FileTokenStorage } from "../../adapters/token-storage.js";
|
|
3
|
-
import open from "open";
|
|
4
3
|
import { AuthError, createManagementApiSdk } from "@prisma/management-api-sdk";
|
|
4
|
+
import open from "open";
|
|
5
5
|
import events from "node:events";
|
|
6
6
|
import http from "node:http";
|
|
7
7
|
import readline from "node:readline/promises";
|
|
@@ -40,6 +40,7 @@ async function promptForProjectSetupChoice(options) {
|
|
|
40
40
|
const rawName = await textPrompt({
|
|
41
41
|
input: options.context.runtime.stdin,
|
|
42
42
|
output: options.context.runtime.stderr,
|
|
43
|
+
signal: options.context.runtime.signal,
|
|
43
44
|
message: "Project name",
|
|
44
45
|
placeholder: suggestedName.name,
|
|
45
46
|
validate: (value) => validateProjectSetupNameText(value, suggestedName.name)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
2
1
|
import path from "node:path";
|
|
2
|
+
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
3
3
|
import { Result, TaggedError, UnhandledException } from "better-result";
|
|
4
4
|
//#region src/lib/project/local-pin.ts
|
|
5
5
|
const LOCAL_RESOLUTION_PIN_RELATIVE_PATH = ".prisma/local.json";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { formatCommandArgument } from "../../shell/command-arguments.js";
|
|
1
2
|
import { CliError } from "../../shell/errors.js";
|
|
2
3
|
import { LOCAL_RESOLUTION_PIN_RELATIVE_PATH, readLocalResolutionPin } from "./local-pin.js";
|
|
3
|
-
import { formatCommandArgument } from "../../shell/command-arguments.js";
|
|
4
|
-
import { readFile } from "node:fs/promises";
|
|
5
4
|
import path from "node:path";
|
|
5
|
+
import { readFile } from "node:fs/promises";
|
|
6
6
|
import { Result, TaggedError, matchError } from "better-result";
|
|
7
7
|
//#region src/lib/project/resolution.ts
|
|
8
8
|
var ProjectNotFoundError = class extends TaggedError("ProjectNotFoundError")() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import "../../shell/command-arguments.js";
|
|
1
2
|
import { CliError, usageError } from "../../shell/errors.js";
|
|
2
3
|
import { shortenHomePath } from "../fs/home-path.js";
|
|
3
4
|
import { LOCAL_RESOLUTION_PIN_RELATIVE_PATH, ensureLocalResolutionPinGitignore, writeLocalResolutionPin } from "./local-pin.js";
|
|
4
|
-
import "../../shell/command-arguments.js";
|
|
5
5
|
import { projectAmbiguousError, projectNotFoundError } from "./resolution.js";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { Result, matchError } from "better-result";
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { formatShellCommand } from "../shell/command-arguments.js";
|
|
2
|
+
import { formatDescriptorLabel } from "../shell/command-meta.js";
|
|
3
|
+
import { renderSummaryLine } from "../shell/ui.js";
|
|
4
|
+
//#region src/presenters/agent.ts
|
|
5
|
+
function renderAgentInstall(context, descriptor, result) {
|
|
6
|
+
const ui = context.ui;
|
|
7
|
+
const rail = ui.dim("│");
|
|
8
|
+
return [
|
|
9
|
+
renderSummaryLine(ui, "success", `${formatDescriptorLabel(descriptor)} → ${operationSummary(result)} Prisma skills.`),
|
|
10
|
+
"",
|
|
11
|
+
`${rail} ${ui.accent("skills:")} ${result.skills.status.replace("-", " ")}`,
|
|
12
|
+
`${rail} ${ui.dim(formatShellCommand(result.skills.command))}`
|
|
13
|
+
];
|
|
14
|
+
}
|
|
15
|
+
function renderAgentStatus(context, descriptor, result) {
|
|
16
|
+
const ui = context.ui;
|
|
17
|
+
const rail = ui.dim("│");
|
|
18
|
+
return [
|
|
19
|
+
`${ui.strong(formatDescriptorLabel(descriptor))} ${ui.dim("→")} ${ui.dim(`Checking ${result.statusScope} Prisma skills.`)}`,
|
|
20
|
+
"",
|
|
21
|
+
`${rail} ${ui.accent("skills:")} ${result.skillsInstalled ? "installed" : "not found"}`,
|
|
22
|
+
...renderInstalledSkills(context, result.skills),
|
|
23
|
+
`${rail}`,
|
|
24
|
+
`${rail} ${ui.accent("source:")} ${formatStatusSource(result)}`,
|
|
25
|
+
`${rail} ${ui.dim(formatShellCommand(result.skillsListCommand))}`,
|
|
26
|
+
...renderProjectStatusDetails(context, result)
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
function serializeAgentInstall(result) {
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
function serializeAgentStatus(result) {
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
function formatSetupPromptStatus(result) {
|
|
36
|
+
if (result.skillsInstalled) return "not needed";
|
|
37
|
+
if (result.promptDismissedAt) return `dismissed ${result.promptDismissedAt}`;
|
|
38
|
+
return "active";
|
|
39
|
+
}
|
|
40
|
+
function formatStatusSource(result) {
|
|
41
|
+
if (result.statusSource === "skills-cli") return result.statusScope === "global" ? "skills list -g --json" : "skills list --json";
|
|
42
|
+
if (result.statusSource === "skills-lock") return result.skillsLockPath;
|
|
43
|
+
return "unavailable";
|
|
44
|
+
}
|
|
45
|
+
function renderProjectStatusDetails(context, result) {
|
|
46
|
+
if (result.statusScope !== "project") return [];
|
|
47
|
+
const ui = context.ui;
|
|
48
|
+
const rail = ui.dim("│");
|
|
49
|
+
return [
|
|
50
|
+
`${rail}`,
|
|
51
|
+
`${rail} ${ui.accent("skills lock:")} ${result.skillsLockInstalled ? "installed" : "not found"}`,
|
|
52
|
+
`${rail} ${ui.dim(result.skillsLockPath)}`,
|
|
53
|
+
`${rail}`,
|
|
54
|
+
`${rail} ${ui.accent("setup prompt:")} ${formatSetupPromptStatus(result)}`
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
function renderInstalledSkills(context, skills) {
|
|
58
|
+
const ui = context.ui;
|
|
59
|
+
const rail = ui.dim("│");
|
|
60
|
+
if (skills.length === 0) return [`${rail} ${ui.dim("No Prisma skills reported.")}`];
|
|
61
|
+
return skills.map((skill) => {
|
|
62
|
+
const agents = skill.agents.length > 0 ? skill.agents.join(", ") : "no agents reported";
|
|
63
|
+
return `${rail} ${skill.name} ${ui.dim(`${skill.scope}; ${agents}`)}`;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function operationSummary(result) {
|
|
67
|
+
if (result.skills.status === "would-install") return "Would install";
|
|
68
|
+
return operationLabel(result.operation);
|
|
69
|
+
}
|
|
70
|
+
function operationLabel(operation) {
|
|
71
|
+
return operation === "update" ? "Updated" : "Installed";
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
export { renderAgentInstall, renderAgentStatus, serializeAgentInstall, serializeAgentStatus };
|
package/dist/presenters/auth.js
CHANGED
|
@@ -25,7 +25,7 @@ function renderAuthSuccess(context, descriptor, command, result) {
|
|
|
25
25
|
context: rows,
|
|
26
26
|
operationDescription: "Applying authentication session changes",
|
|
27
27
|
operationCount: 1,
|
|
28
|
-
details: ["Session stored in local CLI state."]
|
|
28
|
+
details: ["Session stored in local CLI state.", ...result.agentSetupTip ? [`Install Prisma skills for this project with ${result.agentSetupTip.command}.`] : []]
|
|
29
29
|
}, context.ui);
|
|
30
30
|
}
|
|
31
31
|
if (command === "auth.logout") return renderMutate({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { formatCommandArgument } from "../shell/command-arguments.js";
|
|
1
2
|
import { formatDescriptorLabel } from "../shell/command-meta.js";
|
|
2
3
|
import { padDisplay, renderNextSteps, renderSummaryLine, renderVerboseBlock } from "../shell/ui.js";
|
|
3
4
|
import { shortenHomePath } from "../lib/fs/home-path.js";
|
|
4
|
-
import { formatCommandArgument } from "../shell/command-arguments.js";
|
|
5
5
|
import { renderMutate, renderShow, serializeList } from "../output/patterns.js";
|
|
6
6
|
import { renderResolvedProjectContextBlock } from "./verbose-context.js";
|
|
7
7
|
import stringWidth from "string-width";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const PRISMA_CLI_PACKAGE_SPEC = `@prisma/cli@latest`;
|
|
2
|
+
const DEFAULT_PRISMA_CLI_PACKAGE_RUNNER = ["npx", "-y"];
|
|
3
|
+
const PRISMA_CLI_BINARY = "prisma-cli";
|
|
4
|
+
function formatPrismaCliCommand(args, options = {}) {
|
|
5
|
+
return [...getPrismaCliCommandPrefix(options), ...args].join(" ");
|
|
6
|
+
}
|
|
7
|
+
function getPrismaCliCommandPrefix({ invocation = "package", packageRunner = DEFAULT_PRISMA_CLI_PACKAGE_RUNNER }) {
|
|
8
|
+
if (invocation === "binary") return [PRISMA_CLI_BINARY];
|
|
9
|
+
return [...packageRunner, PRISMA_CLI_PACKAGE_SPEC];
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { formatPrismaCliCommand };
|
|
@@ -2,5 +2,11 @@
|
|
|
2
2
|
function formatCommandArgument(value) {
|
|
3
3
|
return /^[A-Za-z0-9._/-]+$/.test(value) && !value.startsWith("-") ? value : `'${value.replace(/'/g, "'\\''")}'`;
|
|
4
4
|
}
|
|
5
|
+
function formatShellCommand(command) {
|
|
6
|
+
return command.map(formatShellCommandWord).join(" ");
|
|
7
|
+
}
|
|
8
|
+
function formatShellCommandWord(value) {
|
|
9
|
+
return /^[A-Za-z0-9_./:@=-]+$/.test(value) ? value : `'${value.replace(/'/g, "'\\''")}'`;
|
|
10
|
+
}
|
|
5
11
|
//#endregion
|
|
6
|
-
export { formatCommandArgument };
|
|
12
|
+
export { formatCommandArgument, formatShellCommand };
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
import { resolvePrismaCliPackageCommandFormatterSync } from "../lib/agent/cli-command.js";
|
|
2
|
+
import { PRISMA_AGENT_INSTALL_ARGS, PRISMA_AGENT_STATUS_ARGS, PRISMA_AGENT_UPDATE_ARGS, PRISMA_COMPUTE_AGENT_SKILL } from "../lib/agent/constants.js";
|
|
1
3
|
//#region src/shell/command-meta.ts
|
|
2
4
|
const COMMAND_DESCRIPTOR_ID = Symbol("prisma.commandDescriptorId");
|
|
5
|
+
function agentCommandExamples(runtime, commands) {
|
|
6
|
+
const formatCommand = resolvePrismaCliPackageCommandFormatterSync(runtime.cwd);
|
|
7
|
+
return commands.map((command) => formatCommand(command));
|
|
8
|
+
}
|
|
3
9
|
const DESCRIPTORS = [
|
|
4
10
|
{
|
|
5
11
|
id: "root",
|
|
@@ -14,6 +20,71 @@ const DESCRIPTORS = [
|
|
|
14
20
|
description: "Show CLI build and environment",
|
|
15
21
|
examples: ["prisma-cli version", "prisma-cli version --json"]
|
|
16
22
|
},
|
|
23
|
+
{
|
|
24
|
+
id: "agent",
|
|
25
|
+
path: ["prisma", "agent"],
|
|
26
|
+
description: "Install Prisma context for AI coding agents",
|
|
27
|
+
examples: (runtime) => agentCommandExamples(runtime, [
|
|
28
|
+
PRISMA_AGENT_INSTALL_ARGS,
|
|
29
|
+
PRISMA_AGENT_UPDATE_ARGS,
|
|
30
|
+
PRISMA_AGENT_STATUS_ARGS
|
|
31
|
+
])
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "agent.install",
|
|
35
|
+
path: [
|
|
36
|
+
"prisma",
|
|
37
|
+
"agent",
|
|
38
|
+
"install"
|
|
39
|
+
],
|
|
40
|
+
description: "Install Prisma skills for AI coding agents",
|
|
41
|
+
examples: (runtime) => agentCommandExamples(runtime, [
|
|
42
|
+
PRISMA_AGENT_INSTALL_ARGS,
|
|
43
|
+
[
|
|
44
|
+
...PRISMA_AGENT_INSTALL_ARGS,
|
|
45
|
+
"--agent",
|
|
46
|
+
"codex"
|
|
47
|
+
],
|
|
48
|
+
[...PRISMA_AGENT_INSTALL_ARGS, "--all-agents"],
|
|
49
|
+
[
|
|
50
|
+
...PRISMA_AGENT_INSTALL_ARGS,
|
|
51
|
+
"--skill",
|
|
52
|
+
PRISMA_COMPUTE_AGENT_SKILL
|
|
53
|
+
]
|
|
54
|
+
])
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: "agent.update",
|
|
58
|
+
path: [
|
|
59
|
+
"prisma",
|
|
60
|
+
"agent",
|
|
61
|
+
"update"
|
|
62
|
+
],
|
|
63
|
+
description: "Refresh Prisma skills for AI coding agents",
|
|
64
|
+
examples: (runtime) => agentCommandExamples(runtime, [
|
|
65
|
+
PRISMA_AGENT_UPDATE_ARGS,
|
|
66
|
+
[
|
|
67
|
+
...PRISMA_AGENT_UPDATE_ARGS,
|
|
68
|
+
"--agent",
|
|
69
|
+
"codex"
|
|
70
|
+
],
|
|
71
|
+
[...PRISMA_AGENT_UPDATE_ARGS, "--all-agents"]
|
|
72
|
+
])
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: "agent.status",
|
|
76
|
+
path: [
|
|
77
|
+
"prisma",
|
|
78
|
+
"agent",
|
|
79
|
+
"status"
|
|
80
|
+
],
|
|
81
|
+
description: "Show installed Prisma skills",
|
|
82
|
+
examples: (runtime) => agentCommandExamples(runtime, [
|
|
83
|
+
PRISMA_AGENT_STATUS_ARGS,
|
|
84
|
+
[...PRISMA_AGENT_STATUS_ARGS, "--json"],
|
|
85
|
+
[...PRISMA_AGENT_STATUS_ARGS, "--global"]
|
|
86
|
+
])
|
|
87
|
+
},
|
|
17
88
|
{
|
|
18
89
|
id: "auth",
|
|
19
90
|
path: ["prisma", "auth"],
|
|
@@ -350,6 +421,7 @@ const DESCRIPTORS = [
|
|
|
350
421
|
"prisma-cli app deploy --db",
|
|
351
422
|
"prisma-cli app deploy --db --yes",
|
|
352
423
|
"prisma-cli app deploy --app my-app --framework nextjs --http-port 3000",
|
|
424
|
+
"prisma-cli app deploy --app my-app --region us-west-1",
|
|
353
425
|
"prisma-cli app deploy --branch feat-login --framework hono",
|
|
354
426
|
"prisma-cli app deploy --prod --yes",
|
|
355
427
|
"prisma-cli app deploy --framework bun --entry src/server.ts"
|
|
@@ -2,9 +2,9 @@ import { CliError, authConfigInvalidError, authRequiredError, commandCanceledErr
|
|
|
2
2
|
import { getCommandDescriptor } from "./command-meta.js";
|
|
3
3
|
import { resolveGlobalFlags } from "./global-flags.js";
|
|
4
4
|
import { createCommandContext } from "./runtime.js";
|
|
5
|
-
import { cliErrorToJson, writeHumanError, writeHumanLines, writeJsonError, writeJsonEvent, writeJsonSuccess } from "./output.js";
|
|
6
5
|
import { collectCommandDiagnostics } from "../lib/diagnostics.js";
|
|
7
6
|
import { renderCommandDiagnostics } from "./diagnostics-output.js";
|
|
7
|
+
import { cliErrorToJson, writeHumanError, writeHumanLines, writeJsonError, writeJsonEvent, writeJsonSuccess } from "./output.js";
|
|
8
8
|
import { AuthError } from "@prisma/management-api-sdk";
|
|
9
9
|
//#region src/shell/command-runner.ts
|
|
10
10
|
function toCliError(error, runtime) {
|
package/dist/shell/help.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { formatDescriptorLabel, getDescriptorForCommand } from "./command-meta.js";
|
|
2
|
-
import { COMPACT_GLOBAL_OPTION_FLAGS, resolveGlobalFlags } from "./global-flags.js";
|
|
3
2
|
import { createShellUi, padDisplay, wrapText } from "./ui.js";
|
|
3
|
+
import { COMPACT_GLOBAL_OPTION_FLAGS, resolveGlobalFlags } from "./global-flags.js";
|
|
4
4
|
//#region src/shell/help.ts
|
|
5
5
|
function renderHelp(command, runtime) {
|
|
6
6
|
const descriptor = getDescriptorForCommand(command);
|
|
@@ -12,7 +12,7 @@ function renderHelp(command, runtime) {
|
|
|
12
12
|
if (visibleCommands.length > 0) lines.push(...renderCommandRows(rail, ui, visibleCommands));
|
|
13
13
|
lines.push(...renderLongDescription(rail, ui, descriptor.longDescription));
|
|
14
14
|
lines.push(...renderVisibleOptions(rail, ui, visibleCommands, visibleOptions));
|
|
15
|
-
lines.push(...renderExamples(rail, descriptor.examples));
|
|
15
|
+
lines.push(...renderExamples(rail, runtime, descriptor.examples));
|
|
16
16
|
lines.push(...renderDocsPath(rail, ui, descriptor.docsPath));
|
|
17
17
|
lines.push("");
|
|
18
18
|
return `${lines.join("\n")}`;
|
|
@@ -30,12 +30,13 @@ function renderVisibleOptions(rail, ui, visibleCommands, visibleOptions) {
|
|
|
30
30
|
function shouldLabelGlobalOptions(visibleCommands, visibleOptions) {
|
|
31
31
|
return visibleCommands.length > 0 && visibleOptions.every((option) => COMPACT_GLOBAL_OPTION_FLAGS.includes(option.flags));
|
|
32
32
|
}
|
|
33
|
-
function renderExamples(rail, examples) {
|
|
34
|
-
|
|
33
|
+
function renderExamples(rail, runtime, examples) {
|
|
34
|
+
const resolvedExamples = typeof examples === "function" ? examples(runtime) : examples;
|
|
35
|
+
if (!resolvedExamples || resolvedExamples.length === 0) return [];
|
|
35
36
|
return [
|
|
36
37
|
`${rail}`,
|
|
37
38
|
`${rail} Examples:`,
|
|
38
|
-
...
|
|
39
|
+
...resolvedExamples.map((example) => `${rail} $ ${example}`)
|
|
39
40
|
];
|
|
40
41
|
}
|
|
41
42
|
function renderDocsPath(rail, ui, docsPath) {
|
package/dist/shell/prompt.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { usageError } from "./errors.js";
|
|
2
2
|
import { confirm, isCancel, select, text } from "@clack/prompts";
|
|
3
3
|
//#region src/shell/prompt.ts
|
|
4
|
+
const PROMPT_CANCELED_SUMMARY = "Interactive prompt canceled";
|
|
4
5
|
async function selectPrompt(options) {
|
|
5
6
|
const promptOptions = options.choices.map((choice) => ({
|
|
6
7
|
label: choice.label,
|
|
@@ -9,31 +10,34 @@ async function selectPrompt(options) {
|
|
|
9
10
|
const response = await select({
|
|
10
11
|
input: options.input,
|
|
11
12
|
output: options.output,
|
|
13
|
+
signal: options.signal,
|
|
12
14
|
message: options.message,
|
|
13
15
|
options: promptOptions
|
|
14
16
|
});
|
|
15
|
-
if (isCancel(response)) throw usageError(
|
|
17
|
+
if (isCancel(response)) throw usageError(PROMPT_CANCELED_SUMMARY, "The command was canceled before a selection was made.", "Re-run the command and choose an option to continue.");
|
|
16
18
|
return response;
|
|
17
19
|
}
|
|
18
20
|
async function textPrompt(options) {
|
|
19
21
|
const response = await text({
|
|
20
22
|
input: options.input,
|
|
21
23
|
output: options.output,
|
|
24
|
+
signal: options.signal,
|
|
22
25
|
message: options.message,
|
|
23
26
|
placeholder: options.placeholder,
|
|
24
27
|
validate: options.validate
|
|
25
28
|
});
|
|
26
|
-
if (isCancel(response)) throw usageError(
|
|
29
|
+
if (isCancel(response)) throw usageError(PROMPT_CANCELED_SUMMARY, "The command was canceled before a value was entered.", "Re-run the command and provide a value to continue.");
|
|
27
30
|
return response;
|
|
28
31
|
}
|
|
29
32
|
async function confirmPrompt(options) {
|
|
30
33
|
const response = await confirm({
|
|
31
34
|
input: options.input,
|
|
32
35
|
output: options.output,
|
|
36
|
+
signal: options.signal,
|
|
33
37
|
message: options.message,
|
|
34
38
|
initialValue: options.initialValue ?? false
|
|
35
39
|
});
|
|
36
|
-
if (isCancel(response)) throw usageError(
|
|
40
|
+
if (isCancel(response)) throw usageError(PROMPT_CANCELED_SUMMARY, "The command was canceled before a confirmation was made.", "Re-run the command and choose an option to continue.");
|
|
37
41
|
return response;
|
|
38
42
|
}
|
|
39
43
|
function disposePromptState(_input) {}
|
package/dist/shell/runtime.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { createShellUi } from "./ui.js";
|
|
1
2
|
import { LocalStateStore } from "../adapters/local-state.js";
|
|
2
3
|
import { MockApi } from "../adapters/mock-api.js";
|
|
3
|
-
import { createShellUi } from "./ui.js";
|
|
4
4
|
import { renderHelp } from "./help.js";
|
|
5
|
-
import { findComputeConfigDir } from "@prisma/compute-sdk/config";
|
|
6
5
|
import path from "node:path";
|
|
6
|
+
import { findComputeConfigDir } from "@prisma/compute-sdk/config";
|
|
7
7
|
//#region src/shell/runtime.ts
|
|
8
8
|
const DEFAULT_STATE_DIR_NAME = path.join(".prisma", "cli");
|
|
9
9
|
function configureRuntimeCommand(command, runtime) {
|