Skip to content

Commit 5aa7a1c

Browse files
authored
Merge pull request #3 from bitrefill/feat/no-interactive
feat: --no-interactive for headless CI
2 parents 9bf1cde + 120203d commit 5aa7a1c

2 files changed

Lines changed: 26 additions & 1 deletion

File tree

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ On first run, the CLI opens your browser for OAuth authorization. Credentials ar
2222

2323
Generate an API key at [bitrefill.com/account/developers](https://www.bitrefill.com/account/developers) and pass it via the `--api-key` option or the `BITREFILL_API_KEY` environment variable. This skips the OAuth flow entirely.
2424

25+
### Non-interactive / CI
26+
27+
In environments without a TTY (e.g. CI, Docker, scripts), or when `CI=true`, the CLI cannot complete browser-based OAuth. Pass `--no-interactive` to fail fast with a clear message, or use `--api-key` / `BITREFILL_API_KEY` instead.
28+
2529
```bash
2630
# Option
2731
bitrefill --api-key YOUR_API_KEY search-products --query "Netflix"
@@ -39,7 +43,7 @@ Node does not load `.env` files automatically. After editing `.env`, either expo
3943
## Usage
4044

4145
```bash
42-
bitrefill [--api-key <key>] [--json] <command> [options]
46+
bitrefill [--api-key <key>] [--json] [--no-interactive] <command> [options]
4347
```
4448

4549
### Human-readable output (default)

src/index.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ function resolveJsonMode(): boolean {
5252
return process.argv.some((arg) => arg === '--json');
5353
}
5454

55+
function resolveInteractive(): boolean {
56+
if (process.argv.includes('--no-interactive')) return false;
57+
if (process.env.CI === 'true') return false;
58+
if (!process.stdin.isTTY) return false;
59+
return true;
60+
}
61+
5562
function createOutputFormatter(jsonMode: boolean): OutputFormatter {
5663
return jsonMode ? createJsonFormatter() : createHumanFormatter();
5764
}
@@ -262,6 +269,16 @@ async function main(): Promise<void> {
262269
const mcpUrl = resolveMcpUrl(apiKey);
263270
const useOAuth = !apiKey && !process.env.MCP_URL;
264271

272+
if (useOAuth && !resolveInteractive()) {
273+
formatter.error(
274+
new Error(
275+
'Authorization required but running in non-interactive mode.\n' +
276+
'Use --api-key or set BITREFILL_API_KEY to authenticate without a browser.'
277+
)
278+
);
279+
process.exit(1);
280+
}
281+
265282
// Phase 1: connect and discover tools
266283
const { client, transport } = await createMcpClient(
267284
mcpUrl,
@@ -289,6 +306,10 @@ async function main(): Promise<void> {
289306
.option(
290307
'--json',
291308
'Output raw JSON (TOON decoded); use with jq. Non-result messages go to stderr.'
309+
)
310+
.option(
311+
'--no-interactive',
312+
'Disable browser-based auth and interactive prompts (auto-detected in CI / non-TTY)'
292313
);
293314

294315
program

0 commit comments

Comments
 (0)