From 31d292d26910858bd2e8b43bb7c0130bec09795a Mon Sep 17 00:00:00 2001 From: Justin Helmer Date: Thu, 17 Sep 2026 01:00:10 -0700 Subject: [PATCH] fix(cloud): align Trigger.dev connect copy with the console The console (nominal #3280) quotes Trigger.dev's preset names the way Trigger.dev writes them ("No restrictions", "Observer", "Deploy only") and asks for the project ref with "This key cannot name its project. Paste the project ref from the project's settings page (it starts with proj_)." The CLI said the same things in different words. Both surfaces now lead with the same sentences; the CLI keeps its pointer to the `project` line in trigger.config.ts, which Trigger.dev's config docs confirm is the project ref. The prompt label is "Project ref" with a proj_ placeholder, as in the console. No behaviour changes. The `/project ref/i` match on the API's `detail` is untouched; #3280 changed only the API `guidance` strings. The test fixtures now carry the API's real `detail` strings so the match is proven against what the API sends. Co-Authored-By: Claude Fable 5.1 --- src/commands/cloud/connect.ts | 16 +++++++++------- test/cloud-connect-triggerdev.test.ts | 14 +++++++------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/commands/cloud/connect.ts b/src/commands/cloud/connect.ts index 7210884..235c396 100644 --- a/src/commands/cloud/connect.ts +++ b/src/commands/cloud/connect.ts @@ -327,13 +327,15 @@ export async function connectTurso( } } -const TRIGGERDEV_PROJECT_REF_HINT = - 'The project ref is the `project` line in trigger.config.ts and starts with proj_.'; +const TRIGGERDEV_PROJECT_REF_WHERE = + "Paste the project ref from the project's settings page (it starts with proj_). It is also the `project` line in trigger.config.ts."; + +const TRIGGERDEV_PROJECT_REF_HINT = `This key cannot name its project. ${TRIGGERDEV_PROJECT_REF_WHERE}`; const TRIGGERDEV_HEADLESS_HINT = - 'Create an environment API key in your Trigger.dev project (production environment > API Keys, No restrictions access preset), then re-run:\n' + + 'Create an environment API key in your Trigger.dev project (production environment > API Keys, "No restrictions" access preset), then re-run:\n' + 'polylane cloud connect --provider triggerdev --api-key \n' + - `Add --project-ref when the API asks for it. ${TRIGGERDEV_PROJECT_REF_HINT}`; + `Add --project-ref when the API answers that the key cannot name its project. ${TRIGGERDEV_PROJECT_REF_WHERE}`; // The generated client trails the deployed API spec; the triggerdev body // shape is the contract from the API-side design record. @@ -376,8 +378,8 @@ export async function connectTriggerdev( note(`${err.message}\n${TRIGGERDEV_PROJECT_REF_HINT}`, 'Trigger.dev project ref'); const picked = await promptTextOrBack( { nonInteractive: config.nonInteractive }, - 'Trigger.dev project ref (proj_...)', - { validate: (v: string) => (v.trim() ? undefined : 'Required') } + 'Project ref', + { placeholder: 'proj_…', validate: (v: string) => (v.trim() ? undefined : 'Required') } ); if (picked === BACK) return BACK; return send({ ...body, projectRef: picked.trim() }); @@ -588,7 +590,7 @@ async function connectProvider( { message: 'Trigger.dev environment API key', instructions: - 'In your Trigger.dev project, open the production environment, then API Keys, and create a key with the No restrictions access preset. That preset is the only kind on the Free and Hobby plans; on Pro you may instead use restricted keys such as Observer plus Deploy only, adding them one at a time. Re-running this command with another key adds it to the same account.', + 'In your production environment open API Keys and create a key with the "No restrictions" access preset. That preset is the only kind on the Free and Hobby plans; on Pro you may instead use restricted keys such as "Observer" plus "Deploy only", adding them one at a time. Re-running this command with another key adds it to the same account.', link: 'https://cloud.trigger.dev', linkLabel: 'Open Trigger.dev', }, diff --git a/test/cloud-connect-triggerdev.test.ts b/test/cloud-connect-triggerdev.test.ts index a515be1..649f703 100644 --- a/test/cloud-connect-triggerdev.test.ts +++ b/test/cloud-connect-triggerdev.test.ts @@ -9,8 +9,10 @@ import type { PolylaneAPI } from '../src/generated/client'; const config = { nonInteractive: true } as Config; const body = { workspaceId: 'ws_1', provider: 'triggerdev', apiKey: 'tr_key' } as const; -const REF_REQUIRED = - 'This API key is valid for multiple projects. Specify the project ref of the project to connect.'; +// The API's `detail` strings, verbatim from nominal +// apps/apis/api-cloud-accounts/src/routers/cloud-accounts/connects/triggerdev.ts. +const REF_REQUIRED = 'The Trigger.dev project ref is required for a restricted key'; +const RUNS_REQUIRED = 'This Trigger.dev API key cannot read runs'; function mockApi(connect: (body: unknown) => Promise): PolylaneAPI { return { cloudAccountsConnect: connect } as unknown as PolylaneAPI; @@ -50,6 +52,8 @@ describe('connectTriggerdev', () => { err.exitCode === ExitCode.USAGE && err.message.includes('project ref') && (err.hint?.includes('--project-ref') ?? false) && + (err.hint?.includes('This key cannot name its project.') ?? false) && + (err.hint?.includes("project's settings page") ?? false) && (err.hint?.includes('trigger.config.ts') ?? false) ); }); @@ -66,11 +70,7 @@ describe('connectTriggerdev', () => { }); it('rethrows other 400s untouched, including a key that cannot read runs', async () => { - const original = new ApiError( - 400, - 'This API key cannot read runs. Create a key with the No restrictions access preset, or a restricted key that includes run read access.', - ExitCode.USAGE - ); + const original = new ApiError(400, RUNS_REQUIRED, ExitCode.USAGE); const api = mockApi(async () => { throw original; });