Skip to content

fix(web,paths,server): WSL2-aware Open in IDE link#1504

Open
blankse wants to merge 2 commits into
coleam00:devfrom
blankse:fix/1502-wsl-vscode-uri
Open

fix(web,paths,server): WSL2-aware Open in IDE link#1504
blankse wants to merge 2 commits into
coleam00:devfrom
blankse:fix/1502-wsl-vscode-uri

Conversation

@blankse
Copy link
Copy Markdown
Contributor

@blankse blankse commented Apr 30, 2026

Summary

  • Problem: The Open in IDE buttons emit vscode://file/<path> directly. When Archon runs inside WSL2 and the user is browsing from a Windows host, that URI hands a Linux path to Windows VS Code, which can't resolve it. The IDE launches with an empty / "file not found" window.
  • Why it matters: Every Windows + WSL2 dev who clicks Open in IDE today gets a broken link. The button is silently useless for that very common setup.
  • What changed: Detect WSL on the server, expose it via /api/health, and have the Web UI build the WSL-flavoured vscode://vscode-remote/wsl+<distro>/<path> URI when the server reports it. Plain vscode://file/... is preserved for every other environment.
  • What did not change: No new dependencies, no new endpoints, no schema migration. The button is hidden the same way for Docker servers (existing is_docker plumbing).

UX Journey

Before

Windows browser            Web UI                Archon (in WSL2)            Windows VS Code
───────────────            ──────                ────────────────            ───────────────
clicks "Open in IDE" ──▶   builds            ──▶ /api/health
                           vscode://file//home/.../foo
                           opens scheme   ──────────────────────────────▶  receives raw Linux path
                                                                            tries to open on Windows fs
                                                                            "file not found" [X]

After

Windows browser            Web UI                Archon (in WSL2)            Windows VS Code
───────────────            ──────                ────────────────            ───────────────
clicks "Open in IDE" ──▶   reads health        ──▶ /api/health
                           {is_wsl: true,
                            wsl_distro: "Ubuntu"}
                           builds
                           vscode://vscode-remote/wsl+Ubuntu/home/.../foo
                           opens scheme   ──────────────────────────────▶  WSL remote opens path [+]
                                                                            workspace loads correctly

Architecture Diagram

Before

@archon/paths ── isDocker ──▶ @archon/server (/api/health) ──▶ @archon/web (HealthResponse)
                                                                      │
                                                                      ├─▶ Header.tsx:    vscode://file/<path>
                                                                      └─▶ WorkflowRunCard.tsx: vscode://file/<path>

After

@archon/paths ── isDocker ──┐
              ─ isWSL [+]   ┼─▶ @archon/server (/api/health) [~] ──▶ @archon/web (HealthResponse) [~]
              ─ getWSLDistroName [+]                                          │
                                                                              ├─▶ ideUri() helper [+]
                                                                              ├─▶ Header.tsx [~]
                                                                              └─▶ WorkflowRunCard.tsx [~]

Connection inventory:

From To Status Notes
@archon/paths exports isWSL, getWSLDistroName new analogous to existing isDocker
/api/health response is_wsl, wsl_distro new fields additive; existing schema unchanged
@archon/web/lib/ide-uri.ts (new module) new small URI helper with full unit tests
Header.tsx, WorkflowRunCard.tsx, WorkflowRunGroup.tsx, ChatInterface.tsx, DashboardPage.tsx ideUri() modified inline vscode://file/... → helper call

Label Snapshot

  • Risk: risk: low
  • Size: size: M
  • Scope: web (primary), paths, server
  • Module: web:dashboard, web:layout, paths:archon-paths, server:routes/api

Change Metadata

  • Change type: bug
  • Primary scope: multi

Linked Issue

Validation Evidence

bun --filter @archon/paths test
# 174 pass, 0 fail (4 new tests for isWSL / getWSLDistroName)

bun --filter @archon/web test
# pass; 21 tests across 2 files including new ide-uri.test.ts (10 cases)

bun --filter @archon/server test packages/server/src/routes/api.health.test.ts
# 24 pass, 0 fail (no regressions)

bun run type-check
# all 10 packages: Exited with code 0

NODE_OPTIONS=--max-old-space-size=8192 bun x eslint <changed files>
# clean

ide-uri.test.ts covers each branch: default URI form, WSL2 form with various distro inputs, missing-distro fallback to default URI, Windows-style backslash normalisation, and URL-encoding of distro names containing special characters.

Security Impact

  • New permissions/capabilities? No — server reads process.env.WSL_DISTRO_NAME (already in env) and /proc/sys/kernel/osrelease (read-only, no privilege required).
  • New external network calls? No
  • Secrets/tokens handling changed? No
  • File system access scope changed? No — single read of /proc/sys/kernel/osrelease per /api/health request (~30 s polling cadence in the UI).

Compatibility / Migration

  • Backward compatible? Yesis_wsl defaults to false outside WSL, wsl_distro is optional. Existing is_docker-based UI behaviour is unchanged.
  • Config/env changes? No
  • Database migration needed? No

Human Verification

  • Verified scenarios:
    • On a WSL2 Ubuntu host with the Web UI opened from a Windows browser, the Open in IDE button now produces vscode://vscode-remote/wsl+Ubuntu/.... VS Code opens the workspace correctly via the WSL remote.
    • On the same machine with WSL_DISTRO_NAME unset (simulating a non-WSL run), the link falls back to vscode://file/... — the existing behaviour.
  • Edge cases checked:
    • Backslash normalisation still applied in both branches.
    • Distro names with special characters get encodeURIComponent'd (covered by tests).
  • What was not verified:
    • Headless ~/.vscode-server/... path: detection path uses env-var first, so any in-distro VS Code Server session is also covered, but I haven't manually clicked the button from VS Code's built-in browser.
    • api.generated.d.ts was not regenerated (the manually-maintained HealthResponse interface in web/src/lib/api.ts is what the components consume); a follow-up bun --filter @archon/web generate:types against a live dev server can refresh the OpenAPI-derived types.

Side Effects / Blast Radius

  • Affected subsystems: Web UI Open-in-IDE button (Header + WorkflowRunCard) and the /api/health response shape. is_docker consumers (the same components) are unchanged.
  • Potential unintended effects: clients that depended on the exact /api/health response shape via strict equality would now see two extra fields. The schema already declares version and activePlatforms as optional, so any well-formed client should be tolerant — but worth flagging.
  • Guardrails: server tests assert all the existing fields; the new fields are additive.

Rollback Plan

  • Fast rollback: git revert <this commit> — single commit, clean revert. No data migrations.
  • Feature flags or config toggles: none introduced; behaviour is determined entirely by the runtime environment.
  • Observable failure symptoms: Open in IDE button reverts to its pre-fix behaviour (broken link in WSL2 + Windows-browser setups; works elsewhere).

Risks and Mitigations

  • Risk: /proc/sys/kernel/osrelease read might fail on some exotic environments (containers without /proc, frozen rootfs).
    • Mitigation: the read is wrapped in try/catch and falls back to false on any error. The env-var path (WSL_DISTRO_NAME) is checked first and short-circuits without touching /proc in the common case.
  • Risk: A WSL distro name containing characters that aren't safe in URLs.
    • Mitigation: encodeURIComponent is applied around wsl_distro in ideUri(), with a test case that covers spaces.

Summary by CodeRabbit

  • New Features

    • Server health now reports whether it’s running under WSL and (when available) the active distro.
    • Added WSL-aware IDE URI generation and updated “Open in IDE” links across the UI to use it.
  • Tests

    • Added tests for WSL detection and for IDE URI generation covering non-WSL and WSL scenarios.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 346f9691-ebda-4d0f-9002-45d4ce4bbfec

📥 Commits

Reviewing files that changed from the base of the PR and between a80f30c and 6370488.

📒 Files selected for processing (1)
  • packages/paths/src/archon-paths.test.ts

📝 Walkthrough

Walkthrough

Adds WSL detection helpers to @archon/paths, surfaces is_wsl/wsl_distro in /api/health, introduces ideUri() to build WSL-aware vscode:// URIs, and threads WSL context into web UI components and tests.

Changes

WSL Integration

Layer / File(s) Summary
Paths detection & tests
packages/paths/src/archon-paths.ts, packages/paths/src/archon-paths.test.ts, packages/paths/src/index.ts
Adds isWSL() (env + /proc probe), getWSLDistroName(), exports them, and updates tests to snapshot WSL_DISTRO_NAME.
Server health reporting
packages/server/src/routes/api.ts
Imports WSL helpers and adds is_wsl: boolean and optional wsl_distro: string to /api/health schema and payload.
IDE URI helper & tests
packages/web/src/lib/ide-uri.ts, packages/web/src/lib/ide-uri.test.ts
Adds ideUri(path, env?) producing vscode://file/... or vscode://vscode-remote/wsl+<encoded_distro>/... with normalization and encoding tests.
Web UI wiring and types
packages/web/src/lib/api.ts, packages/web/src/components/layout/Header.tsx, packages/web/src/components/dashboard/WorkflowRunCard.tsx, packages/web/src/components/dashboard/WorkflowRunGroup.tsx, packages/web/src/components/chat/ChatInterface.tsx, packages/web/src/routes/DashboardPage.tsx
Extends HealthResponse, threads isWsl/wslDistro into Header and workflow cards, and replaces inline vscode:// URL construction with ideUri().

Sequence Diagram

sequenceDiagram
  participant Browser as Browser (Windows)
  participant ArchonServer as Archon Server (WSL2)
  participant WebClient as Web Client
  participant VSCode as VS Code

  Browser->>ArchonServer: GET /api/health
  ArchonServer->>ArchonServer: isWSL(), getWSLDistroName()
  ArchonServer-->>Browser: { is_wsl: true, wsl_distro: "Ubuntu" }

  Browser->>WebClient: receive health
  WebClient->>WebClient: ideUri(path, { is_wsl, wsl_distro })
  WebClient->>VSCode: window.open(vscode://vscode-remote/wsl+Ubuntu/<path>)
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I checked the paths both near and far,
From /proc to env — I found the star.
Links now hop through WSL with glee,
VS Code opens home, as it should be. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately and concisely summarizes the main change—adding WSL2-aware URI generation for the Open in IDE link.
Description check ✅ Passed The PR description comprehensively covers the problem, motivation, architecture changes, testing, and security considerations, closely following the template structure.
Linked Issues check ✅ Passed All objectives from issue #1502 are met: WSL detection added to @archon/paths with tests, /api/health now exposes is_wsl and wsl_distro, ideUri() helper created with full test coverage, and all affected components updated.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #1502 requirements. No unrelated refactors, dependency upgrades, or scope creep detected across the five affected packages.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/web/src/lib/ide-uri.ts (1)

21-21: ⚡ Quick win

Extract env to a named interface instead of inline object typing.

Please define a dedicated interface (e.g., IdeUriEnv) and use it in the function signature for consistency with the TypeScript guidelines.

Proposed change
+interface IdeUriEnv {
+  is_wsl?: boolean;
+  wsl_distro?: string;
+}
+
-export function ideUri(path: string, env?: { is_wsl?: boolean; wsl_distro?: string }): string {
+export function ideUri(path: string, env?: IdeUriEnv): string {

As per coding guidelines: "Use interface for defining object shapes in TypeScript".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/web/src/lib/ide-uri.ts` at line 21, The inline env object type in
the ideUri function should be extracted to a named interface: create and export
an interface (e.g., IdeUriEnv) with properties is_wsl?: boolean and wsl_distro?:
string, replace the inline typing in the ideUri(path: string, env?: { ... })
signature with env?: IdeUriEnv, and update any imports/usage accordingly to keep
types consistent across the module and follow TypeScript interface conventions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/paths/src/archon-paths.test.ts`:
- Around line 95-101: The test title says "returns false when WSL_DISTRO_NAME is
unset and not on a WSL kernel" but only asserts a boolean; update the test to be
deterministic by mocking the kernel-check branch and then assert false (or
change the title to match the current assertion). Specifically, in the test that
references isWSL(), unset process.env.WSL_DISTRO_NAME, stub/mock the
kernel-release check used by isWSL() so it returns a non-WSL value (e.g.,
contains no "microsoft"), then assert expect(isWSL()).toBe(false);
alternatively, if you prefer not to mock, rename the test to reflect that it
only verifies a boolean return.

---

Nitpick comments:
In `@packages/web/src/lib/ide-uri.ts`:
- Line 21: The inline env object type in the ideUri function should be extracted
to a named interface: create and export an interface (e.g., IdeUriEnv) with
properties is_wsl?: boolean and wsl_distro?: string, replace the inline typing
in the ideUri(path: string, env?: { ... }) signature with env?: IdeUriEnv, and
update any imports/usage accordingly to keep types consistent across the module
and follow TypeScript interface conventions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c86ebc30-1858-405e-a025-c72816fb8ed0

📥 Commits

Reviewing files that changed from the base of the PR and between 2945f2e and 824e2f4.

📒 Files selected for processing (12)
  • packages/paths/src/archon-paths.test.ts
  • packages/paths/src/archon-paths.ts
  • packages/paths/src/index.ts
  • packages/server/src/routes/api.ts
  • packages/web/src/components/chat/ChatInterface.tsx
  • packages/web/src/components/dashboard/WorkflowRunCard.tsx
  • packages/web/src/components/dashboard/WorkflowRunGroup.tsx
  • packages/web/src/components/layout/Header.tsx
  • packages/web/src/lib/api.ts
  • packages/web/src/lib/ide-uri.test.ts
  • packages/web/src/lib/ide-uri.ts
  • packages/web/src/routes/DashboardPage.tsx

Comment thread packages/paths/src/archon-paths.test.ts Outdated
@Wirasm
Copy link
Copy Markdown
Collaborator

Wirasm commented May 4, 2026

@blankse related to #1502 — WSL2 vscode:// URI fix.

)

The Open-in-IDE buttons emit a `vscode://file/<path>` URI. When Archon
runs inside WSL2 and the browser is on the Windows host, that URI hands
a Linux path to Windows VS Code, which can't resolve it — the IDE
launches with an empty / "file not found" window.

The correct form for that case is:

  vscode://vscode-remote/wsl+<distro>/<path>

This change wires the detection from the server through to the link
construction so each setup gets the right URI:

paths
  - isWSL(): two-signal detection (WSL_DISTRO_NAME env var, then
    /proc/sys/kernel/osrelease containing "microsoft").
  - getWSLDistroName(): exposes WSL_DISTRO_NAME for the URI.
  - Both exported from @archon/paths and tested.

server
  - GET /api/health gains `is_wsl` (always present) and `wsl_distro`
    (only when known). Schema updated accordingly.

web
  - HealthResponse type in src/lib/api.ts mirrors the server fields.
  - New helper src/lib/ide-uri.ts builds the right URI based on
    {is_wsl, wsl_distro}, with tests for each branch (default,
    WSL2 path, broken inputs, distro-name encoding).
  - Header, WorkflowRunCard, WorkflowRunGroup, ChatInterface and
    DashboardPage now plumb the two new health fields the same way
    they already plumb is_docker, and call ideUri() instead of
    inlining a vscode://file/... template literal.

Tests: paths and web tests pass; the existing api.health tests still
pass (the new fields don't break the response-schema assertions —
HealthResponse fields are optional except is_docker / is_wsl).

Note: api.generated.d.ts not regenerated here because the manual
HealthResponse interface in src/lib/api.ts is what the components
consume; running `bun --filter @archon/web generate:types` against
a live dev server will refresh the generated types in a follow-up.
@blankse blankse force-pushed the fix/1502-wsl-vscode-uri branch from 8a9c3b3 to a80f30c Compare May 21, 2026 12:19
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/web/src/lib/api.ts (1)

427-456: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Out-of-scope changes: saveWorkflow and deleteWorkflow modifications.

The additions of the optional source?: WorkflowSource parameter and the conditional query-string logic for source === 'global' are not mentioned in the PR objectives (issue #1502) or the current layer description ("thread props into UI components"). No components in this layer use the new source parameter, and the PR focuses exclusively on WSL detection and IDE URI generation.

These changes should either be removed or split into a separate PR with clear justification and usage examples.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web/src/lib/api.ts` around lines 427 - 456, The additions of the
optional source?: WorkflowSource parameter and the source === 'global' query
logic are out-of-scope; revert saveWorkflow and deleteWorkflow to their original
signatures and behavior by removing the source parameter and any conditional
query-string code in both functions (restore building params only from cwd), and
update any touched call sites/tests accordingly; alternatively, if you intend to
keep this feature, extract the source changes into a separate PR with a clear
description, usage examples, and updates to any callers that need the new source
argument (reference functions saveWorkflow and deleteWorkflow).
♻️ Duplicate comments (1)
packages/server/src/routes/api.ts (1)

445-457: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Same path issue in delete workflow handler.

The delete handler has the same potential nested path bug as the save handler (see comment on lines 384-386, 406-410). When targetSource !== 'global' and no project context exists, workingDir falls back to getArchonHome(), producing join(getArchonHome(), getWorkflowFolderSearchPaths()[0], ...), which may create a nested .archon/.archon/workflows path.

Apply the same fix here: default to global scope or handle the no-project-context case explicitly.

Also applies to: 459-462

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/server/src/routes/api.ts` around lines 445 - 457, The delete
workflow handler constructs workingDir using targetSource, getArchonHome() and
getWorkflowFolderSearchPaths(), which can produce a nested
.archon/.archon/workflows when targetSource !== 'global' and project context is
missing; fix it in the delete workflow handler by using the same approach as the
save handler: if no project context exists default the scope to 'global' (or
explicitly branch to build workingDir from getArchonHome() alone) instead of
joining getArchonHome() with getWorkflowFolderSearchPaths()[0]; update the code
that computes workingDir (and the analogous code around lines 459-462) to check
for project context before using getWorkflowFolderSearchPaths() so paths aren’t
nested.
🧹 Nitpick comments (2)
packages/web/src/routes/DashboardPage.tsx (1)

378-379: 💤 Low value

Consider defaulting isWsl for consistency.

ChatInterface.tsx explicitly defaults isWsl to false when health is unavailable:

const isWsl = health?.is_wsl ?? false;

Here, you pass health?.is_wsl directly, which may be undefined until the health query resolves. Both approaches work (the props and ideUri should handle undefined), but applying the same defensive default across all call sites would improve consistency and make the fallback behavior explicit.

Suggested change for consistency
+  const isWsl = health?.is_wsl ?? false;
+  const wslDistro = health?.wsl_distro;
+
   // Split into active and history (from server-filtered results)
   ...
                        <WorkflowRunCard
                          key={run.id}
                          run={run}
                          isDocker={health?.is_docker}
-                         isWsl={health?.is_wsl}
-                         wslDistro={health?.wsl_distro}
+                         isWsl={isWsl}
+                         wslDistro={wslDistro}

(Apply similarly at lines 397–398.)

Also applies to: 397-398

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web/src/routes/DashboardPage.tsx` around lines 378 - 379, The
DashboardPage is passing health?.is_wsl directly to the ChatInterface, which can
be undefined until the health query resolves; make this consistent with
ChatInterface.tsx by defaulting the prop when calling the component (use
health?.is_wsl ?? false for the isWsl prop) and apply the same defensive default
at the other call site noted (the second occurrence around where wslDistro/isWsl
are passed). Update the prop expression(s) for isWsl while leaving wslDistro
as-is, so both call sites explicitly pass a boolean fallback for isWsl to match
ChatInterface's expected behavior.
packages/server/src/routes/api.ts (1)

2760-2761: ⚡ Quick win

Eliminate duplicate call to getWSLDistroName().

Line 2761 calls getWSLDistroName() twice—once in the condition and once in the value. Store the result in a variable to follow DRY and avoid redundant filesystem/env reads.

♻️ Refactor to eliminate duplicate call
   const stats = lockManager.getStats();
   const runningWorkflowRows = await workflowDb.getRunningWorkflows();
+  const wslDistro = getWSLDistroName();

   // Merge lock-based and DB-based active tracking.
   ...
   return c.json({
     status: 'ok',
     ...
     is_docker: isDocker(),
     is_wsl: isWSL(),
-    ...(getWSLDistroName() ? { wsl_distro: getWSLDistroName() } : {}),
+    ...(wslDistro ? { wsl_distro: wslDistro } : {}),
     activePlatforms: activePlatforms ? [...activePlatforms] : ['Web'],
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/server/src/routes/api.ts` around lines 2760 - 2761, The code calls
getWSLDistroName() twice when building the object (condition and value); cache
the result in a local variable (e.g., const wslDistro = getWSLDistroName())
before the object literal and then use isWSL() for is_wsl and wsl_distro:
wslDistro only when wslDistro is truthy so you remove the duplicate call and
preserve the same conditional behavior around getWSLDistroName().
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/web/src/lib/api.ts`:
- Around line 427-456: The additions of the optional source?: WorkflowSource
parameter and the source === 'global' query logic are out-of-scope; revert
saveWorkflow and deleteWorkflow to their original signatures and behavior by
removing the source parameter and any conditional query-string code in both
functions (restore building params only from cwd), and update any touched call
sites/tests accordingly; alternatively, if you intend to keep this feature,
extract the source changes into a separate PR with a clear description, usage
examples, and updates to any callers that need the new source argument
(reference functions saveWorkflow and deleteWorkflow).

---

Duplicate comments:
In `@packages/server/src/routes/api.ts`:
- Around line 445-457: The delete workflow handler constructs workingDir using
targetSource, getArchonHome() and getWorkflowFolderSearchPaths(), which can
produce a nested .archon/.archon/workflows when targetSource !== 'global' and
project context is missing; fix it in the delete workflow handler by using the
same approach as the save handler: if no project context exists default the
scope to 'global' (or explicitly branch to build workingDir from getArchonHome()
alone) instead of joining getArchonHome() with
getWorkflowFolderSearchPaths()[0]; update the code that computes workingDir (and
the analogous code around lines 459-462) to check for project context before
using getWorkflowFolderSearchPaths() so paths aren’t nested.

---

Nitpick comments:
In `@packages/server/src/routes/api.ts`:
- Around line 2760-2761: The code calls getWSLDistroName() twice when building
the object (condition and value); cache the result in a local variable (e.g.,
const wslDistro = getWSLDistroName()) before the object literal and then use
isWSL() for is_wsl and wsl_distro: wslDistro only when wslDistro is truthy so
you remove the duplicate call and preserve the same conditional behavior around
getWSLDistroName().

In `@packages/web/src/routes/DashboardPage.tsx`:
- Around line 378-379: The DashboardPage is passing health?.is_wsl directly to
the ChatInterface, which can be undefined until the health query resolves; make
this consistent with ChatInterface.tsx by defaulting the prop when calling the
component (use health?.is_wsl ?? false for the isWsl prop) and apply the same
defensive default at the other call site noted (the second occurrence around
where wslDistro/isWsl are passed). Update the prop expression(s) for isWsl while
leaving wslDistro as-is, so both call sites explicitly pass a boolean fallback
for isWsl to match ChatInterface's expected behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bf295104-dff2-4228-be5e-4abf665dc0b3

📥 Commits

Reviewing files that changed from the base of the PR and between 8a9c3b3 and a80f30c.

📒 Files selected for processing (12)
  • packages/paths/src/archon-paths.test.ts
  • packages/paths/src/archon-paths.ts
  • packages/paths/src/index.ts
  • packages/server/src/routes/api.ts
  • packages/web/src/components/chat/ChatInterface.tsx
  • packages/web/src/components/dashboard/WorkflowRunCard.tsx
  • packages/web/src/components/dashboard/WorkflowRunGroup.tsx
  • packages/web/src/components/layout/Header.tsx
  • packages/web/src/lib/api.ts
  • packages/web/src/lib/ide-uri.test.ts
  • packages/web/src/lib/ide-uri.ts
  • packages/web/src/routes/DashboardPage.tsx
✅ Files skipped from review due to trivial changes (2)
  • packages/web/src/lib/ide-uri.ts
  • packages/web/src/lib/ide-uri.test.ts

The fallback test asserted only `typeof isWSL() === 'boolean'`, which
trivially passes regardless of the actual /proc detection result.
Address CodeRabbit feedback by deriving the expected value from the
same source the implementation reads (/proc/sys/kernel/osrelease), so
the assertion is pinned to real behavior on both Linux CI and WSL2
hosts. Bun's mock.module() is process-global and irreversible per
repo policy, so reading the source file directly is the cleanest
deterministic option.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@Wirasm
Copy link
Copy Markdown
Collaborator

Wirasm commented May 25, 2026

Review Summary

Verdict: minor-fixes-needed

Your WSL detection feature is clean and well-scoped. Tests cover happy paths, error paths, and edge cases thoroughly. The ideUri() extraction from Header.tsx and WorkflowRunCard.tsx is exactly the kind of abstraction CLAUDE.md's Rule of Three encourages. A few small changes remain before merge.

Suggested fixes

  • packages/paths/src/archon-paths.ts:62: Add return type to isWSL():
    export function isWSL(): boolean {
  • packages/paths/src/archon-paths.ts:88: Add return type to getWSLDistroName():
    export function getWSLDistroName(): string | undefined {
  • packages/web/src/lib/ide-uri.ts:26: Add return type to ideUri():
    export function ideUri(path: string, isWsl: boolean, wslDistro?: string): string {

Minor / nice-to-have

  • packages/paths/src/archon-paths.ts — catch block at line 69: Add an inline comment explaining why false is the correct safe fallback when /proc/sys/kernel/osrelease cannot be read. The fallback itself is correct; the missing context is what CLAUDE.md's "Fail Fast + Explicit Errors" rule flags.

  • .env.example: Document WSL_DISTRO_NAME so users know they can override WSL distro detection:

    # WSL_DISTRO_NAME=Ubuntu  # override WSL distro detection

Compliments

  • Excellent test coverage — ideUri() has 8 test cases covering happy paths, regression guard for missing distro name, backslash normalization, and URL-encoding of special characters.
  • The multi-paragraph JSDoc on isWSL() explains the two-signal detection strategy, the no-caching decision with call-frequency context, and the specific caller need. Exactly the kind of non-obvious WHY that prevents future misuse.
  • getWSLDistroName() correctly documents the asymmetric result when isWSL() is true via /proc fallback — undefined is the right sentinel when the env var is absent, and you've captured exactly why.

Reviewed via maintainer-review-pr workflow (Pi/Minimax). Aspects run: code-review, error-handling, test-coverage, comment-quality.

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.

Open in IDE: vscode:// link broken when Archon runs in WSL2 and the browser is on Windows

2 participants