Merged
Conversation
…ss to allow returning immediately to support agentic workflows
…o to JSON output for login flow and clean up URL, clean up non-atomic file for polling
…daemon survives terminal close. move PKCE from being stored on disk to passing through an environment variable
…nd resume that and give the user an informative error message with the auth URL
… non-interactive flow in pc target
…eturned internally, target should be handling its own output
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
29 tasks
austin-denoble
added a commit
that referenced
this pull request
Apr 6, 2026
…target` fixes (#83) ## Problem After previous changes to daemonize the login flow and improve overall I/O, there were still some rough edges when working with the CLI through an agent. Lack of consistent `--json` flag representation was still an issue for a few flags, primarily around not supporting a shorthand option. The `pc target` command also needed changes to better support "headless", or agentic operation effectively. In-client documentation around the specifics of some of these operations also need to be improved to better guide users and agents when authenticating. ## Solution This PR improves the CLI's behavior in agentic/non-TTY contexts (Claude Code, Cursor, other AI coding agents). It builds on the daemon-backed login flow from #82 ### `-j` shorthand added to login commands `pc login` and `pc auth login` were missing the `-j` shorthand for `--json`, inconsistent with every other command. Fixed. ### Lazy auth completion Added `login.EnsureAuthenticated`, called from a `PersistentPreRun` hook on the root command. After a successful browser login, the next command run — any command — automatically detects the completed session, reloads credentials, and initializes the target org/project context. A second `pc login --json` call is no longer required before running other commands. Commands that don't require authentication are explicitly exempted: `pc login`, `pc logout`, `pc auth login/logout/configure/clear/status/_daemon`, `pc auth local-keys`/`list`, `pc target` (which handles its own auth after local-state early returns), `pc version`, and all `pc config` subcommands. ### `pc target` fixes - **TTY auto-detection** — `pc target` now detects non-TTY stdout and enables JSON mode automatically, consistent with `pc login`. - **No-flags JSON mode** — `pc target --json` with no targeting flags now returns the current target context as JSON (equivalent to `--show --json`) instead of an error. This early return is correctly placed before auth and API calls, so it works for API-key users and requires no credentials. - **`--show` and `--clear` unblocked** — These are local-state-only operations; they now return before the auth gate and before any API calls. - **Re-auth URL stays on stderr** — When `pc target` triggers an org-switch re-auth, the auth URL is printed to stderr only. Stdout remains a single JSON document, keeping output compatible with `jq .` and other single-document parsers. - **Missing `return` after `exit.Error`** — Added `return` guards after all `exit.Error` calls in target and root pre-run, preventing fall-through when the exit handler is mocked in tests. ### `applyAuthContext` / `RunPostAuthSetup` refactor Extracted the org/project state-setting logic from `RunPostAuthSetup` into a new `applyAuthContext` helper that returns the user's email. This eliminates a redundant `oauth.Token` + `ParseClaimsUnverified` call that `RunPostAuthSetup` was making immediately after `applyAuthContext` had already fetched the same data. `applyAuthContext` now also always writes `state.TargetProj` (clearing it when the org has no projects), preventing stale project data from a previous session from appearing in the authenticated JSON response. ### Root pre-run JSON error output `EnsureAuthenticated` errors in the root `PersistentPreRun` now check both TTY state and the command's own `--json`/`-j` flag, so auth errors are machine-readable when a caller explicitly requests JSON even in a TTY context. ### Deduplication Extracted `printTargetContextJSON()` in `target.go`, replacing three identical blocks that each read `state.GetTargetContext()`, masked the API key, and printed JSON. ### Documentation Updated `pc login`, `pc auth login`, and `pc target` help text to document the interactive vs. agentic flows, the two-call pending/authenticated pattern, session resumability, and the lazy context initialization behavior. Also fixed a typo in `pc target`'s example (`-project` → `--project`). ## Type of Change - [X] Bug fix (non-breaking change which fixes an issue) - [X] 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 ### Interactive login (TTY) - [ ] `pc login` opens a browser and completes auth, sets target org/project, prints success message - [ ] `pc auth login` same as above ### Agentic login (non-TTY / `--json`) - [ ] `pc login --json` returns `{"status":"pending","url":"...","session_id":"..."}` and exits immediately - [ ] `-j` shorthand works identically on both `pc login` and `pc auth login` - [ ] Second `pc login --json` after completing browser auth returns `{"status":"authenticated",...}` with org/project populated - [ ] Running any other command (e.g. `pc index list --json`) after browser auth — without a second `pc login` call — succeeds and sets target context automatically - [ ] Piping output (`pc login | cat`) triggers non-TTY path automatically without needing `--json` ### Lazy auth / `EnsureAuthenticated` - [ ] After `pc login --json` + browser auth, `pc index list --json` works without a second login call - [ ] `pc auth status` works with no credentials (not blocked by auth gate) - [ ] `pc auth local-keys list` works with no credentials (not blocked by auth gate) - [ ] `pc version` works with no credentials - [ ] All `pc config` subcommands work with no credentials ### `pc target` - [ ] `pc target --show` works with no credentials - [ ] `pc target --clear` works with no credentials - [ ] `pc target --json` (no flags) returns current target context as JSON, works with no credentials - [ ] `pc target --json --org "name"` sets org and returns updated context as JSON - [ ] `pc target --json --org "name" --project "name"` sets both and returns updated context - [ ] `pc target` in a TTY launches interactive selector as before - [ ] `pc target` in a non-TTY (or with `--json`) without targeting flags returns current context rather than erroring ### Auth errors - [ ] Running a command requiring auth with no credentials returns `{"error":"..."}` to stdout when stdout is non-TTY - [ ] Running a command requiring auth with no credentials and `--json` flag returns `{"error":"..."}` to stdout even in a TTY - [ ] "authentication in progress" error includes the auth URL when daemon is still running <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Adds a global authentication pre-check for most commands and changes login/target behavior in non-TTY JSON mode, which could affect automation and command execution paths if the skip list or auth detection is incorrect. > > **Overview** > **Adds a root-level auth gate for most commands.** `pc` now runs `login.EnsureAuthenticated()` in `PersistentPreRun`, with a curated skip list for commands that manage credentials/local state, and auto-detects JSON mode (non-TTY stdout or `--json/-j`) to format auth errors appropriately. > > **Improves non-interactive/agentic UX.** `login` and `auth login` gain `-j` shorthand and updated help/examples; `target` now auto-enables JSON mode in non-TTY contexts, supports `pc target --json` as an auth-free “show current context” path, and centralizes JSON context printing. > > **Refactors and extends post-auth setup.** Login utilities split context initialization into `applyAuthContext()`, ensure target project state is cleared when no projects exist, keep stdout clean during wait-mode by printing auth URLs to stderr, and introduce `EnsureAuthenticated()` to lazily complete pending daemon sessions and auto-initialize org/project context after successful browser auth. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit ddb7ecd. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Reworks the OAuth login flow to work correctly in agentic contexts (Claude Code, Cursor, other AI coding agents) where stdin/stdout are not interactive TTYs.
Problem
The previous
pc loginflow blocked on stdin waiting for[Enter], and the auth URL was either hidden or percent-encoded in ways that made it hard for agents to extract. There was no machine-readable way to surface the URL and get a non-blocking result.Solution: daemon-backed two-call pattern
First call (
pc login --json): spawns a detached background daemon that owns the OAuth callback server on127.0.0.1:59049, emits{"status":"pending","url":"...","session_id":"..."}to stdout, and exits immediately. The daemon keeps listening for the browser redirect.Second call (
pc login --json): detects the pending session, polls the daemon's result file until auth completes, then emits{"status":"authenticated","email":"...","org_id":"...","org_name":"...","project_id":"...","project_name":"..."}.If the second call is killed before the daemon finishes, a third call resumes seamlessly — the daemon keeps running regardless.
Non-agentic users (
pc loginwithout--json, TTY stdout) are completely unaffected.Key details
~/.config/pinecone/sessions/(mode 0600, 5-minute TTL) — PKCE verifier is passed to the daemon via environment variable and never touches disk.pc targetre-auth uses aWait: truemode that blocks until the token is acquired (daemon path, but synchronous), printing the auth URL to stderr so it's visible without polluting stdout.CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESSso it survives terminal close.GetAndSetAccessTokenso all callers (includingpc target) correctly use the daemon path in non-TTY environments.Note
Medium Risk
Changes the CLI OAuth login flow to spawn a detached background process and persist session state/results on disk, which can impact authentication reliability across platforms and failure modes. Also modifies re-auth behavior in
pc targetto block until tokens are acquired.Overview
Daemonizes
pc login --jsonOAuth flow by introducing a hiddenpc auth _daemonsubcommand that runs the local callback server in a detached process, exchanges the auth code, stores the token, and writes a session result file.Adds resumable, file-backed login sessions (
sessions/state+result) so JSON login can return immediately with{"status":"pending"...}and be polled/resumed on subsequent invocations, with cleanup/expiry handling and cross-platform process detachment.Refactors token acquisition and post-auth setup: splits interactive vs JSON paths, adds
Options.Waitfor callers that must block until credentials exist, and updatespc targetre-auth to useWait: truewhile keeping JSON output behavior separate viaRunPostAuthSetup.Written by Cursor Bugbot for commit 596f676. This will update automatically on new commits. Configure here.