Skip to content

feat: 普通“新建任务”(侧边栏的独立会话)现在只会选择本地设备,不会再从云设备/本地设备里挑。 - #2550

Merged
qdaxb merged 3 commits into
wecode-ai:mainfrom
Micro66:human/yak-20260810-053932
Aug 11, 2026
Merged

qdaxb merged 3 commits into
wecode-ai:mainfrom
Micro66:human/yak-20260810-053932

Conversation

@Micro66

@Micro66 Micro66 commented Aug 10, 2026 •

Copy link
Copy Markdown
Collaborator

背景

普通“新建任务”(侧边栏的独立会话)是本地编码会话,应当固定跑在本机设备上。此前设备选择会在云设备 / 本地设备之间挑选,甚至可能回退到记忆中的云设备,导致任务被分配到云设备上执行。

改动

  • wework/src/lib/device-selection.ts:抽出 isLocalStandaloneDevice(排除 cloud / remote),isWeWorkSelectableStandaloneDevice 只接受本地独立设备;sortStandaloneDevices 排序改为本地设备优先,不再把云设备排在前面;有可用本地设备时不再回退到历史云设备。
  • wework/src/components/chat/composer/project-work-bar-utils.ts:复用 device-selection 里的 isLocalStandaloneDevice,删除重复实现。
  • wework/src/features/workbench/useWorkbenchDataRefresh.ts:设备/runtime-work 刷新时,若存在已打开的 standalone workspace,保留其设备(例如云端工作区),不再被本地优先规则改写成本地设备。
  • wework/src/components/layout/DesktopSidebar.tsx:standalone 项目行不再与已存在的同路径工作区重复渲染;同路径的本地项目与(别名后的)云端项目只显示一行。
  • 新增/更新单测:覆盖“本地设备优先”“不回落云设备”“仅有云/远程设备时返回 null”“本地设备低于 WeWork executor 版本时不选”“打开云端工作区后刷新仍保留云设备”“同路径已存在其他设备工作区时不渲染 standalone 行”等场景。

影响

用户从侧边栏新建独立会话时,任务只会选择本地设备,行为与“本地编码”语义一致;已打开的云端/远程工作区不受影响,也不会出现重复项目行。

验证

  • 相关单测:device-selection、WorkbenchProvider、DesktopSidebar 共 253 个用例全部通过
  • Prettier / ESLint 检查通过
  • 对照实验:不含本改动(main + 注释)的 Cloud E2E 两次通过,含本改动的 Cloud E2E 暴露重复项目行回归;修复后 CI 重新验证中
  • 真实 Tauri 桌面验证(ai:verify)尚未在本会话执行,合入前可补跑

Summary by CodeRabbit

  • Improvements
    • Improved device selection to prioritize compatible local devices.
    • Local standalone devices are now identified consistently across the app.
    • Cloud workspaces are handled more reliably when no local device is available.
    • Device selection now better accounts for online status and compatibility.
    • Preserved the selected workspace and path during refreshes.
    • Prevented duplicate project entries when the same workspace path is already represented.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR centralizes local-device detection, restricts standalone selection to compatible local devices, preserves cloud standalone workspace state during refreshes, and deduplicates workspace paths across devices.

Changes

Standalone device flow

Layer / File(s) Summary
Local standalone device selection
wework/src/lib/device-selection.ts, wework/src/lib/device-selection.test.ts, wework/src/components/chat/composer/project-work-bar-utils.ts
The selector identifies and prioritizes local devices. Tests cover local, cloud, remote, remembered, and incompatible-device cases. The composer utility re-exports the shared helper.
Cloud standalone workspace refresh preservation
wework/src/features/workbench/useWorkbenchDataRefresh.ts, wework/src/features/workbench/WorkbenchProvider.test.tsx
Refresh operations preserve the selected cloud device when a standalone workspace path is active. Tests cover cloud workspace refreshes and local-device setup.
Cross-device workspace deduplication
wework/src/components/layout/DesktopSidebar.tsx, wework/src/components/layout/DesktopSidebar.test.tsx, wework/src/features/workbench/WorkbenchProvider.test.tsx
Runtime project deduplication compares normalized workspace paths across devices. Tests verify that duplicate local and cloud records produce one retained project row.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant WorkbenchProvider
  participant useWorkbenchDataRefresh
  participant DeviceSelection
  participant DesktopSidebar
  WorkbenchProvider->>useWorkbenchDataRefresh: refresh standalone workspace
  useWorkbenchDataRefresh->>DeviceSelection: resolve device using workspace path
  DeviceSelection-->>useWorkbenchDataRefresh: preserve active device
  useWorkbenchDataRefresh-->>WorkbenchProvider: return refreshed workspace records
  WorkbenchProvider->>DesktopSidebar: render runtime projects
  DesktopSidebar-->>WorkbenchProvider: suppress duplicate path entries
Loading

Possibly related PRs

  • wecode-ai/Wegent#2212: Shares device and workspace selection changes and refresh reconciliation coverage.
  • wecode-ai/Wegent#2516: Modifies cloud workspace refresh behavior in the same refresh hook and provider tests.
  • wecode-ai/Wegent#1906: Shares runtime-project identity and workspace deduplication changes in DesktopSidebar.

Suggested reviewers: qdaxb

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了主要变更:侧边栏普通新建任务的独立会话仅选择本地设备。
✨ 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.

@Micro66
Micro66 marked this pull request as ready for review August 10, 2026 12:08

@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: 2

🤖 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 `@wework/src/lib/device-selection.test.ts`:
- Around line 46-53: Update the tests around getPreferredStandaloneDeviceId to
stop claiming both fixtures are selectable, renaming them to describe local
selection and remembered-cloud replacement. Add direct assertions for
sortStandaloneDevices that map device_id values and verify local-device precedes
cloud-device, ensuring the locality comparator’s ordering is tested
independently.

In `@wework/src/lib/device-selection.ts`:
- Around line 24-25: Update isLocalStandaloneDevice to return true only when
device.device_type is the recognized local type, rather than treating every
non-cloud/non-remote value as local. Add tests covering missing, null, and
unknown device types, and verify the re-exported helper isLocalStandaloneDevice
behavior remains local-only.
🪄 Autofix

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 Plus

Run ID: 5a6a0c14-2721-4063-aedd-92f2156e17c9

📥 Commits

Reviewing files that changed from the base of the PR and between 87598bb and badbb94.

📒 Files selected for processing (4)
  • wework/src/components/chat/composer/project-work-bar-utils.ts
  • wework/src/features/workbench/WorkbenchProvider.test.tsx
  • wework/src/lib/device-selection.test.ts
  • wework/src/lib/device-selection.ts

Comment on lines +46 to +53
test('prefers the local device when cloud and local devices are both selectable', () => {
const devices = [
selectableDevice({ device_id: 'cloud-device', name: 'Cloud Device', device_type: 'cloud' }),
selectableDevice({ device_id: 'local-device', name: 'Local Device', device_type: 'local' }),
]

expect(getPreferredStandaloneDeviceId(devices)).toBe('local-device')
})

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make these tests exercise the sorting contract.

The cloud-device fixture has device_type: 'cloud', so isWeWorkSelectableStandaloneDevice rejects it before getPreferredStandaloneDeviceId compares ordering. These assertions pass even if the new sortStandaloneDevices locality comparator is removed or reversed. The first test title also says that both devices are selectable, which is false.

Add a direct sortStandaloneDevices order assertion. Rename the current tests to describe local selection and remembered-cloud replacement.

Suggested assertion
expect(sortStandaloneDevices(devices).map(device => device.device_id)).toEqual([
  'local-device',
  'cloud-device',
])

Also applies to: 55-62

🤖 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/device-selection.test.ts` around lines 46 - 53, Update the
tests around getPreferredStandaloneDeviceId to stop claiming both fixtures are
selectable, renaming them to describe local selection and remembered-cloud
replacement. Add direct assertions for sortStandaloneDevices that map device_id
values and verify local-device precedes cloud-device, ensuring the locality
comparator’s ordering is tested independently.

Comment on lines +24 to +25
export function isLocalStandaloneDevice(device: Pick<SelectableDevice, 'device_type'>): boolean {
return device.device_type !== 'cloud' && device.device_type !== 'remote'

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject unknown device types as local.

SelectableDevice.device_type is optional. This condition returns true for undefined, null, and every unrecognized value. isWeWorkSelectableStandaloneDevice can then select a device that is not known to be local, which breaks the local-only contract.

Return device.device_type === 'local', or use an explicit allow-list if the device schema defines additional local types. Add tests for missing and unknown device types. The shared helper re-exported by project-work-bar-utils.ts inherits this behavior.

Proposed fix
 export function isLocalStandaloneDevice(device: Pick<SelectableDevice, 'device_type'>): boolean {
-  return device.device_type !== 'cloud' && device.device_type !== 'remote'
+  return device.device_type === 'local'
 }
📝 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 isLocalStandaloneDevice(device: Pick<SelectableDevice, 'device_type'>): boolean {
return device.device_type !== 'cloud' && device.device_type !== 'remote'
export function isLocalStandaloneDevice(device: Pick<SelectableDevice, 'device_type'>): boolean {
return device.device_type === 'local'
}
🤖 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/device-selection.ts` around lines 24 - 25, Update
isLocalStandaloneDevice to return true only when device.device_type is the
recognized local type, rather than treating every non-cloud/non-remote value as
local. Add tests covering missing, null, and unknown device types, and verify
the re-exported helper isLocalStandaloneDevice behavior remains local-only.

@Micro66

Micro66 commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

Re-triggering CI on the same commit because the Wework Desktop E2E (Cloud) job failed with what looks like a timing-sensitive duplicate-project-row assertion (the branch change does not touch project creation/removal paths).

@Micro66

Micro66 commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

Re-triggering CI on the same commit after adding the standalone-device refresh fix; the Cloud E2E progressed past the earlier duplicate-row assertion and hit a later dedup assertion in a run where other desktop E2E scenarios also failed.

@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.

Caution

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

⚠️ Outside diff range comments (1)
wework/src/components/layout/DesktopSidebar.tsx (1)

360-372: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Deduplicate workspace paths by runtime identity, not by string only.

runtimeWorkHasWorkspace treats equal paths on independent executors as the same workspace, and the test covers two different deviceId values without alias context. Use an identity key such as ${remoteHostId ?? deviceId}\0${normalizedPath}, or pass device aliases through standaloneDeviceId/standaloneWorkspacePath, so the one-row expectation covers the same alias and two rows are possible for different hosts.

🤖 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/DesktopSidebar.tsx` around lines 360 - 372,
Update runtimeWorkHasWorkspace in
wework/src/components/layout/DesktopSidebar.tsx to match workspaces by runtime
identity plus normalized path, using remoteHostId when available and otherwise
deviceId, rather than the path alone. Update the corresponding expectations and
fixtures in wework/src/components/layout/DesktopSidebar.test.tsx lines 4530-4565
so identical paths under the same alias remain one row while different hosts can
produce two rows.
🧹 Nitpick comments (1)
wework/src/features/workbench/WorkbenchProvider.test.tsx (1)

6213-6215: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Assert the retained runtime project identity.

These assertions allow the refresh to retain the cloud project with zero tasks. Assert that runtime-task-titles contains Local task, or expose and assert the retained workspace device ID.

Proposed test assertion
 expect(screen.getByTestId('runtime-project-count')).toHaveTextContent('1')
+expect(screen.getByTestId('runtime-task-titles')).toHaveTextContent('Local task')
 expect(screen.getByTestId('standalone-device-id')).toHaveTextContent('device-local')
🤖 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.test.tsx` around lines 6213 -
6215, Strengthen the duplicate-workspace refresh test by asserting that the
retained runtime project is the local copy: verify runtime-task-titles contains
“Local task,” or expose and assert the retained workspace device ID. Keep the
existing project-count assertion and ensure the assertion distinguishes the
local project from the cloud project with zero tasks.
🤖 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 `@wework/src/components/layout/DesktopSidebar.tsx`:
- Around line 360-372: Update runtimeWorkHasWorkspace in
wework/src/components/layout/DesktopSidebar.tsx to match workspaces by runtime
identity plus normalized path, using remoteHostId when available and otherwise
deviceId, rather than the path alone. Update the corresponding expectations and
fixtures in wework/src/components/layout/DesktopSidebar.test.tsx lines 4530-4565
so identical paths under the same alias remain one row while different hosts can
produce two rows.

---

Nitpick comments:
In `@wework/src/features/workbench/WorkbenchProvider.test.tsx`:
- Around line 6213-6215: Strengthen the duplicate-workspace refresh test by
asserting that the retained runtime project is the local copy: verify
runtime-task-titles contains “Local task,” or expose and assert the retained
workspace device ID. Keep the existing project-count assertion and ensure the
assertion distinguishes the local project from the cloud project with zero
tasks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b44843cd-b96c-4a9c-932a-90b4f4c5cf80

📥 Commits

Reviewing files that changed from the base of the PR and between 3bb40fe and 8b42dee.

📒 Files selected for processing (3)
  • wework/src/components/layout/DesktopSidebar.test.tsx
  • wework/src/components/layout/DesktopSidebar.tsx
  • wework/src/features/workbench/WorkbenchProvider.test.tsx

@qdaxb
qdaxb added this pull request to the merge queue Aug 11, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 11, 2026
@qdaxb
qdaxb added this pull request to the merge queue Aug 11, 2026
Merged via the queue into wecode-ai:main with commit 2d7105f Aug 11, 2026
47 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