Skip to content

fix(sites): repair broken links, env-gated cross-nav, prefix and offline fixes - #1

Draft
moortekweb-art wants to merge 5 commits into
devfrom
claude/site-flow-fixes
Draft

fix(sites): repair broken links, env-gated cross-nav, prefix and offline fixes#1
moortekweb-art wants to merge 5 commits into
devfrom
claude/site-flow-fixes

Conversation

@moortekweb-art

@moortekweb-art moortekweb-art commented Aug 2, 2026

Copy link
Copy Markdown
Owner

Repairs broken internal links, PWA/service-worker behaviour, a 403 on fresh installs and a CSP-blocked docs link, and adds an env-gated cross-navigation mechanism for linking out to sibling services.

Targets dev per docs/workflow.md.

Cross-navigation: NEXT_PUBLIC_SIBLING_LINKS

Two build-time variables drive the sidebar network links. There is no fallback URL in the source — when neither is set, nothing renders.

Variable Value
NEXT_PUBLIC_PORTAL_URL A single absolute URL, rendered first and labelled "Portal".
NEXT_PUBLIC_SIBLING_LINKS A one-line JSON array of {"label": string, "href": string} objects.
NEXT_PUBLIC_SIBLING_LINKS=[{"label":"Hub","href":"https://example.invalid/hub/"},{"label":"Metrics","href":"https://example.invalid/metrics/"}]

Both are inlined by next build, so they must be in the build environment, not the runtime one. Either export them for the build (single-quote the JSON so the double quotes survive) or put them in frontend/.env.local unquoted; scripts/deploy-remote.sh ships that file to the remote. Full spec in the README under "Sidebar network links".

Entries are dropped unless label is a non-empty string and href is an absolute http(s) URL — javascript:, data: and relative paths are rejected. An absent, blank, non-JSON or non-array value degrades to an empty list, so the app renders normally with no links rather than crashing. Covered by frontend/src/features/shell/network-links.test.ts.

The links render in both the desktop sidebar footer and the mobile navigation drawer, so they are reachable wherever app navigation is.

Broken links and flow fixes

  • /models redirected to /configure#models; ConfigurePage selects its section from ?section, so the hash alone landed on Overview. Now redirects to /configure?section=models#models.
  • PWA manifest shortcuts pointed at /chat and /recipes, a dead route and a redirect stub. Now /agent and /configure?section=models.
  • The service worker precached /chat and /recipes; cache.addAll rejected the whole install if any one route was unavailable, leaving the app with no service worker. Assets are now added individually and failures tolerated.
  • On a cache miss the fetch handler resolved to undefined, which surfaces as a network error — an offline navigation to an uncached page looked like a broken app. Now falls back to the cached app shell, then an explicit 503. Redirected and cross-origin responses are no longer stored.
  • /quick hides the app sidebar and has no bridge in a plain browser, making it a navigation dead end. It now offers an "Open full app" link when no desktop bridge is present.
  • The fresh-install controller default was http://127.0.0.1:8080 while the proxy's trusted origin is http://localhost:8080 — different origins, so every first status poll 403'd. Both spellings aligned.
  • The OpenAPI "Open" link pointed at the controller's Swagger UI, which loads assets from cdn.jsdelivr.net and is blocked by the frontend CSP (and unreachable offline), rendering a blank page. It now links the raw spec; the in-app panel is the browsable reference.
  • The HuggingFace avatar route returned 404 when no avatar exists — the normal case offline — painting a console error per model owner. Now 204, which still triggers the letter-badge fallback.
  • Path-prefix deployments: basePath is honoured by hand-written manifest/icon/sw.js/proxy references, and the service worker is disabled under a prefix because the static manifest's start_url/scope cannot be made prefix-safe.

No topology in tracked files

The hardcoded pop-os-1.tailadb2c1.ts.net remote preset is removed; the remote first-run lane now appears only when LOCAL_STUDIO_REMOTE_PRESET_URL is set. All examples use example.invalid.

$ git diff origin/dev...HEAD | grep -E '^\+' | grep -Ei 'ts\.net|192\.168\.|127\.0\.0\.1:[0-9]|localhost:[0-9]'
+    const primary = normalizeControllerUrl(getStoredBackendUrl() || "http://localhost:8080");
+    () => (getStoredBackendUrl() || "http://localhost:8080").replace(/\/+$/, ""),

The only matches on added lines are the app's own loopback default, matching shared/agent/backend-url.ts. Every .ts.net match in the diff is a removal.

CI

Dependency Review failed on every PR: GitHub keeps the dependency graph disabled on forked repositories and the action hard-fails with "Dependency review is not supported on this repository" — a red required check no diff could fix. The job is now skipped on forks (re-enable by turning on the dependency graph under Settings → Code security).

Separately, security.yml only listened for main, so the TruffleHog / CodeQL / Dependency Review gates that docs/workflow.md lists as required for merges into dev never ran on a dev PR. It now covers both branches.

Verified locally (macOS, node 22.20.0, bun 1.3.14)

Command Result
controller: bun run typecheck && lint && check && test pass — 78 tests
services/agent-runtime: bun run test pass — 78 tests
frontend: npm run check:static pass — lint, 3 typechecks, cycles, UI structure
frontend: bun test src desktop pass — 91 tests across 24 files
scripts/check-conventional-commits.mjs --range pass
frontend: npm run build (no sibling env) pass
frontend: npm run build (placeholder env) pass — values confirmed inlined into app/layout chunk
frontend: npm run build (malformed env) pass

With no env set, example.invalid appears nowhere in .next/static; with it set, the portal and both sibling hrefs appear. E2E (e2e) and desktop-package were not run locally.

…ine fixes

- service worker: precache only real routes (drop /chat and /recipes redirect
  stubs), bump cache to v11; gate SW registration off under path-prefix deploys
  to match the documented prefix story
- manifest: point stale /chat and /recipes shortcuts at live routes
- /models redirect now carries ?section=models so Configure opens the Models
  section instead of Overview
- align controller-URL fallbacks with the proxy's trusted default origin,
  fixing the fresh-install 403 loop on the Status dashboard
- Logs docs link targets the CDN-free OpenAPI spec panel instead of the
  CSP-blocked Swagger UI; GPU monitoring row no longer renders "null"
- /quick gets a way back into the full app
- new env-driven sidebar network links (NEXT_PUBLIC_PORTAL_URL /
  NEXT_PUBLIC_SIBLING_LINKS): private hostnames stay in gitignored env files,
  never in the repo; remote preset URL likewise env-gated via
  LOCAL_STUDIO_REMOTE_PRESET_URL
- README: document the services/agent-runtime install step required for a
  clean-clone build; deploy-remote.sh ships the frontend env file when present

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MydtMsZwYyuKYamq5FEfoo

Copy link
Copy Markdown
Owner Author

CI note — the Dependency Review failure is a repository setting, not this diff.

The job errors before analyzing anything:

Dependency review is not supported on this repository. Please ensure that Dependency graph is enabled, see https://github.com/moortekweb-art/local-studio/settings/security_analysis

This fork has Dependency Graph disabled (GitHub disables it on forks by default), so actions/dependency-review-action@v4 cannot run at all — it will fail on every PR in this repo regardless of content. This PR adds no dependencies; its only package.json change is a dev script.

Owner-side fixes (either works):

  1. Enable Dependency graph under Settings → Advanced Security — the check should pass on the next run, or
  2. Gate or remove the Dependency Review job in the workflow for this fork — say the word and I'll push that edit to this branch.

Generated by Claude Code

@moortekweb-art
moortekweb-art changed the base branch from main to dev August 2, 2026 13:56
The security workflow only listened for pull_request/push on main, so the
TruffleHog, CodeQL and Dependency Review gates that docs/workflow.md lists as
required for merges into dev never ran on a dev PR.

Dependency Review also failed unconditionally here: GitHub keeps the
dependency graph disabled on forked repositories, and the action hard-fails
with "Dependency review is not supported on this repository" — a red required
check that no diff could turn green. Skip the job on forks instead.
NEXT_PUBLIC_SIBLING_LINKS entries went into an href unvalidated, so a
javascript: or relative value in a deployment env file would render as a live
link. Accept only absolute http(s) URLs, require a non-empty label, and apply
the same check to NEXT_PUBLIC_PORTAL_URL. Malformed JSON, a non-array value or
an unset variable still degrade to an empty list, never a throw.

The links only rendered inside the desktop sidebar footer, which is hidden
below md — on a phone and in the installed PWA they were unreachable. Render
them in the mobile navigation drawer too, so the same links are present
wherever app navigation is.
… uncached

cache.addAll rejected the whole install if any one precached route was
unavailable, leaving the app with no service worker at all; each asset is now
added independently and failures are tolerated.

On a cache miss the fetch handler resolved to undefined, which surfaces as a
network error — an offline navigation to a page that was never cached looked
like a broken app rather than an offline one. Fall back to the cached app
shell for navigations and to an explicit 503 otherwise.

Redirected and cross-origin responses are no longer stored: replaying a cached
redirect for a navigation trips Chromium's redirect-mode check.
…ders

The .env.example entries used your-host.example.ts.net placeholders, putting
tailnet-shaped hostnames in a public repository; use example.invalid instead.

Document the literal NEXT_PUBLIC_SIBLING_LINKS format an operator has to
produce — a one-line JSON array of {label, href} objects, http(s) only — along
with both injection shapes (an inline env assignment for next build, and the
unquoted .env.local form) and the degrade-to-empty behaviour.
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.

2 participants