Tags: clerk/cli
Tags
feat(keyless): make keyless the default and let agents configure a ke… …yless instance (#395) * feat(keyless): make keyless the default again and let agents configure a keyless instance Restores keyless mode as the default for unauthenticated `clerk init` (reversing PR #268), and extends keyless so an agent can bootstrap and configure Clerk end to end without a Clerk account. Init: - Unauthenticated runs on keyless-capable frameworks use keyless again — human bootstrap and all agent runs. Existing-project human runs still log in. - `--login` forces the authenticated flow; `--keyless` now forces keyless even when signed in. `--keyless --login`, `--keyless --app`, and agent `--login` while signed out are usage errors. - `--template <b2b-saas|b2c-saas|native|waitlist>` pre-configures the keyless application at creation. Operating a keyless instance (Backend API, instance secret key only): - `clerk config pull` and `clerk config patch` cover seven resource groups. - `clerk enable/disable orgs`, `clerk whoami`, and `clerk env pull` work with no account. Billing stays account-only and says why. - Keys are also discovered from `.clerk/.tmp/keyless.json`, so an application a Clerk SDK minted for itself is reachable from the CLI. Account credentials are deliberately not part of the keyless decision: only `--app` or a linked profile selects the account path, so these commands work with or without a platform API key or login session. * feat(keyless): configure an unclaimed application end to end without an account Close the gaps between "keyless is the default" and "keyless actually works with no human intervention": - config patch validates instance fields against the Backend API's own schema before sending — PATCH /v1/instance answers 204 and silently discards unknown fields, so a typo or an account-only setting (password, social, second_factors, ...) used to print "Config pushed successfully" and change nothing. The refusal names the accepted fields and, for settings BAPI has no route for at all, says claiming is the only path. - config patch no longer prints a stale eventually-consistent re-read as the result of a write; bodyless groups are reported as unconfirmed. - allowlist_identifiers/blocklist_identifiers point at `clerk api` (which reaches them keyless) instead of demanding a login. - users open explains that an unclaimed app has no dashboard page and offers `clerk api /users/<id>`, instead of blaming "not linked" and suggesting remedies that need an application ID that doesn't exist yet. - whoami/env pull detect publishable/secret keys that belong to different applications; env pull refuses to write a mismatched pair. - doctor, open, users, api, env pull, whoami, enable/disable orgs and templates verified end to end on a live unclaimed instance, all under --mode agent with non-TTY stdin: no hangs, no prompts, no browser. docs/keyless-demos: before/after screenshots proving CLI writes reach the live hosted UI pre-claim (orgs step inserted into the sign-in flow, allowlist enforced then lifted), with a README on the FAPI /v1/environment oracle and its limits. * fix(keyless): address CodeRabbit findings on secret handling and error classification - demo-env.sh: bound the accountless-application curl request with connect/max timeouts, and stop echoing the raw minting response (it can contain a live secret_key when only one of the two fields fails to parse). - 09-health-and-users.tape: redact the claim token before it's recorded by piping `clerk open --print` through sed. - open/README.md: add a language to the fenced usage-error example (MD040). - bapi-command.ts: describeBapiTarget now checks options.secretKey first, mirroring resolveBapiSecretKey's actual precedence. - credential-store.ts: exclude 429 from isUnrecoverableRefreshFailure so a rate-limited token refresh isn't reported as an expired session. * chore(keyless): remove demo assets from the repo * fix(keyless): address CodeRabbit findings on doctor side effects, claim-url trust, and env-file key priority * fix(keyless): address review feedback on key precedence, init guard, and doctor diagnostics - Restore CLERK_SECRET_KEY's precedence: the env var wins over a linked profile again, and --instance next to it stays a no-op instead of a usage error. Routing it through resolveKeylessTarget had silently changed both, breaking invocations that work on main; real env-var-path tests pin it now. - init's keep-the-existing-app guard also recognizes an application the SDK minted for itself (.clerk/.tmp/keyless.json), instead of silently orphaning it with a replacement. - doctor reports a malformed local secret key as one named failing check with a remedy, instead of five anonymous 'Check crashed' lines. - whoami: keyless next-steps no longer point at clerk link (which cannot work pre-claim), and an unlinked directory holding a local secret key is called out, since clerk api/users will use that key's instance, not the account. - Smaller review items: billing asserts on an already-resolved target, config schema resolves its target once, apply-patch dry-run messages reuse the verb, claim-url validation inlined, keylessTargetStubs covers every export for module mocks, positive test for the non-429 refresh refusal, keyless disable-orgs test, README corrections, changeset trimmed. * refactor(keyless): gather user-facing keyless copy into lib/copy.ts One function per sentence with typed parameters, so a future i18n layer can swap the module's bodies without touching call sites; pluralisation and agreement rules move with the prose. No visible string changes. * docs(changeset): take the keyless-default release to major Signed-out `clerk init` changes behaviour — it now mints a keyless application instead of launching the browser login — so the release is not purely additive even with CLERK_SECRET_KEY precedence restored. * test(env): restore the iOS test's closing brace lost in a rebase conflict seam * fix(keyless): surface malformed local keys and exported key overrides Resolve the local secret key error in checkLoggedIn even when a stored account token exists, so a broken local CLERK_SECRET_KEY isn't hidden behind "Logged in" — other commands still prefer that key over the account session. whoami now also detects an exported CLERK_SECRET_KEY when a directory is linked, matching resolveBapiSecretKey's precedence: that env var overrides even a linked profile, so whoami's answer was wrong for the commands that honor it. Also list a `clerk api /<path>` example for every key, not just the first, when telling the user which keys are already reachable on an unclaimed application. Addresses CodeRabbit review feedback on PR #395.
fix(users): confirm before creating a user, and unstick the skill aud… …it (#400) * fix(users): confirm before creating a user `users create` registers `--yes` as "Skip confirmation prompt" and its `setExamples` recommend passing it, but no prompt existed. The flag was declared on `CreateUserOptions` and never read, so the user was created immediately in every mode. The surrounding code already assumed a prompt: the `catch` handles `UserAbortError` and `isPromptExitError`, neither of which anything inside the `try` could throw. Nearly every existing test threads `yes: true` through to the BAPI call. This wires up the gate those were written against. Human mode now prints the redacted request body and confirms before the POST, matching `clerk api`, `config push`, `unlink`, and `impersonate`. Agent mode is untouched: `isHuman()` is false there, so it never prompts and `--dry-run` stays the safety net. Chose this over dropping the flag because `--help` and the shipped examples have been telling people the prompt exists. Removing `--yes` would break the documented invocations; adding the prompt makes them correct. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs(skills): point audit-clerk-skill at clerk/skills The audit that keeps the `clerk-cli` skill in sync with this binary targets `skills/clerk-cli/SKILL.md`. #315 moved the skill out to clerk/skills, so that path has not existed here since. The audit has been checking nothing, which is how the skill drifted into promising confirmation prompts and a guidance-only agent login that neither exist. Retarget it at a `$SKILL_ROOT` clone of clerk/skills, and drop the `{{CLI_VERSION}}` and `clerk skill install` references that went with the bundled copy. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
chore(test): fail fast when Bun predates `—parallel` test isolation (#… …392) * chore(test): fail fast when Bun predates --parallel test isolation bun test --parallel (and --isolate) first shipped in Bun 1.3.13. Older Bun silently ignores the flags, runs every test file in one process, and lets mock.module() registrations bleed across files — surfacing as hundreds of order-dependent failures. Bun does not enforce engines.bun at install time, so raise the floor to >=1.3.13 and add a preflight (scripts/check-bun-version.ts) that both test scripts run first, failing loudly with an upgrade hint instead of a confusing test cascade. Also sync stale docs that still referenced the removed scripts/run-tests.ts runner (gone since #280) and its flags — notably e2e.md, which documented `test:e2e:op -- --filter react` to scope a run when a forwarded positional pattern now broadens the run to the whole (expensive) e2e suite instead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(test): correct stale test commands surfaced in review - e2e.md: the single-fixture example targeted the fixture project dir (test/e2e/fixtures/react/), which matches no tests; point at the test file (test/e2e/react.test.ts) instead, and fix the patch filename (1.58.2 -> 1.60.0). - CLAUDE.md: CI runs `bun run test`, not a bare `bun test`. - CONTRIBUTING.md: steer contributors to `bun run test` (isolation + version preflight) over bare `bun test`, and replace the removed runner's --filter/--debug/--har flags with the env-var equivalents. - run-e2e-op.ts: the JSDoc example used the dead --filter flag; forwarded args now go to `bun test`, where a positional path broadens the run. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(test): use a real E2E test name in run-e2e-op.ts example The `-t "sign in"` example matched no test name. The registered names are "project builds with no errors", "typecheck passes with no errors", and "app loads and auth flow works" — use "project builds". Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
docs(e2e): align fixture-authoring docs with the #280 manifest harness ( #393) The E2E fixture-authoring docs still described the pre-#280 harness. Update them to match the current manifest-driven setup: - Fixture config now lives in test/e2e/fixtures.manifest.ts (keyed by name), not exported from each test file; tests call createFixtureHarness(name). - Correct the exported helpers to the plural runFixtureTests()/runBrowserTests() in CONTRIBUTING.md (were the singular runFixtureTest()/runBrowserTest()). - Fixture setup uses `npm ci` (fixtures migrated from bun to npm with a checked-in package-lock.json), not `bun install`. - Refresh the FixtureConfig field list (drop removed `description`/`pinned`, add `pinnedDependencyRanges`/`packageJsonOverrides`) and drop the stale `--force`/non-pinned refresh flags (the script only accepts `--only`). Follow-up to #392, which deliberately scoped this rewrite out. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
fix(orgs): enable organization creation defaults with --auto-create (#… …390) The API only auto-creates organizations when both organization_creation_defaults.enabled and the nested automatic_organization_creation.enabled are true. The --auto-create flag previously patched only the nested flag, so on instances where the umbrella setting was never enabled the command succeeded silently but no organization was ever auto-created. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
build(deps): bump actions/setup-node from 6 to 7 (#385) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6 to 7. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](actions/setup-node@v6...v7) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
PreviousNext