@prisma/cli 3.0.0-beta.25 → 3.0.0-beta.27
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/cli2.js +13 -3
- package/dist/commands/feedback/index.js +20 -0
- package/dist/controllers/agent-setup.js +52 -0
- package/dist/controllers/app.js +2 -41
- package/dist/controllers/feedback.js +86 -0
- package/dist/controllers/init.js +3 -0
- package/dist/presenters/feedback.js +26 -0
- package/dist/shell/command-meta.js +7 -0
- package/dist/shell/output.js +65 -3
- package/package.json +1 -1
package/dist/cli2.js
CHANGED
|
@@ -3,7 +3,7 @@ import { attachCommandDescriptor } from "./shell/command-meta.js";
|
|
|
3
3
|
import { createShellUi } from "./shell/ui.js";
|
|
4
4
|
import { addCompactGlobalFlags } from "./shell/global-flags.js";
|
|
5
5
|
import { configureRuntimeCommand, createCommandContext } from "./shell/runtime.js";
|
|
6
|
-
import { formatUnexpectedError, writeHumanError, writeJsonError, writeJsonSuccess } from "./shell/output.js";
|
|
6
|
+
import { formatUnexpectedError, unexpectedErrorFeedbackCommand, writeHumanError, writeJsonError, writeJsonSuccess, writeJsonUnexpectedError } from "./shell/output.js";
|
|
7
7
|
import { createAgentCommand } from "./commands/agent/index.js";
|
|
8
8
|
import "./shell/prompt.js";
|
|
9
9
|
import { createAppCommand } from "./commands/app/index.js";
|
|
@@ -11,10 +11,11 @@ import { createAuthCommand } from "./commands/auth/index.js";
|
|
|
11
11
|
import { createBranchCommand } from "./commands/branch/index.js";
|
|
12
12
|
import { createBuildCommand } from "./commands/build/index.js";
|
|
13
13
|
import { createDatabaseCommand } from "./commands/database/index.js";
|
|
14
|
+
import { getCliName, getCliVersion } from "./lib/version.js";
|
|
15
|
+
import { createFeedbackCommand } from "./commands/feedback/index.js";
|
|
14
16
|
import { createGitCommand } from "./commands/git/index.js";
|
|
15
17
|
import { createInitCommand } from "./commands/init/index.js";
|
|
16
18
|
import { createProjectCommand } from "./commands/project/index.js";
|
|
17
|
-
import { getCliName, getCliVersion } from "./lib/version.js";
|
|
18
19
|
import { runVersion } from "./controllers/version.js";
|
|
19
20
|
import { createVersionCommand } from "./commands/version/index.js";
|
|
20
21
|
import { maybeWriteCachedUpdateNotification } from "./shell/update-check.js";
|
|
@@ -37,7 +38,15 @@ async function runCli(options = {}) {
|
|
|
37
38
|
return process.exitCode ?? 0;
|
|
38
39
|
} catch (error) {
|
|
39
40
|
if (error instanceof CommanderError) return error.code === "commander.helpDisplayed" ? 0 : 2;
|
|
40
|
-
|
|
41
|
+
if (runtime.argv.includes("--json")) {
|
|
42
|
+
writeJsonUnexpectedError({
|
|
43
|
+
stdout: runtime.stdout,
|
|
44
|
+
stderr: runtime.stderr
|
|
45
|
+
}, runtime.argv, error);
|
|
46
|
+
return 1;
|
|
47
|
+
}
|
|
48
|
+
const quiet = runtime.argv.includes("--quiet") || runtime.argv.includes("-q");
|
|
49
|
+
runtime.stderr.write(formatUnexpectedError(error, runtime.argv.includes("--trace"), quiet ? void 0 : unexpectedErrorFeedbackCommand(runtime.argv, error)));
|
|
41
50
|
return 1;
|
|
42
51
|
} finally {
|
|
43
52
|
runtime.stdin;
|
|
@@ -50,6 +59,7 @@ function createProgram(runtime) {
|
|
|
50
59
|
program.name("prisma").showSuggestionAfterError();
|
|
51
60
|
program.addCommand(createVersionCommand(runtime));
|
|
52
61
|
program.addCommand(createInitCommand(runtime));
|
|
62
|
+
program.addCommand(createFeedbackCommand(runtime));
|
|
53
63
|
program.addCommand(createAgentCommand(runtime));
|
|
54
64
|
program.addCommand(createAuthCommand(runtime));
|
|
55
65
|
program.addCommand(createProjectCommand(runtime));
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { attachCommandDescriptor } from "../../shell/command-meta.js";
|
|
2
|
+
import { addGlobalFlags } from "../../shell/global-flags.js";
|
|
3
|
+
import { configureRuntimeCommand } from "../../shell/runtime.js";
|
|
4
|
+
import { runCommand } from "../../shell/command-runner.js";
|
|
5
|
+
import { runFeedback } from "../../controllers/feedback.js";
|
|
6
|
+
import { renderFeedbackSuccess } from "../../presenters/feedback.js";
|
|
7
|
+
import { Command, Option } from "commander";
|
|
8
|
+
//#region src/commands/feedback/index.ts
|
|
9
|
+
function createFeedbackCommand(runtime) {
|
|
10
|
+
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("feedback"), runtime), "feedback");
|
|
11
|
+
command.argument("<message>", "Feedback text (up to 4000 characters)").addOption(new Option("--email <address>", "Contact email if you want a reply; feedback is anonymous without it"));
|
|
12
|
+
addGlobalFlags(command);
|
|
13
|
+
command.action(async (message, options) => {
|
|
14
|
+
const flags = options;
|
|
15
|
+
await runCommand(runtime, "feedback", options, (context) => runFeedback(context, message, { email: flags.email }), { renderHuman: (context, descriptor, result) => renderFeedbackSuccess(context, descriptor, result) });
|
|
16
|
+
});
|
|
17
|
+
return command;
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { createFeedbackCommand };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { resolvePrismaCliPackageCommand } from "../lib/agent/cli-command.js";
|
|
2
|
+
import { PRISMA_AGENT_INSTALL_ARGS, PRISMA_COMPUTE_AGENT_SKILL } from "../lib/agent/constants.js";
|
|
3
|
+
import { readPrismaAgentSetupStatus, shouldOfferPrismaAgentSetup } from "../lib/agent/setup-status.js";
|
|
4
|
+
import { runAgentInstall } from "./agent.js";
|
|
5
|
+
import { renderSummaryLine } from "../shell/ui.js";
|
|
6
|
+
import { canPrompt } from "../shell/runtime.js";
|
|
7
|
+
import { confirmPrompt } from "../shell/prompt.js";
|
|
8
|
+
//#region src/controllers/agent-setup.ts
|
|
9
|
+
/**
|
|
10
|
+
* One-time interactive offer to install the Prisma Compute skill for the
|
|
11
|
+
* project. Shared by the commands that establish a project setup (init,
|
|
12
|
+
* deploy); the answer is remembered, so whichever command runs first asks.
|
|
13
|
+
* Returns warnings; a failed install must not fail the calling command.
|
|
14
|
+
*/
|
|
15
|
+
async function maybePromptForAgentSetup(context, projectDir) {
|
|
16
|
+
if (!canPrompt(context) || context.flags.yes || context.flags.quiet) return [];
|
|
17
|
+
if (!shouldOfferPrismaAgentSetup(await readPrismaAgentSetupStatus({
|
|
18
|
+
cwd: projectDir,
|
|
19
|
+
stateStore: context.stateStore,
|
|
20
|
+
signal: context.runtime.signal,
|
|
21
|
+
requiredSkill: "prisma-compute"
|
|
22
|
+
}))) return [];
|
|
23
|
+
if (!await confirmPrompt({
|
|
24
|
+
input: context.runtime.stdin,
|
|
25
|
+
output: context.runtime.stderr,
|
|
26
|
+
signal: context.runtime.signal,
|
|
27
|
+
message: "Install the Prisma Compute skill for this project?",
|
|
28
|
+
initialValue: true
|
|
29
|
+
})) {
|
|
30
|
+
await context.stateStore.setAgentSetupPromptDismissedAt((/* @__PURE__ */ new Date()).toISOString());
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
await runAgentInstall(context, { skill: [PRISMA_COMPUTE_AGENT_SKILL] }, "install", { cwd: projectDir });
|
|
35
|
+
if (!context.flags.quiet && !context.flags.json) context.output.stderr.write(`${renderSummaryLine(context.ui, "success", "Installed the Prisma Compute skill for this project.")}\n\n`);
|
|
36
|
+
return [];
|
|
37
|
+
} catch (error) {
|
|
38
|
+
const message = error instanceof Error ? error.message : "Prisma skill install failed.";
|
|
39
|
+
if (!context.flags.quiet && !context.flags.json) context.output.stderr.write(`${renderSummaryLine(context.ui, "warning", `Skipped Prisma skill install: ${message}`)}\n\n`);
|
|
40
|
+
return [`The Prisma Compute skill was not installed. Run ${await resolvePrismaCliPackageCommand({
|
|
41
|
+
cwd: projectDir,
|
|
42
|
+
signal: context.runtime.signal,
|
|
43
|
+
args: [
|
|
44
|
+
...PRISMA_AGENT_INSTALL_ARGS,
|
|
45
|
+
"--skill",
|
|
46
|
+
PRISMA_COMPUTE_AGENT_SKILL
|
|
47
|
+
]
|
|
48
|
+
})} to try again.`];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { maybePromptForAgentSetup };
|
package/dist/controllers/app.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import { resolvePrismaCliPackageCommand } from "../lib/agent/cli-command.js";
|
|
2
|
-
import { PRISMA_AGENT_INSTALL_ARGS, PRISMA_COMPUTE_AGENT_SKILL } from "../lib/agent/constants.js";
|
|
3
|
-
import { readPrismaAgentSetupStatus, shouldOfferPrismaAgentSetup } from "../lib/agent/setup-status.js";
|
|
4
1
|
import { formatCommandArgument } from "../shell/command-arguments.js";
|
|
5
2
|
import { CliError, authRequiredError, featureUnavailableError, usageError, workspaceRequiredError } from "../shell/errors.js";
|
|
6
|
-
import {
|
|
7
|
-
import { renderCommandHeader, renderSummaryLine } from "../shell/ui.js";
|
|
3
|
+
import { renderCommandHeader } from "../shell/ui.js";
|
|
8
4
|
import { canPrompt } from "../shell/runtime.js";
|
|
9
5
|
import { writeJsonEvent } from "../shell/output.js";
|
|
10
6
|
import { SERVICE_TOKEN_ENV_VAR, getApiBaseUrl } from "../lib/auth/client.js";
|
|
@@ -32,6 +28,7 @@ import { requireComputeAuth } from "../lib/auth/guard.js";
|
|
|
32
28
|
import { readAuthState } from "../lib/auth/auth-ops.js";
|
|
33
29
|
import { readLocalGitBranch } from "../lib/git/local-branch.js";
|
|
34
30
|
import { promptForProjectSetupChoice } from "../lib/project/interactive-setup.js";
|
|
31
|
+
import { maybePromptForAgentSetup } from "./agent-setup.js";
|
|
35
32
|
import { createSelectPromptPort } from "./select-prompt-port.js";
|
|
36
33
|
import { requireAuthenticatedAuthState } from "./auth.js";
|
|
37
34
|
import { listRealWorkspaceProjects } from "./project.js";
|
|
@@ -2096,42 +2093,6 @@ function maybeRenderProjectLinked(context, directory, projectName, localPinPath)
|
|
|
2096
2093
|
if (context.flags.json || context.flags.quiet) return;
|
|
2097
2094
|
context.output.stderr.write(`${context.ui.success("✔")} Linked "${directory}" to Project "${projectName}"\nSaved ${localPinPath}\n\n`);
|
|
2098
2095
|
}
|
|
2099
|
-
async function maybePromptForAgentSetup(context, projectDir) {
|
|
2100
|
-
if (!canPrompt(context) || context.flags.yes) return [];
|
|
2101
|
-
if (!shouldOfferPrismaAgentSetup(await readPrismaAgentSetupStatus({
|
|
2102
|
-
cwd: projectDir,
|
|
2103
|
-
stateStore: context.stateStore,
|
|
2104
|
-
signal: context.runtime.signal,
|
|
2105
|
-
requiredSkill: "prisma-compute"
|
|
2106
|
-
}))) return [];
|
|
2107
|
-
if (!await confirmPrompt({
|
|
2108
|
-
input: context.runtime.stdin,
|
|
2109
|
-
output: context.runtime.stderr,
|
|
2110
|
-
signal: context.runtime.signal,
|
|
2111
|
-
message: "Install the Prisma Compute skill for this project?",
|
|
2112
|
-
initialValue: true
|
|
2113
|
-
})) {
|
|
2114
|
-
await context.stateStore.setAgentSetupPromptDismissedAt((/* @__PURE__ */ new Date()).toISOString());
|
|
2115
|
-
return [];
|
|
2116
|
-
}
|
|
2117
|
-
try {
|
|
2118
|
-
await runAgentInstall(context, { skill: [PRISMA_COMPUTE_AGENT_SKILL] }, "install", { cwd: projectDir });
|
|
2119
|
-
if (!context.flags.quiet && !context.flags.json) context.output.stderr.write(`${renderSummaryLine(context.ui, "success", "Installed the Prisma Compute skill for this project.")}\n\n`);
|
|
2120
|
-
return [];
|
|
2121
|
-
} catch (error) {
|
|
2122
|
-
const message = error instanceof Error ? error.message : "Prisma skill install failed.";
|
|
2123
|
-
if (!context.flags.quiet && !context.flags.json) context.output.stderr.write(`${renderSummaryLine(context.ui, "warning", `Skipped Prisma skill install: ${message}`)}\n\n`);
|
|
2124
|
-
return [`The Prisma Compute skill was not installed. Run ${await resolvePrismaCliPackageCommand({
|
|
2125
|
-
cwd: projectDir,
|
|
2126
|
-
signal: context.runtime.signal,
|
|
2127
|
-
args: [
|
|
2128
|
-
...PRISMA_AGENT_INSTALL_ARGS,
|
|
2129
|
-
"--skill",
|
|
2130
|
-
PRISMA_COMPUTE_AGENT_SKILL
|
|
2131
|
-
]
|
|
2132
|
-
})} to try again.`];
|
|
2133
|
-
}
|
|
2134
|
-
}
|
|
2135
2096
|
async function maybeCustomizeDeploySettings(context, options) {
|
|
2136
2097
|
if (!options.firstDeploy || context.flags.yes || options.explicitFramework || options.explicitEntrypoint || options.explicitHttpPort || !canPrompt(context)) return {
|
|
2137
2098
|
framework: options.framework,
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { CliError, usageError } from "../shell/errors.js";
|
|
2
|
+
import { getCliVersion } from "../lib/version.js";
|
|
3
|
+
//#region src/controllers/feedback.ts
|
|
4
|
+
const DEFAULT_FEEDBACK_ENDPOINT = "https://hiieirp2pwqnjvq9axzyg6d0.fra.prisma.build/feedback";
|
|
5
|
+
const FEEDBACK_TIMEOUT_MS = 3e3;
|
|
6
|
+
const MAX_MESSAGE_LENGTH = 4e3;
|
|
7
|
+
const MAX_EMAIL_LENGTH = 320;
|
|
8
|
+
const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
9
|
+
async function runFeedback(context, messageArg, flags) {
|
|
10
|
+
const message = messageArg.trim();
|
|
11
|
+
if (!message) throw usageError("Feedback message required", "The message argument is empty.", "Pass a non-empty message.", ["prisma-cli feedback \"the deploy flow is great\""]);
|
|
12
|
+
if (message.length > MAX_MESSAGE_LENGTH) throw usageError("Feedback message too long", `The message is ${message.length} characters; the limit is ${MAX_MESSAGE_LENGTH}.`, "Shorten the message.");
|
|
13
|
+
const email = flags.email?.trim();
|
|
14
|
+
if (email !== void 0 && (email.length > MAX_EMAIL_LENGTH || !EMAIL_PATTERN.test(email))) throw usageError("Invalid email", `"${flags.email}" is not a valid email address of at most ${MAX_EMAIL_LENGTH} characters.`, "Pass a valid address with --email, or drop the flag to stay anonymous.", ["prisma-cli feedback \"please add X\" --email you@example.com"]);
|
|
15
|
+
const feedbackContext = {
|
|
16
|
+
cliVersion: getCliVersion(),
|
|
17
|
+
nodeVersion: process.version,
|
|
18
|
+
platform: process.platform,
|
|
19
|
+
arch: process.arch
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
command: "feedback",
|
|
23
|
+
result: {
|
|
24
|
+
id: await postFeedback(context, context.runtime.env.PRISMA_CLI_FEEDBACK_URL || DEFAULT_FEEDBACK_ENDPOINT, {
|
|
25
|
+
message,
|
|
26
|
+
...email ? { email } : {},
|
|
27
|
+
meta: { ...feedbackContext }
|
|
28
|
+
}),
|
|
29
|
+
email: email ?? null,
|
|
30
|
+
context: feedbackContext
|
|
31
|
+
},
|
|
32
|
+
warnings: [],
|
|
33
|
+
nextSteps: []
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
async function postFeedback(context, endpoint, body) {
|
|
37
|
+
let response;
|
|
38
|
+
try {
|
|
39
|
+
response = await fetch(endpoint, {
|
|
40
|
+
method: "POST",
|
|
41
|
+
headers: {
|
|
42
|
+
"content-type": "application/json",
|
|
43
|
+
"user-agent": `prisma-cli/${getCliVersion()}`
|
|
44
|
+
},
|
|
45
|
+
body: JSON.stringify(body),
|
|
46
|
+
signal: AbortSignal.any([context.runtime.signal, AbortSignal.timeout(FEEDBACK_TIMEOUT_MS)])
|
|
47
|
+
});
|
|
48
|
+
} catch (error) {
|
|
49
|
+
if (context.runtime.signal.aborted) throw error;
|
|
50
|
+
throw feedbackSendFailed(error instanceof Error && error.name === "TimeoutError" ? TIMEOUT_DETAIL : `The feedback service could not be reached${error instanceof Error && error.cause instanceof Error ? ` (${error.cause.message})` : ""}.`);
|
|
51
|
+
}
|
|
52
|
+
if (!response.ok) throw feedbackSendFailed(`The feedback service responded with HTTP ${response.status}${await readServiceError(context, response)}.`);
|
|
53
|
+
let payload;
|
|
54
|
+
try {
|
|
55
|
+
payload = await response.json();
|
|
56
|
+
} catch (error) {
|
|
57
|
+
if (context.runtime.signal.aborted) throw error;
|
|
58
|
+
if (!(error instanceof SyntaxError)) throw feedbackSendFailed(error instanceof Error && error.name === "TimeoutError" ? TIMEOUT_DETAIL : "The feedback service response could not be read.");
|
|
59
|
+
payload = null;
|
|
60
|
+
}
|
|
61
|
+
return typeof payload?.id === "string" ? payload.id : null;
|
|
62
|
+
}
|
|
63
|
+
const TIMEOUT_DETAIL = `The feedback service did not answer within ${FEEDBACK_TIMEOUT_MS / 1e3} seconds.`;
|
|
64
|
+
async function readServiceError(context, response) {
|
|
65
|
+
let payload;
|
|
66
|
+
try {
|
|
67
|
+
payload = await response.json();
|
|
68
|
+
} catch (error) {
|
|
69
|
+
if (context.runtime.signal.aborted) throw error;
|
|
70
|
+
return "";
|
|
71
|
+
}
|
|
72
|
+
return typeof payload?.error?.message === "string" ? ` (${payload.error.message})` : "";
|
|
73
|
+
}
|
|
74
|
+
function feedbackSendFailed(detail) {
|
|
75
|
+
return new CliError({
|
|
76
|
+
code: "FEEDBACK_SEND_FAILED",
|
|
77
|
+
domain: "cli",
|
|
78
|
+
summary: "Feedback could not be delivered",
|
|
79
|
+
why: detail,
|
|
80
|
+
fix: "Check your network and rerun the command.",
|
|
81
|
+
exitCode: 1,
|
|
82
|
+
nextSteps: []
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
//#endregion
|
|
86
|
+
export { runFeedback };
|
package/dist/controllers/init.js
CHANGED
|
@@ -5,6 +5,7 @@ import { canPrompt } from "../shell/runtime.js";
|
|
|
5
5
|
import { confirmPrompt, isPromptCancelError, selectPrompt, textPrompt } from "../shell/prompt.js";
|
|
6
6
|
import { readLocalResolutionPin } from "../lib/project/local-pin.js";
|
|
7
7
|
import { readBunPackageEntrypoint, readBunPackageJson } from "../lib/app/bun-project.js";
|
|
8
|
+
import { maybePromptForAgentSetup } from "./agent-setup.js";
|
|
8
9
|
import { runProjectLink } from "./project.js";
|
|
9
10
|
import { detectDeployFramework } from "./app.js";
|
|
10
11
|
import { execa } from "execa";
|
|
@@ -112,6 +113,7 @@ async function runInit(context, flags) {
|
|
|
112
113
|
onWarning: (message) => warnings.push(message),
|
|
113
114
|
formatCommand
|
|
114
115
|
});
|
|
116
|
+
warnings.push(...await maybePromptForAgentSetup(context, cwd));
|
|
115
117
|
const unlinked = link.status !== "linked" && link.status !== "already-linked";
|
|
116
118
|
const typesMissing = types.status !== "installed" && types.status !== "already-installed";
|
|
117
119
|
return {
|
|
@@ -391,6 +393,7 @@ async function runInitConversion(context, flags, jsonConfigPath, formatCommand)
|
|
|
391
393
|
onWarning: (message) => warnings.push(message),
|
|
392
394
|
formatCommand
|
|
393
395
|
});
|
|
396
|
+
warnings.push(...await maybePromptForAgentSetup(stepContext, loaded.configDir));
|
|
394
397
|
const unlinked = link.status !== "already-linked" && link.status !== "linked";
|
|
395
398
|
const typesMissing = types.status !== "installed" && types.status !== "already-installed";
|
|
396
399
|
return {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { renderShow } from "../output/patterns.js";
|
|
2
|
+
//#region src/presenters/feedback.ts
|
|
3
|
+
function renderFeedbackSuccess(context, descriptor, result) {
|
|
4
|
+
return renderShow({
|
|
5
|
+
title: "Feedback sent. Thank you!",
|
|
6
|
+
descriptor,
|
|
7
|
+
fields: [
|
|
8
|
+
...result.id ? [{
|
|
9
|
+
key: "id",
|
|
10
|
+
value: result.id
|
|
11
|
+
}] : [],
|
|
12
|
+
{
|
|
13
|
+
key: "sent as",
|
|
14
|
+
value: result.email ?? "anonymous",
|
|
15
|
+
tone: result.email ? "default" : "dim"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
key: "included",
|
|
19
|
+
value: `CLI ${result.context.cliVersion}, node ${result.context.nodeVersion}, ${result.context.platform} ${result.context.arch}`,
|
|
20
|
+
tone: "dim"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}, context.ui);
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { renderFeedbackSuccess };
|
|
@@ -20,6 +20,13 @@ const DESCRIPTORS = [
|
|
|
20
20
|
description: "Show CLI build and environment",
|
|
21
21
|
examples: ["prisma-cli version", "prisma-cli version --json"]
|
|
22
22
|
},
|
|
23
|
+
{
|
|
24
|
+
id: "feedback",
|
|
25
|
+
path: ["prisma", "feedback"],
|
|
26
|
+
description: "Send feedback to the Prisma CLI team",
|
|
27
|
+
longDescription: "Anonymous unless --email is passed. Every submission includes the CLI version, node version, and OS platform/arch, and nothing else.",
|
|
28
|
+
examples: ["prisma-cli feedback \"the deploy flow is great\"", "prisma-cli feedback \"please add X\" --email you@example.com"]
|
|
29
|
+
},
|
|
23
30
|
{
|
|
24
31
|
id: "init",
|
|
25
32
|
path: ["prisma", "init"],
|
package/dist/shell/output.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatCommandArgument } from "./command-arguments.js";
|
|
1
2
|
import { renderNextSteps, renderSummaryLine } from "./ui.js";
|
|
2
3
|
//#region src/shell/output.ts
|
|
3
4
|
function writeJsonSuccess(output, success) {
|
|
@@ -23,15 +24,76 @@ function cliErrorToJson(error) {
|
|
|
23
24
|
docsUrl: error.docsUrl
|
|
24
25
|
};
|
|
25
26
|
}
|
|
26
|
-
function formatUnexpectedError(error, trace) {
|
|
27
|
+
function formatUnexpectedError(error, trace, feedbackCommand) {
|
|
28
|
+
const feedbackLine = feedbackCommand ? `Tell us what happened: ${feedbackCommand}` : null;
|
|
27
29
|
const debug = error instanceof Error ? error.stack ?? error.message : String(error);
|
|
28
|
-
if (trace) return
|
|
30
|
+
if (trace) return [
|
|
31
|
+
debug,
|
|
32
|
+
...feedbackLine ? [feedbackLine] : [],
|
|
33
|
+
""
|
|
34
|
+
].join("\n");
|
|
29
35
|
return [
|
|
30
36
|
`Unexpected CLI error: ${error instanceof Error && error.message ? error.message : String(error)}`,
|
|
31
37
|
"More: Re-run with --trace for deeper diagnostics",
|
|
38
|
+
...feedbackLine ? [feedbackLine] : [],
|
|
32
39
|
""
|
|
33
40
|
].join("\n");
|
|
34
41
|
}
|
|
42
|
+
/** Command groups whose second argv token names the subcommand. */
|
|
43
|
+
const COMMAND_GROUPS = new Set([
|
|
44
|
+
"agent",
|
|
45
|
+
"auth",
|
|
46
|
+
"project",
|
|
47
|
+
"git",
|
|
48
|
+
"branch",
|
|
49
|
+
"build",
|
|
50
|
+
"database",
|
|
51
|
+
"app"
|
|
52
|
+
]);
|
|
53
|
+
/** Best-effort `command` label for a crash that predates envelope assembly. */
|
|
54
|
+
function unexpectedErrorCommandLabel(argv) {
|
|
55
|
+
const [group, action] = argv.filter((arg) => !arg.startsWith("-"));
|
|
56
|
+
if (!group) return "unknown";
|
|
57
|
+
return action && COMMAND_GROUPS.has(group) ? `${group}.${action}` : group;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Pre-filled feedback command for a crash, so the report arrives carrying the
|
|
61
|
+
* failing command and the error's first line.
|
|
62
|
+
*/
|
|
63
|
+
function unexpectedErrorFeedbackCommand(argv, error) {
|
|
64
|
+
return `prisma-cli feedback ${formatCommandArgument(`${unexpectedErrorCommandLabel(argv).replace(".", " ")} crashed: ${(error instanceof Error && error.message ? error.message : String(error)).split("\n")[0]}`.slice(0, 200))}`;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* A crash must not break the `--json` contract: agents still get a structured
|
|
68
|
+
* envelope, with a recover action pointing at the feedback command.
|
|
69
|
+
*/
|
|
70
|
+
function writeJsonUnexpectedError(output, argv, error) {
|
|
71
|
+
const feedbackCommand = unexpectedErrorFeedbackCommand(argv, error);
|
|
72
|
+
output.stdout.write(`${JSON.stringify({
|
|
73
|
+
ok: false,
|
|
74
|
+
command: unexpectedErrorCommandLabel(argv),
|
|
75
|
+
error: {
|
|
76
|
+
code: "UNEXPECTED_ERROR",
|
|
77
|
+
domain: "cli",
|
|
78
|
+
severity: "error",
|
|
79
|
+
summary: "Unexpected CLI error",
|
|
80
|
+
why: error instanceof Error && error.message ? error.message : String(error),
|
|
81
|
+
fix: "Re-run with --trace for deeper diagnostics, and report the crash.",
|
|
82
|
+
where: null,
|
|
83
|
+
meta: {},
|
|
84
|
+
docsUrl: null
|
|
85
|
+
},
|
|
86
|
+
warnings: [],
|
|
87
|
+
nextSteps: [feedbackCommand],
|
|
88
|
+
nextActions: [{
|
|
89
|
+
kind: "run-command",
|
|
90
|
+
journey: "recover",
|
|
91
|
+
label: "Report this crash to the Prisma team",
|
|
92
|
+
command: feedbackCommand,
|
|
93
|
+
reason: "This looks like a CLI bug; the pre-filled report carries the failing command and error."
|
|
94
|
+
}]
|
|
95
|
+
}, null, 2)}\n`);
|
|
96
|
+
}
|
|
35
97
|
function writeJsonError(output, command, error) {
|
|
36
98
|
output.stdout.write(`${JSON.stringify({
|
|
37
99
|
ok: false,
|
|
@@ -79,4 +141,4 @@ function writeHumanError(output, ui, error, options) {
|
|
|
79
141
|
writeHumanLines(output, lines);
|
|
80
142
|
}
|
|
81
143
|
//#endregion
|
|
82
|
-
export { cliErrorToJson, formatUnexpectedError, writeHumanError, writeHumanLines, writeJsonError, writeJsonEvent, writeJsonSuccess };
|
|
144
|
+
export { cliErrorToJson, formatUnexpectedError, unexpectedErrorFeedbackCommand, writeHumanError, writeHumanLines, writeJsonError, writeJsonEvent, writeJsonSuccess, writeJsonUnexpectedError };
|