Skip to content

Conversation

@ucswift
Copy link
Member

@ucswift ucswift commented Feb 2, 2026

Summary by CodeRabbit

  • New Features

    • Desktop app support for Windows, macOS, and Linux (startup & preload behavior).
    • Web/Electron-friendly CallKeep stub providing no-op/mock call handling for browsers.
  • Chores

    • CI/CD updated to build and publish multi-platform desktop artifacts and streamline release notes.
    • Added Electron build tooling and scripts to project configuration.
    • Added project coding standards/guidelines for mobile/web/React Native development.
    • Removed legacy Bluetooth service exports.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 2, 2026

📝 Walkthrough

Walkthrough

Adds Electron desktop support (main/preload), CI jobs to build and publish Electron artifacts, package.json Electron build/scripts, developer guidelines, a web CallKeep stub, Bluetooth export changes, and a small import fix.

Changes

Cohort / File(s) Summary
Electron runtime
electron/main.js, electron/preload.js
New Electron main and preload scripts: BrowserWindow creation, env-based URL loading, lifecycle handlers, version injection into DOM, and DevTools in development.
CI / Release workflow
.github/workflows/react-native-cicd.yml
Added build-electron matrix job (macos/windows/linux) to build/upload Electron artifacts; added publish-release job to gather artifacts, create RELEASE_NOTES.md, publish GitHub Release, and post notes to Changerawr.
Package config & scripts
package.json
Switched main to electron/main.js; added electron:dev, electron:pack scripts; added electron/electron-builder/electron-is-dev/concurrently/wait-on deps and a top-level build config for electron-builder.
Developer guidelines
.agent/rules/agent.md
New comprehensive guidelines for TypeScript, React Native / Expo, mobile UI/styling, performance, testing, i18n, accessibility, state management, data fetching, and recommended libraries/patterns.
Platform services
src/services/callkeep.service.web.ts, src/services/bluetooth-audio/index.ts
Added web/Electron CallKeep stub with no-op/mocked APIs; removed/commented exports for native/web Bluetooth audio services.
Imports
src/features/livekit-call/store/useLiveKitCallStore.ts
Changed zustand import from default to named export to match library signature.

Sequence Diagram(s)

sequenceDiagram
  participant GH as GitHub Actions
  participant Matrix as Build Runners (macos / windows / linux)
  participant Artifact as Artifact Storage
  participant Release as Release Action
  participant Changerawr as Changerawr API

  GH->>Matrix: start build-electron (matrix job)
  Matrix-->>Artifact: upload dist/electron artifacts
  GH->>GH: wait for build-and-deploy & build-electron
  GH->>Artifact: download all artifacts in publish-release
  GH->>Release: prepare RELEASE_NOTES.md & publish release (attach artifacts)
  Release-->>GH: release published
  GH->>Changerawr: POST release notes
  Changerawr-->>GH: ack
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • RD-T39 Fixing build #72 — Modifies the same CI workflow and overlaps on package.json and bluetooth-audio exports; likely directly related to CI and Bluetooth export changes.

Suggested reviewers

  • github-actions

Poem

🐰 I hopped from branch to branch with glee,
Built little windows for the world to see,
Scripts and notes in tidy rows,
Stubbed a call where the web wind blows,
Desktop blooms — a rabbit's jubilee! 🎉

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
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.
Title check ❓ Inconclusive The title 'Develop' is vague and does not convey any meaningful information about the specific changes in the changeset, which include Electron integration, CI/CD workflow updates, Bluetooth service modifications, and CallKeep service implementation. Provide a descriptive title that captures the main change, such as 'Add Electron desktop app support and CI/CD workflows' or 'Integrate Electron with updated deployment pipeline'.
✅ Passed checks (1 passed)
Check name Status Explanation
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 unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch develop

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In @.agent/rules/agent.md:
- Line 9: Update the guideline sentence in .agent/rules/agent.md to fix typos
and hyphenation: change "mobile application" phrasing to "mobile-friendly"
(hyphenated), remove the repeated "and", ensure platform names are capitalized
as "iOS and Android", and rephrase for clarity to something like "This is a
mobile application, so ensure all components are mobile-friendly, responsive,
and support both iOS and Android platforms; optimize the app for both
platforms." Locate the exact sentence shown in the diff and replace it with the
corrected, hyphenated version.

In @.github/workflows/react-native-cicd.yml:
- Around line 563-569: The build-electron job is missing an explicit permissions
block which leaves GITHUB_TOKEN overly permissive; add a job-level permissions
mapping under the build-electron job (referencing the build-electron job name
and the steps that use secrets.GITHUB_TOKEN) that grants only the minimal scopes
required for your release steps—e.g., set contents: write (and packages: write
if you're publishing packages) and omit other scopes—so the workflow uses least
privilege for release-related actions.
- Around line 600-607: The "🚀 Publish to Release" step (using
ncipollo/release-action@v1) is being executed concurrently by both the
build-and-deploy and build-electron jobs and causes race conditions/422 errors;
fix by removing the release step from per-OS jobs and instead create a single
dedicated publish job (e.g., publish-release) that depends on both
build-and-deploy and build-electron (use needs: [build-and-deploy,
build-electron]), have that job download the artifacts from the other jobs and
run the ncipollo/release-action@v1 step once (with the same tag and
allowUpdates), or alternatively add concurrency protection on the workflow or
add needs: build-and-deploy to build-electron if you prefer simple
serialization—choose one of these approaches and move the "🚀 Publish to
Release" usage into the single coordinating job or serialize jobs to ensure only
one process updates the release tag.

In `@electron/main.js`:
- Around line 9-13: The BrowserWindow webPreferences are insecure for
production; update the webPreferences in the BrowserWindow creation (the
webPreferences object around preload, nodeIntegration, contextIsolation,
webSecurity) to use hardened defaults: set nodeIntegration to false,
contextIsolation to true, and webSecurity to true, and make any relaxed settings
conditional on an environment/dev flag (e.g., only enable
nodeIntegration/contextIsolation=false/webSecurity=false when a clearly-named
isDev or process.env.NODE_ENV === 'development' flag is true). Keep preload.js
as the only renderer→main bridge and ensure the conditional check drives the
three webPreferences values so production builds always use the secure defaults.

In `@package.json`:
- Line 6: Change the package.json "main" field from "electron/main.js" to
"expo-router/entry" to avoid breaking Expo Router's entry resolution, and update
the "electron:dev" npm script to explicitly point to the Electron entry (the
actual Electron bootstrap file, e.g., electron/main.js) so Electron runs the
correct main process file while mobile/web builds use expo-router/entry.
🧹 Nitpick comments (1)
.github/workflows/react-native-cicd.yml (1)

589-607: Release step may fail if no artifacts are produced.

The upload step at line 598 uses if-no-files-found: warn, meaning it won't fail if dist/electron/ contains no artifacts. However, the release step at line 600-607 will still execute and may fail or behave unexpectedly when the artifact globs match nothing.

Consider adding a condition to check if artifacts exist before publishing:

♻️ Proposed fix to conditionally publish
       - name: 📦 Upload build artifacts
         uses: actions/upload-artifact@v4
+        id: upload
         with:
           name: electron-build-${{ matrix.os }}
           path: |
             dist/electron/*.dmg
             dist/electron/*.exe
             dist/electron/*.AppImage
             dist/electron/*.zip
           if-no-files-found: warn

       - name: 🚀 Publish to Release
-        if: github.event_name == 'push' || github.event.inputs.buildType == 'all'
+        if: (github.event_name == 'push' || github.event.inputs.buildType == 'all') && steps.upload.outputs.artifact-id != ''
         uses: ncipollo/release-action@v1

Alternatively, check if files exist before publishing:

      - name: 🔍 Check for artifacts
        id: check-artifacts
        run: |
          if ls dist/electron/*.dmg dist/electron/*.exe dist/electron/*.AppImage dist/electron/*.zip 2>/dev/null; then
            echo "has_artifacts=true" >> $GITHUB_OUTPUT
          else
            echo "has_artifacts=false" >> $GITHUB_OUTPUT
          fi
        shell: bash

- Use functional components and hooks over class components.
- Ensure components are modular, reusable, and maintainable.
- Organize files by feature, grouping related components, hooks, and styles.
- This is a mobile application, so ensure all components are mobile friendly and responsive and support both iOS and Android platforms and ensure that the app is optimized for both platforms.
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix typos/hyphenation in the guidelines text.
Minor wording issues in the doc.

✏️ Suggested edits
-This is a mobile application, so ensure all components are mobile friendly and responsive and support both iOS and Android platforms and ensure that the app is optimized for both platforms.
+This is a mobile application, so ensure all components are mobile-friendly and responsive and support both iOS and Android platforms and ensure that the app is optimized for both platforms.
...
-- The app is multi-lingual, so ensure all text is wrapped in `t()` from `react-i18next` for translations with the dictonary files stored in `src/translations`.
+- The app is multi-lingual, so ensure all text is wrapped in `t()` from `react-i18next` for translations with the dictionary files stored in `src/translations`.

Also applies to: 52-52

🧰 Tools
🪛 LanguageTool

[grammar] ~9-~9: Use a hyphen to join words.
Context: ...ion, so ensure all components are mobile friendly and responsive and support both...

(QB_NEW_EN_HYPHEN)

🤖 Prompt for AI Agents
In @.agent/rules/agent.md at line 9, Update the guideline sentence in
.agent/rules/agent.md to fix typos and hyphenation: change "mobile application"
phrasing to "mobile-friendly" (hyphenated), remove the repeated "and", ensure
platform names are capitalized as "iOS and Android", and rephrase for clarity to
something like "This is a mobile application, so ensure all components are
mobile-friendly, responsive, and support both iOS and Android platforms;
optimize the app for both platforms." Locate the exact sentence shown in the
diff and replace it with the corrected, hyphenated version.

"versionCode": "1",
"private": true,
"main": "expo-router/entry",
"main": "electron/main.js",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cd /repo && pwd && git ls-files | head -20

Repository: Resgrid/Dispatch

Length of output: 115


🏁 Script executed:

cat -n package.json

Repository: Resgrid/Dispatch

Length of output: 13523


🏁 Script executed:

fd -type f -name "app.json" -o -name "eas.json" -o -name "expo.config.*"

Repository: Resgrid/Dispatch

Length of output: 230


🏁 Script executed:

rg -l "entry|main" --type json | head -10

Repository: Resgrid/Dispatch

Length of output: 147


🌐 Web query:

Expo package.json main field entry point resolution

💡 Result:

In Expo, the app’s bundle entry module is taken from the project’s package.json main field (relative to the project root). If you change main, you’re changing what Metro starts bundling. [1]

What main should be

  • Expo Router projects: set
    { "main": "expo-router/entry" }
    (or point main to your own index.js that imports expo-router/entry last). [2]
  • Non–Expo Router projects: main can point to any file, but that file must call registerRootComponent(...) (otherwise your exported component won’t become the root). [1]

How resolution actually happens (why main can seem “ignored”)

Metro doesn’t always use main first. It resolves a package entry by checking package.json fields in order defined by resolverMainFields, whose default is ['browser', 'main']. So if something provides a browser field, Metro will prefer that over main. You can override this in metro.config.js. [3]

Sources: Expo docs on custom entry files [1], Expo Router installation / entrypoint [2], Metro resolver resolverMainFields behavior [3].


Update main field to avoid breaking Expo Router bundling.

Setting main to electron/main.js breaks Expo Router's entry point resolution. Since this project still supports mobile and web builds, the main field must point to expo-router/entry. Update the electron:dev script to explicitly reference the Electron main file:

Required changes
-  "main": "electron/main.js",
+  "main": "expo-router/entry",
   
   "scripts": {
-    "electron:dev": "concurrently \"cross-env BROWSER=none yarn web\" \"wait-on http://localhost:8081 && electron .\"",
+    "electron:dev": "concurrently \"cross-env BROWSER=none yarn web\" \"wait-on http://localhost:8081 && electron electron/main.js\"",
🤖 Prompt for AI Agents
In `@package.json` at line 6, Change the package.json "main" field from
"electron/main.js" to "expo-router/entry" to avoid breaking Expo Router's entry
resolution, and update the "electron:dev" npm script to explicitly point to the
Electron entry (the actual Electron bootstrap file, e.g., electron/main.js) so
Electron runs the correct main process file while mobile/web builds use
expo-router/entry.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @.github/workflows/react-native-cicd.yml:
- Around line 476-487: The job permissions are missing actions: read which is
required by the actions/download-artifact@v4 step; update the job permissions
block (the permissions mapping used by the workflow) to include actions: read in
addition to contents: write so the Download all artifacts step can list and
fetch artifacts successfully when using actions/download-artifact@v4.
- Around line 439-470: The workflow's permissions block lacks the Actions scope
required by actions/upload-artifact; update the top-level permissions (where
permissions: contents: write packages: write is defined) to include actions:
write so artifact uploads won't fail with "Resource not accessible by
integration"—add actions: write alongside the existing permissions entries to
grant the upload-artifact step the required permission.

Comment on lines +476 to +487
permissions:
contents: write
steps:
- name: 🏗 Checkout repository
uses: actions/checkout@v4

- name: 📦 Download all artifacts
uses: actions/download-artifact@v4
with:
path: ./artifacts
merge-multiple: true

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

actions/download-artifact@v4 permissions requirements

💡 Result:

For actions/download-artifact@v4, the permission requirement depends on what you’re downloading:

  • Downloading artifacts from the same repo + same workflow run (default behavior):
    You typically don’t need to add anything unless you’ve restricted the job/workflow GITHUB_TOKEN permissions. The action uses the token’s ability to read Actions artifacts, so ensure the token isn’t missing Actions read.

  • If you set explicit/restricted permissions: add:

    permissions:
      actions: read

    (Otherwise the action may fail to list/download artifacts.) [1][2]

  • Downloading artifacts from a different repo or a different workflow run:
    You must pass github-token: and that token must have Actions (read) permission on the target repository. The action’s README calls this out explicitly. [1]
    For GitHub REST access to artifacts, fine-grained tokens need Actions: read; for private repos, classic PATs generally need repo. [2]

Example (cross-repo / cross-run):

permissions:
  actions: read

steps:
  - uses: actions/download-artifact@v4
    with:
      github-token: ${{ secrets.GH_PAT }} # must have actions:read on target repo
      repository: org/other-repo
      run-id: 123456789
      name: my-artifact

[1][2]


Add actions: read for artifact download.

actions/download-artifact@v4 requires actions: read permission when the job has explicit restricted permissions. With only contents: write set, the download step will fail to list or fetch artifacts.

🔧 Proposed fix
     permissions:
       contents: write
+      actions: read
🤖 Prompt for AI Agents
In @.github/workflows/react-native-cicd.yml around lines 476 - 487, The job
permissions are missing actions: read which is required by the
actions/download-artifact@v4 step; update the job permissions block (the
permissions mapping used by the workflow) to include actions: read in addition
to contents: write so the Download all artifacts step can list and fetch
artifacts successfully when using actions/download-artifact@v4.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.github/workflows/react-native-cicd.yml:
- Around line 483-487: The electron artifacts are being uploaded with their
dist/electron/ prefix so download-artifact@v4 with merge-multiple writes them
into artifacts/dist/electron/*.dmg, but the release step expects
artifacts/*.dmg; update the upload step in the build-electron job (the
actions/upload-artifact invocation that uploads electron outputs) to flatten the
archive by uploading the directory contents rather than the parent folder — e.g.
change the uploaded path from the directory (dist/electron) to a glob that
matches files inside (dist/electron/*) or otherwise configure upload-artifact to
preserve only filenames so downloaded artifacts land at artifacts/*.dmg and the
release action's globs will match.

Comment on lines +483 to +487
- name: 📦 Download all artifacts
uses: actions/download-artifact@v4
with:
path: ./artifacts
merge-multiple: true
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's check the workflow file structure and locate the build-electron job
cat -n .github/workflows/react-native-cicd.yml | head -100

Repository: Resgrid/Dispatch

Length of output: 4170


🏁 Script executed:

# Find the build-electron job and its artifact upload configuration
rg -n "build-electron" .github/workflows/react-native-cicd.yml -A 50 | head -80

Repository: Resgrid/Dispatch

Length of output: 3063


🏁 Script executed:

# Check the upload-artifact configuration in the build-electron job
rg -n "upload-artifact" .github/workflows/react-native-cicd.yml -B 2 -A 5

Repository: Resgrid/Dispatch

Length of output: 613


🏁 Script executed:

# Check the release job to see what artifact paths it expects
rg -n "artifacts glob" .github/workflows/react-native-cicd.yml -B 5 -A 5

Repository: Resgrid/Dispatch

Length of output: 42


🏁 Script executed:

# Look for any artifact glob patterns in the release step
rg -n "artifacts/" .github/workflows/react-native-cicd.yml -B 2 -A 2

Repository: Resgrid/Dispatch

Length of output: 398


🏁 Script executed:

# Search for any GitHub Actions documentation or comments about merge-multiple behavior
rg -i "merge-multiple\|path.*structure\|directory.*preserve" .github/workflows/react-native-cicd.yml -B 2 -A 2

Repository: Resgrid/Dispatch

Length of output: 42


🏁 Script executed:

# Check if there are any other download-artifact steps or artifact handling logic
rg -n "download-artifact\|upload-artifact" .github/workflows/react-native-cicd.yml -B 1 -A 8

Repository: Resgrid/Dispatch

Length of output: 42


🏁 Script executed:

# Check if there's a .nojekyll, script, or documentation about how this workflow handles artifacts
find . -name "*.md" -o -name "*.txt" | xargs grep -l "electron\|artifact" 2>/dev/null | head -10

Repository: Resgrid/Dispatch

Length of output: 42


🏁 Script executed:

# Look for any recent changes or comments about artifact paths
git log --oneline --all -- .github/workflows/react-native-cicd.yml | head -20

Repository: Resgrid/Dispatch

Length of output: 184


🏁 Script executed:

# Check GitHub Actions documentation online for merge-multiple behavior
web_search

Repository: Resgrid/Dispatch

Length of output: 110


🌐 Web query:

GitHub Actions upload-artifact download-artifact merge-multiple directory structure preservation behavior

💡 Result:

  • What gets preserved on upload (actions/upload-artifact): the artifact stores files with their relative paths, with the artifact “root” determined by:

    • Multiple path: entries → GitHub uses the least common ancestor (LCA) of the matched paths as the root of the artifact.
    • Globs → path hierarchy is preserved after the first wildcard (so parts before the first */?/[] are not kept). [1]
  • What happens on download (actions/download-artifact) when multiple artifacts are selected (via pattern, no name, etc.):

    • Default (merge-multiple: false): each artifact is extracted into its own subdirectory named after the artifact under path. [2]
    • With merge-multiple: true: all selected artifacts are extracted into the same path directory, i.e., their internal directory trees are overlaid/merged. [2][3]
    • Collision behavior: if two artifacts contain the same relative file path, the later-extracted one can overwrite the earlier one (so avoid identical paths unless you want last-wins). [2]
  • Practical implication: merge-multiple does not “recreate a per-artifact folder”; it simply controls whether GitHub adds that extra top-level directory per artifact. The internal structure from upload is preserved either way—just either under path/<artifact-name>/... or directly under path/.... [1][2]


Fix artifact paths: electron builds won't be found by release action.

The build-electron job uploads artifacts from dist/electron/* paths. Due to how GitHub Actions handles glob patterns, the dist/electron/ prefix is preserved in the artifact storage. When download-artifact@v4 downloads with merge-multiple: true to ./artifacts, the files end up at artifacts/dist/electron/*.dmg (and similarly for .exe, .AppImage, .zip). However, the release action's glob patterns on line 561 expect files directly at artifacts/*.dmg—this mismatch causes the release step to fail and skip electron build artifacts.

Fix by updating the upload step to avoid nested directory storage:

🔧 Solution: Flatten upload paths
       - name: 📦 Upload build artifacts
         uses: actions/upload-artifact@v4
         with:
           name: electron-build-${{ matrix.os }}
           path: dist/electron/
           if-no-files-found: warn

This uploads the directory contents directly without preserving the dist/electron/ prefix, so files will be at artifacts/*.dmg as expected by the release action.

🤖 Prompt for AI Agents
In @.github/workflows/react-native-cicd.yml around lines 483 - 487, The electron
artifacts are being uploaded with their dist/electron/ prefix so
download-artifact@v4 with merge-multiple writes them into
artifacts/dist/electron/*.dmg, but the release step expects artifacts/*.dmg;
update the upload step in the build-electron job (the actions/upload-artifact
invocation that uploads electron outputs) to flatten the archive by uploading
the directory contents rather than the parent folder — e.g. change the uploaded
path from the directory (dist/electron) to a glob that matches files inside
(dist/electron/*) or otherwise configure upload-artifact to preserve only
filenames so downloaded artifacts land at artifacts/*.dmg and the release
action's globs will match.

@ucswift
Copy link
Member Author

ucswift commented Feb 2, 2026

Approve

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

This PR is approved.

@ucswift ucswift merged commit e71306c into master Feb 2, 2026
11 of 12 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Feb 5, 2026
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