Skip to content

feat(log): expand --verbose diagnostics and surface silent env fallback#183

Merged
wyattjoh merged 10 commits intomainfrom
wyattjoh/roomy-arrhinceratops
Apr 20, 2026
Merged

feat(log): expand --verbose diagnostics and surface silent env fallback#183
wyattjoh merged 10 commits intomainfrom
wyattjoh/roomy-arrhinceratops

Conversation

@wyattjoh
Copy link
Copy Markdown
Contributor

@wyattjoh wyattjoh commented Apr 20, 2026

Summary

Expand --verbose diagnostics across the CLI so network, credential, and config failures come with enough context to diagnose in one run. Also warns users when a saved environment is not available in the current binary (previously a silent fallback to production) and cleans up a few snapshot release rough edges surfaced along the way.

What's new

  • --verbose coverage: every outbound HTTP call logs URL, method, status, and response body on error; credential store, config I/O, environment resolution, OAuth callback, git detection, framework detection, autolink, and package-manager runner probing all gain debug lines. All HTTP now goes through a shared loggedFetch helper, codified in a new .claude/rules/ entry so future call sites can't forget the pattern.
  • Env fallback warning: when the CLI falls back from a saved environment to production because the profile isn't compiled in, it now warns at the info level and lists the available environments. Previously, the only symptom was a surprise 401/403 from the next API call.
  • Snapshot releases: the version string now embeds the commit SHA (e.g. 0.8.6-snapshot.a1b2c3d) instead of a datetime; the job refuses to re-publish an already-published commit (use !snapshot <tag> to force a re-run); snapshot builds now inherit the env-profile secrets the same way canary and stable do, so switch-env staging works on a snapshot install; platform packages publish in parallel, wrapper still follows sequentially.

Test plan

  • Unit + integration suite passes
  • Snapshot build verified end-to-end on this PR
  • Spot-check switch-env staging + an API call on the final snapshot install

…tials

When running with --verbose, log.debug() calls now surface:
- plapi: every outgoing request URL and method, plus status + response body on error
- credentials: which keyring account or fallback file is used for each token lookup
- config: the config file path on every read/write
- env: the active environment name and resolved platformApiUrl on startup
@wyattjoh
Copy link
Copy Markdown
Contributor Author

Stack: wyattjoh/roomy-arrhinceratops

Part of a stacked PR chain. Do not merge manually.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 20, 2026

🦋 Changeset detected

Latest commit: b4d7ed0

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

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

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

@wyattjoh wyattjoh marked this pull request as draft April 20, 2026 15:46
@wyattjoh
Copy link
Copy Markdown
Contributor Author

!snapshot

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 20, 2026

📝 Walkthrough

Walkthrough

The PR adds extensive debug logging and a new loggedFetch wrapper across the CLI core, centralizes PLAPI request handling via plapiFetch, and augments observability in config I/O, credential storage, environment resolution, auth-server, autolink, framework detection, git/runners probing, token exchange, update checks, and tests. It introduces debug-logging guidance files, updates changeset/prerelease formatting, modifies CI workflow secrets passing, and changes several build/release scripts to async/concurrent flows and to validate snapshot versions. Some tests’ HTTP stubs were adjusted to distinguish GET vs non-GET. One exported type/function (LoggedFetchInit/loggedFetch) was added.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat(log): expand --verbose diagnostics and surface silent env fallback' accurately and concisely summarizes the main objectives: enhanced logging/diagnostics and warning users about environment fallback behavior.
Description check ✅ Passed The PR description clearly relates to the changeset, detailing the addition of verbose diagnostics, HTTP logging through loggedFetch, environment fallback warnings, and snapshot release improvements—all reflected in the file modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

Snapshot published

npm install -g clerk@0.8.6-snapshot.v20260420154631
Package Version
clerk 0.8.6-snapshot.v20260420154631

Published from 60cd77a

- Warn (without --verbose) when the saved environment is not available
  in the current binary and the CLI silently falls back to production;
  this surfaces the root cause of 403s on snapshot builds that lack
  non-production profiles
- Always log the active environment in verbose mode, including the
  production default case where setCurrentEnv is never called
- Include env name and target URL in the getAuthToken() debug lines so
  credential source and request target are visible in one place
- Log the profiles source (compile-time, file, or defaults) once per
  process so it is clear why certain environments are unavailable
@wyattjoh wyattjoh marked this pull request as ready for review April 20, 2026 16:03
@wyattjoh wyattjoh marked this pull request as draft April 20, 2026 16:03
Convert run/isPublished/publish in scripts/lib/npm.ts from Bun.spawnSync
to async Bun.spawn, then publish the 8 platform packages concurrently
via Promise.all. The wrapper package is still published after all
platform packages complete.
@wyattjoh wyattjoh marked this pull request as ready for review April 20, 2026 16:04
@wyattjoh wyattjoh marked this pull request as draft April 20, 2026 16:04
@wyattjoh
Copy link
Copy Markdown
Contributor Author

!snapshot

@github-actions
Copy link
Copy Markdown
Contributor

Snapshot published

npm install -g clerk@0.8.6-snapshot.v20260420160518
Package Version
clerk 0.8.6-snapshot.v20260420160518

Published from 8b1492a

…mid-publish

The wrapper publish() call was never awaited. This was harmless when
publish was synchronous but became a bug after the parallel publish
refactor made it async: the finally block restored the original
package.json (with private: true and no optionalDependencies) before
npm publish could read the mutated file, so the wrapper clerk package
silently failed to publish. Platform packages were unaffected since
they use a generated package.json on disk.
@wyattjoh wyattjoh marked this pull request as ready for review April 20, 2026 16:19
@wyattjoh wyattjoh marked this pull request as draft April 20, 2026 16:19
@wyattjoh
Copy link
Copy Markdown
Contributor Author

!snapshot

@github-actions
Copy link
Copy Markdown
Contributor

Snapshot published

npm install -g clerk@0.8.6-snapshot.v20260420162038
Package Version
clerk 0.8.6-snapshot.v20260420162038

Published from 5a504c6

Switch the changeset prereleaseTemplate from {tag}.v{datetime} to
{tag}.{commit}, and rewrite the full 40-char SHA changesets emits to
the 7-char short form so versions stay readable (e.g.
0.8.6-snapshot.a1b2c3d).

Because commit-based versions are deterministic per commit, re-running
!snapshot on the same commit would produce a version npm rejects as a
duplicate. Bail out of the snapshot job up front by calling
isPublished("clerk", version); the build/sign/test/publish jobs all
depend on this step so they skip entirely instead of burning ~30
minutes of runner time for nothing.

To re-publish the same commit intentionally, use a different tag name
(e.g. `!snapshot retry`), which produces `0.8.6-retry.a1b2c3d`.
@wyattjoh wyattjoh marked this pull request as ready for review April 20, 2026 16:28
@wyattjoh wyattjoh marked this pull request as draft April 20, 2026 16:28
…ected

The snapshot-build job was the only build-binaries.yml caller missing
secrets: inherit, so secrets.ENV_PROFILES was undefined in the reusable
workflow. build.ts then skipped the --define CLI_ENV_PROFILES=... step
and the resulting binary fell back to hardcoded defaults (production
only), which is why `switch-env staging` errors with
"Unknown environment" on snapshot installs even though canary works.

Matches the pattern already in place for the stable build and
canary-build jobs.
@wyattjoh wyattjoh marked this pull request as ready for review April 20, 2026 16:34
@wyattjoh wyattjoh marked this pull request as draft April 20, 2026 16:34
@wyattjoh
Copy link
Copy Markdown
Contributor Author

!snapshot

@github-actions
Copy link
Copy Markdown
Contributor

Snapshot published

npm install -g clerk@0.8.6-snapshot.640414d
Package Version
clerk 0.8.6-snapshot.640414d

Published from 640414d

Comment thread .changeset/tired-pillows-divide.md Outdated
Comment thread scripts/lib/npm.ts
Comment thread scripts/releaser.ts
Comment thread scripts/snapshot.ts Outdated
Comment thread packages/cli-core/src/lib/plapi.ts
Comment thread packages/cli-core/src/lib/environment.ts Outdated
Comment thread .github/workflows/release.yml
Add lib/fetch.ts exporting loggedFetch(url, { tag, ...init }) which
emits a "<tag>: METHOD url" debug line before the request and, on
non-ok responses, a "<tag>: status METHOD url — body" debug line
(body read from a cloned response so the caller retains ownership).

Migrate every call site that was duplicating this pattern:
- plapi.ts: the six endpoint functions now go through a local
  plapiFetch wrapper that adds Bearer auth + Accept headers on top
  of loggedFetch. Each public function shrinks to ~4 lines.
- commands/api/bapi.ts: the single bapiRequest swaps fetch for
  loggedFetch with tag="bapi".
- lib/token-exchange.ts: both OAuth calls use tag="oauth".
- lib/update-check.ts: fetchLatestVersion uses tag="update-check".

Mock fixup: several test files were detecting mutating requests via
`init?.method ? mutating : fetched`. plapiFetch now always sets
method explicitly (including "GET"), so the truthy check no longer
distinguishes GET from PATCH/PUT. Update the predicates to check
`init.method !== "GET"` explicitly.

Document the pattern in .claude/rules/debug-logging.md (new) with a
pointer from the existing logging.md rule. Future HTTP call sites
must go through loggedFetch; inline log.debug duplicates at call
sites are no longer needed or desired.
…rk, runners

Apply the debug-logging rule to the remaining non-HTTP subsystems so
--verbose tells the full story when a command fails outside the
network path.

- auth-server: listening port, callback outcome (success, state
  mismatch, no code, OAuth error, timeout)
- git: cached single-line summary of getGitRepoInfo (toplevel,
  commonDir, remote) on success; "not a git repository" on failure
- autolink: detected-key count + sources, match result (app id and
  name), no-match branch. Downgrade the listApplications failure log
  from log.error to log.debug — autolink is a best-effort fallback
  and shouldn't surface errors to the user; the caller proceeds to
  the interactive picker.
- framework: which dep matched or why nothing matched
- runners: detected runners on PATH; yarn dlx probe outcome
@wyattjoh wyattjoh marked this pull request as ready for review April 20, 2026 17:13
@wyattjoh wyattjoh marked this pull request as draft April 20, 2026 17:13
- Delete the redundant empty changeset (.changeset/tired-pillows-divide.md).
  roomy-arrhinceratops.md already bumps clerk for this branch, and scripts/**
  is changeset-exempt, so the empty file was pure noise.
- Make the short-sha substitution regex in scripts/snapshot.ts word-bounded
  (\b[a-f0-9]{40}\b) so it stays correct if prereleaseTemplate is later
  changed to append a suffix after the commit SHA.
- Hoist profilesSourceLogged next to currentEnvName in lib/environment.ts so
  both module-level flags sit above the functions that read them, without
  relying on let-hoisting.
…ader coverage

The original summary only named the four files touched by the first commit
(plapi, credential-store, config, environment). The branch has since grown
to include an info-level fallback warning, HTTP-wide loggedFetch migration,
and debug coverage for the auth server, git helpers, autolink, framework
detection, and runner probing. Rewrite the summary so the changelog entry
reflects what actually ships.
@wyattjoh wyattjoh marked this pull request as ready for review April 20, 2026 17:18
@wyattjoh wyattjoh marked this pull request as draft April 20, 2026 17:18
@wyattjoh wyattjoh changed the title feat(debug): add verbose debug output for network, config, and credentials feat(log): expand --verbose diagnostics and surface silent env fallback Apr 20, 2026
@wyattjoh
Copy link
Copy Markdown
Contributor Author

!snapshot

@github-actions
Copy link
Copy Markdown
Contributor

Snapshot published

npm install -g clerk@0.8.6-snapshot.b4d7ed0
Package Version
clerk 0.8.6-snapshot.b4d7ed0

Published from b4d7ed0

@wyattjoh wyattjoh marked this pull request as ready for review April 20, 2026 17:39
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/cli-core/src/cli-program.ts`:
- Around line 76-85: The fallback branch logs that it’s falling back to
production but never updates the module-scoped environment, leaving a stale env
active; call setCurrentEnv("production") when envName is invalid (inside the
else path) so the active environment state is updated, then keep the existing
log.debug that uses getPlapiBaseUrl() and list available envs via
getAvailableEnvs() to preserve diagnostic messages.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ff0da1f5-bbda-4d61-86c8-e50b16311a17

📥 Commits

Reviewing files that changed from the base of the PR and between 60cd77a and b4d7ed0.

📒 Files selected for processing (25)
  • .changeset/config.json
  • .changeset/roomy-arrhinceratops.md
  • .claude/rules/debug-logging.md
  • .claude/rules/logging.md
  • .github/workflows/release.yml
  • packages/cli-core/src/cli-program.ts
  • packages/cli-core/src/commands/api/bapi.ts
  • packages/cli-core/src/commands/config/push.test.ts
  • packages/cli-core/src/lib/auth-server.ts
  • packages/cli-core/src/lib/autolink.ts
  • packages/cli-core/src/lib/environment.ts
  • packages/cli-core/src/lib/fetch.ts
  • packages/cli-core/src/lib/framework.ts
  • packages/cli-core/src/lib/git.ts
  • packages/cli-core/src/lib/plapi.ts
  • packages/cli-core/src/lib/runners.ts
  • packages/cli-core/src/lib/token-exchange.ts
  • packages/cli-core/src/lib/update-check.ts
  • packages/cli-core/src/test/integration/config-management.test.ts
  • packages/cli-core/src/test/integration/config-put.test.ts
  • packages/cli-core/src/test/integration/dry-run.test.ts
  • scripts/check-release.ts
  • scripts/lib/npm.ts
  • scripts/releaser.ts
  • scripts/snapshot.ts
✅ Files skipped from review due to trivial changes (5)
  • .changeset/config.json
  • .claude/rules/logging.md
  • packages/cli-core/src/lib/git.ts
  • packages/cli-core/src/test/integration/config-put.test.ts
  • packages/cli-core/src/lib/framework.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • .changeset/roomy-arrhinceratops.md
  • packages/cli-core/src/lib/plapi.ts

Comment on lines +76 to 85
setCurrentEnv(envName); // logs env + platformApiUrl
} else {
if (envName) {
log.warn(
`Saved environment "${envName}" is not available in this binary. Falling back to production.`,
);
log.warn(`Available environments: ${getAvailableEnvs().join(", ")}`);
}
log.debug(`env: active environment is "production" (platformApiUrl=${getPlapiBaseUrl()})`);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fallback branch doesn’t actually set production as active env.

When envName is invalid, this path only logs fallback but never updates the active environment state. Since environment state is module-scoped and mutated via setCurrentEnv(), a reused process can keep a stale non-production env from a previous invocation.

Suggested fix
-    if (envName && isValidEnv(envName)) {
-      setCurrentEnv(envName); // logs env + platformApiUrl
-    } else {
+    if (envName && isValidEnv(envName)) {
+      setCurrentEnv(envName); // logs env + platformApiUrl
+    } else {
       if (envName) {
         log.warn(
           `Saved environment "${envName}" is not available in this binary. Falling back to production.`,
         );
         log.warn(`Available environments: ${getAvailableEnvs().join(", ")}`);
       }
-      log.debug(`env: active environment is "production" (platformApiUrl=${getPlapiBaseUrl()})`);
+      setCurrentEnv("production"); // logs env + platformApiUrl
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
setCurrentEnv(envName); // logs env + platformApiUrl
} else {
if (envName) {
log.warn(
`Saved environment "${envName}" is not available in this binary. Falling back to production.`,
);
log.warn(`Available environments: ${getAvailableEnvs().join(", ")}`);
}
log.debug(`env: active environment is "production" (platformApiUrl=${getPlapiBaseUrl()})`);
}
setCurrentEnv(envName); // logs env + platformApiUrl
} else {
if (envName) {
log.warn(
`Saved environment "${envName}" is not available in this binary. Falling back to production.`,
);
log.warn(`Available environments: ${getAvailableEnvs().join(", ")}`);
}
setCurrentEnv("production"); // logs env + platformApiUrl
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cli-core/src/cli-program.ts` around lines 76 - 85, The fallback
branch logs that it’s falling back to production but never updates the
module-scoped environment, leaving a stale env active; call
setCurrentEnv("production") when envName is invalid (inside the else path) so
the active environment state is updated, then keep the existing log.debug that
uses getPlapiBaseUrl() and list available envs via getAvailableEnvs() to
preserve diagnostic messages.

@wyattjoh wyattjoh merged commit eb06da9 into main Apr 20, 2026
10 checks passed
@wyattjoh wyattjoh deleted the wyattjoh/roomy-arrhinceratops branch April 20, 2026 17:47
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.

2 participants