fix(upgrade): clear error on tarball-extract installs + scoped-name registry lookup (#184)#185
fix(upgrade): clear error on tarball-extract installs + scoped-name registry lookup (#184)#185mellanon wants to merge 3 commits into
Conversation
…ookup (#184) Two bugs hit during `arc upgrade soma` (v0.5.0 → v0.5.1) that previously sent the user down dead-ends — both filed in #184. **Bug 1 — `arc upgrade` errored cryptically on tarball-extract installs.** The registry-install pipeline (`downloadPackage` + `extractPackage`) lays down a plain directory with no `.git`. `upgradePackage` always shelled out to `git pull` against that dir and the user saw: `git pull failed: fatal: not a git repository (or any of the parent directories): .git` …with no hint that the documented workaround was `arc remove <name> && arc install @<scope>/<name>`. Fix: detect the tarball-extract case before calling git pull (via the existing `findGitRoot` returning null) and surface a clear, actionable error citing the workaround + the tracking issue. The full in-place fix — running the registry-install pipeline from inside `upgradePackage` (resolve → download → verify → extract → swap) — still needs the install-orchestration code in `src/cli.ts` factored out into a reusable function. Tracked as a follow-up on #184. **Bug 2 — `arc upgrade --check` reported "up to date" against scoped registry entries.** `checkUpgrades` looked up the registry entry by `skill.name` (bare slug, e.g. `soma`), but the registry catalog indexes by scoped name (e.g. `@metafactory/soma`). `findRegistryEntry` only did an exact case-insensitive match, so `result.registryVersion` stayed null, `availableVersion` fell back to `result.repoVersion` (which is also the installed version on a tarball-extract install — nothing pulls it forward), and `compareSemver(installed, available)` returned 0 → `upgradable: false`. This silently lied to the user: registry HAD v0.5.1, install was at v0.5.0, but `arc upgrade soma --check` confidently said "All packages are up to date." Fix: `findRegistryEntry` now does a two-pass lookup — first exact case-insensitive match (unchanged), then, only when the input is unscoped, a fallback that matches against the unscoped tail of any scoped entry. So `findRegistryEntry(cfg, "soma")` resolves to a registry entry whose `name` is `@metafactory/soma`. An exact-scope match always beats a tail-only fallback; multiple scoped entries with the same tail resolve to the first one encountered, in skills → agents → prompts → tools → components → rules order. ## Test coverage - `test/commands/upgrade.test.ts` — two new tests, both failed before the fixes and pass now: - `resolves scoped registry entry from bare installed-name (arc#184)` - `returns actionable error for tarball-extract installs (no .git) (arc#184)` - Full suite: 957 pass / 0 fail. `bunx tsc --noEmit` clean. ## Verified manually ``` $ bun src/cli.ts upgrade soma Cannot upgrade "soma" in place: install at .../metafactory__soma is a registry tarball-extract, not a git checkout. Run `arc remove soma && arc install @<scope>/soma --yes` to upgrade. Tracked at #184 for the in-place fix. ``` Closes one bug-pair from #184. Full in-place upgrade for tarball installs stays open on #184 as the follow-up.
CI's `lint:errors` gate (eslint --quiet) flags `@typescript-eslint/array-type`. The `sections` lookup table introduced for the two-pass findRegistryEntry used `Array<[...]>` syntax; switch to the `[...][]` form the rule requires. Local `bunx tsc --noEmit` passed but didn't catch this — eslint wasn't run locally before the first push. Lint-clean now on all three changed files.
Code Review — PR #185 (arc#184 upgrade fixes)Verdict: APPROVE-WITH-NITS. Both bugs are fixed correctly, the deferral of the in-place tarball upgrade is appropriate and well-documented, and the two new tests are genuine reproducers. No blockers. One HIGH-severity correctness note worth a follow-up, plus a few NITs. Reviewed: HIGH —
|
… hint In-session code review of PR #185 (#184) returned APPROVE-WITH-NITS. Addressing every finding: HIGH — findRegistryEntry pass-2 tail match was first-match-wins across scopes. If two scopes publish the same package name, an unscoped lookup silently resolved to whichever entry came first. Not exploitable (no caller installs from the resolved entry — upgradePackage git-pulls the existing checkout), but it surfaces a misleading version in `arc upgrade --check` / `arc info`. Now collects ALL tail matches and resolves only when exactly one exists; ambiguous (>1) returns null so the caller reports an honest "not found" instead of guessing a scope. LOW — findRegistryEntry: empty / whitespace-only input could match a malformed `@scope/` entry whose tail is the empty string. Added a guard at the top of the function. LOW — upgradePackage: documented the findGitRoot walk-up assumption — findGitRoot climbs 10 parents, so a tarball-extract nested inside an unrelated git repo would be misdetected as a git checkout. Safe for the default reposDir layout; comment makes the assumption explicit. NIT — upgradePackage: the tarball-extract error message used a `@<scope>/` placeholder. Registry installs record repo_url as `@scope/name@version`; parse the scoped ref out of it so the suggested `arc install` command is copy-pasteable. Git installs (URL repo_url) keep the placeholder. NIT — upgrade.test.ts: documented the tarball test's dependency on the OS temp dir not being inside a git repo. Tests: +3 in registry.test.ts (bare→scoped resolution, ambiguous-scope → null, empty-string → null). Full suite 960 pass / 0 fail (one known temp-dir-race flake, green on re-run). eslint --quiet clean on all changed files, tsc clean.
Review findings addressed — all 6 resolvedThanks for the review. Pushed
On the HIGH security assessment — agreed it's not code-execution dependency confusion (no caller installs from the resolved entry; Tests: +3 in Note: the |
Summary
Fixes the two bugs in
arc upgradereported in #184:arc upgrade <name>against a registry-installed package (no.gitdir) used to fail withgit pull failed: fatal: not a git repository. Now surfaces an actionable error pointing to the documented workaround + this issue.--checkcorrectly resolves scoped registry entries.arc upgrade <name> --checkagainst an installed bare-name (e.g.soma) whose registry entry is scoped (@metafactory/soma) now reports the upgrade correctly instead of silently saying "All packages are up to date."Scope
This PR fixes both bugs as reported in #184 but ships only the clear-error variant of Bug 1 — full in-place tarball upgrade still needs the install-orchestration code in
src/cli.tsfactored into a reusable function (the install pipeline is currently inlined). The follow-up is tracked on #184 itself.Bug 2 is fully fixed at the registry-resolution layer (
findRegistryEntry), so every caller benefits:arc info,arc upgrade,arc upgrade --check, future callers.Approach
Bug 1 —
src/commands/upgrade.tsBefore calling
git pull, check iffindGitRoot(installPath)returns null. If so, the install is a tarball extract andgit pullis not the right primitive. Return a structured error citing:arc remove <name> && arc install @<scope>/<name> --yesworkaroundBug 2 —
src/lib/registry.tsfindRegistryEntrynow does a two-pass lookup:@), fall back to matching against the unscoped tail of any scoped entry. SofindRegistryEntry(cfg, "soma")resolves to@metafactory/soma.Exact-scope match always beats tail-only fallback. Multiple scoped entries with the same tail resolve to the first one found, in
skills → agents → prompts → tools → components → rulesorder — same as the original lookup order.Test plan
New test:
resolves scoped registry entry from bare installed-name (arc#184)— failed before, passes now.New test:
returns actionable error for tarball-extract installs (no .git) (arc#184)— failed before, passes now.Full suite green:
bun test→ 957 pass / 0 fail.Type-check clean:
bunx tsc --noEmit.Manual repro against the live install:
What this does NOT include
src/cli.tsinto a reusable function. Tracked as a follow-up note on arc upgrade: extracted-tarball install + version-check both broken (soma#127 reproducer) #184.arc install(the bug only affectedarc upgrade).Closes the clear-error + check-comparison parts of #184. Tracking issue stays open for the in-place upgrade follow-up.
🤖 Generated with Claude Code