Skip to content

Add mobile project actions over sync#579

Merged
arul28 merged 5 commits into
mainfrom
ade/when-remote-conenctoin-latopo-dekstop-b2b52eed
Jun 15, 2026
Merged

Add mobile project actions over sync#579
arul28 merged 5 commits into
mainfrom
ade/when-remote-conenctoin-latopo-dekstop-b2b52eed

Conversation

@arul28

@arul28 arul28 commented Jun 15, 2026

Copy link
Copy Markdown
Owner

Summary

Describe the change.

What Changed

Key files and behaviors.

Validation

How you tested.

Risks

Anything to watch.

ADE   Open in ADE  ·  ade/when-remote-conenctoin-latopo-dekstop-b2b52eed branch  ·  PR #579

Summary by CodeRabbit

  • New Features

    • Added mobile project management capabilities: browse, open, create, and clone projects remotely via sync
    • Added GitHub repository browsing and selection on mobile devices
    • Enhanced directory navigation and default project location selection for mobile workflows
  • Bug Fixes

    • Fixed permission mode resolution to use explicit configuration values when available
  • Tests

    • Expanded test coverage for mobile project actions and sync connection handling

Greptile Summary

This PR adds mobile project management capabilities over the sync channel — browse, open, create, and clone projects on the paired machine from the iOS project-home screen — and introduces a machine-wide fallback sync handler (brainProjectActionsSyncHandler) that serves these actions even before any project host is active.

  • New RemoteProjectAddSheet Swift view covers Open / Create / Clone flows, backed by six new request/result envelope pairs wired end-to-end through both the per-project syncHostService and the new brain-level fallback handler.
  • sharedSyncListener gains a setFallbackConnectionHandler API with a grace-period suppression window so reconnecting phones still park for adoption by the next primary host during handoff, not dispatched to the fallback.
  • workCliPermissionMode stops falling back to runtimeMode when wire.permissionMode is nil, returning nil instead.

Confidence Score: 4/5

Mostly safe to merge; the one real defect is confined to a rare failure path in the brain fallback handler's project-switch completion.

The completionAttempted flag is set before completeProjectConnection is awaited, making the catch-block retry guard permanently false. When completeProjectConnection (i.e. scopeRegistry.switchSyncHost) throws, the phone holds a success response but the machine never activates the new project's sync host. The user ends up in a state where the selected project appears switched on the phone but produces no sync connection until they manually re-select it. All other paths — the new iOS UI, the shared-listener handoff suppression, the new desktop/headless catalog provider methods — look correct and are well-tested.

apps/ade-cli/src/services/sync/brainProjectActionsSyncHandler.ts — the project_switch_request handler's retry condition for completeProjectConnection

Important Files Changed

Filename Overview
apps/ade-cli/src/services/sync/brainProjectActionsSyncHandler.ts New machine-wide fallback sync handler. Handles auth (bootstrap + pairing), rate-limited PIN pairing, and project actions. Dead retry code in project_switch_request means completeProjectConnection is never retried on failure, leaving the machine without an active sync host for the selected project.
apps/ade-cli/src/cli.ts Extracts machineProjectCatalogProvider into a standalone object (including browse/open/create/clone/listGitHubRepos actions), attaches the brain fallback handler to the shared listener, and fixes startSyncHost to call ensureListening when no active scope exists. Refactoring is clean.
apps/ade-cli/src/services/sync/sharedSyncListener.ts Adds setFallbackConnectionHandler API and a fallbackSuppressedUntilMs grace-period mechanism that prevents the fallback handler from claiming reconnecting-phone sockets during the handoff window. Logic is correct and well-tested.
apps/ade-cli/src/services/sync/syncHostService.ts Extracts SyncProjectCatalogProvider type, adds projectActionsEnabled to hello_ok, and adds handler functions for all new project-action envelope types. New action handlers correctly broadcast catalog updates to all connected peers on success.
apps/desktop/src/main/main.ts Adds openMobileSyncProject, createMobileSyncProject, and cloneMobileSyncProject desktop-side handlers, wires them into the projectCatalogProvider. Path resolution and error handling follow the same pattern as the headless CLI path.
apps/ios/ADE/App/RemoteProjectAddSheet.swift New iOS sheet covering open/create/clone flows. Stale-request guard in RemoteProjectDirectoryBrowser.load() is correct; isSubmitting guards on all action methods prevent double submission; hasGitHubHost properly validates via URL host component rather than substring search.
apps/ios/ADE/Services/SyncService.swift Adds supportsProjectActions flag, new request helpers, and methods for all six project-action endpoints. featureEnabled helper cleanly replaces duplicated feature-flag parsing. Stale-catalog deduplication in applyMachineProjectActionResponse is correct.
apps/ios/ADE/Views/Work/WorkNewChatScreen.swift Removes the runtimeMode fallback in workCliPermissionMode, returning nil when wire.permissionMode is nil/empty. Intentional clean-up of implicit fallback behaviour.
apps/desktop/src/shared/types/sync.ts Adds projectActions feature flag type and nine new envelope type aliases for the project-action protocol messages. Additions are additive and consistent with existing envelope patterns.

Sequence Diagram

sequenceDiagram
    participant iOS as iOS (RemoteProjectAddSheet)
    participant BH as Brain Fallback Handler
    participant SH as syncHostService (active project)
    participant CP as machineProjectCatalogProvider

    Note over iOS,CP: Before any project selected (no active host)
    iOS->>BH: hello (bootstrap/paired auth)
    BH-->>iOS: hello_ok (projectActions.enabled: true)
    iOS->>BH: project_browse_request
    BH->>CP: browseDirectories()
    CP-->>BH: ProjectBrowseResult
    BH-->>iOS: project_browse_result
    iOS->>BH: project_open_request / create / clone
    BH->>CP: openProject / createProject / cloneProject
    CP-->>BH: SyncMobileProjectSummary
    BH-->>iOS: project_open_result + project_catalog
    iOS->>BH: project_switch_request
    BH->>CP: prepareProjectConnection()
    CP-->>BH: SyncProjectSwitchResultPayload
    BH-->>iOS: project_switch_result
    BH->>CP: completeProjectConnection() ← scopeRegistry.switchSyncHost
    Note over iOS,SH: Active project host takes over shared listener
    iOS->>SH: project_browse_request / open / create / clone
    SH->>CP: browseDirectories / openProject / createProject / cloneProject
    CP-->>SH: result
    SH-->>iOS: result + broadcast project_catalog to all peers
Loading

Comments Outside Diff (3)

  1. apps/ade-cli/src/services/sync/brainProjectActionsSyncHandler.ts, line 753-783 (link)

    P1 Double project_switch_result response after completeProjectConnection failure

    When prepareProjectConnection succeeds and then completeProjectConnection throws, the handler sends both a success response (line 759) AND an error response (line 778) for the same requestId. The iOS resolver matches the first (success) response and discards the second, but the machine never completes the sync-host activation — scopeRegistry.switchSyncHost is retried best-effort before the error send, but if both attempts fail the phone believes it has switched projects while no project sync host is actually active. The user sees stale or empty sync state until they manually re-select the project.

    The catch block should not send a second project_switch_result when result is non-null. The retry of completeProjectConnection is correct, but the fallback error send on line 778 should be guarded: if (!result) { send(...) }.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/ade-cli/src/services/sync/brainProjectActionsSyncHandler.ts
    Line: 753-783
    
    Comment:
    **Double `project_switch_result` response after `completeProjectConnection` failure**
    
    When `prepareProjectConnection` succeeds and then `completeProjectConnection` throws, the handler sends both a success response (line 759) AND an error response (line 778) for the same `requestId`. The iOS resolver matches the first (success) response and discards the second, but the machine never completes the sync-host activation — `scopeRegistry.switchSyncHost` is retried best-effort before the error send, but if both attempts fail the phone believes it has switched projects while no project sync host is actually active. The user sees stale or empty sync state until they manually re-select the project.
    
    The catch block should not send a second `project_switch_result` when `result` is non-null. The retry of `completeProjectConnection` is correct, but the fallback error send on line 778 should be guarded: `if (!result) { send(...) }`.
    
    How can I resolve this? If you propose a fix, please make it concise.

    Fix in Claude Code

  2. apps/ios/ADE/Views/Work/WorkNewChatScreen.swift, line 3343-3349 (link)

    P2 Removed runtimeMode fallback silently changes existing behavior

    The old logic returned runtimeMode as a fallback when wire.permissionMode was nil. The new code always returns nil in that case. If any active provider/mode combination yields a nil wire.permissionMode, callers that previously received a non-nil mode string will now receive nil and skip setting a permission mode entirely. Consider confirming that no active provider+runtimeMode pair relied on the runtimeMode fallback before shipping.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/ios/ADE/Views/Work/WorkNewChatScreen.swift
    Line: 3343-3349
    
    Comment:
    **Removed `runtimeMode` fallback silently changes existing behavior**
    
    The old logic returned `runtimeMode` as a fallback when `wire.permissionMode` was `nil`. The new code always returns `nil` in that case. If any active provider/mode combination yields a `nil` `wire.permissionMode`, callers that previously received a non-nil mode string will now receive `nil` and skip setting a permission mode entirely. Consider confirming that no active provider+`runtimeMode` pair relied on the `runtimeMode` fallback before shipping.
    
    How can I resolve this? If you propose a fix, please make it concise.

    Fix in Claude Code

  3. apps/ade-cli/src/services/sync/brainProjectActionsSyncHandler.ts, line 817-851 (link)

    P1 Dead retry code leaves machine in inconsistent state after completeProjectConnection failure

    completionAttempted is set to true (line 826) immediately before completeProjectConnection is awaited (line 827). This means when completeProjectConnection throws, we enter the catch block with result non-null AND completionAttempted already true, so the guard if (result && !completionAttempted) is always false — the retry block on lines 836-843 is unreachable dead code.

    Consequence: when completeProjectConnection (which calls scopeRegistry.switchSyncHost) fails, the phone has already received a success project_switch_result and will attempt to connect to a sync host that was never fully activated. The machine logs a warning but takes no corrective action.

    The fix is to set completionAttempted = true after the completeProjectConnection call so the catch block's retry guard can actually fire. The existing test only checks that a second result is not sent; it does not verify that completeProjectConnection is retried on failure.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/ade-cli/src/services/sync/brainProjectActionsSyncHandler.ts
    Line: 817-851
    
    Comment:
    **Dead retry code leaves machine in inconsistent state after `completeProjectConnection` failure**
    
    `completionAttempted` is set to `true` (line 826) immediately **before** `completeProjectConnection` is awaited (line 827). This means when `completeProjectConnection` throws, we enter the catch block with `result` non-null AND `completionAttempted` already `true`, so the guard `if (result && !completionAttempted)` is always `false` — the retry block on lines 836-843 is unreachable dead code.
    
    Consequence: when `completeProjectConnection` (which calls `scopeRegistry.switchSyncHost`) fails, the phone has already received a success `project_switch_result` and will attempt to connect to a sync host that was never fully activated. The machine logs a warning but takes no corrective action.
    
    The fix is to set `completionAttempted = true` **after** the `completeProjectConnection` call so the catch block's retry guard can actually fire. The existing test only checks that a second result is not sent; it does not verify that `completeProjectConnection` is retried on failure.
    
    How can I resolve this? If you propose a fix, please make it concise.

    Fix in Claude Code

Fix All in Claude Code

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
apps/ade-cli/src/services/sync/brainProjectActionsSyncHandler.ts:817-851
**Dead retry code leaves machine in inconsistent state after `completeProjectConnection` failure**

`completionAttempted` is set to `true` (line 826) immediately **before** `completeProjectConnection` is awaited (line 827). This means when `completeProjectConnection` throws, we enter the catch block with `result` non-null AND `completionAttempted` already `true`, so the guard `if (result && !completionAttempted)` is always `false` — the retry block on lines 836-843 is unreachable dead code.

Consequence: when `completeProjectConnection` (which calls `scopeRegistry.switchSyncHost`) fails, the phone has already received a success `project_switch_result` and will attempt to connect to a sync host that was never fully activated. The machine logs a warning but takes no corrective action.

The fix is to set `completionAttempted = true` **after** the `completeProjectConnection` call so the catch block's retry guard can actually fire. The existing test only checks that a second result is not sent; it does not verify that `completeProjectConnection` is retried on failure.

Reviews (4): Last reviewed commit: "Guard remote open project submissions" | Re-trigger Greptile

@vercel

vercel Bot commented Jun 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
ade Ignored Ignored Preview Jun 15, 2026 9:40am

@mintlify

mintlify Bot commented Jun 15, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
ade-ac1c6011 🟢 Ready View Preview Jun 15, 2026, 8:51 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR implements a "Mobile Sync Project Actions" feature enabling iOS clients to browse, open, create, and clone machine-side projects over the existing WebSocket sync protocol. It adds new protocol envelope types, expands the sync host service with project-action routing, introduces a headless brain fallback WebSocket handler, wires both desktop and CLI providers, and delivers an iOS multi-step sheet UI with supporting SyncService APIs.

Changes

Mobile Sync Project Actions

Layer / File(s) Summary
Sync protocol: new payload and envelope types
apps/desktop/src/shared/types/sync.ts
SyncFeatureFlags gains projectActions; new payload types for browse, default-parent-dir, open, create, clone, and list-my-github-repos results are added; corresponding request/response envelope types are defined and added to the SyncEnvelope union.
SyncHostService: SyncProjectCatalogProvider type and message routing
apps/ade-cli/src/services/sync/syncHostService.ts, apps/ade-cli/src/services/sync/syncService.ts
Exports SyncProjectCatalogProvider type; re-types SyncHostServiceArgs.projectCatalogProvider; adds projectActionsEnabled to buildSyncHostHelloOkPayload; implements new local handler functions for browse/open/create/clone/GitHub-repos requests; extends inbound message switch to route all new envelope types. syncService.ts adopts the shared type.
SharedSyncListener: fallback connection handler
apps/ade-cli/src/services/sync/sharedSyncListener.ts
Adds setFallbackConnectionHandler API; introduces fallbackHandler and fallbackSuppressedUntilMs state; updates connection dispatch to use the fallback when no primary handler is active; suppresses fallback during primary handler detach transitions.
brainProjectActionsSyncHandler: headless WebSocket handler
apps/ade-cli/src/services/sync/brainProjectActionsSyncHandler.ts
New file implementing the full headless brain connection handler: secret file management, peer metadata validation, hello/pairing payload parsing, PIN/pairing stores, per-IP cooldown failure tracker, authenticated envelope dispatch for all project-action types plus heartbeat, and WebSocket lifecycle wiring.
CLI headless brain wiring
apps/ade-cli/src/cli.ts
Imports scaffold/repo-root utilities; builds machineProjectCatalogProvider backed by ProjectRegistry/ProjectScopeRegistry; calls setFallbackConnectionHandler(createBrainProjectActionsSyncHandler(...)) with secrets paths; updates ProjectScopeRegistry to use the shared provider.
Desktop main.ts: project-actions provider wiring
apps/desktop/src/main/main.ts
Extends syncService.projectCatalogProvider with browseDirectories, getDefaultParentDir, openProject, createProject, cloneProject, and listMyGitHubRepos implementations delegating to the scaffold service and new project root helpers.
iOS: remote models, SyncService APIs, and feature flag
apps/ios/ADE/Models/RemoteModels.swift, apps/ios/ADE/Services/SyncService.swift
Adds browse/action/GitHub-repo Codable models; introduces supportsProjectActions capability flag with canRunRemoteProjectActions guard; adds requestMachineProjectPayload helper and browse/open/create/clone/listRepos methods; refactors hello feature parsing; extends socket receive switch for all project_*_result types.
iOS: RemoteProjectAddSheet UI and ContentView integration
apps/ios/ADE/App/RemoteProjectAddSheet.swift, apps/ios/ADE/App/ContentView.swift
New 859-line RemoteProjectAddSheet with state-driven chooser, directory browser, create/clone forms, success screen, and all supporting components (button styles, notices, string utilities). ProjectHomeView gains addProjectSheetPresented state, ProjectHomeAddProjectRow, and a .sheet presenting the new flow when canRunRemoteProjectActions is true.
Tests: brain handler, listener handoff, desktop host, iOS
apps/ade-cli/src/services/sync/syncHostService.test.ts, apps/desktop/src/main/services/sync/syncHostService.test.ts, apps/ios/ADETests/ADETests.swift
CLI tests cover brain handler pairing/rate-limit behavior and shared listener connection parking during handoff; desktop tests assert hello_ok project-actions feature flag and validate the full open/create/clone/browse/GitHub-repos request-response sequence; iOS test extends runtime-scoped envelope type assertions.
iOS: workCliPermissionMode nil fallback removal
apps/ios/ADE/Views/Work/WorkNewChatScreen.swift
Removes the runtimeMode fallback so workCliPermissionMode returns nil when wire.permissionMode is absent or empty.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • arul28/ADE#575: Both PRs touch the construction of SyncMobileProjectSummary objects in cli.ts for the brain sync catalog provider — the retrieved PR adds iconDataUrl to the same registry-to-summary mapping path extended here.
  • arul28/ADE#195: Touches the same desktop sync integration points in apps/desktop/src/main/main.ts and sync service wiring that this PR extends with project-action provider methods.

Suggested labels

desktop, ios

🚥 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.
Title check ✅ Passed The title 'Add mobile project actions over sync' directly summarizes the main change: extending sync functionality with new mobile project management capabilities (open/create/clone/browse projects).
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ade/when-remote-conenctoin-latopo-dekstop-b2b52eed

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.

@arul28

arul28 commented Jun 15, 2026

Copy link
Copy Markdown
Owner Author

@copilot review but do not make fixes

@arul28 arul28 force-pushed the ade/when-remote-conenctoin-latopo-dekstop-b2b52eed branch from 17b47ab to 88c4557 Compare June 15, 2026 08:54
@arul28

arul28 commented Jun 15, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@arul28 arul28 changed the title When Remote Conenctoin Latopo Dekstop Add mobile project actions over sync Jun 15, 2026
Comment thread apps/ios/ADE/App/RemoteProjectAddSheet.swift

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 88c4557189

ℹ️ About Codex in GitHub

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

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

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

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

Comment thread apps/ade-cli/src/cli.ts
})
: null;
let scopeRegistry: InstanceType<typeof ProjectScopeRegistry>;
sharedSyncListener?.setFallbackConnectionHandler(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Bind the fallback listener when no projects exist

When projectRegistry.list() is empty, runSyncHostStartupLoop calls startSyncHost, which falls through to scopeRegistry.resolveActiveSyncHost() and returns null without ever calling sharedSyncListener.ensureListening(). Registering the fallback handler here therefore does not open the sync port on a fresh/headless machine, so a phone cannot pair or use the Add project flow to create the first project. Please ensure the shared listener is bound for the fallback path even when no project scope is available.

Useful? React with 👍 / 👎.

Comment on lines +432 to +433
if mode == .open, selectedPath == nil {
selectedPath = result?.openableProjectRoot

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Clear stale project selection when browsing a new path

If the user selected a repo, then edits or pastes a different path in the text field, the next load leaves the old selectedPath intact because this branch only assigns when it is nil. Since targetPath prefers selectedPath, tapping Open project can open the previously selected repo while the browser is showing a different folder. Reset or recompute the selection whenever a new browse result is loaded.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🤖 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 `@apps/ade-cli/src/cli.ts`:
- Around line 13065-13083: The function mobileProjectSummaryForHeadlessRecord
currently always returns isOpen: true even when scopeRegistry.get fails to
initialize the project runtime. Modify the catch block to track initialization
failure, and only return isOpen: true when scope initialization succeeds. You
should either set a flag when the scope fails to initialize and pass isOpen:
false in the return statement, or set isOpen: false directly in the catch block
instead of just resetting laneCount.
- Around line 13111-13116: The listProjects method in
machineProjectCatalogProvider maps all registered projects through
toMobileProjectSummary which hard-codes isAvailable: true, causing deleted or
moved projects to appear selectable. Modify the mapping logic in
projectRegistry.list().map() to check if each project record is still valid
before mapping it to a mobile project summary. If a project entry is stale
(deleted or moved), either filter it out or ensure isAvailable is set to false
in the summary to prevent unavailable projects from appearing as selectable in
the mobile catalog.
- Around line 13247-13256: The bootstrap token is currently being stored as
plaintext in a file when passed via bootstrapTokenPath to
createBrainProjectActionsSyncHandler. This needs to be refactored to use
encrypted storage instead. Locate the ensureBootstrapToken function that writes
the bootstrap token and modify it to use EncryptedFileCredentialStore (which is
already used elsewhere for PIN and paired-device secrets) rather than writing
directly to a plaintext file with only filesystem permissions. Update the
createBrainProjectActionsSyncHandler call to pass the encrypted credential store
instance instead of a direct file path for the bootstrap token, ensuring it
matches the encryption approach used for the PIN and paired-devices secrets.
- Around line 13033-13041: Remove the `as never` type cast from the
githubService parameter in the createProjectScaffoldService call within the
createHeadlessProjectScaffoldService function. Since HeadlessGitHubService is
already aliased to GithubService, the types are compatible and the cast is
unnecessary and obscures type safety. Simply pass githubService directly without
the type assertion.

In `@apps/ade-cli/src/services/sync/brainProjectActionsSyncHandler.ts`:
- Around line 323-354: The completeProjectConnection method is being called
twice in the "project_switch_request" case handler: once in the try block (line
330) and potentially again in the catch block (lines 340-343) if result exists.
To prevent duplicate invocations and potential side effects or inconsistent
state, introduce a boolean flag that tracks whether the first
completeProjectConnection call on line 330 completed successfully. Set this flag
to true only after that call completes without throwing. Then in the catch
block, only invoke completeProjectConnection if the flag is false, ensuring it
is called at most once per request handling.

In `@apps/ade-cli/src/services/sync/syncHostService.ts`:
- Around line 2545-2547: The current code in the sendProjectCatalog call only
sends the refreshed project catalog to the requesting peer. To fix this issue,
broadcast the refreshed catalog to all connected peers after mutations from
open/create/clone project actions, not just the requester. Modify the
sendProjectCatalog call to iterate through and send the payload returned by
buildProjectCatalogPayload to all connected clients/peers, ensuring that LAN
discovery metadata and other connected phones receive the updated catalog and
remain in sync.

In `@apps/ios/ADE/App/RemoteProjectAddSheet.swift`:
- Around line 425-434: The selectedPath field retains stale values from previous
path selections when users manually edit the path. In the load() function, the
condition checking if selectedPath == nil prevents the selection from being
updated on subsequent loads. Remove the selectedPath == nil check from the
conditional so that selectedPath is always reset to the newly computed
result?.openableProjectRoot value whenever mode == .open, ensuring the selection
stays synchronized with the currently browsed path.
- Around line 71-87: The onCreate and onClone callbacks fire unguarded Task
blocks that can be triggered multiple times via rapid user taps, causing
duplicate project creation or clone attempts. Add a state property (like
isSubmitting or similar) to track whether a request is currently in flight. In
both the onCreate callback (which calls createProject) and onClone callback
(which calls cloneProject), check this flag before starting the Task, set it to
true when the operation begins, and reset it to false when the operation
completes. Additionally, pass this submission state to RemoteProjectCreateForm
and RemoteProjectCloneForm so they can disable their action buttons while the
request is running, preventing further user interaction until the current
operation finishes.

In `@apps/ios/ADE/Services/SyncService.swift`:
- Around line 1772-1790: The `limit` parameter in the
`browseMachineProjectDirectories` function is being passed directly to the
payload without validation, which allows negative, zero, or oversized values to
be sent to the host. Before adding the `limit` value to the payload dictionary,
clamp it to a valid range (ensure it is at least 1 and at most a reasonable
upper bound such as the default value of 80 or a suitable maximum) to prevent
invalid values from causing host-side errors or unnecessary load.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d7abd029-4e85-49d8-8796-f8db3d4d43cf

📥 Commits

Reviewing files that changed from the base of the PR and between 97d1c14 and 17b47ab.

⛔ Files ignored due to path filters (4)
  • apps/ios/ADE.xcodeproj/project.pbxproj is excluded by !**/*.xcodeproj/project.pbxproj
  • docs/ARCHITECTURE.md is excluded by !docs/**
  • docs/features/sync-and-multi-device/README.md is excluded by !docs/**
  • docs/features/sync-and-multi-device/ios-companion.md is excluded by !docs/**
📒 Files selected for processing (15)
  • apps/ade-cli/src/cli.ts
  • apps/ade-cli/src/services/sync/brainProjectActionsSyncHandler.ts
  • apps/ade-cli/src/services/sync/sharedSyncListener.ts
  • apps/ade-cli/src/services/sync/syncHostService.test.ts
  • apps/ade-cli/src/services/sync/syncHostService.ts
  • apps/ade-cli/src/services/sync/syncService.ts
  • apps/desktop/src/main/main.ts
  • apps/desktop/src/main/services/sync/syncHostService.test.ts
  • apps/desktop/src/shared/types/sync.ts
  • apps/ios/ADE/App/ContentView.swift
  • apps/ios/ADE/App/RemoteProjectAddSheet.swift
  • apps/ios/ADE/Models/RemoteModels.swift
  • apps/ios/ADE/Services/SyncService.swift
  • apps/ios/ADE/Views/Work/WorkNewChatScreen.swift
  • apps/ios/ADETests/ADETests.swift

Comment thread apps/ade-cli/src/cli.ts
Comment thread apps/ade-cli/src/cli.ts
Comment thread apps/ade-cli/src/cli.ts
Comment thread apps/ade-cli/src/cli.ts
Comment thread apps/ade-cli/src/services/sync/brainProjectActionsSyncHandler.ts
Comment thread apps/ade-cli/src/services/sync/syncHostService.ts
Comment thread apps/ios/ADE/App/RemoteProjectAddSheet.swift
Comment thread apps/ios/ADE/App/RemoteProjectAddSheet.swift
Comment thread apps/ios/ADE/Services/SyncService.swift
@arul28

arul28 commented Jun 15, 2026

Copy link
Copy Markdown
Owner Author

@codex review

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bbc3c5ee0e

ℹ️ About Codex in GitHub

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

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

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

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

Comment on lines +387 to +389
selectedPath = nil
path = parentPath
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Clear stale directory results before changing paths

When the user taps “Go up”, path changes but result still describes the previous directory until the debounced browse request finishes. During that window the primary button’s targetPath is still derived from the stale result, so a quick “Open project”/“Use directory” tap can act on the previous folder while the text field shows the parent. Clear result (or disable the primary action) before updating the path.

Useful? React with 👍 / 👎.

Comment on lines +577 to +579
private var hasGitHubHost: Bool {
guard let host = URL(string: trimmedUrl)?.host?.lowercased() else { return false }
return host == "github.com" || host.hasSuffix(".github.com")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Accept GitHub SSH clone URLs

For the URL clone path, this validation only accepts URLs that URL(string:) gives a host, so the standard GitHub SSH form git@github.com:owner/repo.git keeps the Clone button disabled even though the host-side clone parser accepts that shape. Users with SSH remotes/keys cannot submit an otherwise valid GitHub repository from iOS; mirror the backend/Desktop validation here or defer validation to the host.

Useful? React with 👍 / 👎.

@arul28

arul28 commented Jun 15, 2026

Copy link
Copy Markdown
Owner Author

@codex review

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ffccf6a761

ℹ️ About Codex in GitHub

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

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

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

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

Comment on lines +382 to +385
send(peer.ws, "project_switch_result", {
ok: false,
message: error instanceof Error ? error.message : String(error),
}, envelope.requestId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid double-resolving project switch requests

When the fallback handler has already sent a successful project_switch_result, any exception from completeProjectConnection falls into this catch and sends another project_switch_result with the same request id. In that scenario iOS resolves and removes the pending request on the first response, so it treats the switch as successful while the host activation may have failed and discards the later error; guard this error send once a result has already been delivered, and just log/retry completion instead.

Useful? React with 👍 / 👎.

Comment thread apps/ios/ADE/App/RemoteProjectAddSheet.swift
@arul28

arul28 commented Jun 15, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@arul28

arul28 commented Jun 15, 2026

Copy link
Copy Markdown
Owner Author

@codex review

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f83603ad6a

ℹ️ About Codex in GitHub

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

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

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

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

Comment thread apps/ade-cli/src/cli.ts
const activeScope = await scopeRegistry.resolveActiveSyncHost();
if (activeScope) return activeScope;
if (sharedSyncListener) {
await sharedSyncListener.ensureListening([DEFAULT_SYNC_HOST_PORT]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Guard fallback listener with sync singleton

When no preferred or active project exists, this path still binds the shared phone-sync listener on the default port, but it bypasses the normal sync host startup path that acquires acquireSyncHostSingleton before owning that port. That lets a project-less brain squat on the WebSocket port with no singleton owner; another ADE channel/brain can then acquire the lease and still fail/retry on EADDRINUSE, leaving mobile sync unavailable until the idle brain exits. The fallback listener should acquire the same singleton lease, or avoid binding until it can own it.

Useful? React with 👍 / 👎.

@arul28 arul28 merged commit f6ba358 into main Jun 15, 2026
27 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.

1 participant