Skip to content

feat(cli): improve agent discoverability and add headless auth login#291

Draft
rafa-thayto wants to merge 2 commits into
mainfrom
empty-legume
Draft

feat(cli): improve agent discoverability and add headless auth login#291
rafa-thayto wants to merge 2 commits into
mainfrom
empty-legume

Conversation

@rafa-thayto
Copy link
Copy Markdown
Contributor

Summary

Closes the five agentcli-bench gaps (D3, A4, P3, P2, T7) and adds a clerk auth login --token <key> flow for CI / agents.

  • Top-level help discoverability: clerk --help now renders an Examples: block and an Environment: section listing the five CLERK_* env vars the binary actually reads (CLERK_SECRET_KEY, CLERK_MODE, CLERK_CONFIG_DIR, CLERK_UPDATE_CHANNEL, CLERK_NO_UPDATE_CHECK). Implemented via a new setEnvVars() declaration-merging helper in lib/help.ts, mirroring the existing setExamples() pattern.
  • --json field documentation: apps list|create, users list|create, and doctor --json now describe the JSON shape in the option description so agents/consumers know what to expect.
  • Headless authentication (clerk auth login --token <key>): accepts a Clerk PLAPI access token inline or via - (stdin). Validates JWT shape, size cap (8 KB), and azp audience claim locally before the userinfo network call, then persists with no refresh token. A --token - invocation on a TTY refuses up-front instead of hanging on EOF. Sibling awaitConcurrentRefresh skips the race-detection loop for token-only sessions so two parallel logins don't collide on the empty-refresh sentinel.

Background: vault handoff doc — diffs the Clerk CLI's agentcli-bench score (44.5) against resend (55.7) and prescribes the five gap closures landed here. Expected score after this PR is ~52–55 overall.

A property test guards the Environment: list against drift — every documented CLERK_* name must actually be read in cli-core/src/.

Test plan

  • bun run format / bun run lint / bun run typecheck / bun run test pass locally (CI will re-run)
  • clerk --help renders the new Examples: and Environment: sections
  • clerk auth login --help shows --token <key> and references CLERK_SECRET_KEY for per-instance API access
  • clerk auth login --token <jwt> with a fresh valid token logs in without OAuth and persists the session
  • clerk auth login --token sk_test_xxx rejects with a clear "expected a JWT" message before hitting the network
  • clerk auth login --token - refuses on a TTY and reads from stdin when piped
  • cat token.txt | clerk auth login --token - works end-to-end
  • clerk users list --json and clerk apps list --json still emit pipeable JSON
  • Re-run agentcli-bench against the freshly-compiled binary and confirm D3, A4, P3, P2, T7 improve as expected

Closes the five agentcli-bench gaps (D3, A4, P3, P2, T7) and adds a
`clerk auth login --token <key>` flow for CI / agents:

- Top-level `Examples:` block on `clerk --help` (D3)
- New `Environment:` help section via `setEnvVars()`, documenting the
  five `CLERK_*` env vars the binary actually reads (A4)
- `--json` field descriptions on `apps list|create`, `users list|create`,
  and `doctor --json` so consumers know the shape (P3)
- Verified `--json` + `isAgent()` coverage across data-returning
  subcommands (P2)
- `clerk auth login --token <key>` for headless auth: accepts a Clerk
  PLAPI access token (or `-` for stdin), validates JWT shape and
  audience (`azp` claim, soft check with back-compat) locally before
  the userinfo call, persists with no refresh token. Sibling
  `awaitConcurrentRefresh` skips the race-detection loop for token-only
  sessions so two parallel logins don't collide on the empty-refresh
  sentinel (T7)

A property test guards the `Environment:` list against drift — every
documented `CLERK_*` name must be one the CLI actually reads.
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 15, 2026

🦋 Changeset detected

Latest commit: 0396b1c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
clerk Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

login.ts now imports storeAccessToken, assertValidAccessToken, and
getJwtAuthorizedParty from credential-store.ts. The shared test stubs
were missing these exports, causing login.test.ts to fail with
"Export named 'storeAccessToken' not found" when Bun resolved the
mocked module.
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