Repository navigation
Add an opt-in beta npm release channel (version-skew Phase 1) - #267
Conversation
Design for gracefully handling a CLI newer than its server (npm `latest` outruns per-tier server rollout). Recommends per-endpoint version-compare guards fed by a shared last-seen-version cache, with a beta dist-tag channel and a deferred capability-endpoint path. Refined through a spec-review flow (6 rounds to sign-off). Reviewed-via: kcap review flow (spec-review), signed off clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…file Task 3 surfaced that the plan targeted the legacy v1 CapacitorConfig; the live config is v2 profile-based (AppConfig.Load/CapacitorConfig is dead for real users, and persisting a flat CapacitorConfig would corrupt the v2 config). Move update_channel to Profile (next to update_check), read via GetActiveProfileAsync, persist via SaveProfileConfig. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e-aware comparison
…nnel switch actually applies
…npm tarball; fix stale cache comment Persist --beta/--stable to the profile GetActiveProfileAsync() actually read (ResolvedProfile?.ProfileName ?? active_profile), not blindly to active_profile, so the switch sticks for the profile the user is on (KCAP_PROFILE, .kcap.json, git-remote match, or `kcap use` binding). Excludes bin/kcap.test.js from the npm tarball via a nested bin/.npmignore (a root-level npmignore doesn't work against directory globs in "files"). Corrects a stale comment referencing the old non-channel cache filename.
PR Summary by QodoAdd opt-in beta npm release channel for kcap CLI updates (Phase 1)
AI Description
Diagram
High-Level Assessment
Files changed (19)
|
Code Review by Qodo
Context used 1.
|
…eck/import settings from the v2 profile Deletes AppConfig.Load(); moves UpdateCommand + ImportCommand onto the v2 profile; demotes CapacitorConfig -> LegacyV1Config (migration-only DTO); removes the unused v1 indented JSON context; fixes update_check defaulting to false on v1->v2 migration. Closes #268
… migrated Fires only on a genuine v1->v2 migration (result.ShouldPersist), best-effort and at most once per process. Lets us watch whether any v1 configs still exist in the wild before eventually removing the ConfigMigration path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addresses Qodo review on #267: Profile.UpdateChannel is read unvalidated from disk and flows into the update-check cache path and the registry URL. Validate the resolved channel against a {latest, beta} allowlist (normalize + fall back to latest), so a corrupted/hand-edited value containing '..' or a rooted path can never escape the config dir or break the check. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What & why
The kcap CLI and the Capacitor server share a consolidated version bump but ship through different channels: the server rolls out per tenant tier (
internal→stable/micro) while the CLI publishes to npm's singlelatestdist-tag on every release. So an internal-first release dragsstable/microusers onto a CLI newer than their server — a hard failure for daemon features, MCP tools, and agent-invoked commands (core recording stays backward-compatible).This is Phase 1 of the version-skew design: an opt-in beta npm release channel so internal-first releases go to a
betadist-tag andlateststays matched to thestable/microcohort. It's a noise reducer, not the correctness mechanism — that's Phase 2 (server-version guards), tracked separately.Closes #266
Closes #268
AI-1177
What's in it
PrereleaseSemver) — ordersbeta.1 < beta.2 < release, which the existingSemverCompare(strips prerelease) can't.npm publish --tag beta, leavinglatestuntouched;scripts/npm-dist-tag.shderives the tag;RELEASING.mddocuments the invariant (internal-first → prerelease;latestonly oncestable/microcan serve it).update_channelon the v2Profile(defaultlatest).kcap update --beta/--stable— persists the choice onto the resolved active profile, queries the matching dist-tag, per-channel cache, prerelease-aware comparison, and exposesinstall_tagin the--checkJSON.--beta/--stableto its probe and installs the resolved dist-tag (instead of hardcoded@latest).kcap update) andhelp-update.txt.Default behavior is unchanged: no opt-in ⇒
latest.Also in this PR: retire the live v1 config read path (Closes #268)
Working on the channel setting surfaced that
kcap update'supdate_checkgate (andImportCommand) read the dead legacy flat config viaAppConfig.Load(), which returns all-default values for v2-profile users. Rather than patch one caller, this retires the whole live v1 read path:AppConfig.Load(); movedUpdateCommandandImportCommandonto the v2 profile (GetActiveProfileAsync()).CapacitorConfig→LegacyV1Config, now a migration-only DTO used solely byConfigMigration; removed the unused v1 indented JSON context.update_checkmigrated tofalseinstead of the v1 defaulttrue.Notable during review
update_channelwas moved from the legacy v1CapacitorConfigto the v2Profile— the legacy record is dead for real (v2-profile) users and persisting it would corrupt the config.KCAP_PROFILE/ repo-bound users.Testing
PrereleaseSemverprecedence,update_channelround-trip,ResolveChannel, v1→v2ConfigMigration(incl. theupdate_checkabsent/false/true trio), a WireMock integration test for the channel dist-tag query, and the launcherresolveInstallSpec/probeArgs(node).Follow-ups (not in this PR)
X.Y.Z-beta.Nscheme), a--check+--betadoc note, and a binary↔launcherinstall_tagcontract test.🤖 Generated with Claude Code