feat(deploy): add read-only deploy verification - #312

Merged
wyattjoh merged 26 commits into
wyattjoh/deployfrom
wyattjoh/deploy-agent-mode
May 29, 2026
Merged

feat(deploy): add read-only deploy verification#312
wyattjoh merged 26 commits into
wyattjoh/deployfrom
wyattjoh/deploy-agent-mode

Conversation

@wyattjoh

@wyattjohwyattjoh commented May 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds clerk deploy status as a read-only verification gate for DNS, SSL, email DNS, and OAuth readiness.
  • Makes agent-mode clerk deploy return a JSON handoff instead of trying to run the interactive wizard.
  • Shows a spinner during the brief post-trigger wait while Clerk processes the DNS check.
  • Refactors deploy status resolution for shared human and agent flows, updates docs and skill guidance, and adds tests plus Bun test isolation guidance.

Testing

  • bun test --isolate packages/cli-core/src/cli-program.test.ts packages/cli-core/src/test/integration/completion.test.ts packages/cli-core/src/commands/deploy/status-command.test.ts packages/cli-core/src/commands/deploy/index.test.ts --timeout 20000
  • bun run format
  • bun run format:check
  • bun run lint
  • bun run typecheck
  • bun run test

Review

  • Independent subagent review found no findings.

@changeset-bot

changeset-botBot commented May 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 19caa25

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

This PR includes changesets to release 1 package
NameType
clerkMinor

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 ready for review May 29, 2026 13:28
@wyattjoh
wyattjoh requested a review from rafa-thaytoMay 29, 2026 13:29
@rafa-thayto

Copy link
Copy Markdown
Contributor

!snapshot

@github-actions

Copy link
Copy Markdown
Contributor

Snapshot published

npm install -g clerk@1.5.1-snapshot.19caa25
PackageVersion
clerk1.5.1-snapshot.19caa25

Published from 19caa25

@wyattjoh
wyattjoh merged commit 688f965 into wyattjoh/deployMay 29, 2026
2 checks passed
@wyattjoh
wyattjoh deleted the wyattjoh/deploy-agent-mode branch May 29, 2026 13:35
@wyattjoh
wyattjoh restored the wyattjoh/deploy-agent-mode branch May 29, 2026 13:35
rafa-thayto added a commit that referenced this pull request May 29, 2026
* feat(deploy): implement resumable deploy wizard
* fix(deploy): address review feedback on resumable wizard
- Preserve completed providers when pausing OAuth setup mid-loop, so
`clerk deploy --continue` can finish multi-provider stacks.
- Surface a warning for OAuth providers enabled in dev that the wizard
does not yet support, instead of silently skipping them.
- Close the gutter as Paused (not Failed) when DNS verification times
out, since the state is recoverable via --continue.
- Tighten the production-domain regex to reject malformed inputs like
example..com or example-.com before they reach the API.
* refactor(deploy): isolate lifecycle api calls
Move deploy lifecycle endpoint wrappers into the shared PLAPI client while routing the deploy wizard through a command-local adapter that defaults to mocked operations until the backend endpoints are ready.
* feat(deploy): resolve production state from API
* fix(deploy): route test failures through api path
* fix(deploy): remove gutter tone plumbing
* fix(deploy): require human mode for production setup
* refactor(deploy): route lifecycle test failures through api mock
* refactor(deploy): extract mock api into its own module
* refactor(deploy): route lifecycle through live PLAPI and map errors
Switch the deploy command from the in-process mock lifecycle to the live
PLAPI endpoints. Add a typed error mapper that translates known PLAPI
failures (plan_insufficient, home_url_taken, ssl_retry_throttled, etc.)
into CliError with stable codes, with a recovery path for the
production_instance_exists case so the wizard re-derives state instead
of surfacing the error.
Surface per-component progress (DNS / SSL / mail) during deploy_status
polling, and drop the four hidden --test-fail-* CLI options now that
failure injection is routed through the test's module mock.
Collapse the api/mock indirection layer to a thin re-export of the
plapi endpoints + a no-op configureMockDeployApi stub for the test
seam, and strip the dead mockDeployApi implementation that the
indirection used to back.
* feat(deploy): replace DNS handoff confirm with verify-or-skip choice
Swap the "Continue to OAuth setup?" yes/no prompt during initial
production setup for the same verify/skip select used when resuming.
Choosing skip records DNS as pending and continues to OAuth instead of
pausing the deploy, so the dashboard remains the single place to monitor
propagation.
* feat(deploy): refresh DNS verification for current API surface
- Tolerate getDeployStatus failures inside the reconcile-path snapshot
read so the deploy continues to the verify-or-skip prompt instead of
failing before the user can react.
- Split the snapshot fetch into separate "Reading development
configuration" and "Reading production configuration" spinners so the
gutter reflects what is actually being loaded.
- Add triggerDomainDnsCheck (POST .../dns_check) and call it best-effort
when the user picks "Check DNS now" so an active check job is kicked
rather than waiting on background reconciliation.
- Type the dns_ok/ssl_ok/mail_ok booleans on DeployStatusResponse and use
them to name the specific pending component in the timeout warning.
* refactor(deploy): drop ./api.ts and ./mock.ts test indirection
Switch deploy command imports back to lib/plapi.ts directly and remove the
./mock.ts harness plus the --test-force-* / --test-fail-* CLI flags it
backed. The wrappers were added for an earlier mockable-deploy-API
experiment that is no longer needed.
* feat(deploy): add bindZoneFile formatter for DNS records export
* feat(deploy): add per-component spinner label lookup
* feat(deploy): sequence DNS verification feedback per component
Replace the single-spinner pollDeployStatus loop with a chained
mail/dns/ssl spinner sequence that emits a per-component success
line as each boolean flips true. Add a defensive status === "complete"
check after all three components succeed so the proxy_ok server-side
case fails closed rather than reporting verified. When all DNS
components are resolved but the server has not yet marked the
deployment complete, exit the verification path without reaching
finishDeploy.
* feat(deploy): show DNS records on the resume verification path
* feat(deploy): offer BIND zone export after DNS records
After the DNS records block in both runDnsSetup and
runExistingDomainDnsVerification, prompt the user (default: no) to
export the records as a clerk-<domain>.zone BIND zone file.
* docs(deploy): document per-component verification and BIND export
* docs(changeset): document clerk deploy production wizard
* refactor(plapi): drop unused is_secondary from CreateProductionInstanceParams
* refactor(plapi): allow null active_domain and guard in deploy wizard
* fix(deploy): remove Domain Connect prompt and address review feedback
The Domain Connect URL helper returned Cloudflare's template for every
domain regardless of the actual registrar — a misleading prompt for any
user not on Cloudflare. Remove it entirely until NS-based registrar
detection lands as its own change.
Other cleanups from the same review pass: runDeploy throws a NOT_LINKED
CliError on unlinked directories instead of warning and exiting zero;
startNewDeploy's 409 production_instance_exists recovery now persists
the recovered production instance id to the profile; OAuth skip routes
through deployPausedError so its exit code matches Ctrl-C (1 instead of
silent 0); runDnsVerification loops on timeout retry instead of
recursing; and runOAuthSetup drops the redundant startIndex slice since
the completed set already skips previously-saved providers.
* fix(deploy): use domain status for verification
Switch production deploy verification to the application domain status endpoint and remove obsolete retry-specific handling. Cap domain status polling to the shared 10-second budget while keeping 3-second intervals.
* fix(deploy): defer DNS verification until after OAuth
* fix(deploy): refresh dns checks before polling
Trigger a fresh domain DNS check before status polling and retry status reads with exponential backoff while updating the spinner countdown.
* fix(deploy): report dns verification pauses
* feat(deploy): type instance config schemas
* feat(deploy): derive oauth provider descriptors from schema
* feat(deploy): use schema-driven oauth setup
* feat(deploy): resume oauth setup from schema descriptors
* feat(deploy): preserve oauth provider special prompts
* docs(deploy): document schema-driven oauth setup
* fix(deploy): warn generically for unsupported oauth providers
* fix(deploy): ignore optional oauth schema fields
* fix(deploy): support public oauth providers
* fix(deploy): use verbose for debug output
* fix(deploy): remove oauth provider allowlist
* refactor(deploy): derive oauth compatibility metadata
* refactor(deploy): simplify oauth provider overrides
* fix(ci): retry transient cleanup API failures
* fix(deploy): adapt to platform instance response
* fix(deploy): update retry status copy
* Update packages/cli-core/src/commands/deploy/copy.ts
Co-authored-by: Rafael Thayto <rafa.thayto@gmail.com>
* Revert "Update packages/cli-core/src/commands/deploy/copy.ts"
This reverts commit fa5821c.
* fix(review): address deploy PR feedback
- give each deploy status component its own retry budget
- normalize absent domain status components as pending
- load resume domain and OAuth provider state concurrently
- collapse repeated OAuth provider override lookups
* fix(deploy): link domain settings in next steps
Add a direct Clerk Dashboard domains URL to deploy completion output so users can manage their production domain configuration.
* feat(deploy): add read-only deploy verification (#312)
* refactor(deploy): extract poll core into status.ts
* refactor(deploy): move state resolution into status.ts, rename dnsComplete
* feat(deploy): add resolveDeployState discriminator
* feat(deploy): add buildDeployStatusReport payload builder
* feat(deploy): add clerk deploy check command
* feat(deploy): tailor agent-mode deploy into a read-only handoff
* feat(deploy): register clerk deploy check subcommand
* docs(deploy): document deploy check and agent handoff
* fix(deploy): surface agent status read failures
* docs(clerk-cli): document deploy agent workflow
* fix(deploy): avoid backoff in agent check
* fix(deploy): check domain status as one DNS verification
* fix(deploy): include domains URL in agent next action
* fix(deploy): prompt agents to open domains URL
* docs(clerk-cli): warn deploy wizard needs a terminal
* fix(cli): address deploy review follow-ups
* fix(deploy): persist live production instance metadata
* chore: added link for codex
* docs(clerk-cli): clarify deploy check agent workflow
* refactor(deploy): remove unused status check helper
* test(deploy): avoid leaking deploy check mocks
* docs(testing): document bun test isolation
* docs: remove hidden bird command from readme
* feat(deploy): rename status check command
* fix(deploy): humanize status dashboard guidance
* refactor(deploy): tighten status resolution
* fix(deploy): label DKIM records as email in DNS handoff
cnameTargetLabel keyed off the full `clk._domainkey`/`clk2._domainkey` labels, but host.split(".", 1)[0] only ever yields the first label ("clk"/"clk2"), so those cases were dead and DKIM records rendered as a generic "CNAME". Match the actual prefixes so DKIM records show the email label.
* refactor(deploy): drop unreachable OAuth completion guards
runOAuthSetup pauses by throwing DeployPausedError on skip or interrupt, so it never returns a partial list. The `completed.length < providers.length` guards after it were dead code implying a contract that does not exist. Remove them and document the pause-by-throw contract on runOAuthSetup instead.
* fix(deploy): re-prompt Google OAuth JSON after docs
* fix(deploy): re-prompt oauth credentials after walkthrough
---------
Co-authored-by: Rafael Thayto <rafa.thayto@gmail.com>
Sign up for freeto 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

@wyattjoh@rafa-thayto
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(deploy): add read-only deploy verification - #312

Merged
wyattjoh merged 26 commits into
wyattjoh/deployfrom
wyattjoh/deploy-agent-mode
May 29, 2026
Merged

feat(deploy): add read-only deploy verification#312
wyattjoh merged 26 commits into
wyattjoh/deployfrom
wyattjoh/deploy-agent-mode

Conversation

@wyattjoh

@wyattjohwyattjoh commented May 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds clerk deploy status as a read-only verification gate for DNS, SSL, email DNS, and OAuth readiness.
  • Makes agent-mode clerk deploy return a JSON handoff instead of trying to run the interactive wizard.
  • Shows a spinner during the brief post-trigger wait while Clerk processes the DNS check.
  • Refactors deploy status resolution for shared human and agent flows, updates docs and skill guidance, and adds tests plus Bun test isolation guidance.

Testing

  • bun test --isolate packages/cli-core/src/cli-program.test.ts packages/cli-core/src/test/integration/completion.test.ts packages/cli-core/src/commands/deploy/status-command.test.ts packages/cli-core/src/commands/deploy/index.test.ts --timeout 20000
  • bun run format
  • bun run format:check
  • bun run lint
  • bun run typecheck
  • bun run test

Review

  • Independent subagent review found no findings.

@changeset-bot

changeset-botBot commented May 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 19caa25

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

This PR includes changesets to release 1 package
NameType
clerkMinor

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 ready for review May 29, 2026 13:28
@wyattjoh
wyattjoh requested a review from rafa-thaytoMay 29, 2026 13:29
@rafa-thayto

Copy link
Copy Markdown
Contributor

!snapshot

@github-actions

Copy link
Copy Markdown
Contributor

Snapshot published

npm install -g clerk@1.5.1-snapshot.19caa25
PackageVersion
clerk1.5.1-snapshot.19caa25

Published from 19caa25

@wyattjoh
wyattjoh merged commit 688f965 into wyattjoh/deployMay 29, 2026
2 checks passed
@wyattjoh
wyattjoh deleted the wyattjoh/deploy-agent-mode branch May 29, 2026 13:35
@wyattjoh
wyattjoh restored the wyattjoh/deploy-agent-mode branch May 29, 2026 13:35
rafa-thayto added a commit that referenced this pull request May 29, 2026
* feat(deploy): implement resumable deploy wizard
* fix(deploy): address review feedback on resumable wizard
- Preserve completed providers when pausing OAuth setup mid-loop, so
`clerk deploy --continue` can finish multi-provider stacks.
- Surface a warning for OAuth providers enabled in dev that the wizard
does not yet support, instead of silently skipping them.
- Close the gutter as Paused (not Failed) when DNS verification times
out, since the state is recoverable via --continue.
- Tighten the production-domain regex to reject malformed inputs like
example..com or example-.com before they reach the API.
* refactor(deploy): isolate lifecycle api calls
Move deploy lifecycle endpoint wrappers into the shared PLAPI client while routing the deploy wizard through a command-local adapter that defaults to mocked operations until the backend endpoints are ready.
* feat(deploy): resolve production state from API
* fix(deploy): route test failures through api path
* fix(deploy): remove gutter tone plumbing
* fix(deploy): require human mode for production setup
* refactor(deploy): route lifecycle test failures through api mock
* refactor(deploy): extract mock api into its own module
* refactor(deploy): route lifecycle through live PLAPI and map errors
Switch the deploy command from the in-process mock lifecycle to the live
PLAPI endpoints. Add a typed error mapper that translates known PLAPI
failures (plan_insufficient, home_url_taken, ssl_retry_throttled, etc.)
into CliError with stable codes, with a recovery path for the
production_instance_exists case so the wizard re-derives state instead
of surfacing the error.
Surface per-component progress (DNS / SSL / mail) during deploy_status
polling, and drop the four hidden --test-fail-* CLI options now that
failure injection is routed through the test's module mock.
Collapse the api/mock indirection layer to a thin re-export of the
plapi endpoints + a no-op configureMockDeployApi stub for the test
seam, and strip the dead mockDeployApi implementation that the
indirection used to back.
* feat(deploy): replace DNS handoff confirm with verify-or-skip choice
Swap the "Continue to OAuth setup?" yes/no prompt during initial
production setup for the same verify/skip select used when resuming.
Choosing skip records DNS as pending and continues to OAuth instead of
pausing the deploy, so the dashboard remains the single place to monitor
propagation.
* feat(deploy): refresh DNS verification for current API surface
- Tolerate getDeployStatus failures inside the reconcile-path snapshot
read so the deploy continues to the verify-or-skip prompt instead of
failing before the user can react.
- Split the snapshot fetch into separate "Reading development
configuration" and "Reading production configuration" spinners so the
gutter reflects what is actually being loaded.
- Add triggerDomainDnsCheck (POST .../dns_check) and call it best-effort
when the user picks "Check DNS now" so an active check job is kicked
rather than waiting on background reconciliation.
- Type the dns_ok/ssl_ok/mail_ok booleans on DeployStatusResponse and use
them to name the specific pending component in the timeout warning.
* refactor(deploy): drop ./api.ts and ./mock.ts test indirection
Switch deploy command imports back to lib/plapi.ts directly and remove the
./mock.ts harness plus the --test-force-* / --test-fail-* CLI flags it
backed. The wrappers were added for an earlier mockable-deploy-API
experiment that is no longer needed.
* feat(deploy): add bindZoneFile formatter for DNS records export
* feat(deploy): add per-component spinner label lookup
* feat(deploy): sequence DNS verification feedback per component
Replace the single-spinner pollDeployStatus loop with a chained
mail/dns/ssl spinner sequence that emits a per-component success
line as each boolean flips true. Add a defensive status === "complete"
check after all three components succeed so the proxy_ok server-side
case fails closed rather than reporting verified. When all DNS
components are resolved but the server has not yet marked the
deployment complete, exit the verification path without reaching
finishDeploy.
* feat(deploy): show DNS records on the resume verification path
* feat(deploy): offer BIND zone export after DNS records
After the DNS records block in both runDnsSetup and
runExistingDomainDnsVerification, prompt the user (default: no) to
export the records as a clerk-<domain>.zone BIND zone file.
* docs(deploy): document per-component verification and BIND export
* docs(changeset): document clerk deploy production wizard
* refactor(plapi): drop unused is_secondary from CreateProductionInstanceParams
* refactor(plapi): allow null active_domain and guard in deploy wizard
* fix(deploy): remove Domain Connect prompt and address review feedback
The Domain Connect URL helper returned Cloudflare's template for every
domain regardless of the actual registrar — a misleading prompt for any
user not on Cloudflare. Remove it entirely until NS-based registrar
detection lands as its own change.
Other cleanups from the same review pass: runDeploy throws a NOT_LINKED
CliError on unlinked directories instead of warning and exiting zero;
startNewDeploy's 409 production_instance_exists recovery now persists
the recovered production instance id to the profile; OAuth skip routes
through deployPausedError so its exit code matches Ctrl-C (1 instead of
silent 0); runDnsVerification loops on timeout retry instead of
recursing; and runOAuthSetup drops the redundant startIndex slice since
the completed set already skips previously-saved providers.
* fix(deploy): use domain status for verification
Switch production deploy verification to the application domain status endpoint and remove obsolete retry-specific handling. Cap domain status polling to the shared 10-second budget while keeping 3-second intervals.
* fix(deploy): defer DNS verification until after OAuth
* fix(deploy): refresh dns checks before polling
Trigger a fresh domain DNS check before status polling and retry status reads with exponential backoff while updating the spinner countdown.
* fix(deploy): report dns verification pauses
* feat(deploy): type instance config schemas
* feat(deploy): derive oauth provider descriptors from schema
* feat(deploy): use schema-driven oauth setup
* feat(deploy): resume oauth setup from schema descriptors
* feat(deploy): preserve oauth provider special prompts
* docs(deploy): document schema-driven oauth setup
* fix(deploy): warn generically for unsupported oauth providers
* fix(deploy): ignore optional oauth schema fields
* fix(deploy): support public oauth providers
* fix(deploy): use verbose for debug output
* fix(deploy): remove oauth provider allowlist
* refactor(deploy): derive oauth compatibility metadata
* refactor(deploy): simplify oauth provider overrides
* fix(ci): retry transient cleanup API failures
* fix(deploy): adapt to platform instance response
* fix(deploy): update retry status copy
* Update packages/cli-core/src/commands/deploy/copy.ts
Co-authored-by: Rafael Thayto <rafa.thayto@gmail.com>
* Revert "Update packages/cli-core/src/commands/deploy/copy.ts"
This reverts commit fa5821c.
* fix(review): address deploy PR feedback
- give each deploy status component its own retry budget
- normalize absent domain status components as pending
- load resume domain and OAuth provider state concurrently
- collapse repeated OAuth provider override lookups
* fix(deploy): link domain settings in next steps
Add a direct Clerk Dashboard domains URL to deploy completion output so users can manage their production domain configuration.
* feat(deploy): add read-only deploy verification (#312)
* refactor(deploy): extract poll core into status.ts
* refactor(deploy): move state resolution into status.ts, rename dnsComplete
* feat(deploy): add resolveDeployState discriminator
* feat(deploy): add buildDeployStatusReport payload builder
* feat(deploy): add clerk deploy check command
* feat(deploy): tailor agent-mode deploy into a read-only handoff
* feat(deploy): register clerk deploy check subcommand
* docs(deploy): document deploy check and agent handoff
* fix(deploy): surface agent status read failures
* docs(clerk-cli): document deploy agent workflow
* fix(deploy): avoid backoff in agent check
* fix(deploy): check domain status as one DNS verification
* fix(deploy): include domains URL in agent next action
* fix(deploy): prompt agents to open domains URL
* docs(clerk-cli): warn deploy wizard needs a terminal
* fix(cli): address deploy review follow-ups
* fix(deploy): persist live production instance metadata
* chore: added link for codex
* docs(clerk-cli): clarify deploy check agent workflow
* refactor(deploy): remove unused status check helper
* test(deploy): avoid leaking deploy check mocks
* docs(testing): document bun test isolation
* docs: remove hidden bird command from readme
* feat(deploy): rename status check command
* fix(deploy): humanize status dashboard guidance
* refactor(deploy): tighten status resolution
* fix(deploy): label DKIM records as email in DNS handoff
cnameTargetLabel keyed off the full `clk._domainkey`/`clk2._domainkey` labels, but host.split(".", 1)[0] only ever yields the first label ("clk"/"clk2"), so those cases were dead and DKIM records rendered as a generic "CNAME". Match the actual prefixes so DKIM records show the email label.
* refactor(deploy): drop unreachable OAuth completion guards
runOAuthSetup pauses by throwing DeployPausedError on skip or interrupt, so it never returns a partial list. The `completed.length < providers.length` guards after it were dead code implying a contract that does not exist. Remove them and document the pause-by-throw contract on runOAuthSetup instead.
* fix(deploy): re-prompt Google OAuth JSON after docs
* fix(deploy): re-prompt oauth credentials after walkthrough
---------
Co-authored-by: Rafael Thayto <rafa.thayto@gmail.com>
Sign up for freeto 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

@wyattjoh@rafa-thayto
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(deploy): add read-only deploy verification - #312

Merged
wyattjoh merged 26 commits into
wyattjoh/deployfrom
wyattjoh/deploy-agent-mode
May 29, 2026
Merged

feat(deploy): add read-only deploy verification#312
wyattjoh merged 26 commits into
wyattjoh/deployfrom
wyattjoh/deploy-agent-mode

Conversation

@wyattjoh

@wyattjohwyattjoh commented May 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds clerk deploy status as a read-only verification gate for DNS, SSL, email DNS, and OAuth readiness.
  • Makes agent-mode clerk deploy return a JSON handoff instead of trying to run the interactive wizard.
  • Shows a spinner during the brief post-trigger wait while Clerk processes the DNS check.
  • Refactors deploy status resolution for shared human and agent flows, updates docs and skill guidance, and adds tests plus Bun test isolation guidance.

Testing

  • bun test --isolate packages/cli-core/src/cli-program.test.ts packages/cli-core/src/test/integration/completion.test.ts packages/cli-core/src/commands/deploy/status-command.test.ts packages/cli-core/src/commands/deploy/index.test.ts --timeout 20000
  • bun run format
  • bun run format:check
  • bun run lint
  • bun run typecheck
  • bun run test

Review

  • Independent subagent review found no findings.

@changeset-bot

changeset-botBot commented May 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 19caa25

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

This PR includes changesets to release 1 package
NameType
clerkMinor

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 ready for review May 29, 2026 13:28
@wyattjoh
wyattjoh requested a review from rafa-thaytoMay 29, 2026 13:29
@rafa-thayto

Copy link
Copy Markdown
Contributor

!snapshot

@github-actions

Copy link
Copy Markdown
Contributor

Snapshot published

npm install -g clerk@1.5.1-snapshot.19caa25
PackageVersion
clerk1.5.1-snapshot.19caa25

Published from 19caa25

@wyattjoh
wyattjoh merged commit 688f965 into wyattjoh/deployMay 29, 2026
2 checks passed
@wyattjoh
wyattjoh deleted the wyattjoh/deploy-agent-mode branch May 29, 2026 13:35
@wyattjoh
wyattjoh restored the wyattjoh/deploy-agent-mode branch May 29, 2026 13:35
rafa-thayto added a commit that referenced this pull request May 29, 2026
* feat(deploy): implement resumable deploy wizard
* fix(deploy): address review feedback on resumable wizard
- Preserve completed providers when pausing OAuth setup mid-loop, so
`clerk deploy --continue` can finish multi-provider stacks.
- Surface a warning for OAuth providers enabled in dev that the wizard
does not yet support, instead of silently skipping them.
- Close the gutter as Paused (not Failed) when DNS verification times
out, since the state is recoverable via --continue.
- Tighten the production-domain regex to reject malformed inputs like
example..com or example-.com before they reach the API.
* refactor(deploy): isolate lifecycle api calls
Move deploy lifecycle endpoint wrappers into the shared PLAPI client while routing the deploy wizard through a command-local adapter that defaults to mocked operations until the backend endpoints are ready.
* feat(deploy): resolve production state from API
* fix(deploy): route test failures through api path
* fix(deploy): remove gutter tone plumbing
* fix(deploy): require human mode for production setup
* refactor(deploy): route lifecycle test failures through api mock
* refactor(deploy): extract mock api into its own module
* refactor(deploy): route lifecycle through live PLAPI and map errors
Switch the deploy command from the in-process mock lifecycle to the live
PLAPI endpoints. Add a typed error mapper that translates known PLAPI
failures (plan_insufficient, home_url_taken, ssl_retry_throttled, etc.)
into CliError with stable codes, with a recovery path for the
production_instance_exists case so the wizard re-derives state instead
of surfacing the error.
Surface per-component progress (DNS / SSL / mail) during deploy_status
polling, and drop the four hidden --test-fail-* CLI options now that
failure injection is routed through the test's module mock.
Collapse the api/mock indirection layer to a thin re-export of the
plapi endpoints + a no-op configureMockDeployApi stub for the test
seam, and strip the dead mockDeployApi implementation that the
indirection used to back.
* feat(deploy): replace DNS handoff confirm with verify-or-skip choice
Swap the "Continue to OAuth setup?" yes/no prompt during initial
production setup for the same verify/skip select used when resuming.
Choosing skip records DNS as pending and continues to OAuth instead of
pausing the deploy, so the dashboard remains the single place to monitor
propagation.
* feat(deploy): refresh DNS verification for current API surface
- Tolerate getDeployStatus failures inside the reconcile-path snapshot
read so the deploy continues to the verify-or-skip prompt instead of
failing before the user can react.
- Split the snapshot fetch into separate "Reading development
configuration" and "Reading production configuration" spinners so the
gutter reflects what is actually being loaded.
- Add triggerDomainDnsCheck (POST .../dns_check) and call it best-effort
when the user picks "Check DNS now" so an active check job is kicked
rather than waiting on background reconciliation.
- Type the dns_ok/ssl_ok/mail_ok booleans on DeployStatusResponse and use
them to name the specific pending component in the timeout warning.
* refactor(deploy): drop ./api.ts and ./mock.ts test indirection
Switch deploy command imports back to lib/plapi.ts directly and remove the
./mock.ts harness plus the --test-force-* / --test-fail-* CLI flags it
backed. The wrappers were added for an earlier mockable-deploy-API
experiment that is no longer needed.
* feat(deploy): add bindZoneFile formatter for DNS records export
* feat(deploy): add per-component spinner label lookup
* feat(deploy): sequence DNS verification feedback per component
Replace the single-spinner pollDeployStatus loop with a chained
mail/dns/ssl spinner sequence that emits a per-component success
line as each boolean flips true. Add a defensive status === "complete"
check after all three components succeed so the proxy_ok server-side
case fails closed rather than reporting verified. When all DNS
components are resolved but the server has not yet marked the
deployment complete, exit the verification path without reaching
finishDeploy.
* feat(deploy): show DNS records on the resume verification path
* feat(deploy): offer BIND zone export after DNS records
After the DNS records block in both runDnsSetup and
runExistingDomainDnsVerification, prompt the user (default: no) to
export the records as a clerk-<domain>.zone BIND zone file.
* docs(deploy): document per-component verification and BIND export
* docs(changeset): document clerk deploy production wizard
* refactor(plapi): drop unused is_secondary from CreateProductionInstanceParams
* refactor(plapi): allow null active_domain and guard in deploy wizard
* fix(deploy): remove Domain Connect prompt and address review feedback
The Domain Connect URL helper returned Cloudflare's template for every
domain regardless of the actual registrar — a misleading prompt for any
user not on Cloudflare. Remove it entirely until NS-based registrar
detection lands as its own change.
Other cleanups from the same review pass: runDeploy throws a NOT_LINKED
CliError on unlinked directories instead of warning and exiting zero;
startNewDeploy's 409 production_instance_exists recovery now persists
the recovered production instance id to the profile; OAuth skip routes
through deployPausedError so its exit code matches Ctrl-C (1 instead of
silent 0); runDnsVerification loops on timeout retry instead of
recursing; and runOAuthSetup drops the redundant startIndex slice since
the completed set already skips previously-saved providers.
* fix(deploy): use domain status for verification
Switch production deploy verification to the application domain status endpoint and remove obsolete retry-specific handling. Cap domain status polling to the shared 10-second budget while keeping 3-second intervals.
* fix(deploy): defer DNS verification until after OAuth
* fix(deploy): refresh dns checks before polling
Trigger a fresh domain DNS check before status polling and retry status reads with exponential backoff while updating the spinner countdown.
* fix(deploy): report dns verification pauses
* feat(deploy): type instance config schemas
* feat(deploy): derive oauth provider descriptors from schema
* feat(deploy): use schema-driven oauth setup
* feat(deploy): resume oauth setup from schema descriptors
* feat(deploy): preserve oauth provider special prompts
* docs(deploy): document schema-driven oauth setup
* fix(deploy): warn generically for unsupported oauth providers
* fix(deploy): ignore optional oauth schema fields
* fix(deploy): support public oauth providers
* fix(deploy): use verbose for debug output
* fix(deploy): remove oauth provider allowlist
* refactor(deploy): derive oauth compatibility metadata
* refactor(deploy): simplify oauth provider overrides
* fix(ci): retry transient cleanup API failures
* fix(deploy): adapt to platform instance response
* fix(deploy): update retry status copy
* Update packages/cli-core/src/commands/deploy/copy.ts
Co-authored-by: Rafael Thayto <rafa.thayto@gmail.com>
* Revert "Update packages/cli-core/src/commands/deploy/copy.ts"
This reverts commit fa5821c.
* fix(review): address deploy PR feedback
- give each deploy status component its own retry budget
- normalize absent domain status components as pending
- load resume domain and OAuth provider state concurrently
- collapse repeated OAuth provider override lookups
* fix(deploy): link domain settings in next steps
Add a direct Clerk Dashboard domains URL to deploy completion output so users can manage their production domain configuration.
* feat(deploy): add read-only deploy verification (#312)
* refactor(deploy): extract poll core into status.ts
* refactor(deploy): move state resolution into status.ts, rename dnsComplete
* feat(deploy): add resolveDeployState discriminator
* feat(deploy): add buildDeployStatusReport payload builder
* feat(deploy): add clerk deploy check command
* feat(deploy): tailor agent-mode deploy into a read-only handoff
* feat(deploy): register clerk deploy check subcommand
* docs(deploy): document deploy check and agent handoff
* fix(deploy): surface agent status read failures
* docs(clerk-cli): document deploy agent workflow
* fix(deploy): avoid backoff in agent check
* fix(deploy): check domain status as one DNS verification
* fix(deploy): include domains URL in agent next action
* fix(deploy): prompt agents to open domains URL
* docs(clerk-cli): warn deploy wizard needs a terminal
* fix(cli): address deploy review follow-ups
* fix(deploy): persist live production instance metadata
* chore: added link for codex
* docs(clerk-cli): clarify deploy check agent workflow
* refactor(deploy): remove unused status check helper
* test(deploy): avoid leaking deploy check mocks
* docs(testing): document bun test isolation
* docs: remove hidden bird command from readme
* feat(deploy): rename status check command
* fix(deploy): humanize status dashboard guidance
* refactor(deploy): tighten status resolution
* fix(deploy): label DKIM records as email in DNS handoff
cnameTargetLabel keyed off the full `clk._domainkey`/`clk2._domainkey` labels, but host.split(".", 1)[0] only ever yields the first label ("clk"/"clk2"), so those cases were dead and DKIM records rendered as a generic "CNAME". Match the actual prefixes so DKIM records show the email label.
* refactor(deploy): drop unreachable OAuth completion guards
runOAuthSetup pauses by throwing DeployPausedError on skip or interrupt, so it never returns a partial list. The `completed.length < providers.length` guards after it were dead code implying a contract that does not exist. Remove them and document the pause-by-throw contract on runOAuthSetup instead.
* fix(deploy): re-prompt Google OAuth JSON after docs
* fix(deploy): re-prompt oauth credentials after walkthrough
---------
Co-authored-by: Rafael Thayto <rafa.thayto@gmail.com>
Sign up for freeto 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

@wyattjoh@rafa-thayto
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(deploy): add read-only deploy verification - #312

Merged
wyattjoh merged 26 commits into
wyattjoh/deployfrom
wyattjoh/deploy-agent-mode
May 29, 2026
Merged

feat(deploy): add read-only deploy verification#312
wyattjoh merged 26 commits into
wyattjoh/deployfrom
wyattjoh/deploy-agent-mode

Conversation

@wyattjoh

@wyattjohwyattjoh commented May 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds clerk deploy status as a read-only verification gate for DNS, SSL, email DNS, and OAuth readiness.
  • Makes agent-mode clerk deploy return a JSON handoff instead of trying to run the interactive wizard.
  • Shows a spinner during the brief post-trigger wait while Clerk processes the DNS check.
  • Refactors deploy status resolution for shared human and agent flows, updates docs and skill guidance, and adds tests plus Bun test isolation guidance.

Testing

  • bun test --isolate packages/cli-core/src/cli-program.test.ts packages/cli-core/src/test/integration/completion.test.ts packages/cli-core/src/commands/deploy/status-command.test.ts packages/cli-core/src/commands/deploy/index.test.ts --timeout 20000
  • bun run format
  • bun run format:check
  • bun run lint
  • bun run typecheck
  • bun run test

Review

  • Independent subagent review found no findings.

@changeset-bot

changeset-botBot commented May 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 19caa25

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

This PR includes changesets to release 1 package
NameType
clerkMinor

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 ready for review May 29, 2026 13:28
@wyattjoh
wyattjoh requested a review from rafa-thaytoMay 29, 2026 13:29
@rafa-thayto

Copy link
Copy Markdown
Contributor

!snapshot

@github-actions

Copy link
Copy Markdown
Contributor

Snapshot published

npm install -g clerk@1.5.1-snapshot.19caa25
PackageVersion
clerk1.5.1-snapshot.19caa25

Published from 19caa25

@wyattjoh
wyattjoh merged commit 688f965 into wyattjoh/deployMay 29, 2026
2 checks passed
@wyattjoh
wyattjoh deleted the wyattjoh/deploy-agent-mode branch May 29, 2026 13:35
@wyattjoh
wyattjoh restored the wyattjoh/deploy-agent-mode branch May 29, 2026 13:35
rafa-thayto added a commit that referenced this pull request May 29, 2026
* feat(deploy): implement resumable deploy wizard
* fix(deploy): address review feedback on resumable wizard
- Preserve completed providers when pausing OAuth setup mid-loop, so
`clerk deploy --continue` can finish multi-provider stacks.
- Surface a warning for OAuth providers enabled in dev that the wizard
does not yet support, instead of silently skipping them.
- Close the gutter as Paused (not Failed) when DNS verification times
out, since the state is recoverable via --continue.
- Tighten the production-domain regex to reject malformed inputs like
example..com or example-.com before they reach the API.
* refactor(deploy): isolate lifecycle api calls
Move deploy lifecycle endpoint wrappers into the shared PLAPI client while routing the deploy wizard through a command-local adapter that defaults to mocked operations until the backend endpoints are ready.
* feat(deploy): resolve production state from API
* fix(deploy): route test failures through api path
* fix(deploy): remove gutter tone plumbing
* fix(deploy): require human mode for production setup
* refactor(deploy): route lifecycle test failures through api mock
* refactor(deploy): extract mock api into its own module
* refactor(deploy): route lifecycle through live PLAPI and map errors
Switch the deploy command from the in-process mock lifecycle to the live
PLAPI endpoints. Add a typed error mapper that translates known PLAPI
failures (plan_insufficient, home_url_taken, ssl_retry_throttled, etc.)
into CliError with stable codes, with a recovery path for the
production_instance_exists case so the wizard re-derives state instead
of surfacing the error.
Surface per-component progress (DNS / SSL / mail) during deploy_status
polling, and drop the four hidden --test-fail-* CLI options now that
failure injection is routed through the test's module mock.
Collapse the api/mock indirection layer to a thin re-export of the
plapi endpoints + a no-op configureMockDeployApi stub for the test
seam, and strip the dead mockDeployApi implementation that the
indirection used to back.
* feat(deploy): replace DNS handoff confirm with verify-or-skip choice
Swap the "Continue to OAuth setup?" yes/no prompt during initial
production setup for the same verify/skip select used when resuming.
Choosing skip records DNS as pending and continues to OAuth instead of
pausing the deploy, so the dashboard remains the single place to monitor
propagation.
* feat(deploy): refresh DNS verification for current API surface
- Tolerate getDeployStatus failures inside the reconcile-path snapshot
read so the deploy continues to the verify-or-skip prompt instead of
failing before the user can react.
- Split the snapshot fetch into separate "Reading development
configuration" and "Reading production configuration" spinners so the
gutter reflects what is actually being loaded.
- Add triggerDomainDnsCheck (POST .../dns_check) and call it best-effort
when the user picks "Check DNS now" so an active check job is kicked
rather than waiting on background reconciliation.
- Type the dns_ok/ssl_ok/mail_ok booleans on DeployStatusResponse and use
them to name the specific pending component in the timeout warning.
* refactor(deploy): drop ./api.ts and ./mock.ts test indirection
Switch deploy command imports back to lib/plapi.ts directly and remove the
./mock.ts harness plus the --test-force-* / --test-fail-* CLI flags it
backed. The wrappers were added for an earlier mockable-deploy-API
experiment that is no longer needed.
* feat(deploy): add bindZoneFile formatter for DNS records export
* feat(deploy): add per-component spinner label lookup
* feat(deploy): sequence DNS verification feedback per component
Replace the single-spinner pollDeployStatus loop with a chained
mail/dns/ssl spinner sequence that emits a per-component success
line as each boolean flips true. Add a defensive status === "complete"
check after all three components succeed so the proxy_ok server-side
case fails closed rather than reporting verified. When all DNS
components are resolved but the server has not yet marked the
deployment complete, exit the verification path without reaching
finishDeploy.
* feat(deploy): show DNS records on the resume verification path
* feat(deploy): offer BIND zone export after DNS records
After the DNS records block in both runDnsSetup and
runExistingDomainDnsVerification, prompt the user (default: no) to
export the records as a clerk-<domain>.zone BIND zone file.
* docs(deploy): document per-component verification and BIND export
* docs(changeset): document clerk deploy production wizard
* refactor(plapi): drop unused is_secondary from CreateProductionInstanceParams
* refactor(plapi): allow null active_domain and guard in deploy wizard
* fix(deploy): remove Domain Connect prompt and address review feedback
The Domain Connect URL helper returned Cloudflare's template for every
domain regardless of the actual registrar — a misleading prompt for any
user not on Cloudflare. Remove it entirely until NS-based registrar
detection lands as its own change.
Other cleanups from the same review pass: runDeploy throws a NOT_LINKED
CliError on unlinked directories instead of warning and exiting zero;
startNewDeploy's 409 production_instance_exists recovery now persists
the recovered production instance id to the profile; OAuth skip routes
through deployPausedError so its exit code matches Ctrl-C (1 instead of
silent 0); runDnsVerification loops on timeout retry instead of
recursing; and runOAuthSetup drops the redundant startIndex slice since
the completed set already skips previously-saved providers.
* fix(deploy): use domain status for verification
Switch production deploy verification to the application domain status endpoint and remove obsolete retry-specific handling. Cap domain status polling to the shared 10-second budget while keeping 3-second intervals.
* fix(deploy): defer DNS verification until after OAuth
* fix(deploy): refresh dns checks before polling
Trigger a fresh domain DNS check before status polling and retry status reads with exponential backoff while updating the spinner countdown.
* fix(deploy): report dns verification pauses
* feat(deploy): type instance config schemas
* feat(deploy): derive oauth provider descriptors from schema
* feat(deploy): use schema-driven oauth setup
* feat(deploy): resume oauth setup from schema descriptors
* feat(deploy): preserve oauth provider special prompts
* docs(deploy): document schema-driven oauth setup
* fix(deploy): warn generically for unsupported oauth providers
* fix(deploy): ignore optional oauth schema fields
* fix(deploy): support public oauth providers
* fix(deploy): use verbose for debug output
* fix(deploy): remove oauth provider allowlist
* refactor(deploy): derive oauth compatibility metadata
* refactor(deploy): simplify oauth provider overrides
* fix(ci): retry transient cleanup API failures
* fix(deploy): adapt to platform instance response
* fix(deploy): update retry status copy
* Update packages/cli-core/src/commands/deploy/copy.ts
Co-authored-by: Rafael Thayto <rafa.thayto@gmail.com>
* Revert "Update packages/cli-core/src/commands/deploy/copy.ts"
This reverts commit fa5821c.
* fix(review): address deploy PR feedback
- give each deploy status component its own retry budget
- normalize absent domain status components as pending
- load resume domain and OAuth provider state concurrently
- collapse repeated OAuth provider override lookups
* fix(deploy): link domain settings in next steps
Add a direct Clerk Dashboard domains URL to deploy completion output so users can manage their production domain configuration.
* feat(deploy): add read-only deploy verification (#312)
* refactor(deploy): extract poll core into status.ts
* refactor(deploy): move state resolution into status.ts, rename dnsComplete
* feat(deploy): add resolveDeployState discriminator
* feat(deploy): add buildDeployStatusReport payload builder
* feat(deploy): add clerk deploy check command
* feat(deploy): tailor agent-mode deploy into a read-only handoff
* feat(deploy): register clerk deploy check subcommand
* docs(deploy): document deploy check and agent handoff
* fix(deploy): surface agent status read failures
* docs(clerk-cli): document deploy agent workflow
* fix(deploy): avoid backoff in agent check
* fix(deploy): check domain status as one DNS verification
* fix(deploy): include domains URL in agent next action
* fix(deploy): prompt agents to open domains URL
* docs(clerk-cli): warn deploy wizard needs a terminal
* fix(cli): address deploy review follow-ups
* fix(deploy): persist live production instance metadata
* chore: added link for codex
* docs(clerk-cli): clarify deploy check agent workflow
* refactor(deploy): remove unused status check helper
* test(deploy): avoid leaking deploy check mocks
* docs(testing): document bun test isolation
* docs: remove hidden bird command from readme
* feat(deploy): rename status check command
* fix(deploy): humanize status dashboard guidance
* refactor(deploy): tighten status resolution
* fix(deploy): label DKIM records as email in DNS handoff
cnameTargetLabel keyed off the full `clk._domainkey`/`clk2._domainkey` labels, but host.split(".", 1)[0] only ever yields the first label ("clk"/"clk2"), so those cases were dead and DKIM records rendered as a generic "CNAME". Match the actual prefixes so DKIM records show the email label.
* refactor(deploy): drop unreachable OAuth completion guards
runOAuthSetup pauses by throwing DeployPausedError on skip or interrupt, so it never returns a partial list. The `completed.length < providers.length` guards after it were dead code implying a contract that does not exist. Remove them and document the pause-by-throw contract on runOAuthSetup instead.
* fix(deploy): re-prompt Google OAuth JSON after docs
* fix(deploy): re-prompt oauth credentials after walkthrough
---------
Co-authored-by: Rafael Thayto <rafa.thayto@gmail.com>
Sign up for freeto 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

@wyattjoh@rafa-thayto
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(deploy): add read-only deploy verification - #312

Merged
wyattjoh merged 26 commits into
wyattjoh/deployfrom
wyattjoh/deploy-agent-mode
May 29, 2026
Merged

feat(deploy): add read-only deploy verification#312
wyattjoh merged 26 commits into
wyattjoh/deployfrom
wyattjoh/deploy-agent-mode

Conversation

@wyattjoh

@wyattjohwyattjoh commented May 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds clerk deploy status as a read-only verification gate for DNS, SSL, email DNS, and OAuth readiness.
  • Makes agent-mode clerk deploy return a JSON handoff instead of trying to run the interactive wizard.
  • Shows a spinner during the brief post-trigger wait while Clerk processes the DNS check.
  • Refactors deploy status resolution for shared human and agent flows, updates docs and skill guidance, and adds tests plus Bun test isolation guidance.

Testing

  • bun test --isolate packages/cli-core/src/cli-program.test.ts packages/cli-core/src/test/integration/completion.test.ts packages/cli-core/src/commands/deploy/status-command.test.ts packages/cli-core/src/commands/deploy/index.test.ts --timeout 20000
  • bun run format
  • bun run format:check
  • bun run lint
  • bun run typecheck
  • bun run test

Review

  • Independent subagent review found no findings.

@changeset-bot

changeset-botBot commented May 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 19caa25

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

This PR includes changesets to release 1 package
NameType
clerkMinor

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 ready for review May 29, 2026 13:28
@wyattjoh
wyattjoh requested a review from rafa-thaytoMay 29, 2026 13:29
@rafa-thayto

Copy link
Copy Markdown
Contributor

!snapshot

@github-actions

Copy link
Copy Markdown
Contributor

Snapshot published

npm install -g clerk@1.5.1-snapshot.19caa25
PackageVersion
clerk1.5.1-snapshot.19caa25

Published from 19caa25

@wyattjoh
wyattjoh merged commit 688f965 into wyattjoh/deployMay 29, 2026
2 checks passed
@wyattjoh
wyattjoh deleted the wyattjoh/deploy-agent-mode branch May 29, 2026 13:35
@wyattjoh
wyattjoh restored the wyattjoh/deploy-agent-mode branch May 29, 2026 13:35
rafa-thayto added a commit that referenced this pull request May 29, 2026
* feat(deploy): implement resumable deploy wizard
* fix(deploy): address review feedback on resumable wizard
- Preserve completed providers when pausing OAuth setup mid-loop, so
`clerk deploy --continue` can finish multi-provider stacks.
- Surface a warning for OAuth providers enabled in dev that the wizard
does not yet support, instead of silently skipping them.
- Close the gutter as Paused (not Failed) when DNS verification times
out, since the state is recoverable via --continue.
- Tighten the production-domain regex to reject malformed inputs like
example..com or example-.com before they reach the API.
* refactor(deploy): isolate lifecycle api calls
Move deploy lifecycle endpoint wrappers into the shared PLAPI client while routing the deploy wizard through a command-local adapter that defaults to mocked operations until the backend endpoints are ready.
* feat(deploy): resolve production state from API
* fix(deploy): route test failures through api path
* fix(deploy): remove gutter tone plumbing
* fix(deploy): require human mode for production setup
* refactor(deploy): route lifecycle test failures through api mock
* refactor(deploy): extract mock api into its own module
* refactor(deploy): route lifecycle through live PLAPI and map errors
Switch the deploy command from the in-process mock lifecycle to the live
PLAPI endpoints. Add a typed error mapper that translates known PLAPI
failures (plan_insufficient, home_url_taken, ssl_retry_throttled, etc.)
into CliError with stable codes, with a recovery path for the
production_instance_exists case so the wizard re-derives state instead
of surfacing the error.
Surface per-component progress (DNS / SSL / mail) during deploy_status
polling, and drop the four hidden --test-fail-* CLI options now that
failure injection is routed through the test's module mock.
Collapse the api/mock indirection layer to a thin re-export of the
plapi endpoints + a no-op configureMockDeployApi stub for the test
seam, and strip the dead mockDeployApi implementation that the
indirection used to back.
* feat(deploy): replace DNS handoff confirm with verify-or-skip choice
Swap the "Continue to OAuth setup?" yes/no prompt during initial
production setup for the same verify/skip select used when resuming.
Choosing skip records DNS as pending and continues to OAuth instead of
pausing the deploy, so the dashboard remains the single place to monitor
propagation.
* feat(deploy): refresh DNS verification for current API surface
- Tolerate getDeployStatus failures inside the reconcile-path snapshot
read so the deploy continues to the verify-or-skip prompt instead of
failing before the user can react.
- Split the snapshot fetch into separate "Reading development
configuration" and "Reading production configuration" spinners so the
gutter reflects what is actually being loaded.
- Add triggerDomainDnsCheck (POST .../dns_check) and call it best-effort
when the user picks "Check DNS now" so an active check job is kicked
rather than waiting on background reconciliation.
- Type the dns_ok/ssl_ok/mail_ok booleans on DeployStatusResponse and use
them to name the specific pending component in the timeout warning.
* refactor(deploy): drop ./api.ts and ./mock.ts test indirection
Switch deploy command imports back to lib/plapi.ts directly and remove the
./mock.ts harness plus the --test-force-* / --test-fail-* CLI flags it
backed. The wrappers were added for an earlier mockable-deploy-API
experiment that is no longer needed.
* feat(deploy): add bindZoneFile formatter for DNS records export
* feat(deploy): add per-component spinner label lookup
* feat(deploy): sequence DNS verification feedback per component
Replace the single-spinner pollDeployStatus loop with a chained
mail/dns/ssl spinner sequence that emits a per-component success
line as each boolean flips true. Add a defensive status === "complete"
check after all three components succeed so the proxy_ok server-side
case fails closed rather than reporting verified. When all DNS
components are resolved but the server has not yet marked the
deployment complete, exit the verification path without reaching
finishDeploy.
* feat(deploy): show DNS records on the resume verification path
* feat(deploy): offer BIND zone export after DNS records
After the DNS records block in both runDnsSetup and
runExistingDomainDnsVerification, prompt the user (default: no) to
export the records as a clerk-<domain>.zone BIND zone file.
* docs(deploy): document per-component verification and BIND export
* docs(changeset): document clerk deploy production wizard
* refactor(plapi): drop unused is_secondary from CreateProductionInstanceParams
* refactor(plapi): allow null active_domain and guard in deploy wizard
* fix(deploy): remove Domain Connect prompt and address review feedback
The Domain Connect URL helper returned Cloudflare's template for every
domain regardless of the actual registrar — a misleading prompt for any
user not on Cloudflare. Remove it entirely until NS-based registrar
detection lands as its own change.
Other cleanups from the same review pass: runDeploy throws a NOT_LINKED
CliError on unlinked directories instead of warning and exiting zero;
startNewDeploy's 409 production_instance_exists recovery now persists
the recovered production instance id to the profile; OAuth skip routes
through deployPausedError so its exit code matches Ctrl-C (1 instead of
silent 0); runDnsVerification loops on timeout retry instead of
recursing; and runOAuthSetup drops the redundant startIndex slice since
the completed set already skips previously-saved providers.
* fix(deploy): use domain status for verification
Switch production deploy verification to the application domain status endpoint and remove obsolete retry-specific handling. Cap domain status polling to the shared 10-second budget while keeping 3-second intervals.
* fix(deploy): defer DNS verification until after OAuth
* fix(deploy): refresh dns checks before polling
Trigger a fresh domain DNS check before status polling and retry status reads with exponential backoff while updating the spinner countdown.
* fix(deploy): report dns verification pauses
* feat(deploy): type instance config schemas
* feat(deploy): derive oauth provider descriptors from schema
* feat(deploy): use schema-driven oauth setup
* feat(deploy): resume oauth setup from schema descriptors
* feat(deploy): preserve oauth provider special prompts
* docs(deploy): document schema-driven oauth setup
* fix(deploy): warn generically for unsupported oauth providers
* fix(deploy): ignore optional oauth schema fields
* fix(deploy): support public oauth providers
* fix(deploy): use verbose for debug output
* fix(deploy): remove oauth provider allowlist
* refactor(deploy): derive oauth compatibility metadata
* refactor(deploy): simplify oauth provider overrides
* fix(ci): retry transient cleanup API failures
* fix(deploy): adapt to platform instance response
* fix(deploy): update retry status copy
* Update packages/cli-core/src/commands/deploy/copy.ts
Co-authored-by: Rafael Thayto <rafa.thayto@gmail.com>
* Revert "Update packages/cli-core/src/commands/deploy/copy.ts"
This reverts commit fa5821c.
* fix(review): address deploy PR feedback
- give each deploy status component its own retry budget
- normalize absent domain status components as pending
- load resume domain and OAuth provider state concurrently
- collapse repeated OAuth provider override lookups
* fix(deploy): link domain settings in next steps
Add a direct Clerk Dashboard domains URL to deploy completion output so users can manage their production domain configuration.
* feat(deploy): add read-only deploy verification (#312)
* refactor(deploy): extract poll core into status.ts
* refactor(deploy): move state resolution into status.ts, rename dnsComplete
* feat(deploy): add resolveDeployState discriminator
* feat(deploy): add buildDeployStatusReport payload builder
* feat(deploy): add clerk deploy check command
* feat(deploy): tailor agent-mode deploy into a read-only handoff
* feat(deploy): register clerk deploy check subcommand
* docs(deploy): document deploy check and agent handoff
* fix(deploy): surface agent status read failures
* docs(clerk-cli): document deploy agent workflow
* fix(deploy): avoid backoff in agent check
* fix(deploy): check domain status as one DNS verification
* fix(deploy): include domains URL in agent next action
* fix(deploy): prompt agents to open domains URL
* docs(clerk-cli): warn deploy wizard needs a terminal
* fix(cli): address deploy review follow-ups
* fix(deploy): persist live production instance metadata
* chore: added link for codex
* docs(clerk-cli): clarify deploy check agent workflow
* refactor(deploy): remove unused status check helper
* test(deploy): avoid leaking deploy check mocks
* docs(testing): document bun test isolation
* docs: remove hidden bird command from readme
* feat(deploy): rename status check command
* fix(deploy): humanize status dashboard guidance
* refactor(deploy): tighten status resolution
* fix(deploy): label DKIM records as email in DNS handoff
cnameTargetLabel keyed off the full `clk._domainkey`/`clk2._domainkey` labels, but host.split(".", 1)[0] only ever yields the first label ("clk"/"clk2"), so those cases were dead and DKIM records rendered as a generic "CNAME". Match the actual prefixes so DKIM records show the email label.
* refactor(deploy): drop unreachable OAuth completion guards
runOAuthSetup pauses by throwing DeployPausedError on skip or interrupt, so it never returns a partial list. The `completed.length < providers.length` guards after it were dead code implying a contract that does not exist. Remove them and document the pause-by-throw contract on runOAuthSetup instead.
* fix(deploy): re-prompt Google OAuth JSON after docs
* fix(deploy): re-prompt oauth credentials after walkthrough
---------
Co-authored-by: Rafael Thayto <rafa.thayto@gmail.com>
Sign up for freeto 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

@wyattjoh@rafa-thayto
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(deploy): add read-only deploy verification - #312

Merged
wyattjoh merged 26 commits into
wyattjoh/deployfrom
wyattjoh/deploy-agent-mode
May 29, 2026
Merged

feat(deploy): add read-only deploy verification#312
wyattjoh merged 26 commits into
wyattjoh/deployfrom
wyattjoh/deploy-agent-mode

Conversation

@wyattjoh

@wyattjohwyattjoh commented May 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds clerk deploy status as a read-only verification gate for DNS, SSL, email DNS, and OAuth readiness.
  • Makes agent-mode clerk deploy return a JSON handoff instead of trying to run the interactive wizard.
  • Shows a spinner during the brief post-trigger wait while Clerk processes the DNS check.
  • Refactors deploy status resolution for shared human and agent flows, updates docs and skill guidance, and adds tests plus Bun test isolation guidance.

Testing

  • bun test --isolate packages/cli-core/src/cli-program.test.ts packages/cli-core/src/test/integration/completion.test.ts packages/cli-core/src/commands/deploy/status-command.test.ts packages/cli-core/src/commands/deploy/index.test.ts --timeout 20000
  • bun run format
  • bun run format:check
  • bun run lint
  • bun run typecheck
  • bun run test

Review

  • Independent subagent review found no findings.

@changeset-bot

changeset-botBot commented May 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 19caa25

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

This PR includes changesets to release 1 package
NameType
clerkMinor

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 ready for review May 29, 2026 13:28
@wyattjoh
wyattjoh requested a review from rafa-thaytoMay 29, 2026 13:29
@rafa-thayto

Copy link
Copy Markdown
Contributor

!snapshot

@github-actions

Copy link
Copy Markdown
Contributor

Snapshot published

npm install -g clerk@1.5.1-snapshot.19caa25
PackageVersion
clerk1.5.1-snapshot.19caa25

Published from 19caa25

@wyattjoh
wyattjoh merged commit 688f965 into wyattjoh/deployMay 29, 2026
2 checks passed
@wyattjoh
wyattjoh deleted the wyattjoh/deploy-agent-mode branch May 29, 2026 13:35
@wyattjoh
wyattjoh restored the wyattjoh/deploy-agent-mode branch May 29, 2026 13:35
rafa-thayto added a commit that referenced this pull request May 29, 2026
* feat(deploy): implement resumable deploy wizard
* fix(deploy): address review feedback on resumable wizard
- Preserve completed providers when pausing OAuth setup mid-loop, so
`clerk deploy --continue` can finish multi-provider stacks.
- Surface a warning for OAuth providers enabled in dev that the wizard
does not yet support, instead of silently skipping them.
- Close the gutter as Paused (not Failed) when DNS verification times
out, since the state is recoverable via --continue.
- Tighten the production-domain regex to reject malformed inputs like
example..com or example-.com before they reach the API.
* refactor(deploy): isolate lifecycle api calls
Move deploy lifecycle endpoint wrappers into the shared PLAPI client while routing the deploy wizard through a command-local adapter that defaults to mocked operations until the backend endpoints are ready.
* feat(deploy): resolve production state from API
* fix(deploy): route test failures through api path
* fix(deploy): remove gutter tone plumbing
* fix(deploy): require human mode for production setup
* refactor(deploy): route lifecycle test failures through api mock
* refactor(deploy): extract mock api into its own module
* refactor(deploy): route lifecycle through live PLAPI and map errors
Switch the deploy command from the in-process mock lifecycle to the live
PLAPI endpoints. Add a typed error mapper that translates known PLAPI
failures (plan_insufficient, home_url_taken, ssl_retry_throttled, etc.)
into CliError with stable codes, with a recovery path for the
production_instance_exists case so the wizard re-derives state instead
of surfacing the error.
Surface per-component progress (DNS / SSL / mail) during deploy_status
polling, and drop the four hidden --test-fail-* CLI options now that
failure injection is routed through the test's module mock.
Collapse the api/mock indirection layer to a thin re-export of the
plapi endpoints + a no-op configureMockDeployApi stub for the test
seam, and strip the dead mockDeployApi implementation that the
indirection used to back.
* feat(deploy): replace DNS handoff confirm with verify-or-skip choice
Swap the "Continue to OAuth setup?" yes/no prompt during initial
production setup for the same verify/skip select used when resuming.
Choosing skip records DNS as pending and continues to OAuth instead of
pausing the deploy, so the dashboard remains the single place to monitor
propagation.
* feat(deploy): refresh DNS verification for current API surface
- Tolerate getDeployStatus failures inside the reconcile-path snapshot
read so the deploy continues to the verify-or-skip prompt instead of
failing before the user can react.
- Split the snapshot fetch into separate "Reading development
configuration" and "Reading production configuration" spinners so the
gutter reflects what is actually being loaded.
- Add triggerDomainDnsCheck (POST .../dns_check) and call it best-effort
when the user picks "Check DNS now" so an active check job is kicked
rather than waiting on background reconciliation.
- Type the dns_ok/ssl_ok/mail_ok booleans on DeployStatusResponse and use
them to name the specific pending component in the timeout warning.
* refactor(deploy): drop ./api.ts and ./mock.ts test indirection
Switch deploy command imports back to lib/plapi.ts directly and remove the
./mock.ts harness plus the --test-force-* / --test-fail-* CLI flags it
backed. The wrappers were added for an earlier mockable-deploy-API
experiment that is no longer needed.
* feat(deploy): add bindZoneFile formatter for DNS records export
* feat(deploy): add per-component spinner label lookup
* feat(deploy): sequence DNS verification feedback per component
Replace the single-spinner pollDeployStatus loop with a chained
mail/dns/ssl spinner sequence that emits a per-component success
line as each boolean flips true. Add a defensive status === "complete"
check after all three components succeed so the proxy_ok server-side
case fails closed rather than reporting verified. When all DNS
components are resolved but the server has not yet marked the
deployment complete, exit the verification path without reaching
finishDeploy.
* feat(deploy): show DNS records on the resume verification path
* feat(deploy): offer BIND zone export after DNS records
After the DNS records block in both runDnsSetup and
runExistingDomainDnsVerification, prompt the user (default: no) to
export the records as a clerk-<domain>.zone BIND zone file.
* docs(deploy): document per-component verification and BIND export
* docs(changeset): document clerk deploy production wizard
* refactor(plapi): drop unused is_secondary from CreateProductionInstanceParams
* refactor(plapi): allow null active_domain and guard in deploy wizard
* fix(deploy): remove Domain Connect prompt and address review feedback
The Domain Connect URL helper returned Cloudflare's template for every
domain regardless of the actual registrar — a misleading prompt for any
user not on Cloudflare. Remove it entirely until NS-based registrar
detection lands as its own change.
Other cleanups from the same review pass: runDeploy throws a NOT_LINKED
CliError on unlinked directories instead of warning and exiting zero;
startNewDeploy's 409 production_instance_exists recovery now persists
the recovered production instance id to the profile; OAuth skip routes
through deployPausedError so its exit code matches Ctrl-C (1 instead of
silent 0); runDnsVerification loops on timeout retry instead of
recursing; and runOAuthSetup drops the redundant startIndex slice since
the completed set already skips previously-saved providers.
* fix(deploy): use domain status for verification
Switch production deploy verification to the application domain status endpoint and remove obsolete retry-specific handling. Cap domain status polling to the shared 10-second budget while keeping 3-second intervals.
* fix(deploy): defer DNS verification until after OAuth
* fix(deploy): refresh dns checks before polling
Trigger a fresh domain DNS check before status polling and retry status reads with exponential backoff while updating the spinner countdown.
* fix(deploy): report dns verification pauses
* feat(deploy): type instance config schemas
* feat(deploy): derive oauth provider descriptors from schema
* feat(deploy): use schema-driven oauth setup
* feat(deploy): resume oauth setup from schema descriptors
* feat(deploy): preserve oauth provider special prompts
* docs(deploy): document schema-driven oauth setup
* fix(deploy): warn generically for unsupported oauth providers
* fix(deploy): ignore optional oauth schema fields
* fix(deploy): support public oauth providers
* fix(deploy): use verbose for debug output
* fix(deploy): remove oauth provider allowlist
* refactor(deploy): derive oauth compatibility metadata
* refactor(deploy): simplify oauth provider overrides
* fix(ci): retry transient cleanup API failures
* fix(deploy): adapt to platform instance response
* fix(deploy): update retry status copy
* Update packages/cli-core/src/commands/deploy/copy.ts
Co-authored-by: Rafael Thayto <rafa.thayto@gmail.com>
* Revert "Update packages/cli-core/src/commands/deploy/copy.ts"
This reverts commit fa5821c.
* fix(review): address deploy PR feedback
- give each deploy status component its own retry budget
- normalize absent domain status components as pending
- load resume domain and OAuth provider state concurrently
- collapse repeated OAuth provider override lookups
* fix(deploy): link domain settings in next steps
Add a direct Clerk Dashboard domains URL to deploy completion output so users can manage their production domain configuration.
* feat(deploy): add read-only deploy verification (#312)
* refactor(deploy): extract poll core into status.ts
* refactor(deploy): move state resolution into status.ts, rename dnsComplete
* feat(deploy): add resolveDeployState discriminator
* feat(deploy): add buildDeployStatusReport payload builder
* feat(deploy): add clerk deploy check command
* feat(deploy): tailor agent-mode deploy into a read-only handoff
* feat(deploy): register clerk deploy check subcommand
* docs(deploy): document deploy check and agent handoff
* fix(deploy): surface agent status read failures
* docs(clerk-cli): document deploy agent workflow
* fix(deploy): avoid backoff in agent check
* fix(deploy): check domain status as one DNS verification
* fix(deploy): include domains URL in agent next action
* fix(deploy): prompt agents to open domains URL
* docs(clerk-cli): warn deploy wizard needs a terminal
* fix(cli): address deploy review follow-ups
* fix(deploy): persist live production instance metadata
* chore: added link for codex
* docs(clerk-cli): clarify deploy check agent workflow
* refactor(deploy): remove unused status check helper
* test(deploy): avoid leaking deploy check mocks
* docs(testing): document bun test isolation
* docs: remove hidden bird command from readme
* feat(deploy): rename status check command
* fix(deploy): humanize status dashboard guidance
* refactor(deploy): tighten status resolution
* fix(deploy): label DKIM records as email in DNS handoff
cnameTargetLabel keyed off the full `clk._domainkey`/`clk2._domainkey` labels, but host.split(".", 1)[0] only ever yields the first label ("clk"/"clk2"), so those cases were dead and DKIM records rendered as a generic "CNAME". Match the actual prefixes so DKIM records show the email label.
* refactor(deploy): drop unreachable OAuth completion guards
runOAuthSetup pauses by throwing DeployPausedError on skip or interrupt, so it never returns a partial list. The `completed.length < providers.length` guards after it were dead code implying a contract that does not exist. Remove them and document the pause-by-throw contract on runOAuthSetup instead.
* fix(deploy): re-prompt Google OAuth JSON after docs
* fix(deploy): re-prompt oauth credentials after walkthrough
---------
Co-authored-by: Rafael Thayto <rafa.thayto@gmail.com>
Sign up for freeto 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

@wyattjoh@rafa-thayto
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(deploy): add read-only deploy verification - #312

Merged
wyattjoh merged 26 commits into
wyattjoh/deployfrom
wyattjoh/deploy-agent-mode
May 29, 2026
Merged

feat(deploy): add read-only deploy verification#312
wyattjoh merged 26 commits into
wyattjoh/deployfrom
wyattjoh/deploy-agent-mode

Conversation

@wyattjoh

@wyattjohwyattjoh commented May 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds clerk deploy status as a read-only verification gate for DNS, SSL, email DNS, and OAuth readiness.
  • Makes agent-mode clerk deploy return a JSON handoff instead of trying to run the interactive wizard.
  • Shows a spinner during the brief post-trigger wait while Clerk processes the DNS check.
  • Refactors deploy status resolution for shared human and agent flows, updates docs and skill guidance, and adds tests plus Bun test isolation guidance.

Testing

  • bun test --isolate packages/cli-core/src/cli-program.test.ts packages/cli-core/src/test/integration/completion.test.ts packages/cli-core/src/commands/deploy/status-command.test.ts packages/cli-core/src/commands/deploy/index.test.ts --timeout 20000
  • bun run format
  • bun run format:check
  • bun run lint
  • bun run typecheck
  • bun run test

Review

  • Independent subagent review found no findings.

@changeset-bot

changeset-botBot commented May 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 19caa25

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

This PR includes changesets to release 1 package
NameType
clerkMinor

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 ready for review May 29, 2026 13:28
@wyattjoh
wyattjoh requested a review from rafa-thaytoMay 29, 2026 13:29
@rafa-thayto

Copy link
Copy Markdown
Contributor

!snapshot

@github-actions

Copy link
Copy Markdown
Contributor

Snapshot published

npm install -g clerk@1.5.1-snapshot.19caa25
PackageVersion
clerk1.5.1-snapshot.19caa25

Published from 19caa25

@wyattjoh
wyattjoh merged commit 688f965 into wyattjoh/deployMay 29, 2026
2 checks passed
@wyattjoh
wyattjoh deleted the wyattjoh/deploy-agent-mode branch May 29, 2026 13:35
@wyattjoh
wyattjoh restored the wyattjoh/deploy-agent-mode branch May 29, 2026 13:35
rafa-thayto added a commit that referenced this pull request May 29, 2026
* feat(deploy): implement resumable deploy wizard
* fix(deploy): address review feedback on resumable wizard
- Preserve completed providers when pausing OAuth setup mid-loop, so
`clerk deploy --continue` can finish multi-provider stacks.
- Surface a warning for OAuth providers enabled in dev that the wizard
does not yet support, instead of silently skipping them.
- Close the gutter as Paused (not Failed) when DNS verification times
out, since the state is recoverable via --continue.
- Tighten the production-domain regex to reject malformed inputs like
example..com or example-.com before they reach the API.
* refactor(deploy): isolate lifecycle api calls
Move deploy lifecycle endpoint wrappers into the shared PLAPI client while routing the deploy wizard through a command-local adapter that defaults to mocked operations until the backend endpoints are ready.
* feat(deploy): resolve production state from API
* fix(deploy): route test failures through api path
* fix(deploy): remove gutter tone plumbing
* fix(deploy): require human mode for production setup
* refactor(deploy): route lifecycle test failures through api mock
* refactor(deploy): extract mock api into its own module
* refactor(deploy): route lifecycle through live PLAPI and map errors
Switch the deploy command from the in-process mock lifecycle to the live
PLAPI endpoints. Add a typed error mapper that translates known PLAPI
failures (plan_insufficient, home_url_taken, ssl_retry_throttled, etc.)
into CliError with stable codes, with a recovery path for the
production_instance_exists case so the wizard re-derives state instead
of surfacing the error.
Surface per-component progress (DNS / SSL / mail) during deploy_status
polling, and drop the four hidden --test-fail-* CLI options now that
failure injection is routed through the test's module mock.
Collapse the api/mock indirection layer to a thin re-export of the
plapi endpoints + a no-op configureMockDeployApi stub for the test
seam, and strip the dead mockDeployApi implementation that the
indirection used to back.
* feat(deploy): replace DNS handoff confirm with verify-or-skip choice
Swap the "Continue to OAuth setup?" yes/no prompt during initial
production setup for the same verify/skip select used when resuming.
Choosing skip records DNS as pending and continues to OAuth instead of
pausing the deploy, so the dashboard remains the single place to monitor
propagation.
* feat(deploy): refresh DNS verification for current API surface
- Tolerate getDeployStatus failures inside the reconcile-path snapshot
read so the deploy continues to the verify-or-skip prompt instead of
failing before the user can react.
- Split the snapshot fetch into separate "Reading development
configuration" and "Reading production configuration" spinners so the
gutter reflects what is actually being loaded.
- Add triggerDomainDnsCheck (POST .../dns_check) and call it best-effort
when the user picks "Check DNS now" so an active check job is kicked
rather than waiting on background reconciliation.
- Type the dns_ok/ssl_ok/mail_ok booleans on DeployStatusResponse and use
them to name the specific pending component in the timeout warning.
* refactor(deploy): drop ./api.ts and ./mock.ts test indirection
Switch deploy command imports back to lib/plapi.ts directly and remove the
./mock.ts harness plus the --test-force-* / --test-fail-* CLI flags it
backed. The wrappers were added for an earlier mockable-deploy-API
experiment that is no longer needed.
* feat(deploy): add bindZoneFile formatter for DNS records export
* feat(deploy): add per-component spinner label lookup
* feat(deploy): sequence DNS verification feedback per component
Replace the single-spinner pollDeployStatus loop with a chained
mail/dns/ssl spinner sequence that emits a per-component success
line as each boolean flips true. Add a defensive status === "complete"
check after all three components succeed so the proxy_ok server-side
case fails closed rather than reporting verified. When all DNS
components are resolved but the server has not yet marked the
deployment complete, exit the verification path without reaching
finishDeploy.
* feat(deploy): show DNS records on the resume verification path
* feat(deploy): offer BIND zone export after DNS records
After the DNS records block in both runDnsSetup and
runExistingDomainDnsVerification, prompt the user (default: no) to
export the records as a clerk-<domain>.zone BIND zone file.
* docs(deploy): document per-component verification and BIND export
* docs(changeset): document clerk deploy production wizard
* refactor(plapi): drop unused is_secondary from CreateProductionInstanceParams
* refactor(plapi): allow null active_domain and guard in deploy wizard
* fix(deploy): remove Domain Connect prompt and address review feedback
The Domain Connect URL helper returned Cloudflare's template for every
domain regardless of the actual registrar — a misleading prompt for any
user not on Cloudflare. Remove it entirely until NS-based registrar
detection lands as its own change.
Other cleanups from the same review pass: runDeploy throws a NOT_LINKED
CliError on unlinked directories instead of warning and exiting zero;
startNewDeploy's 409 production_instance_exists recovery now persists
the recovered production instance id to the profile; OAuth skip routes
through deployPausedError so its exit code matches Ctrl-C (1 instead of
silent 0); runDnsVerification loops on timeout retry instead of
recursing; and runOAuthSetup drops the redundant startIndex slice since
the completed set already skips previously-saved providers.
* fix(deploy): use domain status for verification
Switch production deploy verification to the application domain status endpoint and remove obsolete retry-specific handling. Cap domain status polling to the shared 10-second budget while keeping 3-second intervals.
* fix(deploy): defer DNS verification until after OAuth
* fix(deploy): refresh dns checks before polling
Trigger a fresh domain DNS check before status polling and retry status reads with exponential backoff while updating the spinner countdown.
* fix(deploy): report dns verification pauses
* feat(deploy): type instance config schemas
* feat(deploy): derive oauth provider descriptors from schema
* feat(deploy): use schema-driven oauth setup
* feat(deploy): resume oauth setup from schema descriptors
* feat(deploy): preserve oauth provider special prompts
* docs(deploy): document schema-driven oauth setup
* fix(deploy): warn generically for unsupported oauth providers
* fix(deploy): ignore optional oauth schema fields
* fix(deploy): support public oauth providers
* fix(deploy): use verbose for debug output
* fix(deploy): remove oauth provider allowlist
* refactor(deploy): derive oauth compatibility metadata
* refactor(deploy): simplify oauth provider overrides
* fix(ci): retry transient cleanup API failures
* fix(deploy): adapt to platform instance response
* fix(deploy): update retry status copy
* Update packages/cli-core/src/commands/deploy/copy.ts
Co-authored-by: Rafael Thayto <rafa.thayto@gmail.com>
* Revert "Update packages/cli-core/src/commands/deploy/copy.ts"
This reverts commit fa5821c.
* fix(review): address deploy PR feedback
- give each deploy status component its own retry budget
- normalize absent domain status components as pending
- load resume domain and OAuth provider state concurrently
- collapse repeated OAuth provider override lookups
* fix(deploy): link domain settings in next steps
Add a direct Clerk Dashboard domains URL to deploy completion output so users can manage their production domain configuration.
* feat(deploy): add read-only deploy verification (#312)
* refactor(deploy): extract poll core into status.ts
* refactor(deploy): move state resolution into status.ts, rename dnsComplete
* feat(deploy): add resolveDeployState discriminator
* feat(deploy): add buildDeployStatusReport payload builder
* feat(deploy): add clerk deploy check command
* feat(deploy): tailor agent-mode deploy into a read-only handoff
* feat(deploy): register clerk deploy check subcommand
* docs(deploy): document deploy check and agent handoff
* fix(deploy): surface agent status read failures
* docs(clerk-cli): document deploy agent workflow
* fix(deploy): avoid backoff in agent check
* fix(deploy): check domain status as one DNS verification
* fix(deploy): include domains URL in agent next action
* fix(deploy): prompt agents to open domains URL
* docs(clerk-cli): warn deploy wizard needs a terminal
* fix(cli): address deploy review follow-ups
* fix(deploy): persist live production instance metadata
* chore: added link for codex
* docs(clerk-cli): clarify deploy check agent workflow
* refactor(deploy): remove unused status check helper
* test(deploy): avoid leaking deploy check mocks
* docs(testing): document bun test isolation
* docs: remove hidden bird command from readme
* feat(deploy): rename status check command
* fix(deploy): humanize status dashboard guidance
* refactor(deploy): tighten status resolution
* fix(deploy): label DKIM records as email in DNS handoff
cnameTargetLabel keyed off the full `clk._domainkey`/`clk2._domainkey` labels, but host.split(".", 1)[0] only ever yields the first label ("clk"/"clk2"), so those cases were dead and DKIM records rendered as a generic "CNAME". Match the actual prefixes so DKIM records show the email label.
* refactor(deploy): drop unreachable OAuth completion guards
runOAuthSetup pauses by throwing DeployPausedError on skip or interrupt, so it never returns a partial list. The `completed.length < providers.length` guards after it were dead code implying a contract that does not exist. Remove them and document the pause-by-throw contract on runOAuthSetup instead.
* fix(deploy): re-prompt Google OAuth JSON after docs
* fix(deploy): re-prompt oauth credentials after walkthrough
---------
Co-authored-by: Rafael Thayto <rafa.thayto@gmail.com>
Sign up for freeto 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

@wyattjoh@rafa-thayto
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(deploy): add read-only deploy verification - #312

Merged
wyattjoh merged 26 commits into
wyattjoh/deployfrom
wyattjoh/deploy-agent-mode
May 29, 2026
Merged

feat(deploy): add read-only deploy verification#312
wyattjoh merged 26 commits into
wyattjoh/deployfrom
wyattjoh/deploy-agent-mode

Conversation

@wyattjoh

@wyattjohwyattjoh commented May 29, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds clerk deploy status as a read-only verification gate for DNS, SSL, email DNS, and OAuth readiness.
  • Makes agent-mode clerk deploy return a JSON handoff instead of trying to run the interactive wizard.
  • Shows a spinner during the brief post-trigger wait while Clerk processes the DNS check.
  • Refactors deploy status resolution for shared human and agent flows, updates docs and skill guidance, and adds tests plus Bun test isolation guidance.

Testing

  • bun test --isolate packages/cli-core/src/cli-program.test.ts packages/cli-core/src/test/integration/completion.test.ts packages/cli-core/src/commands/deploy/status-command.test.ts packages/cli-core/src/commands/deploy/index.test.ts --timeout 20000
  • bun run format
  • bun run format:check
  • bun run lint
  • bun run typecheck
  • bun run test

Review

  • Independent subagent review found no findings.

@changeset-bot

changeset-botBot commented May 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 19caa25

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

This PR includes changesets to release 1 package
NameType
clerkMinor

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 ready for review May 29, 2026 13:28
@wyattjoh
wyattjoh requested a review from rafa-thaytoMay 29, 2026 13:29
@rafa-thayto

Copy link
Copy Markdown
Contributor

!snapshot

@github-actions

Copy link
Copy Markdown
Contributor

Snapshot published

npm install -g clerk@1.5.1-snapshot.19caa25
PackageVersion
clerk1.5.1-snapshot.19caa25

Published from 19caa25

@wyattjoh
wyattjoh merged commit 688f965 into wyattjoh/deployMay 29, 2026
2 checks passed
@wyattjoh
wyattjoh deleted the wyattjoh/deploy-agent-mode branch May 29, 2026 13:35
@wyattjoh
wyattjoh restored the wyattjoh/deploy-agent-mode branch May 29, 2026 13:35
rafa-thayto added a commit that referenced this pull request May 29, 2026
* feat(deploy): implement resumable deploy wizard
* fix(deploy): address review feedback on resumable wizard
- Preserve completed providers when pausing OAuth setup mid-loop, so
`clerk deploy --continue` can finish multi-provider stacks.
- Surface a warning for OAuth providers enabled in dev that the wizard
does not yet support, instead of silently skipping them.
- Close the gutter as Paused (not Failed) when DNS verification times
out, since the state is recoverable via --continue.
- Tighten the production-domain regex to reject malformed inputs like
example..com or example-.com before they reach the API.
* refactor(deploy): isolate lifecycle api calls
Move deploy lifecycle endpoint wrappers into the shared PLAPI client while routing the deploy wizard through a command-local adapter that defaults to mocked operations until the backend endpoints are ready.
* feat(deploy): resolve production state from API
* fix(deploy): route test failures through api path
* fix(deploy): remove gutter tone plumbing
* fix(deploy): require human mode for production setup
* refactor(deploy): route lifecycle test failures through api mock
* refactor(deploy): extract mock api into its own module
* refactor(deploy): route lifecycle through live PLAPI and map errors
Switch the deploy command from the in-process mock lifecycle to the live
PLAPI endpoints. Add a typed error mapper that translates known PLAPI
failures (plan_insufficient, home_url_taken, ssl_retry_throttled, etc.)
into CliError with stable codes, with a recovery path for the
production_instance_exists case so the wizard re-derives state instead
of surfacing the error.
Surface per-component progress (DNS / SSL / mail) during deploy_status
polling, and drop the four hidden --test-fail-* CLI options now that
failure injection is routed through the test's module mock.
Collapse the api/mock indirection layer to a thin re-export of the
plapi endpoints + a no-op configureMockDeployApi stub for the test
seam, and strip the dead mockDeployApi implementation that the
indirection used to back.
* feat(deploy): replace DNS handoff confirm with verify-or-skip choice
Swap the "Continue to OAuth setup?" yes/no prompt during initial
production setup for the same verify/skip select used when resuming.
Choosing skip records DNS as pending and continues to OAuth instead of
pausing the deploy, so the dashboard remains the single place to monitor
propagation.
* feat(deploy): refresh DNS verification for current API surface
- Tolerate getDeployStatus failures inside the reconcile-path snapshot
read so the deploy continues to the verify-or-skip prompt instead of
failing before the user can react.
- Split the snapshot fetch into separate "Reading development
configuration" and "Reading production configuration" spinners so the
gutter reflects what is actually being loaded.
- Add triggerDomainDnsCheck (POST .../dns_check) and call it best-effort
when the user picks "Check DNS now" so an active check job is kicked
rather than waiting on background reconciliation.
- Type the dns_ok/ssl_ok/mail_ok booleans on DeployStatusResponse and use
them to name the specific pending component in the timeout warning.
* refactor(deploy): drop ./api.ts and ./mock.ts test indirection
Switch deploy command imports back to lib/plapi.ts directly and remove the
./mock.ts harness plus the --test-force-* / --test-fail-* CLI flags it
backed. The wrappers were added for an earlier mockable-deploy-API
experiment that is no longer needed.
* feat(deploy): add bindZoneFile formatter for DNS records export
* feat(deploy): add per-component spinner label lookup
* feat(deploy): sequence DNS verification feedback per component
Replace the single-spinner pollDeployStatus loop with a chained
mail/dns/ssl spinner sequence that emits a per-component success
line as each boolean flips true. Add a defensive status === "complete"
check after all three components succeed so the proxy_ok server-side
case fails closed rather than reporting verified. When all DNS
components are resolved but the server has not yet marked the
deployment complete, exit the verification path without reaching
finishDeploy.
* feat(deploy): show DNS records on the resume verification path
* feat(deploy): offer BIND zone export after DNS records
After the DNS records block in both runDnsSetup and
runExistingDomainDnsVerification, prompt the user (default: no) to
export the records as a clerk-<domain>.zone BIND zone file.
* docs(deploy): document per-component verification and BIND export
* docs(changeset): document clerk deploy production wizard
* refactor(plapi): drop unused is_secondary from CreateProductionInstanceParams
* refactor(plapi): allow null active_domain and guard in deploy wizard
* fix(deploy): remove Domain Connect prompt and address review feedback
The Domain Connect URL helper returned Cloudflare's template for every
domain regardless of the actual registrar — a misleading prompt for any
user not on Cloudflare. Remove it entirely until NS-based registrar
detection lands as its own change.
Other cleanups from the same review pass: runDeploy throws a NOT_LINKED
CliError on unlinked directories instead of warning and exiting zero;
startNewDeploy's 409 production_instance_exists recovery now persists
the recovered production instance id to the profile; OAuth skip routes
through deployPausedError so its exit code matches Ctrl-C (1 instead of
silent 0); runDnsVerification loops on timeout retry instead of
recursing; and runOAuthSetup drops the redundant startIndex slice since
the completed set already skips previously-saved providers.
* fix(deploy): use domain status for verification
Switch production deploy verification to the application domain status endpoint and remove obsolete retry-specific handling. Cap domain status polling to the shared 10-second budget while keeping 3-second intervals.
* fix(deploy): defer DNS verification until after OAuth
* fix(deploy): refresh dns checks before polling
Trigger a fresh domain DNS check before status polling and retry status reads with exponential backoff while updating the spinner countdown.
* fix(deploy): report dns verification pauses
* feat(deploy): type instance config schemas
* feat(deploy): derive oauth provider descriptors from schema
* feat(deploy): use schema-driven oauth setup
* feat(deploy): resume oauth setup from schema descriptors
* feat(deploy): preserve oauth provider special prompts
* docs(deploy): document schema-driven oauth setup
* fix(deploy): warn generically for unsupported oauth providers
* fix(deploy): ignore optional oauth schema fields
* fix(deploy): support public oauth providers
* fix(deploy): use verbose for debug output
* fix(deploy): remove oauth provider allowlist
* refactor(deploy): derive oauth compatibility metadata
* refactor(deploy): simplify oauth provider overrides
* fix(ci): retry transient cleanup API failures
* fix(deploy): adapt to platform instance response
* fix(deploy): update retry status copy
* Update packages/cli-core/src/commands/deploy/copy.ts
Co-authored-by: Rafael Thayto <rafa.thayto@gmail.com>
* Revert "Update packages/cli-core/src/commands/deploy/copy.ts"
This reverts commit fa5821c.
* fix(review): address deploy PR feedback
- give each deploy status component its own retry budget
- normalize absent domain status components as pending
- load resume domain and OAuth provider state concurrently
- collapse repeated OAuth provider override lookups
* fix(deploy): link domain settings in next steps
Add a direct Clerk Dashboard domains URL to deploy completion output so users can manage their production domain configuration.
* feat(deploy): add read-only deploy verification (#312)
* refactor(deploy): extract poll core into status.ts
* refactor(deploy): move state resolution into status.ts, rename dnsComplete
* feat(deploy): add resolveDeployState discriminator
* feat(deploy): add buildDeployStatusReport payload builder
* feat(deploy): add clerk deploy check command
* feat(deploy): tailor agent-mode deploy into a read-only handoff
* feat(deploy): register clerk deploy check subcommand
* docs(deploy): document deploy check and agent handoff
* fix(deploy): surface agent status read failures
* docs(clerk-cli): document deploy agent workflow
* fix(deploy): avoid backoff in agent check
* fix(deploy): check domain status as one DNS verification
* fix(deploy): include domains URL in agent next action
* fix(deploy): prompt agents to open domains URL
* docs(clerk-cli): warn deploy wizard needs a terminal
* fix(cli): address deploy review follow-ups
* fix(deploy): persist live production instance metadata
* chore: added link for codex
* docs(clerk-cli): clarify deploy check agent workflow
* refactor(deploy): remove unused status check helper
* test(deploy): avoid leaking deploy check mocks
* docs(testing): document bun test isolation
* docs: remove hidden bird command from readme
* feat(deploy): rename status check command
* fix(deploy): humanize status dashboard guidance
* refactor(deploy): tighten status resolution
* fix(deploy): label DKIM records as email in DNS handoff
cnameTargetLabel keyed off the full `clk._domainkey`/`clk2._domainkey` labels, but host.split(".", 1)[0] only ever yields the first label ("clk"/"clk2"), so those cases were dead and DKIM records rendered as a generic "CNAME". Match the actual prefixes so DKIM records show the email label.
* refactor(deploy): drop unreachable OAuth completion guards
runOAuthSetup pauses by throwing DeployPausedError on skip or interrupt, so it never returns a partial list. The `completed.length < providers.length` guards after it were dead code implying a contract that does not exist. Remove them and document the pause-by-throw contract on runOAuthSetup instead.
* fix(deploy): re-prompt Google OAuth JSON after docs
* fix(deploy): re-prompt oauth credentials after walkthrough
---------
Co-authored-by: Rafael Thayto <rafa.thayto@gmail.com>
Sign up for freeto 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

@wyattjoh@rafa-thayto