Repository navigation
fix: report the real --version, and answer "who am I?" per environment (#116, #117) - #146
Merged
Merged
Conversation
`--version` was the literal `.version("0.0.0")`, identical for a released
install and a locally linked dev build. That is worse than a missing version:
it reads like evidence, and in one downstream repo it sent the next person
chasing a PATH problem that did not exist.
The version is now baked in from package.json at build time — `tsup` and
`bun build --compile` both inline the JSON import — and printed alongside the
resolved entry path, so `ct --version` answers "which version" and "which ct"
at once:
1.7.0 (/usr/local/bin/ct)
Inside a standalone binary `import.meta.url` points into bun's embedded
filesystem, which bun's `fs` shim reports as existing; that prefix is
recognised so the binary's own path on disk is shown instead.
Baking the version in makes the artifacts version-sensitive at BUILD time,
which the release pipeline has to respect: the binaries are now recompiled in
semantic-release's prepare step, after the version bump, for the same reason
the tarball is already packed there (#84). Otherwise every released binary
would report the repo's 0.1.0 placeholder. Both jobs call one shared
build-binaries.sh so the two invocations cannot drift.
Fixes #116
Claude-Session: https://claude.ai/code/session_018JShVZYNLaRb4hF5KbHCXG
`plan`, `apply`, `adopt`, `get`, `coverage`, `state`, `refresh` and
`permissions` all take `-e, --env <name>`; `auth status` did not, so the one
command whose entire job is answering "which account is this?" could only ever
answer it for the default host. Finding out which identity `--env dev` would
use meant running something that touches the host for real, or reading
ct.envs.json and the Keychain by hand.
- `ct auth status --env <name>` resolves that env's host and reports the
identity there. The host goes to stderr, so `| jq` still sees only the
identity JSON.
- `ct auth status --all` checks every environment in ct.envs.json — one line
each, with where the token came from and nothing of the token itself:
dev https://mychurch-dev.church.tools ✓ Ada Lovelace (#42) via Keychain
prod https://mychurch.church.tools ✗ no token
It exits non-zero if any environment has no working token, so CI can gate on
it before an apply. A failing env is reported as that env's line rather than
aborting the run, so one unreachable instance cannot hide the others.
- `ct auth logout --env <name>` clears just that host's credentials and leaves
other logins in place (the default blob goes too when it holds a copy of the
same token, so no secret is orphaned).
Token resolution mirrors authedSession exactly — profile `tokenEnv` →
CT_LOGINTOKEN → the host-keyed Keychain entry — so a green line means the same
command with `--env` will authenticate the same way. The stored lookup is
host-keyed, so one env can never report another env's identity. Read-only
throughout: the only network call is the whoami handshake, and only for an env
that has a token to try.
Fixes #117
Claude-Session: https://claude.ai/code/session_018JShVZYNLaRb4hF5KbHCXG
`ct auth status --all` walks every host in ct.envs.json, so the bare `CT_LOGINTOKEN` fallback fanned one instance's token out to all of them — as a `login_token=` query parameter, into every instance's access log — and then reported a green line for envs nothing was configured for. The ambient token is now offered only to the host it is bound to (`CT_HOST`, else the stored default login's host); everything else reports no token. Failures are rendered with `formatError`, so the HTTP status a real `CtApiError` carries survives — 401, 403 and 500 no longer render alike. Token resolution moved inside the try, so a credential store that throws reports that env instead of aborting the sweep, and the preflight now runs `assertMinVersion` too, so a green line cannot be followed by an apply that refuses on the instance version. `ct auth logout --env <name>` still drops the default blob when it holds a copy of the same token — but it now says so, instead of promising that other logins are untouched while commands without `--env` lose their host. Release: the shipped binaries were the only ones never executed — they are recompiled in semantic-release's prepare step, after the smoke jobs ran, on an unpinned `bun-version: latest`. Both jobs now pin the same bun, the recompiled linux binary is smoke-tested again in the release job, and the smoke script asserts `ct --version`, which nothing in CI had ever run on the compiled path. The version constant is injected via `define` (tsup + `bun build`) instead of a default JSON import esbuild cannot tree-shake, which was inlining the whole manifest — devDependencies, scripts, dependency list — into the published bundle; running from source falls back to reading package.json. Finally, cli-version compared a decoded path against a percent-encoded one, which fails for any checkout path needing escaping. Claude-Session: https://claude.ai/code/session_018JShVZYNLaRb4hF5KbHCXG
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two small CLI-surface bugs that both cost more time than their size suggests.
ct --versionprinted0.0.0(#116)src/index.tshad.version("0.0.0")as a literal, so a released install and a locally linked dev build reported the same thing — which is worse than reporting nothing, because it reads like evidence. A downstream repo's handoff notes cited0.0.0as proof that a global dev build was shadowing the pinned one; it wasn't, and the time went into aPATHproblem that did not exist.The version is now baked in from
package.jsonat build time (bothtsupandbun build --compileinline the JSON import), and printed with the resolved entry path, so one command answers both questions:Verified on all three paths:
dist/index.js,npm run devfrom source (reportssrc/index.ts, which makes a dev build obvious), and a realbun build --compilebinary. Inside a standalone binaryimport.meta.urlpoints at/$bunfs/..., which bun'sfsshim reports as existing — so that prefix is recognised explicitly and the binary's own path is shown instead.One thing worth your judgement: baking the version in makes the artifacts version-sensitive at build time, and the release pipeline compiles the binaries in the
buildjob — before semantic-release bumpspackage.json. Left alone, every released binary would report the0.1.0placeholder, i.e. #116 fixed for the npm package but not for the install path the README leads with. So the binaries are now recompiled inside semantic-release'spreparestep, exactly where the tarball is already packed for the same reason (#84), with both jobs calling one shared.github/scripts/build-binaries.sh.The trade-off: the smoke-tested binaries are no longer byte-identical to the attached ones — they differ by the version constant. That is the same trade-off already accepted for the tarball. If you would rather not take it, the last three files of the first commit (
.releaserc.json,release.yml,build-binaries.sh) can be dropped on their own and the rest still fixes the npm path.ct auth statushad no--env(#117)The one command whose entire job is answering "which account is this?" could only answer it for the default host, while every other host-touching command takes
-e, --env.--allexits non-zero when any env has no working token, so CI can gate on it before an apply. A failing env becomes that env's line rather than aborting the run — one unreachable instance cannot hide the others.authedSessionexactly (profiletokenEnv→CT_LOGINTOKEN→ host-keyed Keychain entry), so a green line means the same command with--envwill authenticate the same way. The stored lookup is host-keyed, so one env can never report another's identity — pinned by a test.ct auth status | jqstill sees only the identity JSON.ct auth logout --env <name>clears just that host and leaves other logins in place; the default blob goes too when it holds a copy of the same token, so no secret is orphaned.Read-only throughout: the only network call is the whoami handshake, and only for an env that has a token to try.
Tab completion needed no changes — it reads options off the program, so
ct auth status --env <TAB>completes real env names out ofct.envs.jsonfor free.Validation
npm test— 858 passed, 5 skipped (28 new)npm run typecheck,npx eslint src tests,prettier --check,git diff --checknode .github/scripts/docs-staleness.mjs— all 5 pages current.github/scripts/smoke-test-binary.shct auth status,--env dev,--all,--all --env(rejected) andlogout --env <unknown>exercised against a fixturect.envs.jsonFixes #116
Fixes #117
https://claude.ai/code/session_018JShVZYNLaRb4hF5KbHCXG