Skip to content

Commit 4bafa7e

Browse files
committed
feat(cli-v3): add --no-browser flag and Examples to init/login --help
Adds an obvious bypass for the browser auto-open during auth, the most common friction point for agentic and other non-interactive uses. Also: error loudly when init runs under non-TTY stdin without --yes (previously default-and-exited silently, leaving the project half-initialized) and surface common invocations via an Examples block in --help output.
1 parent 19c1675 commit 4bafa7e

3 files changed

Lines changed: 60 additions & 4 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"trigger.dev": patch
3+
---
4+
5+
Add `--no-browser` flag to `init` and `login` to skip auto-opening the browser during authentication. Also error loudly when `init` is run without `--yes` under non-TTY stdin (previously default-and-exited silently, leaving the project half-initialized). Both commands now show an `Examples` section in `--help`.

packages/cli-v3/src/commands/init.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const InitCommandOptions = CommonCommandOptions.extend({
5757
gitRef: z.string().default("main"),
5858
javascript: z.boolean().default(false),
5959
yes: z.boolean().default(false),
60+
browser: z.boolean().default(true),
6061
});
6162

6263
type InitCommandOptions = z.infer<typeof InitCommandOptions>;
@@ -65,7 +66,23 @@ export function configureInitCommand(program: Command) {
6566
return commonOptions(
6667
program
6768
.command("init")
68-
.description("Initialize your existing project for development with Trigger.dev")
69+
.summary("Initialize your existing project for development with Trigger.dev")
70+
.description(
71+
`Initialize your existing project for development with Trigger.dev.
72+
73+
Examples:
74+
# Interactive setup
75+
$ trigger.dev init
76+
77+
# Non-interactive (CI / scripts)
78+
$ trigger.dev init --yes --project-ref proj_abc123
79+
80+
# Headless / agent (no browser)
81+
$ trigger.dev init --yes --project-ref proj_abc123 --no-browser
82+
83+
# Use a named profile
84+
$ trigger.dev init --profile staging`
85+
)
6986
.argument("[path]", "The path to the project", ".")
7087
.option(
7188
"-p, --project-ref <project ref>",
@@ -89,6 +106,7 @@ export function configureInitCommand(program: Command) {
89106
"Additional arguments to pass to the package manager, accepts CSV for multiple args"
90107
)
91108
.option("-y, --yes", "Skip all prompts and use defaults (requires --project-ref)")
109+
.option("--no-browser", "Don't automatically open the browser during login; print the URL only")
92110
)
93111
.addOption(
94112
new CommandOption(
@@ -118,6 +136,15 @@ async function _initCommand(dir: string, options: InitCommandOptions) {
118136
throw new Error("--project-ref is required when using --yes flag");
119137
}
120138

139+
// Refuse to run interactively when stdin isn't a TTY (CI, agent harness, etc).
140+
// Previously this silently default-and-exited at the first prompt, leaving the
141+
// project half-initialized.
142+
if (!options.yes && !process.stdin.isTTY) {
143+
throw new Error(
144+
"Interactive prompts cannot be used in non-TTY environments. Pass --yes (and --project-ref) to run non-interactively."
145+
);
146+
}
147+
121148
const hasSeenMCPInstallPrompt = readConfigHasSeenMCPInstallPrompt();
122149

123150
if (!hasSeenMCPInstallPrompt) {
@@ -165,6 +192,7 @@ async function _initCommand(dir: string, options: InitCommandOptions) {
165192
embedded: true,
166193
defaultApiUrl: options.apiUrl,
167194
profile: options.profile,
195+
browser: options.browser,
168196
});
169197

170198
if (!authorization.ok) {

packages/cli-v3/src/commands/login.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import { links } from "@trigger.dev/core/v3";
4141

4242
export const LoginCommandOptions = CommonCommandOptions.extend({
4343
apiUrl: z.string(),
44+
browser: z.boolean().default(true),
4445
});
4546

4647
export type LoginCommandOptions = z.infer<typeof LoginCommandOptions>;
@@ -49,7 +50,21 @@ export function configureLoginCommand(program: Command) {
4950
return commonOptions(
5051
program
5152
.command("login")
52-
.description("Login with Trigger.dev so you can perform authenticated actions")
53+
.summary("Login with Trigger.dev so you can perform authenticated actions")
54+
.description(
55+
`Login with Trigger.dev so you can perform authenticated actions.
56+
57+
Examples:
58+
# Interactive login (opens browser)
59+
$ trigger.dev login
60+
61+
# Headless / agent (print URL only)
62+
$ trigger.dev login --no-browser
63+
64+
# Login to a named profile
65+
$ trigger.dev login --profile staging`
66+
)
67+
.option("--no-browser", "Don't automatically open the browser; print the URL only")
5368
)
5469
.version(VERSION, "-v, --version", "Display the version number")
5570
.action(async (options) => {
@@ -67,14 +82,20 @@ export async function loginCommand(options: unknown) {
6782
}
6883

6984
async function _loginCommand(options: LoginCommandOptions) {
70-
return login({ defaultApiUrl: options.apiUrl, embedded: false, profile: options.profile });
85+
return login({
86+
defaultApiUrl: options.apiUrl,
87+
embedded: false,
88+
profile: options.profile,
89+
browser: options.browser,
90+
});
7191
}
7292

7393
export type LoginOptions = {
7494
defaultApiUrl?: string;
7595
embedded?: boolean;
7696
profile?: string;
7797
silent?: boolean;
98+
browser?: boolean;
7899
};
79100

80101
export async function login(options?: LoginOptions): Promise<LoginResult> {
@@ -259,7 +280,9 @@ export async function login(options?: LoginOptions): Promise<LoginResult> {
259280
`Please visit the following URL to login:\n${chalkLink(authorizationCodeResult.url)}`
260281
);
261282

262-
if (await isLinuxServer()) {
283+
if (opts.browser === false) {
284+
log.message("Browser auto-open disabled. Visit the URL above to login.");
285+
} else if (await isLinuxServer()) {
263286
log.message("Please install `xdg-utils` to automatically open the login URL.");
264287
} else {
265288
await open(authorizationCodeResult.url);

0 commit comments

Comments
 (0)