From ea30fa048da112dbf77cd925d04ab1594b67e0c5 Mon Sep 17 00:00:00 2001 From: Aman Varshney Date: Fri, 3 Jul 2026 14:59:50 +0530 Subject: [PATCH 1/3] fix(cli): list Create a new Project first in the setup picker With many projects, creating a new one required paging past the whole list. The interactive project setup picker (project link and app deploy setup) now lists Create a new Project first, with Cancel last; spec examples updated and picker-driving tests adjusted for the new order. --- docs/product/command-spec.md | 5 +++-- packages/cli/src/lib/project/interactive-setup.ts | 4 +++- packages/cli/tests/app-controller.test.ts | 6 +++--- packages/cli/tests/project-controller.test.ts | 2 +- packages/cli/tests/project.test.ts | 4 ++-- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/docs/product/command-spec.md b/docs/product/command-spec.md index 4150a18..33af3a1 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 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..a218f44 100644 --- a/packages/cli/src/lib/project/interactive-setup.ts +++ b/packages/cli/src/lib/project/interactive-setup.ts @@ -45,14 +45,16 @@ 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. 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); From 084e2f16dcbb0c4b44f43beb9302c1a0703d5ddb Mon Sep 17 00:00:00 2001 From: Aman Varshney Date: Fri, 3 Jul 2026 15:04:31 +0530 Subject: [PATCH 2/3] fix(cli): highlight Create a new Project with a + glyph Glyph over color: the prompt library owns the active-row styling (embedded ANSI would break its highlight), and the style guide forbids color-only meaning. The + survives NO_COLOR and non-TTY logs. --- packages/cli/src/lib/project/interactive-setup.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/lib/project/interactive-setup.ts b/packages/cli/src/lib/project/interactive-setup.ts index a218f44..fc922cc 100644 --- a/packages/cli/src/lib/project/interactive-setup.ts +++ b/packages/cli/src/lib/project/interactive-setup.ts @@ -46,9 +46,11 @@ export async function promptForProjectSetupChoice(options: { 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. + // 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 } }, + { label: "+ Create a new Project", value: { kind: "create" as const } }, ...sortedProjects.map((project) => ({ label: duplicateNames.has(project.name) ? `${project.name} (${project.id})` From 0d9ab98022f9d0f586bc73935bf9cb11f82479de Mon Sep 17 00:00:00 2001 From: Aman Varshney Date: Fri, 3 Jul 2026 15:05:40 +0530 Subject: [PATCH 3/3] docs(cli): show the + glyph in the setup picker spec example --- docs/product/command-spec.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/product/command-spec.md b/docs/product/command-spec.md index 33af3a1..7693dbd 100644 --- a/docs/product/command-spec.md +++ b/docs/product/command-spec.md @@ -1299,13 +1299,13 @@ Behavior: ```text ? Which Project should this directory use? - ❯ Create a new Project + ❯ + Create a new Project Acme Dashboard Billing API Cancel ``` -- "Create a new Project" is listed first so it stays reachable without paging through a long project list; Cancel is last +- "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