Skip to content

Codex/feat wework local devices - #1268

Merged
qdaxb merged 1 commit into
wecode-ai:mainfrom
FicoHu:codex/feat-wework-local-devices
Jun 4, 2026
Merged

qdaxb merged 1 commit into
wecode-ai:mainfrom
FicoHu:codex/feat-wework-local-devices

Conversation

@FicoHu

@FicoHu FicoHu commented Jun 4, 2026 •

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Add client-side option to delete local devices (including offline registrations).
    • New device API to remove non-cloud devices.
  • Bug Fixes

    • Attempts to start Terminal/IDE sessions on local-bound devices are blocked with a clear error.
  • Documentation

    • EN/ZH guides clarify cloud vs local device capabilities and toolbar behavior.
  • Improvements

    • Navigation syncs with URL/routes; updated translations and theme-aware device UI styling.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

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: 7c577f93-bd0f-4940-8398-1b42310809a4

📥 Commits

Reviewing files that changed from the base of the PR and between 5e3a7fb and cdb2830.

📒 Files selected for processing (27)
  • backend/app/services/project_device_session_service.py
  • backend/tests/services/test_project_device_session_service.py
  • docs/en/user-guide/ai-devices/local-device-support.md
  • docs/zh/user-guide/ai-devices/local-device-support.md
  • wework/src/App.plugins.test.tsx
  • wework/src/api/devices.test.ts
  • wework/src/api/devices.ts
  • wework/src/components/common/ActionMenu.tsx
  • wework/src/components/layout/DesktopSidebar.tsx
  • wework/src/components/layout/DesktopWorkbenchLayout.test.tsx
  • wework/src/components/layout/DesktopWorkbenchLayout.tsx
  • wework/src/components/layout/DesktopWorkbenchMain.tsx
  • wework/src/components/layout/MobileWorkbenchLayout.tsx
  • wework/src/components/layout/workspace-panels/BottomWorkspacePanel.tsx
  • wework/src/components/layout/workspace-panels/RightWorkspacePanel.tsx
  • wework/src/components/layout/workspace-panels/WorkspacePanelCards.test.tsx
  • wework/src/components/layout/workspace-panels/WorkspacePanelCards.tsx
  • wework/src/components/projects/ProjectCreateDialog.tsx
  • wework/src/components/settings/AddCloudDeviceDialog.tsx
  • wework/src/components/settings/ConnectionsSettingsPage.test.tsx
  • wework/src/components/settings/ConnectionsSettingsPage.tsx
  • wework/src/features/workbench/WorkbenchProvider.test.tsx
  • wework/src/features/workbench/WorkbenchProvider.tsx
  • wework/src/i18n/locales/en/common.json
  • wework/src/i18n/locales/zh-CN/common.json
  • wework/src/lib/device-capabilities.ts
  • wework/src/lib/navigation.ts
✅ Files skipped from review due to trivial changes (4)
  • wework/src/components/common/ActionMenu.tsx
  • wework/src/lib/navigation.ts
  • wework/src/components/settings/AddCloudDeviceDialog.tsx
  • docs/zh/user-guide/ai-devices/local-device-support.md
🚧 Files skipped from review as they are similar to previous changes (19)
  • wework/src/api/devices.test.ts
  • wework/src/api/devices.ts
  • wework/src/components/layout/workspace-panels/BottomWorkspacePanel.tsx
  • wework/src/lib/device-capabilities.ts
  • wework/src/i18n/locales/zh-CN/common.json
  • wework/src/components/layout/workspace-panels/RightWorkspacePanel.tsx
  • wework/src/components/layout/workspace-panels/WorkspacePanelCards.tsx
  • wework/src/features/workbench/WorkbenchProvider.test.tsx
  • docs/en/user-guide/ai-devices/local-device-support.md
  • wework/src/i18n/locales/en/common.json
  • wework/src/components/layout/DesktopWorkbenchLayout.tsx
  • wework/src/components/projects/ProjectCreateDialog.tsx
  • backend/app/services/project_device_session_service.py
  • wework/src/components/layout/MobileWorkbenchLayout.tsx
  • wework/src/components/layout/DesktopSidebar.tsx
  • wework/src/features/workbench/WorkbenchProvider.tsx
  • wework/src/App.plugins.test.tsx
  • wework/src/components/settings/ConnectionsSettingsPage.test.tsx
  • wework/src/components/settings/ConnectionsSettingsPage.tsx

📝 Walkthrough

Walkthrough

Backend validates and rejects terminal/code-server project sessions on local devices. Frontend adds device-capability predicates, threads device lists into workspace panels, hides cloud-only tools for local-device projects, and makes settings/tasks state URL-driven. Connections settings UI, tests, docs, and i18n are updated.

Changes

Local Device Capability Gating and Path-Based Routing

Layer / File(s) Summary
All changes (single checkpoint)
backend/..., wework/..., docs/..., wework/src/lib/*, wework/src/components/*, backend/tests/*, wework/src/i18n/*
Covers backend session validation for local devices, new frontend device-capability and navigation utilities, workspace panel device wiring and cloud-tool gating, connections settings cloud/local separation and capability gating, route-driven settings and task restoration, updated tests, theming/styling updates, and docs/i18n entries.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • wecode-ai/Wegent#1174: Connections settings page foundation and device-actions rendering work related to this PR.
  • wecode-ai/Wegent#1204: Navigation/path utilities and toBrowserPath/app-base-path normalization related to route changes.

Suggested reviewers

  • qdaxb

Poem

🐰 I hop through code and route the way,

Cloud sessions glow at break of day,
Local devices keep some tools away,
Settings follow the browser's sway,
Docs whisper what the UI will say.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Codex/feat wework local devices' is directly related to the main changes in the PR, which implements local device support throughout the codebase including backend validation, frontend UI changes, and documentation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (2)
wework/src/components/layout/workspace-panels/WorkspacePanelCards.test.tsx (1)

228-237: ⚡ Quick win

Add a regression case for missing device_type.

Please add one test where the matched device omits device_type and assert cloud tool cards remain visible. This will lock in the intended “explicit local only” behavior.

🤖 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 `@wework/src/components/layout/workspace-panels/WorkspacePanelCards.test.tsx`
around lines 228 - 237, Add a new test in WorkspacePanelCards.test.tsx that
mirrors the existing "does not show cloud-only project tools for local devices"
case but uses a device object that intentionally omits the device_type field
(e.g., clone localDevices[0] without device_type) and render WorkspacePanelCards
with that devices array; then assert that cloud tool cards
(queryByTestId('workspace-terminal-card'), 'workspace-ide-card',
'workspace-desktop-card') are present (or not null/getByTestId) and that the
local-only message ('workspace-local-device-limited-tools') is not shown,
ensuring the component treats missing device_type as non-local.
wework/src/components/settings/ConnectionsSettingsPage.tsx (1)

1-1020: 🏗️ Heavy lift

Split this file into sub-modules to meet the repo size limit.

This file now exceeds 1000 lines, which increases coupling and review/test overhead for future changes. Please extract sections like settings-nav routing helpers, device card/actions, and archived chats into separate modules.

As per coding guidelines: **/*.{py,ts,tsx,js,jsx}: File size limit: If a file exceeds 1000 lines, split it into multiple sub-modules.

🤖 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 `@wework/src/components/settings/ConnectionsSettingsPage.tsx` around lines 1 -
1020, The file is too large—split it into focused sub-modules: 1) extract the
nav helpers (getSettingsNavFromPath, getSettingsNavPath, settingsNavItems) into
a settingsNav module and export them; 2) move all device-related components
(DeviceCard, DeviceSection, DeviceMetrics, VncDesktopButton, DeviceActionButton,
DeviceIconActionButton, StatusPill, createSettingsDeviceApi,
formatMetricPercent, ConfirmDeviceActionDialog and helper functions like
formatMetricPercent) into a devices module that exports the components and
createSettingsDeviceApi; 3) move ConnectionsDeviceSettingsPage into its own
ConnectionsDeviceSettingsPage module that imports the devices module components
and createSettingsDeviceApi; 4) move ArchivedChatsSettingsPage into an
archivedChats module; then update ConnectionsSettingsPage to import these
modules (and AddCloudDeviceDialog/AppearanceSettingsPage remain where they are)
so the top-level file only composes the sidebar and routing; ensure all moved
functions/components keep their original names and exported/imported types to
preserve usage (e.g., onChanged, onListArchivedTasks, DeviceInfo types).
🤖 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.

Inline comments:
In `@backend/app/services/project_device_session_service.py`:
- Around line 145-150: The guard currently only rejects device_type ==
DeviceType.LOCAL.value and lets missing/unknown values through; change it to
fail-closed by explicitly allowing only the cloud value: read device_type =
spec.get("deviceType") and if device_type != DeviceType.CLOUD.value then raise
the HTTPException (same status and detail or update detail to indicate only
cloud devices are supported). Update the check near the current device_type
handling in project_device_session_service.py so unknown/missing values are
rejected instead of permitted.
- Around line 132-150: Wrap the _ensure_device_supports_project_sessions
function with the OpenTelemetry sync tracer decorator (use `@trace_sync`) and
inside the function set span attributes for device_id and the resolved
deviceType (use set_span_attribute) and emit a span event when rejecting with
the reason (e.g., "Local devices do not support terminal or code-server
sessions") using add_span_event; also record an event or attribute when device
lookup returns no result. Ensure you import the tracing helpers and call
set_span_attribute/add_span_event at the appropriate points in
_ensure_device_supports_project_sessions so telemetry captures device_id,
resolved deviceType, and rejection reason.

In `@wework/src/components/layout/workspace-panels/WorkspacePanelCards.tsx`:
- Around line 115-119: The code treats any device with an undefined device_type
as local by negating supportsCloudSessions; change hasExplicitLocalDevice to
explicitly check the device_type (e.g. const hasExplicitLocalDevice =
Boolean(projectDevice && projectDevice.device_type === 'local')) so only devices
that explicitly mark device_type === 'local' gate off cloud tools, keep
cloudToolsAvailable = !hasExplicitLocalDevice, and if your codebase uses an
enum/constant for device types, compare against that instead of the string
literal.

In `@wework/src/features/workbench/WorkbenchProvider.tsx`:
- Around line 895-897: The current effect sets handledTaskRouteRef.current =
routeKey then calls openTask(taskRoute.taskId, taskRoute.projectId) without
handling rejections, which can leave the guard set and prevent retries; modify
the effect to await/openTask with a .catch or try/catch around the async call,
and on error clear handledTaskRouteRef.current (or only set
handledTaskRouteRef.current after openTask succeeds) so failures un-block future
attempts; use the existing handledTaskRouteRef, openTask, and
taskRoute.taskId/taskRoute.projectId identifiers when applying the fix.
- Around line 856-860: The current flow awaits
resolvedServices.chatStream.joinTask(taskId) which can block navigateTo and
leave the URL stale if joinTask fails; instead, kick off joinTask without
awaiting so route sync is immediate: call
resolvedServices.chatStream.joinTask(taskId) as a fire-and-forget (or attach
.catch(...) to log errors) after computing handledTaskRouteRef.current =
getTaskRouteKey(taskId, routeProjectId) and before/after
navigateTo(buildTaskRoute({ taskId, projectId: routeProjectId })), ensuring
navigateTo is not gated on joinTask success and errors from joinTask are logged
but do not prevent navigation.

In `@wework/src/lib/navigation.ts`:
- Around line 30-41: The parseTaskRoute function currently accepts IDs of "0";
update its regexes to only match positive integers by replacing (\d+) with
([1-9]\d*) in both /^\/projects\/(\d+)\/tasks\/(\d+)$/ and /^\/tasks\/(\d+)$/ so
paths like /tasks/0 or /projects/0/tasks/1 will no longer match and will return
null; adjust any dependent numeric conversion (projectId, taskId) as needed but
keep the existing Number(...) usage after the stricter match.

---

Nitpick comments:
In `@wework/src/components/layout/workspace-panels/WorkspacePanelCards.test.tsx`:
- Around line 228-237: Add a new test in WorkspacePanelCards.test.tsx that
mirrors the existing "does not show cloud-only project tools for local devices"
case but uses a device object that intentionally omits the device_type field
(e.g., clone localDevices[0] without device_type) and render WorkspacePanelCards
with that devices array; then assert that cloud tool cards
(queryByTestId('workspace-terminal-card'), 'workspace-ide-card',
'workspace-desktop-card') are present (or not null/getByTestId) and that the
local-only message ('workspace-local-device-limited-tools') is not shown,
ensuring the component treats missing device_type as non-local.

In `@wework/src/components/settings/ConnectionsSettingsPage.tsx`:
- Around line 1-1020: The file is too large—split it into focused sub-modules:
1) extract the nav helpers (getSettingsNavFromPath, getSettingsNavPath,
settingsNavItems) into a settingsNav module and export them; 2) move all
device-related components (DeviceCard, DeviceSection, DeviceMetrics,
VncDesktopButton, DeviceActionButton, DeviceIconActionButton, StatusPill,
createSettingsDeviceApi, formatMetricPercent, ConfirmDeviceActionDialog and
helper functions like formatMetricPercent) into a devices module that exports
the components and createSettingsDeviceApi; 3) move
ConnectionsDeviceSettingsPage into its own ConnectionsDeviceSettingsPage module
that imports the devices module components and createSettingsDeviceApi; 4) move
ArchivedChatsSettingsPage into an archivedChats module; then update
ConnectionsSettingsPage to import these modules (and
AddCloudDeviceDialog/AppearanceSettingsPage remain where they are) so the
top-level file only composes the sidebar and routing; ensure all moved
functions/components keep their original names and exported/imported types to
preserve usage (e.g., onChanged, onListArchivedTasks, DeviceInfo types).
🪄 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: 25b3a43f-a465-4105-b7ba-239e17af9347

📥 Commits

Reviewing files that changed from the base of the PR and between 6e5edb6 and ccce44e.

📒 Files selected for processing (26)
  • backend/app/services/project_device_session_service.py
  • backend/tests/services/test_project_device_session_service.py
  • docs/en/user-guide/ai-devices/local-device-support.md
  • docs/zh/user-guide/ai-devices/local-device-support.md
  • shared/models/__init__.py
  • shared/models/search_hints.py
  • shared/tests/test_search_hints.py
  • wework/src/api/devices.test.ts
  • wework/src/api/devices.ts
  • wework/src/components/layout/DesktopWorkbenchLayout.test.tsx
  • wework/src/components/layout/DesktopWorkbenchLayout.tsx
  • wework/src/components/layout/DesktopWorkbenchMain.tsx
  • wework/src/components/layout/MobileWorkbenchLayout.tsx
  • wework/src/components/layout/workspace-panels/BottomWorkspacePanel.tsx
  • wework/src/components/layout/workspace-panels/RightWorkspacePanel.tsx
  • wework/src/components/layout/workspace-panels/WorkspacePanelCards.test.tsx
  • wework/src/components/layout/workspace-panels/WorkspacePanelCards.tsx
  • wework/src/components/projects/ProjectCreateDialog.tsx
  • wework/src/components/settings/ConnectionsSettingsPage.test.tsx
  • wework/src/components/settings/ConnectionsSettingsPage.tsx
  • wework/src/features/workbench/WorkbenchProvider.test.tsx
  • wework/src/features/workbench/WorkbenchProvider.tsx
  • wework/src/i18n/locales/en/common.json
  • wework/src/i18n/locales/zh-CN/common.json
  • wework/src/lib/device-capabilities.ts
  • wework/src/lib/navigation.ts

Comment on lines +132 to +150
def _ensure_device_supports_project_sessions(
db: Session,
user_id: int,
device_id: str,
) -> None:
"""Reject project terminal and code-server sessions for local devices."""

device_kind = device_service.get_device_by_device_id(db, user_id, device_id)
if not device_kind:
return

spec = getattr(device_kind, "json", None)
spec = spec.get("spec", {}) if isinstance(spec, dict) else {}
device_type = spec.get("deviceType")
if device_type == DeviceType.LOCAL.value:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Local devices do not support terminal or code-server sessions",
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add tracing on the new session-capability guard.

This new decision point should be instrumented with @trace_sync and span attributes/events (e.g., device_id, resolved deviceType, rejection reason) for production diagnostics and policy auditing. As per coding guidelines, "Use OpenTelemetry tracing decorators: @trace_async or @trace_sync for entire functions, and add_span_event() or set_span_attribute() for adding details to spans".

🤖 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 `@backend/app/services/project_device_session_service.py` around lines 132 -
150, Wrap the _ensure_device_supports_project_sessions function with the
OpenTelemetry sync tracer decorator (use `@trace_sync`) and inside the function
set span attributes for device_id and the resolved deviceType (use
set_span_attribute) and emit a span event when rejecting with the reason (e.g.,
"Local devices do not support terminal or code-server sessions") using
add_span_event; also record an event or attribute when device lookup returns no
result. Ensure you import the tracing helpers and call
set_span_attribute/add_span_event at the appropriate points in
_ensure_device_supports_project_sessions so telemetry captures device_id,
resolved deviceType, and rejection reason.

Comment on lines +145 to +150
device_type = spec.get("deviceType")
if device_type == DeviceType.LOCAL.value:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Local devices do not support terminal or code-server sessions",
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fail closed on deviceType to prevent capability-gate bypass.

This guard currently rejects only deviceType == "local". Missing/unknown values pass through and can still start project sessions. For a cloud-only tool gate, only explicit cloud should be allowed.

🔧 Proposed fix
-    device_type = spec.get("deviceType")
-    if device_type == DeviceType.LOCAL.value:
+    device_type = spec.get("deviceType")
+    if device_type != DeviceType.CLOUD.value:
         raise HTTPException(
             status_code=status.HTTP_400_BAD_REQUEST,
-            detail="Local devices do not support terminal or code-server sessions",
+            detail="Only cloud devices support terminal or code-server sessions",
         )
🤖 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 `@backend/app/services/project_device_session_service.py` around lines 145 -
150, The guard currently only rejects device_type == DeviceType.LOCAL.value and
lets missing/unknown values through; change it to fail-closed by explicitly
allowing only the cloud value: read device_type = spec.get("deviceType") and if
device_type != DeviceType.CLOUD.value then raise the HTTPException (same status
and detail or update detail to indicate only cloud devices are supported).
Update the check near the current device_type handling in
project_device_session_service.py so unknown/missing values are rejected instead
of permitted.

Comment on lines +115 to +119
const projectDevice = projectDeviceId
? devices.find(device => device.device_id === projectDeviceId)
: undefined
const hasExplicitLocalDevice = Boolean(projectDevice && !supportsCloudSessions(projectDevice))
const cloudToolsAvailable = !hasExplicitLocalDevice

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use an explicit local check for local-device gating.

Line 118 currently classifies any non-cloud (including missing device_type) as local. Because DeviceInfo.device_type is optional, this can incorrectly hide Terminal/IDE/Desktop for devices with undefined type.

Suggested fix
-import { supportsCloudSessions } from '`@/lib/device-capabilities`'
@@
-  const hasExplicitLocalDevice = Boolean(projectDevice && !supportsCloudSessions(projectDevice))
+  const hasExplicitLocalDevice = projectDevice?.device_type === 'local'
   const cloudToolsAvailable = !hasExplicitLocalDevice
🤖 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 `@wework/src/components/layout/workspace-panels/WorkspacePanelCards.tsx` around
lines 115 - 119, The code treats any device with an undefined device_type as
local by negating supportsCloudSessions; change hasExplicitLocalDevice to
explicitly check the device_type (e.g. const hasExplicitLocalDevice =
Boolean(projectDevice && projectDevice.device_type === 'local')) so only devices
that explicitly mark device_type === 'local' gate off cloud tools, keep
cloudToolsAvailable = !hasExplicitLocalDevice, and if your codebase uses an
enum/constant for device types, compare against that instead of the string
literal.

Comment thread wework/src/features/workbench/WorkbenchProvider.tsx
Comment on lines +895 to +897
handledTaskRouteRef.current = routeKey
void openTask(taskRoute.taskId, taskRoute.projectId)
}, [

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle route-open failures and clear the route guard on error.

This effect sets handledTaskRouteRef before calling openTask, but it never catches failures. A rejected openTask can leave the guard set and block retries for the same route.

Suggested fix
     handledTaskRouteRef.current = routeKey
-    void openTask(taskRoute.taskId, taskRoute.projectId)
+    void openTask(taskRoute.taskId, taskRoute.projectId).catch(error => {
+      if (handledTaskRouteRef.current === routeKey) {
+        handledTaskRouteRef.current = null
+      }
+      dispatch({
+        type: 'error_set',
+        error: error instanceof Error ? error.message : '会话加载失败',
+      })
+    })
🤖 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 `@wework/src/features/workbench/WorkbenchProvider.tsx` around lines 895 - 897,
The current effect sets handledTaskRouteRef.current = routeKey then calls
openTask(taskRoute.taskId, taskRoute.projectId) without handling rejections,
which can leave the guard set and prevent retries; modify the effect to
await/openTask with a .catch or try/catch around the async call, and on error
clear handledTaskRouteRef.current (or only set handledTaskRouteRef.current after
openTask succeeds) so failures un-block future attempts; use the existing
handledTaskRouteRef, openTask, and taskRoute.taskId/taskRoute.projectId
identifiers when applying the fix.

Comment on lines +30 to +41
export function parseTaskRoute(path: string): TaskRoute | null {
const projectTaskMatch = path.match(/^\/projects\/(\d+)\/tasks\/(\d+)$/)
if (projectTaskMatch) {
return {
projectId: Number(projectTaskMatch[1]),
taskId: Number(projectTaskMatch[2]),
}
}

const taskMatch = path.match(/^\/tasks\/(\d+)$/)
if (taskMatch) {
return { taskId: Number(taskMatch[1]) }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject non-positive IDs in task-route parsing.

The current regex allows 0, so paths like /tasks/0 or /projects/0/tasks/1 are parsed as valid and can trigger invalid task loads.

Suggested fix
 export function parseTaskRoute(path: string): TaskRoute | null {
-  const projectTaskMatch = path.match(/^\/projects\/(\d+)\/tasks\/(\d+)$/)
+  const projectTaskMatch = path.match(/^\/projects\/([1-9]\d*)\/tasks\/([1-9]\d*)$/)
   if (projectTaskMatch) {
     return {
       projectId: Number(projectTaskMatch[1]),
       taskId: Number(projectTaskMatch[2]),
     }
   }

-  const taskMatch = path.match(/^\/tasks\/(\d+)$/)
+  const taskMatch = path.match(/^\/tasks\/([1-9]\d*)$/)
   if (taskMatch) {
     return { taskId: Number(taskMatch[1]) }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function parseTaskRoute(path: string): TaskRoute | null {
const projectTaskMatch = path.match(/^\/projects\/(\d+)\/tasks\/(\d+)$/)
if (projectTaskMatch) {
return {
projectId: Number(projectTaskMatch[1]),
taskId: Number(projectTaskMatch[2]),
}
}
const taskMatch = path.match(/^\/tasks\/(\d+)$/)
if (taskMatch) {
return { taskId: Number(taskMatch[1]) }
export function parseTaskRoute(path: string): TaskRoute | null {
const projectTaskMatch = path.match(/^\/projects\/([1-9]\d*)\/tasks\/([1-9]\d*)$/)
if (projectTaskMatch) {
return {
projectId: Number(projectTaskMatch[1]),
taskId: Number(projectTaskMatch[2]),
}
}
const taskMatch = path.match(/^\/tasks\/([1-9]\d*)$/)
if (taskMatch) {
return { taskId: Number(taskMatch[1]) }
🤖 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 `@wework/src/lib/navigation.ts` around lines 30 - 41, The parseTaskRoute
function currently accepts IDs of "0"; update its regexes to only match positive
integers by replacing (\d+) with ([1-9]\d*) in both
/^\/projects\/(\d+)\/tasks\/(\d+)$/ and /^\/tasks\/(\d+)$/ so paths like
/tasks/0 or /projects/0/tasks/1 will no longer match and will return null;
adjust any dependent numeric conversion (projectId, taskId) as needed but keep
the existing Number(...) usage after the stricter match.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
wework/src/components/layout/DesktopWorkbenchLayout.test.tsx (1)

1-1774: ⚖️ Poor tradeoff

Consider splitting this test file to improve maintainability.

The file exceeds the 1000-line guideline (currently 1774 lines). While comprehensive test coverage is valuable, splitting by feature area would improve maintainability. Consider organizing into separate test files such as:

  • Sidebar interactions (projects, chats, search, settings)
  • Workspace panels (right/bottom panels, resize, close)
  • Environment info (popover, commits, branches)
  • Project creation and management

As per coding guidelines: "File size limit: If a file exceeds 1000 lines, split it into multiple sub-modules"

🤖 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 `@wework/src/components/layout/DesktopWorkbenchLayout.test.tsx` around lines 1
- 1774, The test file DesktopWorkbenchLayout.test.tsx is too large (>1000
lines); split it into multiple focused test files to improve maintainability.
Create separate test modules (for example:
DesktopWorkbenchLayout.sidebar.test.tsx for sidebar interactions referencing
tests that use data-testid like 'projects-section-toggle', 'search-button',
'settings-button'; DesktopWorkbenchLayout.workspace.test.tsx for right/bottom
panel/resizing tests referencing 'toggle-right-workspace-panel-button',
'right-workspace-resize-handle', 'toggle-bottom-workspace-panel-button';
DesktopWorkbenchLayout.environment.test.tsx for environment
popover/commits/branches referencing 'environment-info-button',
'environment-commit-button', 'environment-branch-row';
DesktopWorkbenchLayout.project.test.tsx for project creation/management
referencing 'projects-create-button', 'project-create-dialog',
'create-project-button'). Move related describe/test blocks into these files,
keep shared setup (createRect, mocks, baseProps) in a new test-utils or a shared
setup file and import it into each split file, and update imports to
DesktopWorkbenchLayout and mocked factories so tests still run unchanged.
🤖 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.

Nitpick comments:
In `@wework/src/components/layout/DesktopWorkbenchLayout.test.tsx`:
- Around line 1-1774: The test file DesktopWorkbenchLayout.test.tsx is too large
(>1000 lines); split it into multiple focused test files to improve
maintainability. Create separate test modules (for example:
DesktopWorkbenchLayout.sidebar.test.tsx for sidebar interactions referencing
tests that use data-testid like 'projects-section-toggle', 'search-button',
'settings-button'; DesktopWorkbenchLayout.workspace.test.tsx for right/bottom
panel/resizing tests referencing 'toggle-right-workspace-panel-button',
'right-workspace-resize-handle', 'toggle-bottom-workspace-panel-button';
DesktopWorkbenchLayout.environment.test.tsx for environment
popover/commits/branches referencing 'environment-info-button',
'environment-commit-button', 'environment-branch-row';
DesktopWorkbenchLayout.project.test.tsx for project creation/management
referencing 'projects-create-button', 'project-create-dialog',
'create-project-button'). Move related describe/test blocks into these files,
keep shared setup (createRect, mocks, baseProps) in a new test-utils or a shared
setup file and import it into each split file, and update imports to
DesktopWorkbenchLayout and mocked factories so tests still run unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c9e4ce1b-13b4-4aaf-b7fa-8dee2ee90082

📥 Commits

Reviewing files that changed from the base of the PR and between 86361e1 and 2232ded.

📒 Files selected for processing (5)
  • wework/src/components/layout/DesktopSidebar.tsx
  • wework/src/components/layout/DesktopWorkbenchLayout.test.tsx
  • wework/src/components/settings/AddCloudDeviceDialog.tsx
  • wework/src/components/settings/ConnectionsSettingsPage.test.tsx
  • wework/src/components/settings/ConnectionsSettingsPage.tsx
💤 Files with no reviewable changes (1)
  • wework/src/components/layout/DesktopSidebar.tsx
✅ Files skipped from review due to trivial changes (1)
  • wework/src/components/settings/AddCloudDeviceDialog.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • wework/src/components/settings/ConnectionsSettingsPage.test.tsx
  • wework/src/components/settings/ConnectionsSettingsPage.tsx

@FicoHu
FicoHu force-pushed the codex/feat-wework-local-devices branch from fc49a97 to cdb2830 Compare June 4, 2026 12:08
@qdaxb
qdaxb merged commit 4eb60a6 into wecode-ai:main Jun 4, 2026
22 checks passed
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