Skip to content

release: Capy CLI v0.9.14 - #400

Merged
cvince merged 26 commits into
mainfrom
release/v0.9.14
Nov 6, 2026
Merged

cvince merged 26 commits into
mainfrom
release/v0.9.14

Conversation

@cvince

@cvince cvince commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

What's new

Vercel

  • capy connect vercel imports a Vercel project's environment variables into Capy, one Capy branch per Vercel environment (development, preview, production). --discover finds every Vercel project in the team that matches a folder in your repos.
  • Values Vercel won't give back become placeholders. Sensitive variables, legacy secrets, values Vercel can't decrypt for your token, and values Vercel answers 404 for are kept by name with no value. Fill them with capy edit NAME. A placeholder never stops the rest of the environment from importing.
  • capy deploy vercel writes Capy's values to a Vercel project through the Vercel API. No Vercel CLI needed. It never writes a placeholder, and never deletes or overwrites a variable Vercel shares across several environments; it splits it instead.
  • capy deploy vercel --discover proposes deploy targets for every Vercel project with a matching Capy project, then --plan and --confirm open one pull request per repo with .capy/deploy.json.
    • A preview's git branch is now worked out from the repo's long-lived branches (the production branch, the GitHub default branch, and branches with their own variables), ranked by recent preview deployments. Short-lived feature branches are never picked.
    • Variables scoped to one git branch no longer produce an empty extra target.

Secrets screen

  • Ctrl+S changes the sort in capy secrets: name A-Z or Z-A, deploy status A-Z or Z-A, updated newest or oldest. The footer shows the current sort, and the highlighted row stays highlighted.
  • The footer now fits narrow terminals. When it doesn't fit, the least-needed hints are left out.

Editing

  • capy edit NAME on a terminal asks for the value, like capy add NAME --force.
  • An empty branch, or one with only placeholders, now saves.

Run

  • capy run forwards decrypted secrets to docker compose env_file services.

Fixes

  • The capy secrets screen no longer flickers on fast input; it redraws in place.
  • A Vercel token that stops a run says why, and a saved token is confirmed.

Agents and CI

  • New codes: VERCEL_PREVIEW_DEPLOYMENTS_UNAVAILABLE (notice; discovery goes on without that signal), and the unresolved reason BRANCH_SCOPED_NO_VARIABLES.
  • capy deploy vercel --discover proposals carry evidence.git_branch with the basis and the signals behind each preview branch.

Behaviour changes

  • capy connect vercel no longer writes deploy targets. Use capy deploy vercel --discover.
  • --create-token is removed from capy connect vercel. Create a team-scoped token in Vercel; the prompt says where.

cvince added 24 commits October 1, 2026 12:12
… no vercel binary)

A vercel target whose options carry projectId writes env vars through
Vercel's REST API with the token in _TARGET_VERCEL_TOKEN. Shared
multi-environment records are split, never overwritten or deleted; writes
are read back and hash-checked. Targets without projectId keep the CLI path.
…rs (single project and --discover)

Read-only Vercel REST client with token resolution from the org system store
(_CONNECTOR_VERCEL_TOKEN), team resolution, 429 backoff, and per-environment
import mapping (production, preview, development, custom slugs). Preview
records scoped to a git branch, sensitive, system and legacy secret records
are skipped by stable reason. Discovery matches projects to local repos by
git origin and rootDirectory and reuses the Dokploy discovery sequencer and
local discovery commit.
Error codes shared by both sides are defined once; the token store names
live in vercelApi.ts and are re-exported by vercelTargetApi.ts.
…from the Vercel CLI sign-in) and where-to-get-the-key help on every key ask

- --create-token / --token-expires-days: make _CONNECTOR_VERCEL_TOKEN through the Vercel CLI's sign-in, check it is scoped to exactly the chosen team (else delete it), save it to the org system store; alone it stops after saving, with --project/--discover it continues; refused under --dry-run
- interactive runs with a missing token offer the CLI route next to the hidden prompt
- every Vercel/Dokploy key ask and key refusal carries link + remedy (JSON) and the page URL (stderr); capy system set prints it for the four known names
…-targets; approved token instructions; drop --create-token

- remove capy connect vercel --create-token / --token-expires-days, the Vercel CLI token module, its error codes, the system-store onMissing hook and their tests
- every Vercel token ask or refusal (connect, deploy preflight and setup, capy system set) shows the approved instructions: link + remedy in JSON, stderr in the terminal, "Then paste it here." at a hidden prompt, the team slug when known
- capy deploy target setup for Vercel is API mode only: one question (dashboard link or project name), live check (VERCEL_PROJECT_NOT_FOUND re-asks, VERCEL_URL_INVALID for a bad link), name-back confirm, environment (custom ones included), optional preview branch; no vercel binary, .vercel/project.json or vercel link; setup stays in the terminal
- a target saved without being able to check the project keeps the team slug (teamSlug) and scopes requests by ?slug=
- capy connect vercel --targets writes the vercel-<environment> target for each imported environment without asking (single import and --discover); --dry-run lists them; the discovery commit includes .capy/deploy.json
main's behaviour wins on shared code (connect, deploy, Dokploy, system store,
--resolve/--conflict, exit-3 protocol); the Vercel additions are layered on top.
Vercel connect/discover now run the per-folder gate like Dokploy's, and the
Vercel API-mode tests follow main's deploy test harness. The --web branches of
the old Vercel picker are gone with main's web removal. docs/cli-reference.md
regenerated.
… writes targets

Connect is for retrieval, target is for deploy. capy connect vercel imports
values only: --targets and the interactive deploy-target offer are removed.

capy deploy vercel --discover mirrors capy deploy dokploy --discover (facts,
--plan --dry-run, --plan --confirm; one PR per repo, never prompts, names only).
One target per Vercel project and environment that holds variables: production,
preview (and a preview scoped to a git branch), custom environments, and
development only when it is the only one. The Dokploy modules are shared through
an additive KindOverrides seam; Dokploy output is unchanged. The plan schema is
published as schemas.deploy_vercel_plan.
…y's discovery

Discovery only reads Vercel, so it uses _CONNECTOR_VERCEL_TOKEN (then $VERCEL_TOKEN), not the deploy-side _TARGET_VERCEL_TOKEN.
… add NAME --force

A name on a terminal now uses add's hidden masked prompt and its write path (encrypt, sync, push), creating or overwriting without an overwrite question. Piped values and the no-name editor are unchanged. --dry-run refuses with DRY_RUN_UNSUPPORTED before any prompt.
A 403 is no longer reported as a rejected token. It is VERCEL_NO_ACCESS and names what the token could not access: the team list, a project, or a project's environment variables. 401 stays VERCEL_AUTH_FAILED. Discovery says it needs a token scoped to the whole team.

A token problem carries the token page and two numbered steps. At a terminal, Enter asks for a new token (saved over the old one) and runs again from the token step; one press is one retry. Elsewhere nothing waits.

The system store prints one line naming the secret after saving a value from its hidden prompt.
A value Vercel has but will not return (sensitive, legacy secret, or a value
route answer with decrypted: false) is recorded as a placeholder on the Capy
branch of every environment it is in: a typed flag on the variable's keep.lock
entry with an empty value_hash, a comment line in .env, and nothing else.
Writing a real value for the branch removes the flag.
A target var that is a placeholder on the branch is skipped and reported as
kept. Replacing a value Vercel holds as sensitive asks the first time for a
target (terminal), or needs --replace-sensitive off a terminal; the delivery
record that follows is the record that it was confirmed. Dry run reports both.
… as kept instead of skipped

A sensitive, legacy-secret or not-decrypted name that already has a value in Capy
keeps that value untouched. It is now listed under `kept` (code CAPY_VALUE_KEPT, with
the Vercel reason) in the plain import, --overwrite, --dry-run, --json and the
discover preview/confirm/result, and no longer under `skipped`.
…der-only branch saves

Move the discovery steps both Dokploy and Vercel run out of dokploy.ts into discoverySteps.ts. Refusal codes come from a per-provider table: Dokploy keeps its DOKPLOY_* codes, Vercel reports CONNECTOR_* codes (added to ERROR_CODES and the CLI reference). A typed service error on upload keeps its own code for neutral providers.

A branch with no variables (placeholders only, or everything cleared) uploaded an empty env_blob, which the service refuses with 400. The blob of an empty branch is now a comment line that every reader parses as no variables.
…ariables and the default branch (CAP-730)

The all-branches preview no longer takes the production branch by default. Recent preview deployments,
branch-scoped variables and the GitHub default branch (when it is not the production branch) each name a
branch; agreement is certain, disagreement takes the strongest signal and needs review, no signal keeps the
production branch and needs review. A custom environment's branch rule names its branch. Signals are listed
in the proposal's evidence. A preview scoped to a git branch with no variable in common with its Capy branch
stays unresolved (BRANCH_SCOPED_NO_VARIABLES) instead of becoming an empty proposal. A failed deployments
read is a coded notice, never a failed discovery.
…nly rank the candidates (CAP-730)

Candidates are the production branch, the GitHub default branch and the branches with scoped variables.
Recent preview deployments never add one, so a feature branch or a one-off import branch can no longer become
the PR base. One candidate: the production branch, certain. Several: ranked by deployments, scoped variables,
default branch; certain only when every signal that names a candidate names the winner. Deployment counts in
the evidence are kept for candidates only, with one total for the other branches.
Six sorts: name A-Z/Z-A, deploy status A-Z/Z-A, updated newest/oldest.
Search still decides which rows show; the sort orders them, and the
highlighted row stays highlighted. The footer shows the current sort and
drops whole hints (never mid-word) when the terminal is narrow.
Comment thread tests/deploy/vercelSetup.test.ts Fixed
@cvince
cvince merged commit 8d4b83b into main Nov 6, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants