Skip to content

Fix pc login for agentic workflows#75

Merged
austin-denoble merged 6 commits intomainfrom
adenoble/fix-agentic-login-flow
Mar 24, 2026
Merged

Fix pc login for agentic workflows#75
austin-denoble merged 6 commits intomainfrom
adenoble/fix-agentic-login-flow

Conversation

@austin-denoble
Copy link
Collaborator

@austin-denoble austin-denoble commented Mar 23, 2026

Problem

pc login was unusable in agentic contexts:

  • The OAuth URL was printed as ANSI-styled prose on stdout (Visit https://... to authorize the CLI.), making it impossible for agents to reliably extract the URL from the output.
  • In non-interactive contexts, the command attempted to read from stdin unnecessarily.
  • There was no structured output mode — no --json flag, no machine-readable URL emission.
  • When already authenticated, the command returned nothing to stdout, giving agents no way to detect the existing session.
  • All human-readable output (prompts, status messages, hints) were going to stdout, mixing with any data output that would be relevant for agent / machine interaction.

Solution

Auto-detected JSON output

When stdout is not a TTY (machine / agent capturing output), JSON mode is enabled automatically — no flag
required. --json is also available as an explicit override for users who want structured output in a terminal. The format decision is resolved once at the top of Run() and passed down; GetAndSetAccessToken and other helpers use it directly without re-running TTY detection.

Structured output at each stage

Immediately before blocking on the OAuth callback:

{
    "status": "pending",
    "url": "https://login.pinecone.io/..."
}

After successful authentication:

{
    "status": "authenticated",
    "email": "user@example.com",
    "org_id": "...",
    "project_id": "..."
}

When already logged in:

{
    "status": "already_authenticated",
    "email": "user@example.com",
    "org_id": "..."
}

TTY-gated interactivity

The "Press [Enter]" prompt and stdin-reading goroutine are gated on term.IsTerminal(int(os.Stdin.Fd())). Non-interactive runs skip stdin entirely and block cleanly on the OAuth callback. The prompt is preserved for TTY sessions regardless of JSON mode — a user passing --json in a terminal is still at a keyboard and benefits from browser-open.

All human-readable output routed to stderr

The prose URL line, Enter prompt, success messages, info messages, and hints all go to stderr. In JSON mode, stdout carries only the structured objects above. In prose mode, TTY users see everything in their terminal as before.

Fixed HTML escaping in JSON output

text.IndentJSON and text.InlineJSON now use json.Encoder with SetEscapeHTML(false). The default Go JSON marshaler escapes & as \u0026 — correct for embedding JSON in HTML, wrong for CLI output. This was causing OAuth URLs in the pending JSON object to be un-pasteable. Unit tests added to prevent regression.

Removed dead code

  • IO struct and parameter removed from Run() — was accepted but never used; all writes go directly to os.Stdout/os.Stderr/os.Stdin.
  • Dead --quiet/io.Discard branches removed from both login command files.
  • msg.Blank() added to the msg package for consistent stderr blank-line spacing

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update
  • Infrastructure change (CI configs, etc)
  • Non-code change (docs, etc)
  • None of the above: (explain here)

Test Plan

You can test locally by piping stdin / stdout, or passing the --json flag manually.

# force redirecting stdout to trigger JSON output automatically
./dist/pc_darwin_all/pc login | cat

{
    "status": "pending",
    "url": "https://login.pinecone.io/oauth/authorize?audience=https%3A%2F%2Fus-central1-production-console.cloudfunctions.net%2Fapi%2Fv1&client_id=A4ONXSaOGstwwir0zUztoI6zjyt9zsRH&code_challenge=9LpXGYNRqvQRgd4NWSCIyBGAiZClfzkM_SeFI3_280I&code_challenge_method=S256&redirect_uri=http%3A%2F%2F127.0.0.1%3A59049%2Fauth-callback&response_type=code&scope=openid+profile+email+offline_access&sourceTag=pinecone_cli&state=l_CIfL4pkyhj7N7DmCI1qd0OD72_nCyi1ikGvYvCGdw"
}
Press [Enter] to open the browser, or manually paste the URL above.

{
    "status": "authenticated",
    "email": "austin.d@pinecone.io",
    "org_id": "-NF9kuQiPWth9QLPg5NS",
    "project_id": "504ef178-3aac-49ce-93cd-86dc262e6e43"
}

# login with explicit --json flagged, make sure the browser prompt works when it's displayed
./dist/pc_darwin_all/pc login --json
{
    "status": "pending",
    "url": "https://login.pinecone.io/oauth/authorize?audience=https%3A%2F%2Fus-central1-production-console.cloudfunctions.net%2Fapi%2Fv1&client_id=A4ONXSaOGstwwir0zUztoI6zjyt9zsRH&code_challenge=YoI6PnfYkLeSKzoOzfSQIKxlHduoawCij2LWu2XFg7w&code_challenge_method=S256&redirect_uri=http%3A%2F%2F127.0.0.1%3A59049%2Fauth-callback&response_type=code&scope=openid+profile+email+offline_access&sourceTag=pinecone_cli&state=qEVw2RwQnHX32iQ5wtK7yzxalAZE8wDWtFDH8eTqN6Y"
}

Press [Enter] to open the browser, or manually paste the URL above.

{
    "status": "authenticated",
    "email": "austin.d@pinecone.io",
    "org_id": "-NF9kuQiPWth9QLPg5NS",
    "project_id": "504ef178-3aac-49ce-93cd-86dc262e6e43"
}

# pipe stderr explicitly and trigger --json or stdout explicitly to check that stdout output is clean
./dist/pc_darwin_all/pc login --json 2>/dev/null
./dist/pc_darwin_all/pc login 2>/dev/null | cat
./dist/pc_darwin_all/pc login < /dev/null | cat
{
    "status": "pending",
    "url": "https://login.pinecone.io/oauth/authorize?audience=https%3A%2F%2Fus-central1-production-console.cloudfunctions.net%2Fapi%2Fv1&client_id=A4ONXSaOGstwwir0zUztoI6zjyt9zsRH&code_challenge=BSh06S5jkmTH8lucj8CAVwy5AhGKITxjX7V4knal0Mw&code_challenge_method=S256&redirect_uri=http%3A%2F%2F127.0.0.1%3A59049%2Fauth-callback&response_type=code&scope=openid+profile+email+offline_access&sourceTag=pinecone_cli&state=7y-Jygv-RPLGY4X-kMPJHfd4PeMxphll3x8xA-0MRKY"
}
{
    "status": "authenticated",
    "email": "austin.d@pinecone.io",
    "org_id": "-NF9kuQiPWth9QLPg5NS",
    "project_id": "504ef178-3aac-49ce-93cd-86dc262e6e43"
}

Make sure the traditional login experience works as expected:

./dist/pc_darwin_all/pc login
Visit https://login.pinecone.io/oauth/authorize?audience=https%3A%2F%2Fus-central1-production-console.cloudfunctions.net%2Fapi%2Fv1&client_id=A4ONXSaOGstwwir0zUztoI6zjyt9zsRH&code_challenge=2seMya2Pxhr_ug_shJZkhMxVnVdVT0gD3H8zKACJzYk&code_challenge_method=S256&redirect_uri=http%3A%2F%2F127.0.0.1%3A59049%2Fauth-callback&response_type=code&scope=openid+profile+email+offline_access&sourceTag=pinecone_cli&state=Hm31H8dOMNjGtTdMr4n0Erfa42JqsZo7DEs5vZZ9gfY to authorize the CLI.

Press [Enter] to open the browser, or manually paste the URL above.


[SUCCESS] Logged in as austin.d@pinecone.io. Defaulted to organization ID: -NF9kuQiPWth9QLPg5NS
[INFO] Target org set to pinecone-official.
[INFO] Target project set cmek-integration-tests.

Hint: Run pc target to change the target context.
Hint: Now try pc index -h to learn about index operations.

Note

Medium Risk
Changes pc login/pc auth login output behavior and login helper signatures, which could affect existing scripts and interactive UX, though core OAuth exchange remains the same.

Overview
Improves pc login and pc auth login for non-interactive/agentic use by adding --json and auto-emitting JSON when stdout is not a TTY, while keeping human-readable messaging on interactive terminals.

The login flow now prints structured JSON status objects (e.g. pending with the OAuth URL, authenticated / already_authenticated with claims) to stdout, moves prompts and prose to stderr, and gates the "Press [Enter]" stdin reader on interactive stdin to avoid hanging in piped runs.

Updates shared helpers (login.Run, GetAndSetAccessToken) to take login.Options{Json: ...}, adds msg.Blank() for consistent spacing, and adjusts JSON encoding (text.InlineJSON/IndentJSON) to disable HTML escaping (with new tests).

Written by Cursor Bugbot for commit 64aea12. This will update automatically on new commits. Configure here.

…, tty detection for the input handling on the login flow, supporting JSON output through stdout for agentic use. update target GetAndSetAccessToken to handle things
…style output is going to stderr. add text.encode helper to allows marshalling to JSON without HTML escaping. drive json logic from the top down checking the provided flag along with TTY presence. add unit tests for the new text functionality
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

@austin-denoble austin-denoble merged commit a1d4769 into main Mar 24, 2026
8 checks passed
@austin-denoble austin-denoble deleted the adenoble/fix-agentic-login-flow branch March 24, 2026 18:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant