Skip to content

feat(ecosystem): retry a failed npm update via pnpm - #50

Merged
trsdn merged 1 commit into
mainfrom
feat/npm-pnpm-fallback
Sep 22, 2026
Merged

trsdn merged 1 commit into
mainfrom
feat/npm-pnpm-fallback

Conversation

@trsdn

@trsdn trsdn commented Sep 22, 2026

Copy link
Copy Markdown
Owner

Why

Direct follow-up to #47's real trigger: a corporate npm registry refuses npm install's own fetch for a package while pnpm add succeeds for the exact same package, version and registry — every time, verified across five real packages tonight (squad-cli, copilot, marp-cli, mermaid-cli, corepack), each fixed by hand in a terminal. That's not durable — a sixth npm-tracked tool will hit the same wall eventually. This gives OpenFreshr the same rescue as a button.

What changed

  • EcosystemUninstalling: a capability protocol (mirrors UninstallingBackend's relationship to PackageBackend) — only ecosystems where removal is itself safe and well-understood implement it. NpmEcosystem now conforms: npm uninstall --global -- <name>, same token validation and -- separator as every other action in this codebase.
  • EcosystemCoordinator gains isAvailable(_:) (a fresh, cheap probe, never a stale cached read) and uninstall(_:) (routes only to an ecosystem that actually supports it).
  • AppViewModel.retryViaPnpm(_:): re-runs a failed npm package's update through pnpm instead. Only on a confirmed pnpm success (the coordinator's own rescan, never pnpm's own claim) does it remove the stale npm-tracked copy, so npm outdated stops reporting a package that is verifiably current again, just through a different tool.
  • A "Try via pnpm" button appears on a failed npm package row, but only when pnpm is actually available. Deliberately npm→pnpm specific, not a generic "try another tool" button — that's the one pairing this was verified for.

Testing

  • swift test: 359/359 passing, including new NpmEcosystem uninstall-command tests and EcosystemCoordinator tests for isAvailable/uninstall (routes to a supporting ecosystem, fails cleanly for a non-supporting one, fails cleanly for an unconfigured one).
  • swift format lint --strict: clean.
  • make app: succeeds.

🤖 Generated with Claude Code

https://claude.ai/code/session_01K1v8n32LeqiPZd5vazB8q1

Durable follow-up to the pnpm work (#47): a corporate npm registry was
found to refuse npm's own fetch path for a package while pnpm's
succeeded, for the exact same package, version and registry, every
time — verified directly on five real packages (squad-cli, copilot,
marp-cli, mermaid-cli, corepack), not assumed. Rather than requiring a
person to fix each future occurrence by hand in a terminal, OpenFreshr
now offers that same rescue as a button.

- EcosystemUninstalling: a capability protocol mirroring
  UninstallingBackend's relationship to PackageBackend — only meaningful
  where removal is itself safe and well-understood. NpmEcosystem
  conforms (`npm uninstall --global -- <name>`, same token validation
  and `--` separator as every other action here).
- EcosystemCoordinator gains `isAvailable(_:)` (a fresh, cheap probe —
  never a stale cached read) and `uninstall(_:)`, which routes to an
  ecosystem only when it actually supports removal.
- AppViewModel.retryViaPnpm(_:): re-runs a failed npm package's update
  through pnpm instead. Only on a *confirmed* pnpm success (the
  coordinator's own rescan, never pnpm's claim) does it remove the
  stale npm-tracked copy, so `npm outdated` stops reporting a package
  that is verifiably current again, just through a different tool.
- A "Try via pnpm" button on a failed npm package row, shown only when
  pnpm is actually available. Deliberately npm→pnpm specific, not a
  generic "try another tool" button — that pairing is the one this was
  verified for.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1v8n32LeqiPZd5vazB8q1
@trsdn
trsdn merged commit 8355293 into main Sep 22, 2026
12 checks passed
@trsdn
trsdn deleted the feat/npm-pnpm-fallback branch September 22, 2026 21:29
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.

1 participant