diff --git a/docs/product/command-spec.md b/docs/product/command-spec.md index 4150a18..7693dbd 100644 --- a/docs/product/command-spec.md +++ b/docs/product/command-spec.md @@ -1299,12 +1299,13 @@ Behavior: ```text ? Which Project should this directory use? - ❯ Acme Dashboard + ❯ + Create a new Project + Acme Dashboard Billing API - Create a new Project Cancel ``` +- "Create a new Project" is listed first, highlighted with a `+` glyph that does not rely on color, so it stays reachable without paging through a long project list; Cancel is last - when "Create a new Project" is selected, prompts for a Project name with the package/directory name as a suggestion - when no Project is resolved in `--json` / `--no-interactive` mode, fails with `PROJECT_SETUP_REQUIRED` - `PROJECT_SETUP_REQUIRED` preserves readable recovery commands in `nextSteps` and includes structured `nextActions` for choosing, linking, creating, or retrying with an explicit Project diff --git a/packages/cli/src/lib/project/interactive-setup.ts b/packages/cli/src/lib/project/interactive-setup.ts index 8c39df6..fc922cc 100644 --- a/packages/cli/src/lib/project/interactive-setup.ts +++ b/packages/cli/src/lib/project/interactive-setup.ts @@ -45,14 +45,18 @@ export async function promptForProjectSetupChoice(options: { input: options.context.runtime.stdin, output: options.context.runtime.stderr, message: "Which Project should this directory use?", + // "Create a new Project" stays first so it is reachable without paging + // through a long project list; Cancel stays last by convention. The "+" + // glyph highlights it without color, since the prompt library owns the + // active-row styling and the style guide forbids color-only meaning. choices: [ + { label: "+ Create a new Project", value: { kind: "create" as const } }, ...sortedProjects.map((project) => ({ label: duplicateNames.has(project.name) ? `${project.name} (${project.id})` : project.name, value: { kind: "project" as const, project }, })), - { label: "Create a new Project", value: { kind: "create" as const } }, { label: "Cancel", value: { kind: "cancel" as const } }, ], }); diff --git a/packages/cli/tests/app-controller.test.ts b/packages/cli/tests/app-controller.test.ts index 385b5b7..1eafbcb 100644 --- a/packages/cli/tests/app-controller.test.ts +++ b/packages/cli/tests/app-controller.test.ts @@ -3136,7 +3136,7 @@ describe("app controller", () => { cwd, stateDir, isTTY: true, - stdinText: "\r", + stdinText: "\u001B[B\r", env: { ...process.env, PRISMA_CLI_TEST_REMEMBER_PROJECT_ID: "", @@ -3221,7 +3221,7 @@ describe("app controller", () => { cwd, stateDir, isTTY: true, - stdinText: "\r\r", + stdinText: "\u001B[B\r\r", env: { ...process.env, PRISMA_CLI_TEST_REMEMBER_PROJECT_ID: "", @@ -3528,7 +3528,7 @@ describe("app controller", () => { cwd, stateDir, isTTY: true, - stdinText: "\u001B[B\rinteractive-project\r", + stdinText: "\rinteractive-project\r", env: { ...process.env, PRISMA_CLI_TEST_REMEMBER_PROJECT_ID: "", diff --git a/packages/cli/tests/project-controller.test.ts b/packages/cli/tests/project-controller.test.ts index 2850a37..8f926cf 100644 --- a/packages/cli/tests/project-controller.test.ts +++ b/packages/cli/tests/project-controller.test.ts @@ -283,7 +283,7 @@ describe("project controller", () => { cwd, stateDir, isTTY: true, - stdinText: "\u001B[B\rInteractive Project\r", + stdinText: "\rInteractive Project\r", env: { ...process.env, PRISMA_CLI_TEST_REMEMBER_PROJECT_ID: "", diff --git a/packages/cli/tests/project.test.ts b/packages/cli/tests/project.test.ts index 3a347de..efda39a 100644 --- a/packages/cli/tests/project.test.ts +++ b/packages/cli/tests/project.test.ts @@ -211,7 +211,7 @@ describe("project commands", () => { stateDir, fixturePath, isTTY: true, - stdinText: "\r", + stdinText: "\u001B[B\r", }); const stderr = stripAnsi(result.stderr); @@ -264,7 +264,7 @@ describe("project commands", () => { stateDir, fixturePath: ambiguousFixturePath, isTTY: true, - stdinText: "\r", + stdinText: "\u001B[B\r", }); const stderr = stripAnsi(result.stderr);