Skip to content

fix(wework): align Codex session, project, and summary state - #1987

Merged
qdaxb merged 6 commits into
wecode-ai:mainfrom
icycrystal4:fix/wework-codex-state-persistence
Jul 16, 2026
Merged

qdaxb merged 6 commits into
wecode-ai:mainfrom
icycrystal4:fix/wework-codex-state-persistence

Conversation

@icycrystal4

@icycrystal4 icycrystal4 commented Jul 15, 2026 •

Copy link
Copy Markdown
Collaborator

Related task

  • uRcWQd92iW — 复刻Codex会话与项目状态

Root cause

  • Runtime task creation persisted only the execution model ID. When the selector identity differed from that ID, reopening the conversation could not restore the selected model and its options.
  • Local and remote projects did not share one local Codex project index or one ordering owner, so cross-device drag/pin order and the last active project could not be restored consistently.
  • Cloud device refreshes could temporarily keep stale availability, while offline prompts and device cards exposed executor IDs or generated names instead of a user-friendly address.
  • Recent-project restoration could race with an already-open task route and clear its selected conversation.
  • Wework ensured the local Executor was started before applying the saved Backend URL. The immediately following cloud-connection update could therefore restart the Executor, making the first local-model load fail until a refresh.
  • The summary panel owned its open state inside each cached task pane. That made the state task-scoped, while Codex uses an app-shell-scoped pinned state plus a separate temporary overlay state.

What changed

  • Persist the selector model identity (modelSelection) separately from execution parameters, with compatibility for legacy requests, and restore the conversation model/options when reopening it.
  • Register remote project descriptors in the local Executor's CODEX_HOME/.codex-global-state.json; local and remote projects now share project-order, pinned-project-ids, appearance, and active-project state.
  • Merge indexed remote descriptors with real remote Executor task data while preserving distinct routing keys for sidebar state and remote operations.
  • Route local/remote drag and pin mutations through the local Codex state owner, and synchronize remote rename/remove operations back to the local index.
  • Restore the last active local or remote project once at startup without overriding an explicit workspace, an already-open task (including app-base-path routes), or a user selection.
  • Reconcile cloud device status across logical, socket, runtime, and route identities so online/offline state updates correctly after refresh.
  • Use a user alias when one exists; otherwise show the device IP/transfer host in cloud-device cards and offline notices. Generated values such as sifang-executor-0341b231eb06 and raw device IDs are no longer presented as the user-facing name.
  • Align the device settings surface with current cloud/remote capabilities and remove stale local-device, metrics, and capacity-help UI.
  • Keep explicit development flags for enabling or disabling per-instance Executor home isolation.
  • Apply the saved cloud connection before local_executor_ensure_started, so the Executor starts once with its final Backend URL. Disconnect mode follows the same ordering.
  • Align the task summary with Codex App 26.707.91948: the pinned state defaults open and is shared across task switches, is not stored per task or in localStorage, and resets to open after a full app-shell remount. The constrained-width overlay uses a separate temporary state.
  • Align the available Environment summary items with Codex semantics: keep Wework's required location, alias/IP, device, and path rows; retain dynamic changes, branch, commit/push, and pull-request actions; remove the inert settings action and empty Sources placeholder.

Validation

  • Rebased onto origin/main at 773973edd.
  • Full Wework Vitest suite: 168 files, 1673 tests passed.
  • Focused summary/startup regressions: task switching, app-shell remount, pinned/overlay independence, cloud connect/disconnect ordering, and retry behavior.
  • pnpm --dir wework build (TypeScript and Vite production build).
  • Changed-file ESLint, Prettier, and git diff --check.
  • Full repository pre-push gate:
    • Wework ESLint, TypeScript, and unit tests
    • Backend Black, isort, and syntax checks
    • Executor cargo fmt --check, cargo test --all-features --lib, and cargo clippy

The Wework desktop application was intentionally not started, per request. The desktop E2E scenario is present but was not executed locally; final desktop behavior will be verified manually.

Manual verification

  1. Send a conversation with a non-default/shared cloud model, leave it, reopen it, and confirm the model and options are restored.
  2. Drag a remote project above a local project, restart Wework, and confirm the combined order remains.
  3. Reorder pinned local and remote projects and confirm the pinned order remains.
  4. Open a conversation under a project, then create a new task and confirm that project is selected by default; confirm an explicitly opened task/workspace is never replaced by recent-project restoration.
  5. On the cloud-device page, confirm an unrenamed device such as sifang-executor-0341b231eb06 displays its IP, while a renamed device displays its alias.
  6. Confirm offline notices use the IP instead of a device ID and that refreshing reflects the cloud device's latest online state.
  7. Restart Wework with a saved cloud Backend URL and confirm the local model list is available on the first load without refreshing or an extra Executor restart.
  8. Close the task summary in task A, switch to task B, and confirm it stays closed. Fully quit and reopen Wework, then confirm it defaults open again.
  9. Open the right workspace panel so the summary becomes an overlay, toggle the overlay, then close the right workspace panel and confirm the pinned summary state was not overwritten.
  10. Confirm the Environment summary shows location, device alias/IP, path, changes, branch, commit/push, and pull-request actions without an inert settings button or an empty Sources section.
  11. Verify dev-mac-app.sh --executor-isolation and --no-executor-isolation select isolated and shared Executor homes respectively.

Summary by CodeRabbit

  • New Features

    • Added syncing/activation and improved pinning/order for remote runtime projects in the sidebar.
    • Restores the last selected project and conversation model when returning to a workspace, including “default” model support.
    • Environment summary UI now supports shared pinned and overlay open states across desktop and mobile layouts.
    • Cloud-connected devices execute commands via the correct runtime path.
  • Bug Fixes

    • Improved matching and status updates for local vs remote devices.
    • Offline/unavailable notices now show clearer network identifiers (e.g., device IP).
    • Refined remote project rename/removal/activation behavior and ordering.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds remote-project synchronization, activation, ordering, and active-state tracking across Codex global state, runtime APIs, and the workbench. It also updates model-selection persistence, executor isolation controls, cloud initialization, device identity handling, environment summaries, connection settings, and desktop task-flow coverage.

Changes

Remote project state and runtime integration

Layer / File(s) Summary
Codex remote-project state and oplog
executor/src/runtime_work/codex_global_state.rs, executor/src/runtime_work/handler.rs, executor/src/runtime_work/response.rs
Remote projects are synchronized and activated through new oplog records, global-state keys, project metadata, and sidebar RPC handlers.
Runtime project contracts and adapters
wework/src/types/api.ts, wework/src/api/..., executor/src/runtime_work/...
Runtime workspace/project responses now include sidebar keys, pinned order, active state, remote host identity, and remote-project mutation APIs.
Project restoration and sidebar lifecycle
wework/src/lib/runtime-project-state.ts, wework/src/features/workbench/WorkbenchProvider.tsx, wework/src/components/layout/DesktopSidebar.tsx, wework/src/features/workbench/workbenchCloudStatus.ts
Remote registrations, activation, restoration, merging, sorting, renaming, and removal use stable sidebar runtime identities.

Runtime execution and desktop behavior

Layer / File(s) Summary
Model selection and task context
executor/src/runtime_work/handler.rs, wework/src/types/api.ts, wework/src/features/workbench/useWorkbenchRuntimeMessaging.ts, wework/src/features/workbench/workbenchContextTypes.ts
Runtime handles accept supplied model-selection objects with legacy fallback, and file-change operations accept runtime-task overrides.
Executor isolation and cloud initialization
wework/scripts/dev-mac-app.sh, wework/src-tauri/src/local_executor.rs, wework/src/features/cloud-connection/*, wework/src/features/local-runtime/*, wework/src/App.tsx
CLI isolation overrides are propagated to executor runtime-home selection, while cloud connection state is applied before local executor startup and retry.
Hybrid device routing
wework/src/api/hybrid/hybridServices.ts, wework/src/api/hybrid/hybridServices.test.ts
Local device commands use local services and non-local commands use cloud runtime IPC with runtime device identifiers.

Device and environment UI

Layer / File(s) Summary
Device identity and unavailable labels
wework/src/lib/workbench-device.ts, wework/src/components/layout/DeviceStatusPrompt.tsx, wework/src/components/layout/*OfflineBanner.tsx
Device matching recognizes aliases and runtime routes, and unavailable messages use normalized IP or host values.
Controlled environment summary
wework/src/components/layout/EnvironmentInfoPopover.tsx, wework/src/components/layout/DesktopWorkbenchMain.tsx, wework/src/components/layout/workspace-panels/WorkspacePanelActions.tsx
Environment summary visibility is controlled by parent state, with separate pinned and overlay states and updated offline rendering.
Connections settings
wework/src/components/settings/ConnectionsSettingsPage.tsx, wework/src/components/settings/ConnectionsSettingsPage.test.tsx
Connection settings focus on cloud and remote devices, use normalized display names, and omit local metrics and terminal-specific controls.
Desktop and integration validation
wework/e2e/desktop/task-flow.e2e.mjs, wework/src/features/workbench/*test*, executor/tests/*
Tests cover project activation and restoration, model restoration, remote merging, device matching, controlled summary state, and standalone chat state.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested reviewers: qdaxb

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 is concise and accurately reflects the PR’s main goal of aligning Codex session, project, and summary state behavior.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


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.

@icycrystal4
icycrystal4 force-pushed the fix/wework-codex-state-persistence branch 2 times, most recently from 59b6ec3 to 098d94d Compare July 16, 2026 09:16
@icycrystal4 icycrystal4 changed the title fix(wework): persist Codex session and project state fix(wework): align Codex session, project, and summary state Jul 16, 2026
@icycrystal4
icycrystal4 marked this pull request as ready for review July 16, 2026 13:15

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

🧹 Nitpick comments (1)
wework/src/features/workbench/WorkbenchProvider.tsx (1)

472-544: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Extract the new project lifecycle and sidebar-state responsibilities from oversized modules.

  • wework/src/features/workbench/WorkbenchProvider.tsx#L472-L544: extract synchronization, restoration, and activation into a dedicated hook.
  • wework/src/components/layout/DesktopSidebar.tsx#L2549-L2599: extract sidebar project-state derivation and pinned ordering.
  • wework/src/components/layout/DesktopSidebar.tsx#L3134-L3348: move sortable identity and reorder request construction into that abstraction.

As per coding guidelines, “Keep functions focused, preferably under 50 lines” and “Split source files over 1000 lines.”

🤖 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 472 - 544,
Extract the synchronization, restoration, and activation effects around
localRuntimeStateDeviceId from WorkbenchProvider.tsx into a dedicated
project-lifecycle hook, with no direct change required at the sidebar sites
until that abstraction is available. In DesktopSidebar.tsx, extract sidebar
project-state derivation and pinned ordering from lines 2549-2599, and move
sortable identity plus reorder-request construction from lines 3134-3348 into
the same sidebar-state abstraction; update callers to use the extracted hook
while preserving existing behavior.

Source: Coding guidelines

🤖 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 `@executor/src/runtime_work/codex_global_state.rs`:
- Around line 305-331: Update sync_codex_global_remote_projects to reconcile the
existing remote-project state with the supplied snapshot instead of only
appending upserts: track the normalized remote IDs and labels provided, remove
projects omitted from the snapshot, and explicitly clear stored labels when an
entry has no label. Preserve the existing validation and refresh flow, and add
regression coverage for empty and reduced snapshots.
- Around line 1180-1189: Update the remote activation branch in
apply_project_ui_state to clear or replace ACTIVE_WORKSPACE_ROOTS_KEY before
setting ACTIVE_REMOTE_PROJECT_ID_KEY and SELECTED_REMOTE_HOST_ID_KEY, ensuring
previous local roots are not preserved. Add a local-to-remote activation test
asserting that only the remote project remains active.

In `@wework/src/api/hybrid/hybridServices.ts`:
- Around line 346-350: Update the work.chats iteration in the localDeviceIds
population flow to add a chat’s deviceId only when its workspaceSource is not
'remote', matching the filtering already used in the project.deviceWorkspaces
loop. Keep local chat devices registered and exclude remote chat workspaces.

In `@wework/src/api/local/localServices.ts`:
- Around line 1512-1514: Update the filtering condition in the task-processing
flow around rawTasks and workspaceSource so empty remote projects are matched
using a stable project identity, such as the project key or repository
fingerprint, rather than the display label. Ensure unrelated local and remote
projects with the same label are both preserved.

In `@wework/src/components/settings/ConnectionsSettingsPage.tsx`:
- Around line 320-331: Update deviceDisplayName to retain the existing alias
check, then replace the raw client_ip fallback with
getWorkbenchDeviceUnavailableDisplayName so runtime_transfer_host and
network-host normalization are reused. Preserve the existing name and device_id
fallback behavior.

In `@wework/src/features/workbench/useWorkbenchProjectActions.ts`:
- Around line 154-166: The secondary state-owner mutations in
useWorkbenchProjectActions.ts at lines 154-166 and 199-210 discard RPC
responses. Capture each renameRuntimeWorkspace and removal response, then handle
accepted: false exactly as the corresponding primary rename and removal
operations do, preserving successful behavior while reporting rejected
mutations.

In `@wework/src/features/workbench/useWorkbenchRuntimeMessaging.ts`:
- Line 1092: Update both runtimeTask assignments in
wework/src/features/workbench/useWorkbenchRuntimeMessaging.ts at lines 1092-1092
and 1143-1143 to fall back to state.currentRuntimeTask only when
runtimeTaskOverride is undefined, preserving explicit null values.

In `@wework/src/features/workbench/WorkbenchProvider.tsx`:
- Around line 495-517: Update the project-restore useEffect around
findFirstSelectableProject so it waits while state.isBootstrapping is true
before setting lastProjectRestoreAttemptedRef.current or selecting a fallback
project. Add state.isBootstrapping to the effect dependency list, preserving the
existing route, selection, and workspace guards.
- Around line 477-493: Update the remote-project synchronization effect around
getRuntimeRemoteProjectRegistrations so it still calls syncRuntimeRemoteProjects
with projects: [] when localRuntimeStateDeviceId is valid but the project list
is empty. Remove only the projects.length === 0 early-return condition, while
preserving the device-ID guard, signature deduplication, refresh, and error
handling.

---

Nitpick comments:
In `@wework/src/features/workbench/WorkbenchProvider.tsx`:
- Around line 472-544: Extract the synchronization, restoration, and activation
effects around localRuntimeStateDeviceId from WorkbenchProvider.tsx into a
dedicated project-lifecycle hook, with no direct change required at the sidebar
sites until that abstraction is available. In DesktopSidebar.tsx, extract
sidebar project-state derivation and pinned ordering from lines 2549-2599, and
move sortable identity plus reorder-request construction from lines 3134-3348
into the same sidebar-state abstraction; update callers to use the extracted
hook while preserving existing behavior.
🪄 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: f9d4b70d-2008-4d54-94e5-0d77adda85ec

📥 Commits

Reviewing files that changed from the base of the PR and between 773973e and 098d94d.

📒 Files selected for processing (52)
  • executor/src/runtime_work/codex_global_state.rs
  • executor/src/runtime_work/handler.rs
  • executor/src/runtime_work/response.rs
  • executor/tests/app_runtime_work_workspace_contract.rs
  • wework/e2e/desktop/task-flow.e2e.mjs
  • wework/scripts/dev-mac-app.sh
  • wework/src-tauri/src/local_executor.rs
  • wework/src/App.tsx
  • wework/src/api/executorAccess.ts
  • wework/src/api/hybrid/hybridServices.test.ts
  • wework/src/api/hybrid/hybridServices.ts
  • wework/src/api/local/localServices.test.ts
  • wework/src/api/local/localServices.ts
  • wework/src/api/runtimeWork.ts
  • wework/src/components/layout/ConversationDeviceOfflineBanner.tsx
  • wework/src/components/layout/DesktopSidebar.test.tsx
  • wework/src/components/layout/DesktopSidebar.tsx
  • wework/src/components/layout/DesktopWorkbenchLayout.test.tsx
  • wework/src/components/layout/DesktopWorkbenchMain.tsx
  • wework/src/components/layout/DeviceStatusPrompt.test.tsx
  • wework/src/components/layout/DeviceStatusPrompt.tsx
  • wework/src/components/layout/EnvironmentInfoPopover.test.tsx
  • wework/src/components/layout/EnvironmentInfoPopover.tsx
  • wework/src/components/layout/MobileWorkbenchLayout.test.tsx
  • wework/src/components/layout/MobileWorkbenchLayout.tsx
  • wework/src/components/layout/workspace-panels/WorkspacePanelActions.test.tsx
  • wework/src/components/layout/workspace-panels/WorkspacePanelActions.tsx
  • wework/src/components/settings/ConnectionsSettingsPage.test.tsx
  • wework/src/components/settings/ConnectionsSettingsPage.tsx
  • wework/src/features/cloud-connection/LocalExecutorCloudBridge.test.tsx
  • wework/src/features/cloud-connection/LocalExecutorCloudBridge.tsx
  • wework/src/features/cloud-connection/localExecutorCloudConnection.ts
  • wework/src/features/local-runtime/LocalRuntimeInitializer.test.tsx
  • wework/src/features/local-runtime/LocalRuntimeInitializer.tsx
  • wework/src/features/workbench/WorkbenchProvider.test.tsx
  • wework/src/features/workbench/WorkbenchProvider.tsx
  • wework/src/features/workbench/useWorkbenchProjectActions.ts
  • wework/src/features/workbench/useWorkbenchRuntimeMessaging.ts
  • wework/src/features/workbench/workbenchCloudStatus.test.ts
  • wework/src/features/workbench/workbenchCloudStatus.ts
  • wework/src/features/workbench/workbenchContextTypes.ts
  • wework/src/features/workbench/workbenchReducer.test.ts
  • wework/src/features/workbench/workbenchReducer.ts
  • wework/src/features/workbench/workbenchRuntimeHelpers.test.ts
  • wework/src/features/workbench/workbenchRuntimeHelpers.ts
  • wework/src/i18n/locales/en/common.json
  • wework/src/i18n/locales/zh-CN/common.json
  • wework/src/lib/runtime-project-state.test.ts
  • wework/src/lib/runtime-project-state.ts
  • wework/src/lib/workbench-device.test.ts
  • wework/src/lib/workbench-device.ts
  • wework/src/types/api.ts

Comment on lines +305 to +331
pub(crate) fn sync_codex_global_remote_projects(
projects: &[CodexGlobalRemoteProject],
) -> Result<(), String> {
for project in projects {
let Some(project_key) = clean_text(&project.id) else {
continue;
};
let Some(remote_host_id) = clean_text(&project.host_id) else {
continue;
};
let remote_path = normalize_workspace_path(&project.remote_path);
if remote_path.is_empty() {
continue;
}
append_codex_global_state_op_record(&CodexGlobalStateOplogRecord {
kind: OPLOG_KIND_UPSERT_REMOTE_PROJECT.to_owned(),
workspace_path: remote_path,
project_key: Some(project_key),
remote_host_id: Some(remote_host_id),
label: project.label.as_deref().and_then(clean_text),
updated_at: now_ms(),
..Default::default()
})?;
}
flush_or_watch_codex_global_state_oplog();
refresh_codex_global_project_cache();
Ok(())

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.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Reconcile removed projects and cleared labels during remote sync.

This “sync” only upserts supplied entries, so projects omitted from a later snapshot remain indefinitely. Existing labels also survive when a subsequent entry has no label. Reconcile current remote IDs against the supplied set and remove stale labels/projects, with regression coverage for an empty or reduced snapshot.

Also applies to: 1162-1171

🤖 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 `@executor/src/runtime_work/codex_global_state.rs` around lines 305 - 331,
Update sync_codex_global_remote_projects to reconcile the existing
remote-project state with the supplied snapshot instead of only appending
upserts: track the normalized remote IDs and labels provided, remove projects
omitted from the snapshot, and explicitly clear stored labels when an entry has
no label. Preserve the existing validation and refresh flow, and add regression
coverage for empty and reduced snapshots.

Comment on lines +1180 to +1189
if let Some(remote_host_id) = remote_host_id.and_then(clean_text) {
payload.insert(
ACTIVE_REMOTE_PROJECT_ID_KEY.to_owned(),
Value::String(project_key.to_owned()),
);
payload.insert(
SELECTED_REMOTE_HOST_ID_KEY.to_owned(),
Value::String(remote_host_id),
);
return;

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

Clear local active roots when activating a remote project.

The remote branch sets active-remote-project-id but preserves active-workspace-roots. apply_project_ui_state will therefore mark both the previous local project and the remote project active.

Proposed fix
 if let Some(remote_host_id) = remote_host_id.and_then(clean_text) {
+    payload.remove(ACTIVE_WORKSPACE_ROOTS_KEY);
     payload.insert(
         ACTIVE_REMOTE_PROJECT_ID_KEY.to_owned(),
         Value::String(project_key.to_owned()),

Add a local-to-remote activation test asserting that only the remote project remains active.

📝 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
if let Some(remote_host_id) = remote_host_id.and_then(clean_text) {
payload.insert(
ACTIVE_REMOTE_PROJECT_ID_KEY.to_owned(),
Value::String(project_key.to_owned()),
);
payload.insert(
SELECTED_REMOTE_HOST_ID_KEY.to_owned(),
Value::String(remote_host_id),
);
return;
if let Some(remote_host_id) = remote_host_id.and_then(clean_text) {
payload.remove(ACTIVE_WORKSPACE_ROOTS_KEY);
payload.insert(
ACTIVE_REMOTE_PROJECT_ID_KEY.to_owned(),
Value::String(project_key.to_owned()),
);
payload.insert(
SELECTED_REMOTE_HOST_ID_KEY.to_owned(),
Value::String(remote_host_id),
);
return;
🤖 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 `@executor/src/runtime_work/codex_global_state.rs` around lines 1180 - 1189,
Update the remote activation branch in apply_project_ui_state to clear or
replace ACTIVE_WORKSPACE_ROOTS_KEY before setting ACTIVE_REMOTE_PROJECT_ID_KEY
and SELECTED_REMOTE_HOST_ID_KEY, ensuring previous local roots are not
preserved. Add a local-to-remote activation test asserting that only the remote
project remains active.

Comment on lines +346 to 350
project.deviceWorkspaces.forEach(workspace => {
if (workspace.workspaceSource !== 'remote') localDeviceIds.add(workspace.deviceId)
})
})
work.chats.forEach(workspace => localDeviceIds.add(workspace.deviceId))

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

Exclude remote chat workspaces from localDeviceIds too.

The project loop filters remote sources, but Line 350 still registers every chat device as local. A remote chat can therefore misroute commands and runtime calls to localServices.

Proposed fix
-    work.chats.forEach(workspace => localDeviceIds.add(workspace.deviceId))
+    work.chats.forEach(workspace => {
+      if (workspace.workspaceSource !== 'remote') localDeviceIds.add(workspace.deviceId)
+    })
📝 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
project.deviceWorkspaces.forEach(workspace => {
if (workspace.workspaceSource !== 'remote') localDeviceIds.add(workspace.deviceId)
})
})
work.chats.forEach(workspace => localDeviceIds.add(workspace.deviceId))
project.deviceWorkspaces.forEach(workspace => {
if (workspace.workspaceSource !== 'remote') localDeviceIds.add(workspace.deviceId)
})
})
work.chats.forEach(workspace => {
if (workspace.workspaceSource !== 'remote') localDeviceIds.add(workspace.deviceId)
})
🤖 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/api/hybrid/hybridServices.ts` around lines 346 - 350, Update the
work.chats iteration in the localDeviceIds population flow to add a chat’s
deviceId only when its workspaceSource is not 'remote', matching the filtering
already used in the project.deviceWorkspaces loop. Keep local chat devices
registered and exclude remote chat workspaces.

Comment on lines 1512 to 1514
if (rawTasks.length === 0 && workspaceSource === 'remote' && localWorkspaceLabels.has(label)) {
continue
}

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 | 🏗️ Heavy lift

Do not deduplicate projects by display label.

An empty remote project is dropped whenever an unrelated local project has the same label—for example, /local/frontend and /remote/frontend. Match a stable project identity such as the project key or repository fingerprint instead.

🤖 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/api/local/localServices.ts` around lines 1512 - 1514, Update the
filtering condition in the task-processing flow around rawTasks and
workspaceSource so empty remote projects are matched using a stable project
identity, such as the project key or repository fingerprint, rather than the
display label. Ensure unrelated local and remote projects with the same label
are both preserved.

Comment on lines +320 to +331
function deviceDisplayName(device: DeviceInfo): string {
const name = device.name?.trim()
const defaultNames = [
device.device_id,
device.cloud_config?.deviceName,
device.remote_config?.deviceName,
]
.map(value => value?.trim())
.filter(Boolean)

return (
<div
data-testid="device-metrics"
className="flex flex-wrap items-center gap-3 text-xs text-text-secondary"
>
<span className="inline-flex items-center gap-1">
<span>CPU</span>
<span>{formatMetricPercent(metrics?.cpu_usage)}</span>
</span>
<span className="inline-flex items-center gap-1">
<span>MEM</span>
<span>{formatMetricPercent(metrics?.memory_usage)}</span>
</span>
<span className="inline-flex items-center gap-1">
<span>磁盘</span>
<span>{formatMetricPercent(metrics?.disk_usage)}</span>
</span>
</div>
)
if (name && !defaultNames.includes(name)) return name
return device.client_ip?.trim() || name || device.device_id

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

Reuse the normalized network-host fallback.

Line 331 returns raw client_ip and ignores runtime_transfer_host, so connection cards can show an unnormalized endpoint or generated executor name. Preserve the alias check, then delegate the fallback to getWorkbenchDeviceUnavailableDisplayName.

Proposed fix
+import { getWorkbenchDeviceUnavailableDisplayName } from '`@/lib/workbench-device`'

 function deviceDisplayName(device: DeviceInfo): string {
   const name = device.name?.trim()
   const defaultNames = [
     device.device_id,
     device.cloud_config?.deviceName,
     device.remote_config?.deviceName,
   ]
     .map(value => value?.trim())
     .filter(Boolean)

   if (name && !defaultNames.includes(name)) return name
-  return device.client_ip?.trim() || name || device.device_id
+  return getWorkbenchDeviceUnavailableDisplayName(device) || name || device.device_id
 }

As per coding guidelines, “Use clear names and reuse existing abstractions instead of duplicating logic.”

📝 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
function deviceDisplayName(device: DeviceInfo): string {
const name = device.name?.trim()
const defaultNames = [
device.device_id,
device.cloud_config?.deviceName,
device.remote_config?.deviceName,
]
.map(value => value?.trim())
.filter(Boolean)
return (
<div
data-testid="device-metrics"
className="flex flex-wrap items-center gap-3 text-xs text-text-secondary"
>
<span className="inline-flex items-center gap-1">
<span>CPU</span>
<span>{formatMetricPercent(metrics?.cpu_usage)}</span>
</span>
<span className="inline-flex items-center gap-1">
<span>MEM</span>
<span>{formatMetricPercent(metrics?.memory_usage)}</span>
</span>
<span className="inline-flex items-center gap-1">
<span>磁盘</span>
<span>{formatMetricPercent(metrics?.disk_usage)}</span>
</span>
</div>
)
if (name && !defaultNames.includes(name)) return name
return device.client_ip?.trim() || name || device.device_id
import { getWorkbenchDeviceUnavailableDisplayName } from '`@/lib/workbench-device`'
function deviceDisplayName(device: DeviceInfo): string {
const name = device.name?.trim()
const defaultNames = [
device.device_id,
device.cloud_config?.deviceName,
device.remote_config?.deviceName,
]
.map(value => value?.trim())
.filter(Boolean)
if (name && !defaultNames.includes(name)) return name
return getWorkbenchDeviceUnavailableDisplayName(device) || name || device.device_id
}
🤖 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 320
- 331, Update deviceDisplayName to retain the existing alias check, then replace
the raw client_ip fallback with getWorkbenchDeviceUnavailableDisplayName so
runtime_transfer_host and network-host normalization are reused. Preserve the
existing name and device_id fallback behavior.

Source: Coding guidelines

Comment on lines +154 to +166
if (
runtimeProject?.sidebarStateKey &&
runtimeProject.stateDeviceId &&
runtimeProject.stateDeviceId !== runtimeWorkspace.deviceId
) {
await executorClient.runtime.renameRuntimeWorkspace({
deviceId: runtimeProject.stateDeviceId,
projectKey: runtimeProject.sidebarStateKey,
workspacePath: runtimeWorkspace.workspacePath,
runtime: 'codex',
name,
})
}

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Validate all state-owner mutation responses. Both secondary RPC calls discard accepted, allowing partial mutations to be reported as successful.

  • wework/src/features/workbench/useWorkbenchProjectActions.ts#L154-L166: capture the rename response and handle accepted: false identically to the primary rename.
  • wework/src/features/workbench/useWorkbenchProjectActions.ts#L199-L210: capture the removal response and handle accepted: false identically to the primary removal.
📍 Affects 1 file
  • wework/src/features/workbench/useWorkbenchProjectActions.ts#L154-L166 (this comment)
  • wework/src/features/workbench/useWorkbenchProjectActions.ts#L199-L210
🤖 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/useWorkbenchProjectActions.ts` around lines 154
- 166, The secondary state-owner mutations in useWorkbenchProjectActions.ts at
lines 154-166 and 199-210 discard RPC responses. Capture each
renameRuntimeWorkspace and removal response, then handle accepted: false exactly
as the corresponding primary rename and removal operations do, preserving
successful behavior while reporting rejected mutations.

) => {
const messageSource = messagesOverride ?? []
const runtimeFileChanges = state.currentRuntimeTask
const runtimeTask = runtimeTaskOverride ?? state.currentRuntimeTask

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

Respect explicit null overrides.

The runtimeTaskOverride parameter is typed to allow null. However, the nullish coalescing operator (??) evaluates to the right-hand side for both undefined AND null. If a caller explicitly passes null to indicate "no task," the ?? operator will discard it and erroneously fall back to state.currentRuntimeTask.

To only fall back when the parameter is omitted, check against undefined.

  • wework/src/features/workbench/useWorkbenchRuntimeMessaging.ts#L1092-L1092: Change to const runtimeTask = runtimeTaskOverride !== undefined ? runtimeTaskOverride : state.currentRuntimeTask
  • wework/src/features/workbench/useWorkbenchRuntimeMessaging.ts#L1143-L1143: Change to const runtimeTask = runtimeTaskOverride !== undefined ? runtimeTaskOverride : state.currentRuntimeTask
📍 Affects 1 file
  • wework/src/features/workbench/useWorkbenchRuntimeMessaging.ts#L1092-L1092 (this comment)
  • wework/src/features/workbench/useWorkbenchRuntimeMessaging.ts#L1143-L1143
🤖 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/useWorkbenchRuntimeMessaging.ts` at line 1092,
Update both runtimeTask assignments in
wework/src/features/workbench/useWorkbenchRuntimeMessaging.ts at lines 1092-1092
and 1143-1143 to fall back to state.currentRuntimeTask only when
runtimeTaskOverride is undefined, preserving explicit null values.

Comment on lines +477 to +493
useEffect(() => {
const projects = getRuntimeRemoteProjectRegistrations(
state.runtimeWork,
localRuntimeStateDeviceId
).sort((left, right) => left.id.localeCompare(right.id))
if (!localRuntimeStateDeviceId || projects.length === 0) return
const signature = JSON.stringify({ deviceId: localRuntimeStateDeviceId, projects })
if (remoteProjectSyncSignatureRef.current === signature) return
remoteProjectSyncSignatureRef.current = signature
void executorClient.runtime
.syncRuntimeRemoteProjects({ deviceId: localRuntimeStateDeviceId, projects })
.then(refreshWorkLists)
.catch(error => {
remoteProjectSyncSignatureRef.current = ''
console.warn('[Wework] Failed to sync remote projects into Codex global state', error)
})
}, [executorClient, localRuntimeStateDeviceId, refreshWorkLists, state.runtimeWork])

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Synchronize an empty project list to remove stale registrations.

Line 482 returns when the last remote project disappears, so Codex global state never receives projects: [] and retains removed remote projects.

Proposed fix
-    if (!localRuntimeStateDeviceId || projects.length === 0) return
+    if (!localRuntimeStateDeviceId) return
📝 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
useEffect(() => {
const projects = getRuntimeRemoteProjectRegistrations(
state.runtimeWork,
localRuntimeStateDeviceId
).sort((left, right) => left.id.localeCompare(right.id))
if (!localRuntimeStateDeviceId || projects.length === 0) return
const signature = JSON.stringify({ deviceId: localRuntimeStateDeviceId, projects })
if (remoteProjectSyncSignatureRef.current === signature) return
remoteProjectSyncSignatureRef.current = signature
void executorClient.runtime
.syncRuntimeRemoteProjects({ deviceId: localRuntimeStateDeviceId, projects })
.then(refreshWorkLists)
.catch(error => {
remoteProjectSyncSignatureRef.current = ''
console.warn('[Wework] Failed to sync remote projects into Codex global state', error)
})
}, [executorClient, localRuntimeStateDeviceId, refreshWorkLists, state.runtimeWork])
useEffect(() => {
const projects = getRuntimeRemoteProjectRegistrations(
state.runtimeWork,
localRuntimeStateDeviceId
).sort((left, right) => left.id.localeCompare(right.id))
if (!localRuntimeStateDeviceId) return
const signature = JSON.stringify({ deviceId: localRuntimeStateDeviceId, projects })
if (remoteProjectSyncSignatureRef.current === signature) return
remoteProjectSyncSignatureRef.current = signature
void executorClient.runtime
.syncRuntimeRemoteProjects({ deviceId: localRuntimeStateDeviceId, projects })
.then(refreshWorkLists)
.catch(error => {
remoteProjectSyncSignatureRef.current = ''
console.warn('[Wework] Failed to sync remote projects into Codex global state', error)
})
}, [executorClient, localRuntimeStateDeviceId, refreshWorkLists, state.runtimeWork])
🤖 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 477 - 493,
Update the remote-project synchronization effect around
getRuntimeRemoteProjectRegistrations so it still calls syncRuntimeRemoteProjects
with projects: [] when localRuntimeStateDeviceId is valid but the project list
is empty. Remove only the projects.length === 0 early-return condition, while
preserving the device-ID guard, signature deduplication, refresh, and error
handling.

Comment on lines +495 to +517
useEffect(() => {
if (lastProjectRestoreAttemptedRef.current || !state.runtimeWork) return
if (
projectSelectionStartedRef.current ||
parseRuntimeTaskRoute(stripAppBasePath(window.location.pathname), window.location.search) ||
state.currentProject ||
state.currentRuntimeTask ||
state.standaloneWorkspacePath
) {
lastProjectRestoreAttemptedRef.current = true
return
}
const candidateProjectIds = [
readLastProjectId(user.id),
findActiveRuntimeProjectId(state.runtimeWork),
]
lastProjectRestoreAttemptedRef.current = true
const project = findFirstSelectableProject(
state.projects,
state.runtimeWork,
candidateProjectIds
)
if (project) dispatch({ type: 'project_selected', project })

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

Wait for bootstrap completion before consuming the restore attempt.

runtimeWork may arrive before state.projects. Lines 511–517 then permanently mark restoration attempted, causing a saved cloud project to be missed or an active runtime fallback to be selected instead.

Proposed fix
-    if (lastProjectRestoreAttemptedRef.current || !state.runtimeWork) return
+    if (
+      lastProjectRestoreAttemptedRef.current ||
+      state.isBootstrapping ||
+      !state.runtimeWork
+    ) return

Also add state.isBootstrapping to the dependency list.

🤖 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 495 - 517,
Update the project-restore useEffect around findFirstSelectableProject so it
waits while state.isBootstrapping is true before setting
lastProjectRestoreAttemptedRef.current or selecting a fallback project. Add
state.isBootstrapping to the effect dependency list, preserving the existing
route, selection, and workspace guards.

@icycrystal4
icycrystal4 force-pushed the fix/wework-codex-state-persistence branch from 098d94d to 2438b20 Compare July 16, 2026 13:37

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

♻️ Duplicate comments (3)
wework/src/api/local/localServices.ts (1)

1512-1514: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Do not deduplicate projects by display label.

An empty remote project is dropped whenever an unrelated local project has the same label. Match a stable project identity such as the project key or repository fingerprint instead, as unrelated local and remote projects with the same label should both be preserved.

💻 Proposed fix

You will need to update the pre-pass loop (around line 1461) to track project keys instead of labels, and then update this condition to use the key:

-    if (rawTasks.length === 0 && workspaceSource === 'remote' && localWorkspaceLabels.has(label)) {
+    if (rawTasks.length === 0 && workspaceSource === 'remote' && localWorkspaceKeys.has(projectKey)) {
🤖 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/api/local/localServices.ts` around lines 1512 - 1514, Replace
label-based project tracking in the pre-pass loop with stable project keys or
repository fingerprints, then update the empty-remote check using
localWorkspaceLabels to compare that identity instead. Preserve unrelated local
and remote projects even when their display labels match.
wework/src/api/hybrid/hybridServices.ts (1)

346-348: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Exclude remote chat workspaces from localDeviceIds too.

While you correctly filtered out remote sources for project workspaces here, line 350 still registers every chat device as local without checking its source (work.chats.forEach(workspace => localDeviceIds.add(workspace.deviceId))). A remote chat can therefore misroute commands and runtime calls to localServices.

💻 Proposed fix

Apply the same filtering to the work.chats iteration just below this block:

-    work.chats.forEach(workspace => localDeviceIds.add(workspace.deviceId))
+    work.chats.forEach(workspace => {
+      if (workspace.workspaceSource !== 'remote') localDeviceIds.add(workspace.deviceId)
+    })
🤖 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/api/hybrid/hybridServices.ts` around lines 346 - 348, Update the
work.chats iteration in the surrounding localDeviceIds population logic to add a
chat workspace’s deviceId only when its workspaceSource is not remote, matching
the existing project.deviceWorkspaces filter. Preserve local registration for
non-remote chat workspaces.
wework/src/features/workbench/useWorkbenchRuntimeMessaging.ts (1)

1092-1092: ⚠️ Potential issue | 🟡 Minor

Respect explicit null overrides.

The runtimeTaskOverride parameter is typed to allow null. However, the nullish coalescing operator (??) evaluates to the right-hand side for both undefined AND null. If a caller explicitly passes null to indicate "no task," the ?? operator will discard it and erroneously fall back to state.currentRuntimeTask.

  • wework/src/features/workbench/useWorkbenchRuntimeMessaging.ts#L1092-L1092: Update to const runtimeTask = runtimeTaskOverride !== undefined ? runtimeTaskOverride : state.currentRuntimeTask
  • wework/src/features/workbench/useWorkbenchRuntimeMessaging.ts#L1143-L1143: Update to const runtimeTask = runtimeTaskOverride !== undefined ? runtimeTaskOverride : state.currentRuntimeTask
🤖 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/useWorkbenchRuntimeMessaging.ts` at line 1092,
Respect explicit null runtime-task overrides in both runtime task assignments
within useWorkbenchRuntimeMessaging: update the sites at
wework/src/features/workbench/useWorkbenchRuntimeMessaging.ts lines 1092-1092
and 1143-1143 to fall back to state.currentRuntimeTask only when
runtimeTaskOverride is undefined, preserving null as an intentional no-task
value.
🤖 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.

Duplicate comments:
In `@wework/src/api/hybrid/hybridServices.ts`:
- Around line 346-348: Update the work.chats iteration in the surrounding
localDeviceIds population logic to add a chat workspace’s deviceId only when its
workspaceSource is not remote, matching the existing project.deviceWorkspaces
filter. Preserve local registration for non-remote chat workspaces.

In `@wework/src/api/local/localServices.ts`:
- Around line 1512-1514: Replace label-based project tracking in the pre-pass
loop with stable project keys or repository fingerprints, then update the
empty-remote check using localWorkspaceLabels to compare that identity instead.
Preserve unrelated local and remote projects even when their display labels
match.

In `@wework/src/features/workbench/useWorkbenchRuntimeMessaging.ts`:
- Line 1092: Respect explicit null runtime-task overrides in both runtime task
assignments within useWorkbenchRuntimeMessaging: update the sites at
wework/src/features/workbench/useWorkbenchRuntimeMessaging.ts lines 1092-1092
and 1143-1143 to fall back to state.currentRuntimeTask only when
runtimeTaskOverride is undefined, preserving null as an intentional no-task
value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9bcd565e-f589-4d93-9a6d-cb67fe5946e6

📥 Commits

Reviewing files that changed from the base of the PR and between 098d94d and 2438b20.

📒 Files selected for processing (59)
  • executor/src/runtime_work/codex_global_state.rs
  • executor/src/runtime_work/handler.rs
  • executor/src/runtime_work/response.rs
  • executor/tests/app_runtime_work_workspace_contract.rs
  • wework/e2e/desktop/task-flow.e2e.mjs
  • wework/scripts/dev-mac-app.sh
  • wework/src-tauri/src/local_executor.rs
  • wework/src/App.tsx
  • wework/src/api/executorAccess.ts
  • wework/src/api/hybrid/hybridServices.test.ts
  • wework/src/api/hybrid/hybridServices.ts
  • wework/src/api/local/localServices.test.ts
  • wework/src/api/local/localServices.ts
  • wework/src/api/runtimeWork.ts
  • wework/src/components/layout/ConversationDeviceOfflineBanner.tsx
  • wework/src/components/layout/DesktopSidebar.test.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/DeviceStatusPrompt.test.tsx
  • wework/src/components/layout/DeviceStatusPrompt.tsx
  • wework/src/components/layout/EnvironmentInfoPopover.test.tsx
  • wework/src/components/layout/EnvironmentInfoPopover.tsx
  • wework/src/components/layout/MobileWorkbenchLayout.test.tsx
  • wework/src/components/layout/MobileWorkbenchLayout.tsx
  • wework/src/components/layout/workspace-panels/WorkspacePanelActions.test.tsx
  • wework/src/components/layout/workspace-panels/WorkspacePanelActions.tsx
  • wework/src/components/settings/ConnectionsSettingsPage.test.tsx
  • wework/src/components/settings/ConnectionsSettingsPage.tsx
  • wework/src/components/sites/SitesWorkspace.tsx
  • wework/src/features/cloud-connection/LocalExecutorCloudBridge.test.tsx
  • wework/src/features/cloud-connection/LocalExecutorCloudBridge.tsx
  • wework/src/features/cloud-connection/localExecutorCloudConnection.ts
  • wework/src/features/local-runtime/LocalRuntimeInitializer.test.tsx
  • wework/src/features/local-runtime/LocalRuntimeInitializer.tsx
  • wework/src/features/workbench/WorkbenchProvider.test.tsx
  • wework/src/features/workbench/WorkbenchProvider.tsx
  • wework/src/features/workbench/useWorkbenchProjectActions.ts
  • wework/src/features/workbench/useWorkbenchRuntimeMessaging.ts
  • wework/src/features/workbench/useWorkbenchRuntimeTasks.ts
  • wework/src/features/workbench/workbenchCloudStatus.test.ts
  • wework/src/features/workbench/workbenchCloudStatus.ts
  • wework/src/features/workbench/workbenchContextTypes.ts
  • wework/src/features/workbench/workbenchReducer.test.ts
  • wework/src/features/workbench/workbenchReducer.ts
  • wework/src/features/workbench/workbenchRuntimeHelpers.test.ts
  • wework/src/features/workbench/workbenchRuntimeHelpers.ts
  • wework/src/i18n/locales/en/common.json
  • wework/src/i18n/locales/zh-CN/common.json
  • wework/src/lib/runtime-project-state.test.ts
  • wework/src/lib/runtime-project-state.ts
  • wework/src/lib/workbench-device.test.ts
  • wework/src/lib/workbench-device.ts
  • wework/src/pages/PluginCreatePage.tsx
  • wework/src/pages/PluginManagementPage.tsx
  • wework/src/pages/PluginsPage.tsx
  • wework/src/pages/SitesPage.tsx
  • wework/src/types/api.ts
🚧 Files skipped from review as they are similar to previous changes (44)
  • wework/src/features/cloud-connection/localExecutorCloudConnection.ts
  • wework/src/api/executorAccess.ts
  • wework/src/features/workbench/workbenchReducer.test.ts
  • wework/src/api/local/localServices.test.ts
  • wework/src/lib/workbench-device.test.ts
  • wework/src/components/layout/DesktopSidebar.test.tsx
  • wework/src/App.tsx
  • wework/src/features/cloud-connection/LocalExecutorCloudBridge.test.tsx
  • wework/src/components/layout/EnvironmentInfoPopover.test.tsx
  • wework/src/api/runtimeWork.ts
  • wework/src/i18n/locales/en/common.json
  • wework/src/api/hybrid/hybridServices.test.ts
  • wework/src/features/workbench/workbenchRuntimeHelpers.test.ts
  • wework/src/lib/runtime-project-state.test.ts
  • wework/src/components/layout/MobileWorkbenchLayout.tsx
  • wework/src/components/layout/ConversationDeviceOfflineBanner.tsx
  • wework/src/features/workbench/useWorkbenchProjectActions.ts
  • wework/src/i18n/locales/zh-CN/common.json
  • wework/src/components/layout/workspace-panels/WorkspacePanelActions.tsx
  • wework/src/types/api.ts
  • wework/src/features/cloud-connection/LocalExecutorCloudBridge.tsx
  • executor/src/runtime_work/response.rs
  • wework/src/lib/workbench-device.ts
  • wework/src/features/workbench/workbenchCloudStatus.test.ts
  • wework/src/features/local-runtime/LocalRuntimeInitializer.tsx
  • wework/src/components/layout/DesktopWorkbenchLayout.test.tsx
  • wework/e2e/desktop/task-flow.e2e.mjs
  • wework/src/lib/runtime-project-state.ts
  • wework/src/features/workbench/workbenchCloudStatus.ts
  • wework/scripts/dev-mac-app.sh
  • wework/src/components/layout/DesktopWorkbenchMain.tsx
  • wework/src-tauri/src/local_executor.rs
  • wework/src/features/workbench/workbenchReducer.ts
  • wework/src/components/layout/DeviceStatusPrompt.test.tsx
  • wework/src/components/layout/DeviceStatusPrompt.tsx
  • wework/src/components/layout/EnvironmentInfoPopover.tsx
  • wework/src/features/workbench/WorkbenchProvider.tsx
  • executor/src/runtime_work/handler.rs
  • wework/src/components/layout/DesktopSidebar.tsx
  • wework/src/features/workbench/workbenchContextTypes.ts
  • wework/src/features/workbench/WorkbenchProvider.test.tsx
  • executor/src/runtime_work/codex_global_state.rs
  • wework/src/components/settings/ConnectionsSettingsPage.test.tsx
  • wework/src/components/settings/ConnectionsSettingsPage.tsx

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