Repository navigation
fix(desktop): route Skill Hub through the proxy-aware stack and refuse off-host project installs - #363
Merged
Conversation
…e off-host project installs Hub browsing and installs in the desktop app went straight to Node's fetch, which ignores the system proxy and PAC settings that the gateway SSO calls already honor via Electron's net.fetch. @codev/skillhub now has an injectable transport (setHubTransport) that also carries the silent SSO refresh, the desktop passes net.fetch, and the controller waits out Chromium's proxy initialization once before the first hub request so it is not charged to the 15 s request timeout. Chromium's net::ERR_* codes classify as network errors. The install dialog offered every project of the connected server, but the main process writes to the host disk, so a WSL, sandbox, or remote project landed in the wrong place. "This project" is now disabled off the local server with a note naming the server and pointing at `codev skill pull`, and the controller checks the folder exists on the host before any hub traffic (new `missing-directory` error code). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QaEgv2JVUbep1sBYApZDFW
quickbeard
added a commit
that referenced
this pull request
Sep 14, 2026
…e Electron bridge (#368) * feat(app): serve the whole Skill Hub through the server and retire the Electron bridge Single-skill browse, detail, and install join the Skill Stacks on the server's fork-only v2.skillhub group (skillhub.skill.list / get / install), and the app's Skill Hub pages call them over the SDK like the Stacks tab already did. The Electron IPC bridge — the main-process controller, its proxy warm-up, the preload namespace, platform.skillhub, and the app-owned wire types — is deleted; nothing desktop-side remains. That removes #363's off-host refusal rather than keeping it: the server downloads the skill and installs it where the agent runs, so "This project" is valid for every project the connected server knows — local, WSL, sandbox, or remote — and "project" is resolved server-side from the request's directory, never from a path the renderer sends. It also gives the web app the Skill Hub: the sidebar entry is no longer gated on a desktop capability. A newly installed skill is made visible to the model by disposing the instance, as the stack install already does. The sign-in offer on an auth failure stays, but only when the app's own SSO writes the session the server will read — i.e. when this machine is the server. Hub traffic now takes the sidecar's network path, which honours the system trust store and HTTPS_PROXY-style settings but not a proxy configured only through OS settings or a PAC file; the changelog says so. The plaintext netmind host in the detail page is base64'd like every other one in shipped source. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P1MfYkJD3tQZRgqBKB4gig * fix(skillhub): tolerate the hub's nulls so one card can't fail the whole page The live hub sends unset columns as null (`metadata.publisher`, `author.avatar`, …). The old desktop bridge never validated shapes, but the server's response schema types those fields as optional strings, so a single null card made the Skills tab 500 into "Something went wrong". Nulls now become absent fields at the package's coercion seam, once, so the CLI, the TUI, and the server's strict schema all see one total shape (avatar keeps its null: the hub means "no picture" by it). The exerciser fixture carries the same nulls so CI covers the class, and the browse pages print the server's own message under the generic line instead of hiding it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P1MfYkJD3tQZRgqBKB4gig --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
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.
Problem
Two gaps in the desktop Skill Hub integration, both in the enterprise setups this fork targets:
net.fetchso system proxies, PAC files, and enterprise roots apply — but@codev/skillhubused Node's globalfetch, which honors none of them, and the silent SSO refresh inside it ran on Node's fetch too. Behind a proxy, sign-in worked while the Skill Hub page showed "Couldn't reach the Skill Hub".C:\home\…on Windows) or failed with an unhelpful error. Nothing filtered or warned.Fix
Proxy-aware hub transport
@codev/skillhub: the existinghttpApiseam gains an injectabletransportand an exportedsetHubTransport(fetchImpl).silentSso()inside the package now receives the same transport, so the token refresh that authenticates hub requests follows the proxy too.SKILLHUB_URLis exported for the desktop wiring.createSkillHubControllertakes optionalfetchImpl/warmProxydeps. Main passes the samenet.fetchwrapper the gateway SSO controller uses, andsession.defaultSession.resolveProxy(SKILLHUB_URL)as the warm-up — awaited once before the first hub request, bounded to 60 s, never blocking on failure — so Chromium's proxy initialization is not charged against the hub's 15 s request timeout (the same failure mode fix(desktop): stop the SSO setup timing out on Chromium's network stack #360 fixes for SSO). The resolved proxy is logged for the next report from such a network.net::ERR_*messages classify asnetworkerrors so the page keeps its hub-unreachable state.Off-host project installs refused, not misplaced
server.isLocal(). Off the local server, This project is disabled, the scope defaults to global, and a note names the connected server and points atcodev skill pullon that machine (a global install still lands on this computer, which that server will not see — the note says so).missing-directoryerror code, rendered with a localized message. New keys inen,es,vi.Tests
packages/codev-skillhub: 196/196 pass, including two new transport tests — hub requests use the installed transport; the silent SSO refresh behind a request (token + userinfo) uses it too and the hub request carries the refreshed bearer.packages/desktopsrc/main/skillhub: 9/9 pass, four new — a missing project folder is refused before the hub is contacted;net::ERR_*classifies as network; requests wait for the warm-up once and it runs exactly once; a failed warm-up does not block.bun typecheckclean inpackages/codev-skillhub,packages/desktop,packages/app, and the rootbun typecheck(the pre-push hook) on this branch.Not verified on a real proxied network or against a WSL server (neither available here).
DIVERGENCES.md(desktop Skill Hub wiring row) andCHANGELOG.mdupdated. Note:packages/desktop/src/main/index.tsis also touched by the in-flightgateway-fetch-fallbackbranch; the hunks are adjacent but distinct.🤖 Generated with Claude Code
https://claude.ai/code/session_01QaEgv2JVUbep1sBYApZDFW