Skip to content

feat(link): add the #remote Remote Link page - #5807

Merged
lidge-jun merged 9 commits into
devfrom
codex/remote-link-5-gui
Sep 25, 2026
Merged

lidge-jun merged 9 commits into
devfrom
codex/remote-link-5-gui

Conversation

@lidge-jun

@lidge-jun lidge-jun commented Sep 25, 2026 •

Copy link
Copy Markdown
Owner

Summary

Fifth layer of the remote link stack. #remote now opens Remote Link, the page that links this machine to others over SSH, using the /api/link/* routes from L4.

  • Off first. The page starts with a switch that is off, over a blurred, non-interactive preview. Turning it on asks for this machine's role: Home, or Child. Child shows that the find-home flow is coming, and sends no request.
  • Home. The page lists child computers with a status label next to each dot (connected, reconnecting, failed, including compensation_failed with a removal action).
    • Add child opens a native <dialog> with SSH host candidates and manual entry. Test connection probes the host and shows its fingerprint, which must be ticked before Confirm host. Connect child then applies the link.
    • Failed probes and applies stay on screen with a Retry that repeats the failed step. Cancelling drops the failed state.
  • Remove. Removal asks for confirmation. If the child cannot be reached, a second dialog offers "Remove here only" ({force: true}) and tells the user to run ocx disconnect on the child.
  • Remote Workspace moves to #remote-workspace. When it is available, #remote shows a card linking to it so old bookmarks are one click away. When it is not, the route shows a fallback with a way back.
  • Error codes. Errors are mapped from the 24 codes link-routes.ts emits, and a test fails if the server adds a code the GUI does not know. Tunnel failure reasons are translated.
  • Accessibility. Role choice is a keyboard radiogroup, dialogs trap and restore focus, and status is never shown by color alone.
  • Localization. All 10 GUI locales are updated. The docs-site has a new Remote Link guide in English and all 7 translated locales, with sidebar entries and cross-links from the Remote Hub and Remote Workspace guides.
  • Screenshots. gui/scripts/remote-link-fixture.ts serves the built dashboard with fixed /api/link/* responses, so the screenshots below can be reproduced without SSH.

Stack: #5788 (L1) ← #5798 (L2) ← #5801 (L3) ← #5803 (L4) ← this PR (L5) ← child-initiated flow (L6). Base is codex/remote-link-4-api.

Screenshots

Off (switch and blurred preview), then role choice:

Remote Link off
역할 선택

Add child dialog, then host fingerprint confirmation:

자식 컴퓨터 추가
호스트 키 지문 확인

Home with a connected child (desktop and mobile):

Home connected
Home connected, mobile

All 15 captures (en/ko desktop, en mobile) are under pr-assets@df24377da4/260925-remote-link-home. They were retaken with the fixture serving a hub runtime; the earlier set was taken with a fake connected-client runtime.

Verification

  • cd gui && bun test tests: 2,358 pass, 0 fail. Covers the error-code parity test, every UX state, off and role choice issuing no mutation, the force path, failed-state retry for probe and apply, cancel after a failed apply, stale polling responses, focus restoration, the radiogroup keys, and workspace gating.
  • bun run lint, bun run lint:i18n, bun run build (existing chunk-size warning only): pass.
  • Root: bun run typecheck, bun run structure:check, bun run privacy:scan, tests/gui plus test-layout (457 pass).
  • cd docs-site && bun run build: 513 pages, internal links checked.
  • Screenshots come from the fixture server with headless Chrome at 1440×900 and 390×844.
  • The plan passed three rounds of independent audit. The implementation passed UX/code review (NEAR-PASS; the residual note is fixed with a red-green test in this head).
  • Follow-up (e604b7b): CI on ac92998 failed react-doctor (a #remote fragment with no matching id, an unused effect dependency, two unused test parameters) and the file-size ratchet (gui/src/styles.css grew one line from a duplicate @import). The notice now uses a link-btn button, the effect and tests drop the unused names, and RemoteLink.tsx remains the only importer of styles-remote-link.css. Local react-doctor@0.9.11 --scope changed: no issues. The ratchet test, the Remote Link, Remote Workspace, and locale-parity GUI tests, bun run lint, and bun run build pass.
  • Follow-up (a019d39): with the ratchet fixed, the same CI shard reached headless GUI parity CLI, which requires every GUI management endpoint to map to a CLI resource. /api/link now maps to ocx link in tests/cli/cli-headless-parity.test.ts (81 pass).
  • Follow-up (2b47b70): the page was gated on a connected-client target (targets.connected), so a Home or standalone dashboard, which has its own loopback session but no client connection, stayed on the sign-in notice. The fixture served a fake client runtime, which hid it. The page now needs only the shared session, the fixture serves a hub, and gui/tests/remote-link-route.test.tsx mounts the whole App at #remote for the standalone and hub roles (red before the fix, green after). cd gui && bun test tests: 2,360 pass; lint, React Doctor, and build pass.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed. (docs-site guide in 8 locales)
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults. The GUI uses dashboard-session routes only, shows no keys, and requires an explicit fingerprint confirmation before apply.

@coderabbitai

coderabbitai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: Repository: lidge-jun/opencodex/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: f692e9d9-a429-4827-bc96-23252618c826

📥 Commits

Reviewing files that changed from the base of the PR and between 2f641cc and 2b47b70.

📒 Files selected for processing (128)
  • devlog/_plan/260925_remote_home_child_link/000_prd.md
  • devlog/_plan/260925_remote_home_child_link/001_stack_plan.md
  • devlog/_plan/260925_remote_home_child_link/002_arch_plan.md
  • devlog/_plan/260925_remote_home_child_link/003_decisions.md
  • devlog/_plan/260925_remote_home_child_link/010_wp1_link_core.md
  • devlog/_plan/260925_remote_home_child_link/020_wp2_hub_link_listener.md
  • devlog/_plan/260925_remote_home_child_link/030_wp3_client_link_transport.md
  • devlog/_plan/260925_remote_home_child_link/040_wp4_supervisor_api_cli.md
  • devlog/_plan/260925_remote_home_child_link/050_wp5_remote_gui.md
  • devlog/_plan/260925_remote_home_child_link/060_wp6_client_initiated.md
  • docs-site/astro.config.mjs
  • docs-site/src/content/docs/fr/guides/remote-hub.md
  • docs-site/src/content/docs/fr/guides/remote-link.md
  • docs-site/src/content/docs/fr/guides/remote-workspace.md
  • docs-site/src/content/docs/guides/remote-hub.md
  • docs-site/src/content/docs/guides/remote-link.md
  • docs-site/src/content/docs/guides/remote-workspace.md
  • docs-site/src/content/docs/ja/guides/remote-hub.md
  • docs-site/src/content/docs/ja/guides/remote-link.md
  • docs-site/src/content/docs/ja/guides/remote-workspace.md
  • docs-site/src/content/docs/ko/guides/remote-hub.md
  • docs-site/src/content/docs/ko/guides/remote-link.md
  • docs-site/src/content/docs/ko/guides/remote-workspace.md
  • docs-site/src/content/docs/ru/guides/remote-hub.md
  • docs-site/src/content/docs/ru/guides/remote-link.md
  • docs-site/src/content/docs/ru/guides/remote-workspace.md
  • docs-site/src/content/docs/tr/guides/remote-hub.md
  • docs-site/src/content/docs/tr/guides/remote-link.md
  • docs-site/src/content/docs/tr/guides/remote-workspace.md
  • docs-site/src/content/docs/zh-cn/guides/remote-hub.md
  • docs-site/src/content/docs/zh-cn/guides/remote-link.md
  • docs-site/src/content/docs/zh-cn/guides/remote-workspace.md
  • docs-site/src/content/docs/zh-tw/guides/remote-hub.md
  • docs-site/src/content/docs/zh-tw/guides/remote-link.md
  • docs-site/src/content/docs/zh-tw/guides/remote-workspace.md
  • gui/scripts/remote-link-fixture.ts
  • gui/src/App.tsx
  • gui/src/app-routing.ts
  • gui/src/i18n/de.ts
  • gui/src/i18n/en.ts
  • gui/src/i18n/fr.ts
  • gui/src/i18n/ja.ts
  • gui/src/i18n/ko.ts
  • gui/src/i18n/ru.ts
  • gui/src/i18n/tr.ts
  • gui/src/i18n/vi.ts
  • gui/src/i18n/zh-TW.ts
  • gui/src/i18n/zh.ts
  • gui/src/pages/RemoteLink.tsx
  • gui/src/remote-link-api.ts
  • gui/src/styles-remote-link.css
  • gui/tests/locale-parity.test.ts
  • gui/tests/remote-link-route.test.tsx
  • gui/tests/remote-link.test.tsx
  • gui/tests/remote-workspace.test.tsx
  • gui/tests/sidebar-rows.test.ts
  • scripts/test-layout/layout.json
  • skills/ocx/references/01_management_surface.md
  • src/cli/capabilities.ts
  • src/cli/connect.ts
  • src/cli/dispatch.ts
  • src/cli/help.ts
  • src/cli/link.ts
  • src/cli/registry.ts
  • src/cli/runtime-api.ts
  • src/client/connect.ts
  • src/client/hub-relay.ts
  • src/client/link-relay.ts
  • src/client/machine-listener.ts
  • src/client/runtime.ts
  • src/client/state.ts
  • src/codex/inject/plan.ts
  • src/config/schema/leaf-validators.ts
  • src/link/admission-wait.ts
  • src/link/compensation.ts
  • src/link/fingerprint.ts
  • src/link/paths.ts
  • src/link/routes.ts
  • src/link/ssh-argv.ts
  • src/link/ssh-config.ts
  • src/link/ssh-runner.ts
  • src/link/status-projection.ts
  • src/link/store.ts
  • src/link/supervisor.ts
  • src/link/tunnel-state.ts
  • src/server/audio-client.ts
  • src/server/audio-upstream.ts
  • src/server/auth-cors.ts
  • src/server/hub-usage.ts
  • src/server/index.ts
  • src/server/index/link-listener.ts
  • src/server/index/optional-listeners.ts
  • src/server/index/serve-options.ts
  • src/server/management-api.ts
  • src/server/management-auth.ts
  • src/server/management/context.ts
  • src/server/management/link-routes.ts
  • src/server/management/oauth-account-routes.ts
  • src/server/management/route-registry.ts
  • src/types/config.ts
  • structure/INDEX.md
  • structure/gui-and-management-api.md
  • structure/manifest.json
  • structure/remote-link.md
  • structure/runtime.md
  • tests/cli/cli-headless-parity.test.ts
  • tests/cli/cli-link.test.ts
  • tests/clients/client-link-connect.test.ts
  • tests/clients/client-link-relay.test.ts
  • tests/clients/client-link-runtime.test.ts
  • tests/clients/link-admission-wait.test.ts
  • tests/clients/link-boundary.test.ts
  • tests/clients/link-compensation.test.ts
  • tests/clients/link-fingerprint.test.ts
  • tests/clients/link-routes.test.ts
  • tests/clients/link-ssh-argv.test.ts
  • tests/clients/link-ssh-config.test.ts
  • tests/clients/link-status-projection.test.ts
  • tests/clients/link-store.test.ts
  • tests/clients/link-supervisor.test.ts
  • tests/clients/link-tunnel-state.test.ts
  • tests/codex-integration/injection-link-websocket.test.ts
  • tests/fixtures/test-layout-expected.json
  • tests/lab/core-lab-boundary.test.ts
  • tests/lab/core-link-boundary.test.ts
  • tests/server/link-listener-admission.test.ts
  • tests/server/link-listener-lifecycle.test.ts
  • tests/server/link-management-routes.test.ts
 _______________________________________
< Your code's Big O notation: `O(WTF)`. >
 ---------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the intake: hygiene-blocked Deterministic PR hygiene checks failed label Sep 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Deterministic hygiene checks failed.

  • new_suppression — A new TypeScript, lint, formatter, or similar suppression was added. Fix the underlying issue or obtain suppression-approved. Paths: gui/src/pages/RemoteLink.tsx.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-25T02:20:20.435429Z 01e9f06 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions github-actions Bot added the enhancement New feature or request label Sep 25, 2026
@lidge-jun
lidge-jun requested a review from Ingwannu as a code owner September 25, 2026 02:16
@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

✅ READY

  • all PR quality gates passed.

Hygiene

✅ Deterministic PR hygiene checks passed.

@github-actions
github-actions Bot marked this pull request as draft September 25, 2026 02:16

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 01e9f06da6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


<dialog ref={sheetRef} className="remote-link-sheet" aria-labelledby="remote-link-sheet-title" onCancel={event => { event.preventDefault(); closeSheet(); }}>
<div className="remote-link-sheet-head"><h3 id="remote-link-sheet-title">{t("link.sheetTitle")}</h3><button type="button" className="btn btn-ghost btn-icon" onClick={closeSheet} aria-label={t("link.close")}><IconX /></button></div>
<div className="remote-link-sheet-body"><div><h4>{t("link.candidates")}</h4>{busy === "candidates" ? <p className="remote-link-info">{t("link.loading")}</p> : candidates.length > 0 ? <div className="remote-link-candidates">{candidates.map(candidate => <button type="button" className="remote-link-candidate" key={`${candidate.source}:${candidate.alias}`} onClick={() => setAlias(candidate.alias)}><span>{candidate.alias}</span><small>{candidate.source}</small></button>)}</div> : <p className="remote-link-info">{t("link.noCandidates")}</p>}</div><div className="remote-link-form"><label htmlFor="remote-link-alias">{t("link.alias")}</label><input id="remote-link-alias" value={alias} onChange={event => setAlias(event.target.value)} placeholder={t("link.aliasPlaceholder")} autoComplete="off" /><button type="button" className="btn btn-ghost" onClick={() => void runProbe()} disabled={!alias.trim() || busy !== null}><IconLink />{busy === "probe" ? t("link.probing") : t("link.probe")}</button></div>{probe && <div className="remote-link-panel"><div><span className="remote-link-info">{t("link.hostFingerprint")}</span><p className="remote-link-fingerprint"><code>{probe.fingerprint}</code></p><span className="remote-link-info">{probe.keyType}</span></div><label><input type="checkbox" checked={checkedFingerprint} onChange={event => setCheckedFingerprint(event.target.checked)} /> {t("link.confirmFingerprint")}</label><button type="button" className="btn btn-primary" onClick={() => void confirmHost()} disabled={!checkedFingerprint || busy !== null}>{busy === "confirm" ? t("link.confirming") : t("link.confirm")}</button></div>}{confirmation && <div className="remote-link-panel"><p className="remote-link-info">{t("link.ocxVersion", { version: confirmation.ocxVersion })}</p><button type="button" className="btn btn-primary" onClick={() => void applyLink()} disabled={busy !== null}>{busy === "apply" ? t("link.applying") : t("link.apply")}</button></div>}{actionError && <Notice tone="err"><span className="remote-link-error">{t(actionError)}</span></Notice>}<div className="remote-link-sheet-actions"><button type="button" className="btn btn-ghost" onClick={closeSheet}>{t("link.cancel")}</button></div></div>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reset host proof when changing the alias

After probing host A, selecting candidate B or editing the alias only calls setAlias; the existing probe, confirmation, and fingerprint checkbox remain bound to A. The form therefore appears to target B while Confirm host and Connect child still authenticate and apply A, potentially issuing a link key to the wrong machine. Clear all host-proof state whenever the alias changes, or prevent alias changes once probing begins.

AGENTS.md reference: AGENTS.md:L437-L443

Useful? React with 👍 / 👎.

Comment thread gui/src/App.tsx Outdated
{page === "usage" && <Usage apiBase={sharedBase} connected={targets.connected} apiKeyId={targets.apiKeyId} />}
{page === "storage" && <Storage apiBase={sharedBase} />}
{page === "remote" && <RemoteWorkspace apiBase={sharedBase} hubOrigin={targets.shared.serverOrigin} />}
{page === "remote" && <RemoteLink apiBase={sharedBase} sessionReady={targets.connected && sharedSessionReady} workspaceAvailable={remoteWorkspaceAvailable} onOpenWorkspace={() => navigateToPage("remote-workspace")} />}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Allow paired Home dashboards through the session gate

For normal standalone and hub/Home dashboards, targets.connected is false because it denotes only the connected-client runtime, so this expression passes sessionReady={false} even when sharedSessionReady contains a valid paired dashboard session. RemoteLink consequently renders only the sign-in warning and makes no /api/link/* requests, making the advertised Home workflow inaccessible on the machine that must create the link. Gate this on the actual shared session readiness rather than client topology.

AGENTS.md reference: gui/AGENTS.md:L9-L10

Useful? React with 👍 / 👎.

Comment on lines +173 to +177
} else if (value.links.length === 0) {
setUiState(current => ["role-select", "adding-child", "confirming-host", "applying"].includes(current) ? current : "off");
} else if (value.links.some(link => link.state === "failed")) setUiState("failed");
else if (value.links.some(link => link.state === "reconnecting")) setUiState("reconnecting");
else if (value.links.some(link => link.state === "connected")) setUiState("connected");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Surface listener failures in the page state

When a persisted link restarts but the link listener cannot bind or persist its port, /api/link/status reports listener.state === "failed" while the link rows may still be idle or even retain another non-failed state. This state machine inspects only value.links, so the page can show no failure banner—and may show a connected-looking row—even though the ingress cannot serve the Child. Include the listener state in the failure derivation and render an actionable listener error.

AGENTS.md reference: gui/AGENTS.md:L9-L10

Useful? React with 👍 / 👎.

@lidge-jun

Copy link
Copy Markdown
Owner Author

리뷰 · 우선순위 70 / 80

이 PR은 원격 링크의 다섯 번째 층이다. #remote 가 이 컴퓨터를 다른 컴퓨터에 SSH로 잇는 화면이 된다. 스위치는 꺼진 채로 시작하고, 켜면 집 또는 자식을 고른다. 자식은 아직 요청을 보내지 않는다. 집은 자식 목록을 보여주고, 추가할 때 접속을 시험한 뒤 지문을 체크해야 연결된다. 자식에 닿지 않으면 이 컴퓨터에서만 지울 수 있다. 예전 원격 작업 공간은 #remote-workspace 로 옮긴다. 베이스는 codex/remote-link-4-api 이다. #5788, #5798, #5801, #5803 위에 쌓여 있다. 같은 화면의 다른 열린 PR은 없다.

라인 - gui/src/App.tsx 551행 — 화면을 열 조건이 targets.connected && sharedSessionReady 이다. targets.connected 는 이 대시보드가 다른 집의 자식으로 붙어 있을 때만 참이다. 집 컴퓨터와 혼자 쓰는 설치는 거짓이다 (gui/src/api-targets.ts 의 isConnectedRuntime, standaloneApiTargets). 세션이 있어도 sessionReady 가 거짓이라, #remote 는 로그인 안내만 보여주고 /api/link/* 를 부르지 않는다. 링크를 만드는 쪽은 집인데, 그 화면이 집에서 열리지 않는다.

라인 - gui/src/pages/RemoteLink.tsx 295행 — 후보를 누르거나 별칭을 고치면 setAlias 만 한다. 이미 시험한 지문, 체크, 확인 결과는 그대로다. 입력칸은 새 컴퓨터를 가리키고, 확인과 연결은 아까 시험한 컴퓨터의 별칭과 지문으로 나간다 (confirmHost 233행, applyLink 240행). 다른 컴퓨터에 열쇠가 갈 수 있다.

라인 - gui/src/pages/RemoteLink.tsx 171행 — 상태를 고를 때 links 만 본다. listener.state 가 failed 여도 배너가 없다. 들어오는 문이 죽었는데 자식 줄은 연결된 것처럼 보일 수 있다.

라인 - gui/src/pages/RemoteLink.tsx 85행, 126행, 188행 — 새 lint 끄기가 들어갔다. hygiene 가 new_suppression 으로 실패했고, 이 PR은 draft 다.

메인테이너의 판단이 필요한 지점

집 화면의 세션 조건을 sharedSessionReady 만으로 둘지, 위쪽 할당량 막대처럼 !targets.connected || sharedSessionReady 로 둘지 정해 달라. 자식으로 붙은 대시보드에서만 이 페이지를 열 의도는 설명에 없다.

별칭이 바뀌면 지문을 지울지, 시험이 시작된 뒤에는 별칭을 잠글지 정해 달라. 지문 확인이 이 층의 안전장치다.

리스너 실패를 이 화면에서 보여줄지, 링크 줄의 실패만 보여줄지 정해 달라.

너의 추천

방향은 맞다. 스택에 두고, #5803 이 dev 에 들어간 뒤에 base 를 dev 로 바꿔라. 머지 전에는 집 컴퓨터에서 화면이 실제로 열리게 고치고, 별칭이 바뀌면 지문과 확인을 지워라. lint 끄기를 빼거나 승인을 받은 뒤에 draft 를 풀어라.

이 댓글은 grok-bot이 작성했습니다

@lidge-jun
lidge-jun force-pushed the codex/remote-link-5-gui branch from 01e9f06 to ac92998 Compare September 25, 2026 02:46
@github-actions github-actions Bot removed the intake: hygiene-blocked Deterministic PR hygiene checks failed label Sep 25, 2026
@github-actions
github-actions Bot marked this pull request as ready for review September 25, 2026 02:47

@Ingwannu Ingwannu left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed exact head a019d392d283a6d8a13bef32af78c9424aa54f9a. The lint/React Doctor cleanup is present, but three functional blockers from the current UI remain:

  1. gui/src/App.tsx:548 passes sessionReady={targets.connected && sharedSessionReady}. A normal Home/standalone dashboard has targets.connected === false, so even a valid paired session can never open the link workflow or call /api/link/*. Gate on the actual shared-session readiness, with any topology condition stated separately.
  2. gui/src/pages/RemoteLink.tsx:261 changes alias without clearing probe, confirmation, or checkedFingerprint. After probing host A, the visible field can point at host B while Confirm/Apply still use A's proof. Reset all proof state on every alias change, or lock the alias after probing.
  3. refreshStatus derives failure only from link rows. A persisted link can coexist with listener.state === "failed", leaving the page without an actionable error and potentially showing a connected-looking child while ingress is unavailable. Include listener failure in the page state and rendering.

Please add regressions for Home-session admission, alias changes after probe/confirmation, and failed-listener status. This PR also remains stacked on #5803, whose current head has separate lifecycle blockers.

@Ingwannu Ingwannu left a comment •

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed exact head 2b47b7054a960af3c74728f5d5713ffe045222a5. The new sharedSessionReady gate and Home/standalone route regression fix blocker 1 (focused GUI suites pass 17/17 under CPUQuota=200%, MemoryMax=4G, MemorySwapMax=0, TasksMax=128). Two blockers remain unchanged: (1) candidate clicks and alias input still call setAlias directly without clearing probe, confirmation, or checkedFingerprint, so displayed alias B can coexist with host proof and apply payload for A; (2) refreshStatus still derives UI failure only from link rows and ignores value.listener.state === "failed", so failed ingress can render a connected-looking link without an actionable listener error. Please reset or lock proof state on alias changes and surface listener failure, with regressions for both. This stacked PR also remains blocked by lower-layer #5803.

@lidge-jun
lidge-jun force-pushed the codex/remote-link-4-api branch from a0a5a24 to 1cefb16 Compare September 25, 2026 05:02
Base automatically changed from codex/remote-link-4-api to dev September 25, 2026 05:02
#remote now opens Remote Link: a switch that starts off over a blurred preview, a Home/Child choice (Child waits for the find-home flow), the child list with labelled status, and an add-child dialog that probes an SSH host, shows its fingerprint for confirmation and applies the link. Removing a link offers a local-only removal when the child cannot be reached. Remote Workspace moves to #remote-workspace with a card on #remote when it is available. All ten GUI locales and eight docs-site locales are updated, and a fixture server reproduces the screenshots.
… route

A failed probe or apply stays on screen and Retry repeats the failed step; polling aborts stale requests and never lets an older response win. #remote-workspace shows a fallback with a way back when Remote Workspace is unavailable. The role choice is a keyboard radiogroup, the disconnect dialog returns focus to its button, and tunnel failure reasons are translated.
Workspace visibility is derived from the session instead of reset in an effect, the status parser lives in remote-link-api.ts, status styling keys off data-state, and the first status read runs through an effect event.
The unavailable-workspace notice links to Remote Link with a link-btn button instead of a #remote fragment, the status-poll effect drops an unused dependency, the tests drop unused fetch parameters, and styles.css no longer re-imports the stylesheet RemoteLink.tsx already imports.
The page was gated on a connected-client target, so a Home or standalone dashboard, which has its own loopback session but no client connection, stayed on the sign-in notice. The page now needs only the shared session. The screenshot fixture served a fake client runtime, which hid this; it now serves a hub. An App-level test mounts both roles at #remote.
@lidge-jun
lidge-jun force-pushed the codex/remote-link-5-gui branch from 2b47b70 to 6fa1256 Compare September 25, 2026 05:03
@lidge-jun
lidge-jun merged commit 2858ac3 into dev Sep 25, 2026
5 checks passed
@lidge-jun
lidge-jun deleted the codex/remote-link-5-gui branch September 25, 2026 05:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants