diff --git a/.codex/environments/environment.toml b/.codex/environments/environment.toml index 23e3d526df..77ce37f058 100644 --- a/.codex/environments/environment.toml +++ b/.codex/environments/environment.toml @@ -1,6 +1,6 @@ # THIS IS AUTOGENERATED. DO NOT EDIT MANUALLY version = 1 -name = "CodexMonitor" +name = "OpenCodeMonitor" [setup] script = "npm install" diff --git a/.codex/skills/app-server-events-sync/SKILL.md b/.codex/skills/app-server-events-sync/SKILL.md index 995d752ba7..59b240b140 100644 --- a/.codex/skills/app-server-events-sync/SKILL.md +++ b/.codex/skills/app-server-events-sync/SKILL.md @@ -1,11 +1,11 @@ --- name: app-server-events-sync -description: Maintain CodexMonitor and Codex app-server protocol parity. Use when asked to audit supported or missing app-server notifications/requests, trace event routing, diagnose schema drift in app-server payloads, or update docs/app-server-events.md after upstream Codex changes. +description: Maintain OpenCodeMonitor and OpenCode app-server protocol parity. Use when asked to audit supported or missing app-server notifications/requests, trace event routing, diagnose schema drift in app-server payloads, or update docs/app-server-events.md after upstream OpenCode changes. --- # App-Server Events Sync -Use this skill to keep CodexMonitor app-server integration accurate as `../Codex` evolves. +Use this skill to keep OpenCodeMonitor app-server integration accurate as `../OpenCode` evolves. ## Canonical Source @@ -20,11 +20,11 @@ Treat that file as the canonical runbook and update it when behavior changes. - Read Codex hash from `../Codex` and update the hash in `docs/app-server-events.md` title. 2. Compare notification methods: -- Diff Codex v2 notification method set against CodexMonitor routing in `src/utils/appServerEvents.ts` and `src/features/app/hooks/useAppServerEvents.ts`. +- Diff OpenCode v2 notification method set against OpenCodeMonitor routing in `src/utils/appServerEvents.ts` and `src/features/app/hooks/useAppServerEvents.ts`. - Update `Supported Events` and `Missing Events` sections in `docs/app-server-events.md`. 3. Compare request methods: -- Diff Codex v2 client/server request sets against CodexMonitor outgoing and inbound handling. +- Diff OpenCode v2 client/server request sets against OpenCodeMonitor outgoing and inbound handling. - Update `Supported Requests`, `Missing Client Requests`, and `Server Requests` sections. 4. Investigate schema drift when lists look unchanged: @@ -51,8 +51,8 @@ Treat that file as the canonical runbook and update it when behavior changes. - Item/turn handlers: `src/features/threads/hooks/useThreadItemEvents.ts`, `src/features/threads/hooks/useThreadTurnEvents.ts` - Normalization: `src/features/threads/utils/threadNormalize.ts` - State: `src/features/threads/hooks/useThreadsReducer.ts` -- Outgoing requests: `src/services/tauri.ts`, `src-tauri/src/shared/codex_core.rs` -- Daemon RPC: `src-tauri/src/bin/codex_monitor_daemon/rpc.rs` and `rpc/*` +- Outgoing requests: `src/services/tauri.ts`, `src-tauri/src/shared/opencode_core.rs` +- Daemon RPC: `src-tauri/src/bin/opencode_monitor_daemon/rpc.rs` and `rpc/*` ## References diff --git a/.codex/skills/app-server-events-sync/references/quick-commands.md b/.codex/skills/app-server-events-sync/references/quick-commands.md index 170cb842d9..52f3103cb1 100644 --- a/.codex/skills/app-server-events-sync/references/quick-commands.md +++ b/.codex/skills/app-server-events-sync/references/quick-commands.md @@ -20,7 +20,7 @@ rg -n "SUPPORTED_APP_SERVER_METHODS" src/utils/appServerEvents.ts ```bash awk '/client_request_definitions! \{/,/\/\/\/ DEPRECATED APIs below/' ../Codex/codex-rs/app-server-protocol/src/protocol/common.rs | rg -N -o '=>\s*"[^"]+"\s*\{' | sed -E 's/.*"([^"]+)".*/\1/' | sort -u awk '/server_request_definitions! \{/,/\/\/\/ DEPRECATED APIs below/' ../Codex/codex-rs/app-server-protocol/src/protocol/common.rs | rg -N -o '=>\s*"[^"]+"\s*\{' | sed -E 's/.*"([^"]+)".*/\1/' | sort -u -perl -0777 -ne 'while(/send_request_for_workspace\(\s*&[^,]+\s*,\s*"([^"]+)"/g){print "$1\n"}' src-tauri/src/shared/codex_core.rs | sort -u +perl -0777 -ne 'while(/send_request_for_workspace\(\s*&[^,]+\s*,\s*"([^"]+)"/g){print "$1\n"}' src-tauri/src/shared/opencode_core.rs | sort -u ``` ## Schema Drift diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 856e0a9a67..72bde2d002 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -64,37 +64,25 @@ jobs: security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "" "$KEYCHAIN" - name: Configure notarytool credentials - env: - APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} - APPLE_API_ISSUER_ID: ${{ secrets.APPLE_API_ISSUER_ID }} - APPLE_API_PRIVATE_KEY_B64: ${{ secrets.APPLE_API_PRIVATE_KEY_B64 }} - run: | - set -euo pipefail - mkdir -p private_keys - echo "$APPLE_API_PRIVATE_KEY_B64" | base64 --decode > private_keys/AuthKey.p8 - xcrun notarytool store-credentials "$NOTARY_PROFILE_NAME" \ - --key-id "$APPLE_API_KEY_ID" \ - --issuer "$APPLE_API_ISSUER_ID" \ - --key "private_keys/AuthKey.p8" - name: Write Tauri signing key run: | set -euo pipefail mkdir -p "$HOME/.tauri" - echo "$TAURI_SIGNING_PRIVATE_KEY_B64" | base64 --decode > "$HOME/.tauri/codexmonitor.key" + echo "$TAURI_SIGNING_PRIVATE_KEY_B64" | base64 --decode > "$HOME/.tauri/opencode-monitor.key" - name: Build app bundle run: | set -euo pipefail export TAURI_SIGNING_PRIVATE_KEY - TAURI_SIGNING_PRIVATE_KEY="$(cat "$HOME/.tauri/codexmonitor.key")" + TAURI_SIGNING_PRIVATE_KEY="$(cat "$HOME/.tauri/opencode-monitor.key")" npm run tauri -- build --bundles app - name: Build daemon binaries run: | set -euo pipefail cd src-tauri - cargo build --release --bin codex_monitor_daemon --bin codex_monitor_daemonctl + cargo build --release --bin opencode_monitor_daemon --bin opencode_monitor_daemonctl - name: Bundle OpenSSL and re-sign run: | @@ -106,15 +94,15 @@ jobs: run: | set -euo pipefail ditto -c -k --keepParent \ - "src-tauri/target/release/bundle/macos/Codex Monitor.app" \ - CodexMonitor.zip + "src-tauri/target/release/bundle/macos/OpenCode Monitor.app" \ + OpenCodeMonitor.zip - xcrun notarytool submit CodexMonitor.zip \ + xcrun notarytool submit OpenCodeMonitor.zip \ --keychain-profile "$NOTARY_PROFILE_NAME" \ --wait xcrun stapler staple \ - "src-tauri/target/release/bundle/macos/Codex Monitor.app" + "src-tauri/target/release/bundle/macos/OpenCode Monitor.app" - name: Package artifacts run: | @@ -129,42 +117,42 @@ jobs: ) mkdir -p release-artifacts release-artifacts/dmg-root - rm -rf "release-artifacts/dmg-root/Codex Monitor.app" - ditto "src-tauri/target/release/bundle/macos/Codex Monitor.app" \ - "release-artifacts/dmg-root/Codex Monitor.app" + rm -rf "release-artifacts/dmg-root/OpenCode Monitor.app" + ditto "src-tauri/target/release/bundle/macos/OpenCode Monitor.app" \ + "release-artifacts/dmg-root/OpenCode Monitor.app" ditto -c -k --keepParent \ - "src-tauri/target/release/bundle/macos/Codex Monitor.app" \ - release-artifacts/CodexMonitor.zip + "src-tauri/target/release/bundle/macos/OpenCode Monitor.app" \ + release-artifacts/OpenCodeMonitor.zip - hdiutil create -volname "Codex Monitor" \ + hdiutil create -volname "OpenCode Monitor" \ -srcfolder release-artifacts/dmg-root \ -ov -format UDZO \ - release-artifacts/CodexMonitor_${VERSION}_aarch64.dmg + release-artifacts/OpenCodeMonitor_${VERSION}_aarch64.dmg COPYFILE_DISABLE=1 tar -czf \ - "src-tauri/target/release/bundle/macos/Codex Monitor.app.tar.gz" \ - -C src-tauri/target/release/bundle/macos "Codex Monitor.app" + "src-tauri/target/release/bundle/macos/OpenCode Monitor.app.tar.gz" \ + -C src-tauri/target/release/bundle/macos "OpenCode Monitor.app" npm run tauri signer sign -- \ - -f "$HOME/.tauri/codexmonitor.key" \ + -f "$HOME/.tauri/opencode-monitor.key" \ -p "$TAURI_SIGNING_PRIVATE_KEY_PASSWORD" \ - "src-tauri/target/release/bundle/macos/Codex Monitor.app.tar.gz" + "src-tauri/target/release/bundle/macos/OpenCode Monitor.app.tar.gz" - cp "src-tauri/target/release/bundle/macos/Codex Monitor.app.tar.gz" \ - release-artifacts/CodexMonitor.app.tar.gz - cp "src-tauri/target/release/bundle/macos/Codex Monitor.app.tar.gz.sig" \ - release-artifacts/CodexMonitor.app.tar.gz.sig + cp "src-tauri/target/release/bundle/macos/OpenCode Monitor.app.tar.gz" \ + release-artifacts/OpenCodeMonitor.app.tar.gz + cp "src-tauri/target/release/bundle/macos/OpenCode Monitor.app.tar.gz.sig" \ + release-artifacts/OpenCodeMonitor.app.tar.gz.sig - name: Upload macOS artifacts uses: actions/upload-artifact@v4 with: name: macos-artifacts path: | - release-artifacts/CodexMonitor.zip - release-artifacts/CodexMonitor_*_aarch64.dmg - release-artifacts/CodexMonitor.app.tar.gz - release-artifacts/CodexMonitor.app.tar.gz.sig + release-artifacts/OpenCodeMonitor.zip + release-artifacts/OpenCodeMonitor_*_aarch64.dmg + release-artifacts/OpenCodeMonitor.app.tar.gz + release-artifacts/OpenCodeMonitor.app.tar.gz.sig build_linux: name: linux bundles (${{ matrix.arch }}) @@ -210,13 +198,13 @@ jobs: run: | set -euo pipefail mkdir -p "$HOME/.tauri" - echo "$TAURI_SIGNING_PRIVATE_KEY_B64" | base64 --decode > "$HOME/.tauri/codexmonitor.key" + echo "$TAURI_SIGNING_PRIVATE_KEY_B64" | base64 --decode > "$HOME/.tauri/opencode-monitor.key" - name: build AppImage and RPM run: | set -euo pipefail export TAURI_SIGNING_PRIVATE_KEY - TAURI_SIGNING_PRIVATE_KEY="$(cat "$HOME/.tauri/codexmonitor.key")" + TAURI_SIGNING_PRIVATE_KEY="$(cat "$HOME/.tauri/opencode-monitor.key")" npm run tauri -- build --bundles appimage,rpm - name: Validate Linux bundle outputs @@ -288,7 +276,7 @@ jobs: home = Path.home() target = home / ".tauri" target.mkdir(parents=True, exist_ok=True) - (target / "codexmonitor.key").write_bytes(raw) + (target / "opencode-monitor.key").write_bytes(raw) PY - name: build windows bundles @@ -296,7 +284,7 @@ jobs: run: | set -euo pipefail export TAURI_SIGNING_PRIVATE_KEY - TAURI_SIGNING_PRIVATE_KEY="$(cat "$HOME/.tauri/codexmonitor.key")" + TAURI_SIGNING_PRIVATE_KEY="$(cat "$HOME/.tauri/opencode-monitor.key")" npm run tauri:build:win - name: Upload Windows artifacts @@ -386,7 +374,7 @@ jobs: PY ) - SIGNATURE=$(cat release-artifacts/CodexMonitor.app.tar.gz.sig) + SIGNATURE=$(cat release-artifacts/OpenCodeMonitor.app.tar.gz.sig) LAST_TAG=$(git tag --sort=-version:refname \ | grep -v "^v${VERSION}$" \ | head -n 1 || true) @@ -444,11 +432,11 @@ jobs: artifacts_dir = Path("release-artifacts") def release_url(filename): - return f"https://github.com/Dimillian/CodexMonitor/releases/download/v${VERSION}/{quote(filename)}" + return f"https://github.com/Dimillian/OpenCodeMonitor/releases/download/v${VERSION}/{quote(filename)}" platforms = { "darwin-aarch64": { - "url": release_url("CodexMonitor.app.tar.gz"), + "url": release_url("OpenCodeMonitor.app.tar.gz"), "signature": "${SIGNATURE}", } } @@ -484,7 +472,7 @@ jobs: preferred_installers = [] for candidate in exe_candidates: lowered = candidate.name.lower() - if "codexmonitor" in lowered and ("setup" in lowered or "installer" in lowered): + if "opencode-monitor" in lowered and ("setup" in lowered or "installer" in lowered): preferred_installers.append(candidate) if preferred_installers: windows_installer = preferred_installers[0] @@ -588,10 +576,10 @@ jobs: --title "v${VERSION}" \ --notes-file release-artifacts/release-notes.md \ --target "$GITHUB_SHA" \ - release-artifacts/CodexMonitor.zip \ - release-artifacts/CodexMonitor_*_aarch64.dmg \ - release-artifacts/CodexMonitor.app.tar.gz \ - release-artifacts/CodexMonitor.app.tar.gz.sig \ + release-artifacts/OpenCodeMonitor.zip \ + release-artifacts/OpenCodeMonitor_*_aarch64.dmg \ + release-artifacts/OpenCodeMonitor.app.tar.gz \ + release-artifacts/OpenCodeMonitor.app.tar.gz.sig \ "${appimages[@]}" \ "${rpms[@]}" \ "${windows_exes[@]}" \ @@ -664,13 +652,13 @@ jobs: path = Path("src-tauri/Cargo.lock") content = path.read_text() content, count = re.subn( - r'(?ms)(\[\[package\]\]\nname = "codex-monitor"\nversion = ")[^"]+(")', + r'(?ms)(\[\[package\]\]\nname = "opencode-monitor"\nversion = ")[^"]+(")', r'\g<1>$NEXT_VERSION\2', content, count=1, ) if count != 1: - raise SystemExit("Failed to update codex-monitor version in src-tauri/Cargo.lock") + raise SystemExit("Failed to update opencode-monitor version in src-tauri/Cargo.lock") path.write_text(content) PY @@ -678,19 +666,9 @@ jobs: import plistlib from pathlib import Path - path = Path("src-tauri/gen/apple/codex-monitor_iOS/Info.plist") - with path.open("rb") as f: - data = plistlib.load(f) - - data["CFBundleShortVersionString"] = "$NEXT_VERSION" - data["CFBundleVersion"] = "$NEXT_VERSION" - - with path.open("wb") as f: - plistlib.dump(data, f, sort_keys=False) - PY + path = Path("src-tauri/gen/apple/opencode-monitor_iOS/Info.plist") - git checkout -b "chore/bump-version-${NEXT_VERSION}" - git add package.json package-lock.json src-tauri/Cargo.toml src-tauri/Cargo.lock src-tauri/tauri.conf.json src-tauri/gen/apple/codex-monitor_iOS/Info.plist + git add package.json package-lock.json src-tauri/Cargo.toml src-tauri/Cargo.lock src-tauri/tauri.conf.json src-tauri/gen/apple/opencode-monitor_iOS/Info.plist git commit -m "chore: bump version to ${NEXT_VERSION}" git push origin "chore/bump-version-${NEXT_VERSION}" diff --git a/AGENTS.md b/AGENTS.md index a0f61dae52..44817d14f3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,4 +1,4 @@ -# CodexMonitor Agent Guide +# OpenCodeMonitor Agent Guide All docs must be canonical, with no past commentary, only live state. @@ -8,16 +8,16 @@ This file is the agent contract for how to work in this repo. Detailed navigation/runbooks live in: - `docs/codebase-map.md` (task-oriented file map: "if you need X, edit Y") -- `docs/multi-agent-sync-runbook.md` (upstream `../Codex` sync checklist for multi-agent/config behavior) +- `docs/multi-agent-sync-runbook.md` (upstream `../OpenCode` sync checklist for multi-agent/config behavior) - `README.md` (setup, build, release, and broader project docs) ## Project Snapshot -CodexMonitor is a Tauri app that orchestrates Codex agents across local workspaces. +OpenCodeMonitor is a Tauri app that orchestrates OpenCode agents across local workspaces. - Frontend: React + Vite (`src/`) - Backend app: Tauri Rust process (`src-tauri/src/lib.rs`) -- Backend daemon: JSON-RPC process (`src-tauri/src/bin/codex_monitor_daemon.rs`) +- Backend daemon: JSON-RPC process (`src-tauri/src/bin/opencode_monitor_daemon.rs`) - Shared backend source of truth: `src-tauri/src/shared/*` ## Non-Negotiable Architecture Rules @@ -35,7 +35,7 @@ For backend behavior changes, follow this order: 1. Shared core (`src-tauri/src/shared/*`) when behavior is cross-runtime. 2. App adapter and Tauri command surface (`src-tauri/src/lib.rs` + adapter module). 3. Frontend IPC wrapper (`src/services/tauri.ts`). -4. Daemon RPC surface (`src-tauri/src/bin/codex_monitor_daemon/rpc.rs` + `rpc/*`). +4. Daemon RPC surface (`src-tauri/src/bin/opencode_monitor_daemon/rpc.rs` + `rpc/*`). If you add a backend command, update all relevant layers and tests. @@ -67,8 +67,8 @@ Use project aliases for frontend imports: - Frontend IPC wrapper: `src/services/tauri.ts` - Frontend event hub: `src/services/events.ts` - App command registry: `src-tauri/src/lib.rs` -- Daemon entrypoint: `src-tauri/src/bin/codex_monitor_daemon.rs` -- Daemon RPC router: `src-tauri/src/bin/codex_monitor_daemon/rpc.rs` +- Daemon entrypoint: `src-tauri/src/bin/opencode_monitor_daemon.rs` +- Daemon RPC router: `src-tauri/src/bin/opencode_monitor_daemon/rpc.rs` - Shared workspaces core: `src-tauri/src/shared/workspaces_core.rs` + `src-tauri/src/shared/workspaces_core/*` - Shared git UI core: `src-tauri/src/shared/git_ui_core.rs` + `src-tauri/src/shared/git_ui_core/*` - Threads reducer entrypoint: `src/features/threads/hooks/useThreadsReducer.ts` @@ -160,7 +160,7 @@ Use extra care in high-churn/high-complexity files: - `src/features/threads/hooks/useThreadsReducer.ts` - `src-tauri/src/shared/git_ui_core.rs` - `src-tauri/src/shared/workspaces_core.rs` -- `src-tauri/src/bin/codex_monitor_daemon/rpc.rs` +- `src-tauri/src/bin/opencode_monitor_daemon/rpc.rs` ## Canonical References diff --git a/README.md b/README.md index 8b21f43dd8..dd13d7cf7e 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,19 @@ -# CodexMonitor +# OpenCodeMonitor -[![gitcgr](https://gitcgr.com/badge/Dimillian/CodexMonitor.svg)](https://gitcgr.com/Dimillian/CodexMonitor) +[![gitcgr](https://gitcgr.com/badge/Dimillian/OpenCodeMonitor.svg)](https://gitcgr.com/Dimillian/OpenCodeMonitor) -![CodexMonitor](screenshot.png) +![OpenCodeMonitor](screenshot.png) -CodexMonitor is a Tauri app for orchestrating multiple Codex agents across local workspaces. It provides a sidebar to manage projects, a home screen for quick actions, and a conversation view backed by the Codex app-server protocol. +OpenCodeMonitor is a Tauri app for orchestrating multiple OpenCode agents across local workspaces. It provides a sidebar to manage projects, a home screen for quick actions, and a conversation view backed by the OpenCode app-server protocol. ## Features ### Workspaces & Threads - Add and persist workspaces, group/sort them, and jump into recent agent activity from the home dashboard. -- Spawn one `codex app-server` per workspace, resume threads, and track unread/running state. -- Worktree and clone agents for isolated work; worktrees live under the app data directory (legacy `.codex-worktrees` supported). -- Thread management: pin/rename/archive/copy, per-thread drafts, and stop/interrupt in-flight turns. -- Optional remote backend (daemon) mode for running Codex on another machine. +- Spawn one `opencode app-server` per workspace, resume threads, and track unread/running state. +- Worktree and clone agents for isolated work; worktrees live under the app data directory (legacy `.opencode-worktrees` supported). +- Optional remote backend (daemon) mode for running OpenCode on another machine. - Remote setup helpers for self-hosted connectivity (Tailscale detection/host bootstrap for TCP mode). ### Composer & Agent Controls @@ -52,7 +51,7 @@ CodexMonitor is a Tauri app for orchestrating multiple Codex agents across local - Rust toolchain (stable) - CMake (required for native dependencies; dictation/Whisper uses it) - LLVM/Clang (required on Windows to build dictation dependencies via bindgen) -- Codex CLI installed and available as `codex` in `PATH` (or configure a custom Codex binary in app/workspace settings) +- OpenCode CLI installed and available as `opencode` in `PATH` (or configure a custom OpenCode binary in app/workspace settings) - Git CLI (used for worktree operations) - GitHub CLI (`gh`) for GitHub Issues/PR integrations (optional) @@ -90,11 +89,9 @@ Use this when connecting the iOS app to a desktop-hosted daemon over your Tailsc Canonical runbook: `docs/mobile-ios-tailscale-blueprint.md`. 1. Install and sign in to Tailscale on both desktop and iPhone (same tailnet). -2. On desktop CodexMonitor, open `Settings > Server`. -3. Set a `Remote backend token`. -4. Start the desktop daemon with `Start daemon` (in `Mobile access daemon`). -5. In `Tailscale helper`, use `Detect Tailscale` and note the suggested host (for example `your-mac.your-tailnet.ts.net:4732`). -6. On iOS CodexMonitor, open `Settings > Server`. +2. On desktop OpenCodeMonitor, open `Settings > Server`. + +6. On iOS OpenCodeMonitor, open `Settings > Server`. 7. Enter the desktop Tailscale host and the same token. 8. Tap `Connect & test` and confirm it succeeds. @@ -111,23 +108,20 @@ Build binaries: ```bash cd src-tauri -cargo build --bin codex_monitor_daemon --bin codex_monitor_daemonctl + cargo build --bin opencode_monitor_daemon --bin opencode_monitor_daemonctl ``` Examples: ```bash # Show current daemon status -./target/debug/codex_monitor_daemonctl status + ./target/debug/opencode_monitor_daemonctl status -# Start daemon using host/token from settings.json -./target/debug/codex_monitor_daemonctl start + ./target/debug/opencode_monitor_daemonctl start -# Stop daemon -./target/debug/codex_monitor_daemonctl stop + ./target/debug/opencode_monitor_daemonctl stop -# Print equivalent daemon start command -./target/debug/codex_monitor_daemonctl command-preview + ./target/debug/opencode_monitor_daemonctl command-preview ``` Useful overrides: @@ -135,7 +129,7 @@ Useful overrides: - `--data-dir `: app data dir containing `settings.json` / `workspaces.json` - `--listen `: bind address override - `--token `: token override -- `--daemon-path `: explicit `codex-monitor-daemon` binary path +- `--daemon-path `: explicit `opencode-monitor-daemon` binary path - `--json`: machine-readable output ### iOS Prerequisites @@ -276,13 +270,13 @@ src/ types.ts shared types src-tauri/ src/lib.rs Tauri app backend command registry - src/bin/codex_monitor_daemon.rs remote daemon JSON-RPC process - src/bin/codex_monitor_daemon/rpc/ daemon RPC domain handlers + src/bin/opencode_monitor_daemon.rs remote daemon JSON-RPC process + src/bin/opencode_monitor_daemon/rpc/ daemon RPC domain handlers src/shared/ shared backend core used by app + daemon src/shared/git_ui_core/ git/github shared core modules src/shared/workspaces_core/ workspace/worktree shared core modules src/workspaces/ workspace/worktree adapters - src/codex/ codex app-server adapters + src/opencode/ opencode app-server adapters src/files/ file adapters tauri.conf.json window configuration ``` @@ -290,28 +284,28 @@ src-tauri/ ## Notes - Workspaces persist to `workspaces.json` under the app data directory. -- App settings persist to `settings.json` under the app data directory (theme, backend mode/provider, remote endpoints/tokens, Codex path, default access mode, UI scale, follow-up message behavior). -- Feature settings are supported in the UI and synced to `$CODEX_HOME/config.toml` (or `~/.codex/config.toml`) on load/save. Stable: Collaboration modes (`features.collaboration_modes`), personality (`personality`), and Background terminal (`features.unified_exec`). Experimental: Apps (`features.apps`). Steering capability still follows Codex `features.steer`, but follow-up default behavior is controlled in Settings → Composer. +- App settings persist to `settings.json` under the app data directory (theme, backend mode/provider, remote endpoints/tokens, OpenCode path, default access mode, UI scale, follow-up message behavior). +- Feature settings are supported in the UI and synced to `$OPENCODE_CONFIG_DIR/config.toml` (or `~/.config/opencode/config.toml`) on load/save. Stable: Collaboration modes (`features.collaboration_modes`), personality (`personality`), and Background terminal (`features.unified_exec`). Experimental: Apps (`features.apps`). Steering capability still follows OpenCode `features.steer`, but follow-up default behavior is controlled in Settings → Composer. - On launch and on window focus, the app reconnects and refreshes thread lists for each workspace. - Threads are restored by filtering `thread/list` results using the workspace `cwd`. - Selecting a thread always calls `thread/resume` to refresh messages from disk. - CLI sessions appear if their `cwd` matches the workspace path; they are not live-streamed unless resumed. -- The app uses `codex app-server` over stdio; see `src-tauri/src/lib.rs` and `src-tauri/src/codex/`. -- The remote daemon entrypoint is `src-tauri/src/bin/codex_monitor_daemon.rs`; RPC routing lives in `src-tauri/src/bin/codex_monitor_daemon/rpc.rs` and domain handlers in `src-tauri/src/bin/codex_monitor_daemon/rpc/`. +- The app uses `opencode app-server` over stdio; see `src-tauri/src/lib.rs` and `src-tauri/src/opencode/`. +- The remote daemon entrypoint is `src-tauri/src/bin/opencode_monitor_daemon.rs`; RPC routing lives in `src-tauri/src/bin/opencode_monitor_daemon/rpc.rs` and domain handlers in `src-tauri/src/bin/opencode_monitor_daemon/rpc/`. - Shared domain logic lives in `src-tauri/src/shared/` (notably `src-tauri/src/shared/git_ui_core/` and `src-tauri/src/shared/workspaces_core/`). -- Codex home resolves from workspace settings (if set), then legacy `.codexmonitor/`, then `$CODEX_HOME`/`~/.codex`. -- Worktree agents live under the app data directory (`worktrees/`); legacy `.codex-worktrees/` paths remain supported, and the app no longer edits repo `.gitignore` files. +- OpenCode home resolves from workspace settings (if set), then `$OPENCODE_CONFIG_DIR`/`~/.config/opencode`. +- Worktree agents live under the app data directory (`worktrees/`); legacy `.opencode-worktrees/` paths remain supported, and the app no longer edits repo `.gitignore` files. - UI state (panel sizes, reduced transparency toggle, recent thread activity) is stored in `localStorage`. -- Custom prompts load from `$CODEX_HOME/prompts` (or `~/.codex/prompts`) with optional frontmatter description/argument hints. +- Custom prompts load from `$OPENCODE_CONFIG_DIR/prompts` (or `~/.config/opencode/prompts`) with optional frontmatter description/argument hints. ## Tauri IPC Surface Frontend calls live in `src/services/tauri.ts` and map to commands in `src-tauri/src/lib.rs`. The current surface includes: -- Settings/config/files: `get_app_settings`, `update_app_settings`, `get_codex_config_path`, `get_config_model`, `file_read`, `file_write`, `codex_doctor`, `menu_set_accelerators`. +- Settings/config/files: `get_app_settings`, `update_app_settings`, `get_config_model`, `file_read`, `file_write`, `opencode_doctor`, `menu_set_accelerators`. - Workspaces/worktrees: `list_workspaces`, `is_workspace_path_dir`, `add_workspace`, `add_clone`, `add_worktree`, `worktree_setup_status`, `worktree_setup_mark_ran`, `rename_worktree`, `rename_worktree_upstream`, `apply_worktree_changes`, `update_workspace_settings`, `remove_workspace`, `remove_worktree`, `connect_workspace`, `list_workspace_files`, `read_workspace_file`, `open_workspace_in`, `get_open_app_icon`. - Threads/turns/reviews: `start_thread`, `fork_thread`, `compact_thread`, `list_threads`, `resume_thread`, `archive_thread`, `set_thread_name`, `send_user_message`, `turn_interrupt`, `respond_to_server_request`, `start_review`, `remember_approval_rule`, `get_commit_message_prompt`, `generate_commit_message`, `generate_run_metadata`. -- Account/models/collaboration: `model_list`, `account_rate_limits`, `account_read`, `skills_list`, `apps_list`, `collaboration_mode_list`, `codex_login`, `codex_login_cancel`, `list_mcp_server_status`. +- Account/models/collaboration: `model_list`, `account_rate_limits`, `account_read`, `skills_list`, `apps_list`, `collaboration_mode_list`, `opencode_login`, `opencode_login_cancel`, `list_mcp_server_status`. - Git/GitHub: `get_git_status`, `list_git_roots`, `get_git_diffs`, `get_git_log`, `get_git_commit_diff`, `get_git_remote`, `stage_git_file`, `stage_git_all`, `unstage_git_file`, `revert_git_file`, `revert_git_all`, `commit_git`, `push_git`, `pull_git`, `fetch_git`, `sync_git`, `list_git_branches`, `checkout_git_branch`, `create_git_branch`, `get_github_issues`, `get_github_pull_requests`, `get_github_pull_request_diff`, `get_github_pull_request_comments`. - Prompts: `prompts_list`, `prompts_create`, `prompts_update`, `prompts_delete`, `prompts_move`, `prompts_workspace_dir`, `prompts_global_dir`. - Terminal/dictation/notifications/usage: `terminal_open`, `terminal_write`, `terminal_resize`, `terminal_close`, `dictation_model_status`, `dictation_download_model`, `dictation_cancel_download`, `dictation_remove_model`, `dictation_request_permission`, `dictation_start`, `dictation_stop`, `dictation_cancel`, `send_notification_fallback`, `is_macos_debug_build`, `local_usage_snapshot`. diff --git a/REMOTE_BACKEND_POC.md b/REMOTE_BACKEND_POC.md index 63fe8cfebc..e0ce518dc3 100644 --- a/REMOTE_BACKEND_POC.md +++ b/REMOTE_BACKEND_POC.md @@ -1,6 +1,6 @@ # Remote Backend POC (daemon) -This fork includes a **proof-of-concept** daemon that runs CodexMonitor's backend logic in a separate process (intended for WSL2/Linux), exposing a simple **line-delimited JSON-RPC** protocol over TCP. +This fork includes a **proof-of-concept** daemon that runs OpenCodeMonitor's backend logic in a separate process (intended for WSL2/Linux), exposing a simple **line-delimited JSON-RPC** protocol over TCP. This is **not** wired into the desktop app yet (no UI toggle / remote proxy), but it is useful to validate the architecture and iterate on the protocol. @@ -11,12 +11,12 @@ From the repo root: ```bash cd src-tauri -# pick a strong token (or export CODEX_MONITOR_DAEMON_TOKEN) +# pick a strong token (or export OPENCODE_MONITOR_DAEMON_TOKEN) TOKEN="change-me" -cargo run --bin codex_monitor_daemon -- \ +cargo run --bin opencode_monitor_daemon -- \ --listen 127.0.0.1:4732 \ - --data-dir "$HOME/.local/share/codex-monitor-daemon" \ + --data-dir "$HOME/.local/share/opencode-monitor-daemon" \ --token "$TOKEN" ``` diff --git a/docs/app-server-events.md b/docs/app-server-events.md index 9b21990d31..a448c849d4 100644 --- a/docs/app-server-events.md +++ b/docs/app-server-events.md @@ -1,23 +1,23 @@ -# App-Server Events Reference (Codex `19702e190ebf16f789617ca5f16bfc373c238fe7`) +# App-Server Events Reference (OpenCode `19702e190ebf16f789617ca5f16bfc373c238fe7`) This document helps agents quickly answer: -- Which app-server events CodexMonitor supports right now. -- Which app-server requests CodexMonitor sends right now. -- Where to look in CodexMonitor to add support. -- Where to look in `../Codex` to compare event lists and find emitters. +- Which app-server events OpenCodeMonitor supports right now. +- Which app-server requests OpenCodeMonitor sends right now. +- Where to look in OpenCodeMonitor to add support. +- Where to look in `../OpenCode` to compare event lists and find emitters. When updating this document: -1. Fetch latest refs with `git -C ../Codex fetch --all --prune`. -2. Update the Codex hash in the title using `git -C ../Codex rev-parse origin/main`. -3. Compare Codex events vs CodexMonitor routing. -4. Compare Codex client request methods vs CodexMonitor outgoing request methods. -5. Compare Codex server request methods vs CodexMonitor inbound request handling. +1. Fetch latest refs with `git -C ../OpenCode fetch --all --prune`. +2. Update the OpenCode hash in the title using `git -C ../OpenCode rev-parse origin/main`. +3. Compare OpenCode events vs OpenCodeMonitor routing. +4. Compare OpenCode client request methods vs OpenCodeMonitor outgoing request methods. +5. Compare OpenCode server request methods vs OpenCodeMonitor inbound request handling. 6. Update supported and missing lists below. Related project skill: -- `.codex/skills/app-server-events-sync/SKILL.md` +- `.opencode/skills/app-server-events-sync/SKILL.md` -## Where To Look In CodexMonitor +## Where To Look In OpenCodeMonitor Primary app-server event source of truth (methods + typed parsing helpers): - `src/utils/appServerEvents.ts` @@ -46,13 +46,13 @@ UI rendering of items: Primary outgoing request layer: - `src/services/tauri.ts` -- `src-tauri/src/shared/codex_core.rs` -- `src-tauri/src/codex/mod.rs` -- `src-tauri/src/bin/codex_monitor_daemon.rs` +- `src-tauri/src/shared/opencode_core.rs` +- `src-tauri/src/opencode/mod.rs` +- `src-tauri/src/bin/opencode_monitor_daemon.rs` ## Supported Notifications (Codex v2) -These are the current Codex v2 `ServerNotification` methods that CodexMonitor +These are the current OpenCode v2 `ServerNotification` methods that OpenCodeMonitor supports in `src/utils/appServerEvents.ts` (`SUPPORTED_APP_SERVER_METHODS`) and then either routes in `useAppServerEvents.ts` or handles in feature-specific subscriptions. @@ -86,7 +86,7 @@ subscriptions. - `turn/plan/updated` - `turn/started` -## Additional Stream Methods Handled In CodexMonitor +## Additional Stream Methods Handled In OpenCodeMonitor These arrive on the same frontend event stream but are not Codex v2 `ServerNotification` methods: @@ -97,9 +97,9 @@ These arrive on the same frontend event stream but are not Codex v2 `item/permissions/requestApproval`, via suffix match in `isApprovalRequestMethod(method)` - `item/tool/requestUserInput` (a Codex v2 server request, not a notification) -- `codex/backgroundThread` (CodexMonitor synthetic bridge event) -- `codex/connected` (CodexMonitor synthetic bridge event) -- `codex/event/skills_update_available` (handled via +- `opencode/backgroundThread` (OpenCodeMonitor synthetic bridge event) +- `opencode/connected` (OpenCodeMonitor synthetic bridge event) +- `opencode/event/skills_update_available` (handled via `isSkillsUpdateAvailableEvent(...)` in `useSkills.ts`) ## Conversation Compaction Signals (Codex v2) @@ -109,7 +109,7 @@ Codex currently exposes two compaction signals: - Preferred: `item/started` + `item/completed` with `item.type = "contextCompaction"` (`ThreadItem::ContextCompaction`). - Deprecated: `thread/compacted` (`ContextCompactedNotification`). -CodexMonitor status: +OpenCodeMonitor status: - It routes `item/started` and `item/completed`, so the preferred signal reaches the frontend event layer. - It renders/stores `contextCompaction` items via the normal item lifecycle. @@ -144,9 +144,9 @@ events are currently not routed: - `windows/worldWritableWarning` - `windowsSandbox/setupCompleted` -## Supported Requests (CodexMonitor -> App-Server, v2) +## Supported Requests (OpenCodeMonitor -> App-Server, v2) -These are v2 request methods CodexMonitor currently sends to Codex app-server: +These are v2 request methods OpenCodeMonitor currently sends to Codex app-server: - `thread/start` - `thread/resume` @@ -175,7 +175,7 @@ Notes: ## Missing Client Requests (Codex v2 ClientRequest Methods) -Compared against Codex v2 request methods, CodexMonitor currently does not send: +Compared against Codex v2 request methods, OpenCodeMonitor currently does not send: - `account/logout` - `command/exec` @@ -223,7 +223,7 @@ Compared against Codex v2 request methods, CodexMonitor currently does not send: - `thread/unsubscribe` - `windowsSandbox/setupStart` -## Server Requests (App-Server -> CodexMonitor, v2) +## Server Requests (App-Server -> OpenCodeMonitor, v2) Supported server requests: @@ -255,11 +255,11 @@ Useful follow-ups: Use this workflow to update the lists above: -1. Get the current Codex hash: - - `git -C ../Codex fetch --all --prune && git -C ../Codex rev-parse origin/main` -2. List Codex v2 notification methods: - - `git -C ../Codex show origin/main:codex-rs/app-server-protocol/src/protocol/common.rs | awk '/server_notification_definitions! \\{/,/client_notification_definitions! \\{/' | rg -N -o '=>\\s*\"[^\"]+\"|rename = \"[^\"]+\"' | sed -E 's/.*\"([^\"]+)\".*/\\1/' | sort -u` -3. List CodexMonitor routed methods: +1. Get the current OpenCode hash: + - `git -C ../OpenCode fetch --all --prune && git -C ../OpenCode rev-parse origin/main` +2. List OpenCode v2 notification methods: + - `git -C ../OpenCode show origin/main:opencode-rs/app-server-protocol/src/protocol/common.rs | awk '/server_notification_definitions! \\{/,/client_notification_definitions! \\{/' | rg -N -o '=>\\s*\"[^\"]+\"|rename = \"[^\"]+\"' | sed -E 's/.*\"([^\"]+)\".*/\\1/' | sort -u` +3. List OpenCodeMonitor routed methods: - `rg -n \"SUPPORTED_APP_SERVER_METHODS\" src/utils/appServerEvents.ts` 4. Update the Supported and Missing sections. @@ -267,26 +267,26 @@ Use this workflow to update the lists above: Use this workflow to update request support lists: -1. Get the current Codex hash: - - `git -C ../Codex fetch --all --prune && git -C ../Codex rev-parse origin/main` -2. List Codex client request methods: - - `git -C ../Codex show origin/main:codex-rs/app-server-protocol/src/protocol/common.rs | awk '/client_request_definitions! \\{/,/\\/\\/\\/ DEPRECATED APIs below/' | rg -N -o '=>\\s*\"[^\"]+\"\\s*\\{' | sed -E 's/.*\"([^\"]+)\".*/\\1/' | sort -u` -3. List Codex server request methods: - - `git -C ../Codex show origin/main:codex-rs/app-server-protocol/src/protocol/common.rs | awk '/server_request_definitions! \\{/,/\\/\\/\\/ DEPRECATED APIs below/' | rg -N -o '=>\\s*\"[^\"]+\"\\s*\\{' | sed -E 's/.*\"([^\"]+)\".*/\\1/' | sort -u` -4. List CodexMonitor outgoing requests: - - `perl -0777 -ne 'while(/send_request_for_workspace\\(\\s*&[^,]+\\s*,\\s*\"([^\"]+)\"/g){print \"$1\\n\"}' src-tauri/src/shared/codex_core.rs | sort -u` +1. Get the current OpenCode hash: + - `git -C ../OpenCode fetch --all --prune && git -C ../OpenCode rev-parse origin/main` +2. List OpenCode client request methods: + - `git -C ../OpenCode show origin/main:opencode-rs/app-server-protocol/src/protocol/common.rs | awk '/client_request_definitions! \\{/,/\\/\\/\\/ DEPRECATED APIs below/' | rg -N -o '=>\\s*\"[^\"]+\"\\s*\\{' | sed -E 's/.*\"([^\"]+)\".*/\\1/' | sort -u` +3. List OpenCode server request methods: + - `git -C ../OpenCode show origin/main:opencode-rs/app-server-protocol/src/protocol/common.rs | awk '/server_request_definitions! \\{/,/\\/\\/\\/ DEPRECATED APIs below/' | rg -N -o '=>\\s*\"[^\"]+\"\\s*\\{' | sed -E 's/.*\"([^\"]+)\".*/\\1/' | sort -u` +4. List OpenCodeMonitor outgoing requests: + - `perl -0777 -ne 'while(/send_request_for_workspace\\(\\s*&[^,]+\\s*,\\s*\"([^\"]+)\"/g){print \"$1\\n\"}' src-tauri/src/shared/opencode_core.rs | sort -u` 5. Update the Supported Requests, Missing Client Requests, and Server Requests sections. ## Schema Drift Workflow (Best) Use this when the method list is unchanged but behavior looks off. -1. Confirm the current Codex hash: - - `git -C ../Codex fetch --all --prune && git -C ../Codex rev-parse origin/main` +1. Confirm the current OpenCode hash: + - `git -C ../OpenCode fetch --all --prune && git -C ../OpenCode rev-parse origin/main` 2. Inspect the authoritative notification structs: - - `git -C ../Codex show origin/main:codex-rs/app-server-protocol/src/protocol/v2.rs | rg -n \"struct .*Notification\"` + - `git -C ../OpenCode show origin/main:opencode-rs/app-server-protocol/src/protocol/v2.rs | rg -n \"struct .*Notification\"` 3. For a specific method, jump to its struct definition: - - Example: `git -C ../Codex show origin/main:codex-rs/app-server-protocol/src/protocol/v2.rs | rg -n \"struct TurnPlanUpdatedNotification|struct ThreadTokenUsageUpdatedNotification|struct AccountRateLimitsUpdatedNotification|struct ItemStartedNotification|struct ItemCompletedNotification\"` + - Example: `git -C ../OpenCode show origin/main:opencode-rs/app-server-protocol/src/protocol/v2.rs | rg -n \"struct TurnPlanUpdatedNotification|struct ThreadTokenUsageUpdatedNotification|struct AccountRateLimitsUpdatedNotification|struct ItemStartedNotification|struct ItemCompletedNotification\"` 4. Compare payload shapes to the router expectations: - Parser/source of truth: `src/utils/appServerEvents.ts` - Router: `src/features/app/hooks/useAppServerEvents.ts` @@ -296,7 +296,7 @@ Use this when the method list is unchanged but behavior looks off. - `git -C ../Codex show origin/main:codex-rs/app-server-protocol/src/protocol/v2.rs | rg -n \"enum ThreadItem|CommandExecution|FileChange|McpToolCall|EnteredReviewMode|ExitedReviewMode|ContextCompaction\"` 6. Check for camelCase vs snake_case mismatches: - The protocol uses `#[serde(rename_all = \"camelCase\")]`, but fields are often declared in snake_case. - - CodexMonitor generally defends against this by checking both forms (for example in `threadNormalize.ts` and `useAppServerEvents.ts`), while centralizing method/type parsing in `appServerEvents.ts`. + - OpenCodeMonitor generally defends against this by checking both forms (for example in `threadNormalize.ts` and `useAppServerEvents.ts`), while centralizing method/type parsing in `appServerEvents.ts`. 7. If a schema change is found, fix it at the edges first: - Prefer updating `src/utils/appServerEvents.ts`, `useAppServerEvents.ts`, and `threadNormalize.ts` rather than spreading conditionals into components. @@ -316,8 +316,8 @@ Use this when the method list is unchanged but behavior looks off. - Stored in `useThreadsReducer.ts` (`turnDiffByThread`) - Exposed by `useThreads.ts` for UI consumers - Steering behavior while a turn is processing: - - CodexMonitor attempts `turn/steer` only when steer capability is enabled, the thread is processing, and an active turn id exists. - - If `turn/steer` fails, CodexMonitor does not fall back to `turn/start`; it clears stale processing/turn state when applicable, surfaces an error, and returns `steer_failed`. + - OpenCodeMonitor attempts `turn/steer` only when steer capability is enabled, the thread is processing, and an active turn id exists. + - If `turn/steer` fails, OpenCodeMonitor does not fall back to `turn/start`; it clears stale processing/turn state when applicable, surfaces an error, and returns `steer_failed`. - Local queue fallback on `steer_failed` is handled in the composer queued-send flow (`useQueuedSend`), not by all direct `sendUserMessageToThread` callers. - Feature toggles in Settings: - `experimentalFeature/list` is an app-server request. diff --git a/docs/codebase-map.md b/docs/codebase-map.md index b8a2af8426..92794cbd90 100644 --- a/docs/codebase-map.md +++ b/docs/codebase-map.md @@ -1,6 +1,6 @@ # Codebase Map (Task-Oriented) -Canonical navigation guide for CodexMonitor. Use this as: "if you need X, edit Y". +Canonical navigation guide for OpenCodeMonitor. Use this as: "if you need X, edit Y". Related docs: @@ -14,11 +14,11 @@ For backend behavior, follow this path in order: 1. Frontend callsite: `src/features/**` hooks/components 2. Frontend IPC API: `src/services/tauri.ts` 3. Tauri command registration: `src-tauri/src/lib.rs` (`invoke_handler`) -4. App adapter: `src-tauri/src/{codex,workspaces,git,files,settings,prompts}/*` +4. App adapter: `src-tauri/src/{opencode,workspaces,git,files,settings,prompts}/*` 5. Shared core source of truth: `src-tauri/src/shared/*` -6. Daemon RPC method parity: `src-tauri/src/bin/codex_monitor_daemon/rpc.rs` -7. Daemon state/wiring implementation: `src-tauri/src/bin/codex_monitor_daemon.rs` -8. Standalone daemon lifecycle CLI: `src-tauri/src/bin/codex_monitor_daemonctl.rs` +6. Daemon RPC method parity: `src-tauri/src/bin/opencode_monitor_daemon/rpc.rs` +7. Daemon state/wiring implementation: `src-tauri/src/bin/opencode_monitor_daemon.rs` +8. Standalone daemon lifecycle CLI: `src-tauri/src/bin/opencode_monitor_daemonctl.rs` If a behavior must work in both app and daemon, implement it in `src-tauri/src/shared/*` first. @@ -32,10 +32,10 @@ If a behavior must work in both app and daemon, implement it in `src-tauri/src/s | Change thread state transitions | `src/features/threads/hooks/useThreadsReducer.ts`, `src/features/threads/hooks/threadReducer/*`, `src/features/threads/hooks/useThreads.ts`, focused thread hooks under `src/features/threads/hooks/*` | | Change workspace lifecycle/worktree behavior | `src/features/workspaces/hooks/useWorkspaces.ts`, `src-tauri/src/workspaces/commands.rs`, `src-tauri/src/shared/workspaces_core.rs`, `src-tauri/src/shared/workspaces_core/*`, `src-tauri/src/shared/worktree_core.rs` | | Change settings model/load/update | `src/features/settings/components/SettingsView.tsx`, `src/features/settings/hooks/useAppSettings.ts`, `src/services/tauri.ts`, `src-tauri/src/settings/mod.rs`, `src-tauri/src/shared/settings_core.rs`, `src-tauri/src/types.rs`, `src/types.ts` | -| Change Git/GitHub backend behavior | `src/features/git/hooks/*`, `src/services/tauri.ts`, `src-tauri/src/git/mod.rs`, `src-tauri/src/shared/git_ui_core.rs`, `src-tauri/src/shared/git_ui_core/*`, `src-tauri/src/shared/git_core.rs`, `src-tauri/src/bin/codex_monitor_daemon/rpc.rs`, `src-tauri/src/bin/codex_monitor_daemon/rpc/git.rs` | -| Change prompts CRUD/listing behavior | `src/features/prompts/hooks/useCustomPrompts.ts`, `src/features/prompts/components/PromptPanel.tsx`, `src/services/tauri.ts`, `src-tauri/src/prompts.rs`, `src-tauri/src/shared/prompts_core.rs`, `src-tauri/src/bin/codex_monitor_daemon/rpc.rs` | -| Change file read/write for Agents/config | `src/services/tauri.ts`, `src-tauri/src/files/mod.rs`, `src-tauri/src/shared/files_core.rs`, `src-tauri/src/bin/codex_monitor_daemon/rpc.rs` | -| Add/change daemon JSON-RPC surface | `src-tauri/src/bin/codex_monitor_daemon/rpc.rs`, `src-tauri/src/bin/codex_monitor_daemon/rpc/*`, `src-tauri/src/bin/codex_monitor_daemon.rs`, matching shared core | +| Change Git/GitHub backend behavior | `src/features/git/hooks/*`, `src/services/tauri.ts`, `src-tauri/src/git/mod.rs`, `src-tauri/src/shared/git_ui_core.rs`, `src-tauri/src/shared/git_ui_core/*`, `src-tauri/src/shared/git_core.rs`, `src-tauri/src/bin/opencode_monitor_daemon/rpc.rs`, `src-tauri/src/bin/opencode_monitor_daemon/rpc/git.rs` | +| Change prompts CRUD/listing behavior | `src/features/prompts/hooks/useCustomPrompts.ts`, `src/features/prompts/components/PromptPanel.tsx`, `src/services/tauri.ts`, `src-tauri/src/prompts.rs`, `src-tauri/src/shared/prompts_core.rs`, `src-tauri/src/bin/opencode_monitor_daemon/rpc.rs` | +| Change file read/write for Agents/config | `src/services/tauri.ts`, `src-tauri/src/files/mod.rs`, `src-tauri/src/shared/files_core.rs`, `src-tauri/src/bin/opencode_monitor_daemon/rpc.rs` | +| Add/change daemon JSON-RPC surface | `src-tauri/src/bin/opencode_monitor_daemon/rpc.rs`, `src-tauri/src/bin/opencode_monitor_daemon/rpc/*`, `src-tauri/src/bin/opencode_monitor_daemon.rs`, matching shared core | ## Frontend Navigation @@ -93,7 +93,7 @@ Use TS/Vite aliases for refactor-safe imports: ## Backend App (Tauri) Navigation - Command registry (what frontend can invoke): `src-tauri/src/lib.rs` -- Codex adapters: `src-tauri/src/codex/mod.rs` +- OpenCode adapters: `src-tauri/src/opencode/mod.rs` - Workspace/worktree adapters: `src-tauri/src/workspaces/commands.rs` - Git adapters: `src-tauri/src/git/mod.rs` - Settings adapters: `src-tauri/src/settings/mod.rs` @@ -104,11 +104,11 @@ Use TS/Vite aliases for refactor-safe imports: ## Daemon Navigation -- Daemon entrypoint and state/wiring: `src-tauri/src/bin/codex_monitor_daemon.rs` -- Daemon lifecycle CLI (headless start/stop/status): `src-tauri/src/bin/codex_monitor_daemonctl.rs` -- Daemon JSON-RPC dispatcher/router: `src-tauri/src/bin/codex_monitor_daemon/rpc.rs` -- Daemon domain handlers: `src-tauri/src/bin/codex_monitor_daemon/rpc/*` -- Daemon transport: `src-tauri/src/bin/codex_monitor_daemon/transport.rs` +- Daemon entrypoint and state/wiring: `src-tauri/src/bin/opencode_monitor_daemon.rs` +- Daemon lifecycle CLI (headless start/stop/status): `src-tauri/src/bin/opencode_monitor_daemonctl.rs` +- Daemon JSON-RPC dispatcher/router: `src-tauri/src/bin/opencode_monitor_daemon/rpc.rs` +- Daemon domain handlers: `src-tauri/src/bin/opencode_monitor_daemon/rpc/*` +- Daemon transport: `src-tauri/src/bin/opencode_monitor_daemon/transport.rs` When adding a new method, keep method names and payload shape aligned with `src/services/tauri.ts` and app commands in `src-tauri/src/lib.rs`. @@ -116,9 +116,9 @@ When adding a new method, keep method names and payload shape aligned with `src/ All cross-runtime domain behavior belongs in `src-tauri/src/shared/*`: -- Codex threads/approvals/account/skills/config: `src-tauri/src/shared/codex_core.rs` -- Codex helper commands: `src-tauri/src/shared/codex_aux_core.rs` -- Codex update/version helpers: `src-tauri/src/shared/codex_update_core.rs` +- OpenCode threads/approvals/account/skills/config: `src-tauri/src/shared/opencode_core.rs` +- OpenCode helper commands: `src-tauri/src/shared/opencode_aux_core.rs` +- OpenCode update/version helpers: `src-tauri/src/shared/opencode_update_core.rs` - Workspaces/worktrees: `src-tauri/src/shared/workspaces_core.rs`, `src-tauri/src/shared/workspaces_core/*`, `src-tauri/src/shared/worktree_core.rs` - Settings model/update: `src-tauri/src/shared/settings_core.rs` - Files read/write: `src-tauri/src/shared/files_core.rs` diff --git a/docs/mobile-ios-tailscale-blueprint.md b/docs/mobile-ios-tailscale-blueprint.md index 9aed756a48..52c3a79341 100644 --- a/docs/mobile-ios-tailscale-blueprint.md +++ b/docs/mobile-ios-tailscale-blueprint.md @@ -1,6 +1,6 @@ -# CodexMonitor iOS Remote Blueprint (Tailscale + TCP) +# OpenCodeMonitor iOS Remote Blueprint (Tailscale + TCP) -This document is the canonical runbook for iOS remote usage with a desktop-hosted CodexMonitor backend over Tailscale. +This document is the canonical runbook for iOS remote usage with a desktop-hosted OpenCodeMonitor backend over Tailscale. ## Scope @@ -11,21 +11,21 @@ This document is the canonical runbook for iOS remote usage with a desktop-hoste ## Current Architecture -1. Desktop CodexMonitor hosts the daemon and executes Codex workflows. -2. iOS CodexMonitor connects to the desktop daemon using `remoteBackendHost` + token. +1. Desktop OpenCodeMonitor hosts the daemon and executes OpenCode workflows. +2. iOS OpenCodeMonitor connects to the desktop daemon using `remoteBackendHost` + token. 3. Transport is TCP only (`remoteBackendProvider = "tcp"`). 4. Tailscale is used as the network path between iOS and desktop. ## Prerequisites - Desktop and iPhone are signed into the same Tailscale tailnet. -- Desktop CodexMonitor is installed and able to run local workspaces. +- Desktop OpenCodeMonitor is installed and able to run local workspaces. - iOS build/runtime is available (simulator or device). - A non-empty remote backend token is configured. ## Desktop Setup (Source of Truth) -In desktop CodexMonitor: +In desktop OpenCodeMonitor: 1. Open `Settings > Server`. 2. Set `Remote backend token`. @@ -41,15 +41,15 @@ Headless alternative (no desktop UI required): 1. Build daemon + daemonctl: - `cd src-tauri` - - `cargo build --bin codex_monitor_daemon --bin codex_monitor_daemonctl` -2. Start daemon from CLI: - - `./target/debug/codex_monitor_daemonctl start` -3. Verify daemon status: - - `./target/debug/codex_monitor_daemonctl status` + - `cargo build --bin opencode_monitor_daemon --bin opencode_monitor_daemonctl` + 2. Start daemon from CLI: + - `./target/debug/opencode_monitor_daemonctl start` + 3. Verify daemon status: + - `./target/debug/opencode_monitor_daemonctl status` ## iOS Setup -In iOS CodexMonitor: +In iOS OpenCodeMonitor: 1. Open `Settings > Server` (or the mobile setup wizard). 2. Enter the desktop Tailscale host (including port). diff --git a/docs/multi-agent-sync-runbook.md b/docs/multi-agent-sync-runbook.md index a41dfde38b..3a23e4538b 100644 --- a/docs/multi-agent-sync-runbook.md +++ b/docs/multi-agent-sync-runbook.md @@ -2,7 +2,7 @@ ## Purpose -Keep CodexMonitor's Agents settings behavior in sync with upstream Codex (`../Codex`) whenever Codex changes: +Keep OpenCodeMonitor's Agents settings behavior in sync with upstream OpenCode (`../OpenCode`) whenever OpenCode changes: - multi-agent feature flags - `[agents]` config schema @@ -13,7 +13,7 @@ Keep CodexMonitor's Agents settings behavior in sync with upstream Codex (`../Co - After pulling updates in `../Codex` - Before changing `src-tauri/src/shared/agents_config_core.rs` -- When users report a mismatch between CodexMonitor settings and Codex runtime behavior +- When users report a mismatch between OpenCodeMonitor settings and OpenCode runtime behavior ## Upstream Source Of Truth (Check These First) @@ -38,7 +38,7 @@ Notes: ## Fast Upstream Diff Commands -Run from `CodexMonitor` repo root: +Run from `OpenCodeMonitor` repo root: ```bash cd ../Codex @@ -62,16 +62,16 @@ rg -n "multi_agent|max_threads|max_depth|AgentsToml|AgentRoleToml|config_file|ap codex-rs/core/src/tools/handlers/multi_agents.rs ``` -## CodexMonitor Files To Update If Upstream Changes +## OpenCodeMonitor Files To Update If Upstream Changes 1. Shared read/write core: - `src-tauri/src/shared/agents_config_core.rs` 2. Tauri/app + daemon adapters (keep parity): -- `src-tauri/src/codex/mod.rs` +- `src-tauri/src/opencode/mod.rs` - `src-tauri/src/lib.rs` -- `src-tauri/src/bin/codex_monitor_daemon.rs` -- `src-tauri/src/bin/codex_monitor_daemon/rpc/codex.rs` +- `src-tauri/src/bin/opencode_monitor_daemon.rs` +- `src-tauri/src/bin/opencode_monitor_daemon/rpc/opencode.rs` - `src-tauri/src/remote_backend/mod.rs` 3. Frontend settings contracts + UI: @@ -89,8 +89,8 @@ rg -n "multi_agent|max_threads|max_depth|AgentsToml|AgentRoleToml|config_file|ap 1. Feature flags - Verify upstream key remains `features.multi_agent`. -- Keep CodexMonitor scoped to the new key only (no legacy alias read/write). -- Keep CodexMonitor writes aligned with upstream expectations. +- Keep OpenCodeMonitor scoped to the new key only (no legacy alias read/write). +- Keep OpenCodeMonitor writes aligned with upstream expectations. 2. Agents schema - Verify `[agents]` shape still supports `max_threads`, `max_depth`, plus dynamic role tables. @@ -99,7 +99,7 @@ rg -n "multi_agent|max_threads|max_depth|AgentsToml|AgentRoleToml|config_file|ap 3. Defaults/validation - Check upstream default for `agents.max_threads` and validation constraints. - Check upstream default for `agents.max_depth` and validation constraints. -- Reconcile CodexMonitor guardrails when upstream changes. +- Reconcile OpenCodeMonitor guardrails when upstream changes. 4. Role setup behavior - Verify built-in role names/descriptions and built-in config files (currently includes `explorer.toml`). @@ -111,9 +111,9 @@ rg -n "multi_agent|max_threads|max_depth|AgentsToml|AgentRoleToml|config_file|ap ## Known Intentional Divergence -- Upstream Codex default `agents.max_threads` is `6`. -- CodexMonitor default `agents.max_depth` is `1`. -- CodexMonitor currently enforces a product cap of `12` for `agents.max_threads` and `4` for `agents.max_depth` in UI + backend. +- Upstream OpenCode default `agents.max_threads` is `6`. +- OpenCodeMonitor default `agents.max_depth` is `1`. +- OpenCodeMonitor currently enforces a product cap of `12` for `agents.max_threads` and `4` for `agents.max_depth` in UI + backend. If upstream introduces a hard max or materially changes spawn behavior, revisit this cap and update both: diff --git a/flake.nix b/flake.nix index 8d6e58a3af..4f52bbf20c 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,5 @@ { - description = "CodexMonitor Tauri app for orchestrating Codex agents"; + description = "OpenCodeMonitor Tauri app for orchestrating OpenCode agents"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; @@ -24,7 +24,7 @@ ]; frontend = pkgs.buildNpmPackage { - pname = "codex-monitor-frontend"; + pname = "opencode-monitor-frontend"; version = packageJson.version; src = ./.; nodejs = pkgs.nodejs_20; @@ -44,7 +44,7 @@ }; appPackage = pkgs.rustPlatform.buildRustPackage { - pname = "codex-monitor"; + pname = "opencode-monitor"; version = packageJson.version; src = ./src-tauri; @@ -86,7 +86,7 @@ installPhase = '' mkdir -p $out/bin target_dir="target/${pkgs.stdenv.hostPlatform.rust.rustcTarget}" - cp "$target_dir/release/codex-monitor" $out/bin/ + cp "$target_dir/release/opencode-monitor" $out/bin/ ''; }; in diff --git a/migration-plan/00-summary.md b/migration-plan/00-summary.md new file mode 100644 index 0000000000..ebf06c44ac --- /dev/null +++ b/migration-plan/00-summary.md @@ -0,0 +1,55 @@ +# Migration Plan - CodexMonitor → OpenCodeMonitor + +## Résumé Exécutif + +Ce plan détaille la migration de **CodexMonitor** (Tauri app qui orchestre des agents +OpenAI Codex CLI) vers **OpenCodeMonitor** (Tauri app qui orchestre des agents +OpenCode CLI). + +### Pourquoi cette migration ? + +- Le projet utilisait `@openai/codex` (Codex CLI) comme backend agent. +- L'utilisateur souhaite utiliser **OpenCode CLI** (`opencode`) à la place. +- Les deux CLI ont des architectures, protocoles et formats de configuration + fondamentalement différents. + +### Différence Fondamentale + +| Aspect | Codex CLI | OpenCode CLI | +|--------|-----------|--------------| +| Protocole | JSON-RPC over stdio (`codex app-server`) | API HTTP REST (`opencode serve`) | +| Configuration | `config.toml` (`~/.codex/config.toml`) | `opencode.json` (`~/.config/opencode/opencode.json`) | +| Home | `$CODEX_HOME` / `~/.codex` | `~/.config/opencode/` | +| Auth | Fichier `auth.json` | `opencode.json` + providers | +| Sessions | Threads with turns/items | Sessions with messages | +| Modèle de données | `thread/turn/item` | `session/message` | + +### Envergure du Projet + +| Métrique | Valeur | +|----------|--------| +| Fichiers Rust impactés | ~50+ fichiers | +| Fichiers TypeScript/TSX impactés | ~80+ fichiers | +| Fichiers de documentation | ~8 fichiers | +| Scripts | ~6 fichiers | +| CI/Release | ~2 workflows GitHub | +| **Total estimé** | **~150+ fichiers** | + +### Grands Chantiers + +1. **Renommage systématique** `codex` → `opencode` (projet, binaires, modules, types) +2. **Réécriture du calque de communication** (`WorkspaceSession` JSON-RPC stdio → HTTP client) +3. **Adaptation du système de configuration** (`config.toml` → `opencode.json`) +4. **Refonte du daemon RPC** (adaptation au nouveau protocole) +5. **Mise à jour du frontend** (IPC, types, UI, localStorage) +6. **Documentation, scripts, CI/CD** +7. **Optimisations post-migration** + +### Risques + +- **Haut**: Le protocole HTTP d'OpenCode est différent du JSON-RPC de Codex — toute la couche + `backend/app_server.rs` et `codex_core.rs` doit être réécrite. +- **Moyen**: Le système d'agents (`.codex/agents/`) et les features flags (`config.toml`) + n'ont pas d'équivalent direct dans OpenCode. +- **Moyen**: Le daemon RPC TCP doit être adapté au nouveau protocole. +- **Faible**: Le renommage et la doc sont volumineux mais mécaniques. diff --git a/migration-plan/01-architecture.md b/migration-plan/01-architecture.md new file mode 100644 index 0000000000..01d4a7475d --- /dev/null +++ b/migration-plan/01-architecture.md @@ -0,0 +1,131 @@ +# Architecture: Codex vs OpenCode + +## Architecture Codex (actuelle) + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ CodexMonitor (Tauri App) │ +│ │ +│ ┌──────────┐ ┌────────────────────┐ ┌───────────────────┐ │ +│ │ Frontend │◄──► Tauri IPC (JSON) │ │ codex/mod.rs │ │ +│ │ (React) │ │ lib.rs commands │ │ (Tauri adapter) │ │ +│ └──────────┘ └────────┬───────────┘ └────────┬──────────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌──────────────────────────────────────┐ │ +│ │ shared/codex_core.rs │ │ +│ │ (business logic, JSON-RPC calls) │ │ +│ └────────────────┬─────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌──────────────────────────────────────┐ │ +│ │ backend/app_server.rs │ │ +│ │ WorkspaceSession (JSON-RPC stdio) │ │ +│ │ spawn: codex app-server │ │ +│ └────────────────┬─────────────────────┘ │ +│ │ │ +│ ▼ stdin/stdout │ +│ ┌──────────────────────────────────────┐ │ +│ │ codex app-server (child process) │ │ +│ │ Workspace CWD + CODEX_HOME env │ │ +│ └──────────────────────────────────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────────────────┐ │ +│ │ Remote Mode: TCP → codex-monitor-daemon → codex app-server │ +│ └──────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Flux Actuel (Codex) + +1. L'app Tauri lance `codex app-server` par workspace (process enfant) +2. Communication JSON-RPC bidirectionnelle via stdin/stdout +3. `WorkspaceSession` gère : envoi requêtes, routage réponses, dispatch événements +4. Événements asynchrones poussés vers le frontend via Tauri events +5. Mode remote : TCP → daemon → même protocole JSON-RPC stdio + +## Architecture OpenCode (cible) + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ OpenCodeMonitor (Tauri App) │ +│ │ +│ ┌──────────┐ ┌────────────────────┐ ┌───────────────────┐ │ +│ │ Frontend │◄──► Tauri IPC (JSON) │ │ opencode/mod.rs │ │ +│ │ (React) │ │ lib.rs commands │ │ (Tauri adapter) │ │ +│ └──────────┘ └────────┬───────────┘ └────────┬──────────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌──────────────────────────────────────┐ │ +│ │ shared/opencode_core.rs │ │ +│ │ (business logic, HTTP API calls) │ │ +│ └────────────────┬─────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌──────────────────────────────────────┐ │ +│ │ backend/opencode_server.rs │ │ +│ │ OpenCodeSession (HTTP client) │ │ +│ │ spawn: opencode serve │ │ +│ └────────────────┬─────────────────────┘ │ +│ │ │ +│ ▼ HTTP REST API │ +│ ┌──────────────────────────────────────┐ │ +│ │ opencode serve (child process) │ │ +│ │ API: /session/*, /config, /connect │ │ +│ └──────────────────────────────────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────────────────┐ │ +│ │ Remote Mode: TCP → opencode-monitor-daemon → HTTP │ │ +│ └──────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Flux Cible (OpenCode) + +1. L'app Tauri lance `opencode serve` par workspace (process enfant) +2. Communication via API HTTP REST sur `http://127.0.0.1:{port}` +3. `OpenCodeSession` gère : appels HTTP, polling événements, dispatch +4. Événements récupérés par polling HTTP ou endpoint SSE +5. Mode remote : TCP → daemon → HTTP API + +## Mapping Protocole + +| Codex (JSON-RPC stdio) | OpenCode (HTTP API) | +|------------------------|---------------------| +| `thread/start` | `POST /session` ou `opencode session new` | +| `turn/start` | Envoi message texte dans session | +| `turn/steer` | Envoi message follow-up | +| `turn/interrupt` | `POST /session/:id/stop` | +| `thread/list` | `GET /session` | +| `thread/resume` | `GET /session/:id` | +| `thread/archive` | Fermeture session | +| `model/list` | `GET /models` dans le CLI ou `config.providers()` | +| `account/read` | `GET /me` ou infos provider | +| `review/start` | `/review` dans le prompt | +| `compact/start` | Non applicable (géré par OpenCode) | +| `skills/list` | Skills installés côté OpenCode | +| `app/list` | Non applicable (plugins MCP) | +| `collaborationMode/list` | Non applicable | +| `mcpServerStatus/list` | `GET /mcp` ou config | +| `experimentalFeature/list` | Non applicable | + +## Différences Clés + +### Points d'attention + +1. **OpenCode n'a pas de mode `app-server` dédié** — il utilise `opencode serve` + qui expose une API HTTP REST, pas de JSON-RPC stdio. + +2. **Pas de workspace intégré** dans OpenCode — chaque instance `opencode serve` + gère une session unique. L'orchestration multi-workspace doit être maintenue + par l'app Tauri. + +3. **Événements push** — Codex pousse les événements via stdout (notifications + JSON-RPC). OpenCode n'a pas d'équivalent SSE direct documenté. Solution: + polling périodique ou utiliser `opencode run` en mode non-interactif. + +4. **Configuration** — Codex utilise `config.toml` avec `[features]` pour les + flags. OpenCode utilise `opencode.json` avec une structure différente. + +5. **Login/Auth** — Codex a `account/login/start`. OpenCode utilise `/connect` + pour les providers. diff --git a/migration-plan/02-categories-changes.md b/migration-plan/02-categories-changes.md new file mode 100644 index 0000000000..fd362f5561 --- /dev/null +++ b/migration-plan/02-categories-changes.md @@ -0,0 +1,101 @@ +# Catégories de Changements + +Les changements sont classés en 7 catégories distinctes. + +## 1. Renommage (Mécanique) + +Simples substitutions de noms, sans changement de logique. + +| Pattern source | Pattern cible | +|----------------|---------------| +| `codex` (CLI binaire) | `opencode` | +| `CodexMonitor` | `OpenCodeMonitor` | +| `codex-monitor` | `opencode-monitor` | +| `codex_monitor` | `opencode_monitor` | +| `CODEX_HOME` | `OPENCODE_CONFIG_DIR` ou `XDG_CONFIG_HOME/opencode` | +| `~/.codex/` | `~/.config/opencode/` | +| `com.dimillian.codexmonitor` | `com.dimillian.opencodemonitor` | +| `codex/event/...` | `opencode/event/...` | +| `codexBin`, `codexArgs` | `opencodeBin`, `opencodeArgs` | +| `CodexFeature*` | `OpenCodeFeature*` | +| `gpt-5-codex` (modèle) | Modèle OpenCode correspondant | + +## 2. Changements de Protocole (Complexité Haute) + +Réécriture du calque de communication. + +| Fichier | Changement | +|---------|------------| +| `backend/app_server.rs` | Réécrire `WorkspaceSession` (JSON-RPC stdio) → `OpenCodeSession` (HTTP) | +| `shared/codex_core.rs` | Réécrire tous les appels JSON-RPC → appels HTTP REST | +| `shared/codex_aux_core.rs` | Adapter `codex_doctor_core`, background prompts | +| `codex/mod.rs` → `opencode/mod.rs` | Adapter les Tauri commands | +| `codex/args.rs` | Réviser la résolution d'arguments | +| `events.rs` (Rust backend) | Adapter le format des événements | +| `appServerEvents.ts` (frontend) | Adapter les noms d'événements | +| `utils/codexArgsInput.ts` | Adapter la normalisation d'args | +| `utils/codexArgsProfiles.ts` | Revoir les profils d'args OpenCode | + +## 3. Configuration (Complexité Haute) + +Adaptation des formats de configuration. + +| Fichier | Changement | +|---------|------------| +| `codex/config.rs` → `opencode/config.rs` | Lire/écrire `opencode.json` au lieu de `config.toml` | +| `codex/home.rs` → `opencode/home.rs` | Résoudre `~/.config/opencode/` au lieu de `~/.codex` | +| `shared/config_toml_core.rs` | Adapter ou supprimer (plus de config.toml) | +| `shared/settings_core.rs` | Adapter la synchronisation de settings | +| `shared/agents_config_core.rs` | Adapter/réécrire la gestion d'agents | +| `src/types.ts` (AppSettings) | Renommer `codexBin`/`codexArgs`, adapter types | +| `src/services/tauri.ts` | Adapter les appels IPC | + +## 4. Système d'Agents (Complexité Moyenne) + +OpenCode a un concept d'agents différent. + +| Fichier | Changement | +|---------|------------| +| `shared/agents_config_core.rs` | Adapter au format OpenCode (subagents dans `opencode.json`) | +| `codex/mod.rs` (agent commands) | Adapter les Tauri commands agents | +| Frontend agents UI | Adapter l'UI des paramètres d'agents | + +## 5. Daemon RPC (Complexité Haute) + +Adaptation du daemon TCP au nouveau protocole. + +| Fichier | Changement | +|---------|------------| +| `bin/codex_monitor_daemon.rs` | Réécrire: `opencode_monitor_daemon.rs` | +| `bin/codex_monitor_daemonctl.rs` | Réécrire: `opencode_monitor_daemonctl.rs` | +| `bin/codex_monitor_daemon/rpc/*` | Adapter au nouveau protocole | +| `remote_backend/*` | Adapter le transport | + +## 6. Frontend (Complexité Moyenne) + +Mise à jour de l'UI et de l'IPC. + +| Fichier | Changement | +|---------|------------| +| `src/features/settings/*` | Renommer sections, adapter labels | +| `src/features/app/*` | Renommer hooks, adapter état | +| `src/features/composer/*` | Mettre à jour placeholders, autocomplete | +| `src/features/threads/*` | Renommer storage keys, types | +| `src/services/events.ts` | Adapter les événements | +| `src/services/tauri.ts` | Renommer fonctions IPC | +| `src/types.ts` | Renommer types | +| `src/App.tsx` | Mettre à jour les références | + +## 7. Documentation, Scripts, CI (Complexité Faible) + +Mise à jour mécanique. + +| Fichier | Changement | +|---------|------------| +| `README.md` | Réécrire pour OpenCode | +| `docs/*.md` | Mettre à jour références Codex → OpenCode | +| `docs/index.html` | Réécrire site web | +| `AGENTS.md` | Mettre à jour le fichier agent | +| `scripts/*.sh` | Renommer binaires, chemins | +| `.github/workflows/release.yml` | Adater les artefacts, noms | +| `flake.nix` | Renommer packages | diff --git a/migration-plan/03-rename-patterns.md b/migration-plan/03-rename-patterns.md new file mode 100644 index 0000000000..f5bf86cfef --- /dev/null +++ b/migration-plan/03-rename-patterns.md @@ -0,0 +1,155 @@ +# Mapping de Renommage Complet + +## Règles Générales + +1. `codex` (miniscule, réf. CLI ou concept) → `opencode` +2. `Codex` (majuscule, nom propre) → `OpenCode` +3. `CODEX` (constante/env var) → `OPENCODE` +4. `codex-monitor` (kebab) → `opencode-monitor` +5. `codex_monitor` (snake_case) → `opencode_monitor` +6. `codexMonitor` (camelCase) → `opencodeMonitor` +7. `CodexMonitor` (PascalCase) → `OpenCodeMonitor` + +## Mapping Détaillé + +### Projet et Binaires + +| Ancien | Nouveau | +|--------|---------| +| `CodexMonitor` (projet) | `OpenCodeMonitor` | +| `codex-monitor` (crate/npm) | `opencode-monitor` | +| `codex_monitor_lib` (lib crate) | `opencode_monitor_lib` | +| `codex-monitor` (binary) | `opencode-monitor` | +| `codex_monitor_daemon` | `opencode_monitor_daemon` | +| `codex-monitor-daemon` | `opencode-monitor-daemon` | +| `codex_monitor_daemonctl` | `opencode_monitor_daemonctl` | +| `CODE_MONITOR_DAEMON_TOKEN` | `OPENCODE_MONITOR_DAEMON_TOKEN` | +| `CODEX_MONITOR_DAEMON_PATH` | `OPENCODE_MONITOR_DAEMON_PATH` | +| `TRAY_ID: "codex-monitor-tray"` | `"opencode-monitor-tray"` | +| `.tooltip("Codex Monitor")` | `.tooltip("OpenCode Monitor")` | + +### Chemins de Configuration + +| Ancien | Nouveau | +|--------|---------| +| `$CODEX_HOME` | `$OPENCODE_CONFIG_DIR` | +| `~/.codex` | `~/.config/opencode` | +| `~/.codex/config.toml` | `~/.config/opencode/opencode.json` | +| `~/.codex/auth.json` | (dans opencode.json ou keyring) | +| `~/.codex/agents/` | `~/.config/opencode/subagents/` | +| `~/.codex/prompts/` | `~/.config/opencode/prompts/` | +| `~/.codex/skills/` | (skills OpenCode) | +| `.codex-worktrees/` | `.opencode-worktrees/` | +| `.codexmonitor-*` | `.opencode-monitor-*` | + +### Rust: Modules et Fonctions + +| Ancien | Nouveau | +|--------|---------| +| `mod codex;` | `mod opencode;` | +| `mod codex_args` | `mod opencode_args` | +| `mod codex_config` | `mod opencode_config` | +| `mod codex_home` | `mod opencode_home` | +| `crate::codex::*` | `crate::opencode::*` | +| `shared::codex_core` | `shared::opencode_core` | +| `shared::codex_aux_core` | `shared::opencode_aux_core` | +| `shared::codex_update_core` | `shared::opencode_update_core` | +| `CodexLoginCancelState` | `OpenCodeLoginCancelState` | +| `WorkspaceSession` (dans codex/) | `OpenCodeSession` (dans opencode/) | +| `spawn_workspace_session` | `spawn_opencode_session` | +| `codex_doctor` | `opencode_check` | +| `codex_update` | `opencode_update` | +| `codex_login` / `codex_login_cancel` | `opencode_login` / `opencode_login_cancel` | +| `set_codex_feature_flag` | `set_opencode_feature_flag` | +| `get_codex_config_path` | `get_opencode_config_path` | +| `resolve_default_codex_home` | `resolve_default_opencode_home` | +| `resolve_workspace_codex_home` | `resolve_workspace_opencode_home` | +| `normalize_codex_home` | `normalize_opencode_home` | +| `parse_codex_args` | `parse_opencode_args` | +| `resolve_workspace_codex_args` | `resolve_workspace_opencode_args` | +| `build_codex_command_with_bin` | `build_opencode_command_with_bin` | +| `build_codex_path_env` | `build_opencode_path_env` | +| `check_codex_installation` | `check_opencode_installation` | +| `should_inline_image_path_for_codex` | `should_inline_image_path_for_opencode` | +| `SetWorkspaceRuntimeCodexArgsRequest` | `SetWorkspaceRuntimeOcodeArgsRequest` | +| `WorkspaceRuntimeCodexArgsResult` | `WorkspaceRuntimeOcodeArgsResult` | +| `set_workspace_runtime_codex_args_core` | `set_workspace_runtime_opencode_args_core` | + +### TypeScript/Frontend: Types et Fonctions + +| Ancien | Nouveau | +|--------|---------| +| `codexBin` (AppSettings) | `opencodeBin` | +| `codexArgs` (AppSettings) | `opencodeArgs` | +| `CodexDoctorResult` | `OpenCodeCheckResult` | +| `CodexUpdateResult` | `OpenCodeUpdateResult` | +| `CodexUpdateMethod` | `OpenCodeUpdateMethod` | +| `CodexFeature` | `OpenCodeFeature` | +| `CodexFeatureStage` | `OpenCodeFeatureStage` | +| `ThreadCodexParams` | `ThreadOpenCodeParams` | +| `ThreadCodexParamsMap` | `ThreadOpenCodeParamsMap` | +| `codexArgsOverride` (field) | `opencodeArgsOverride` | +| `makeThreadCodexParamsKey` | `makeThreadOpenCodeParamsKey` | +| `loadThreadCodexParams` | `loadThreadOpenCodeParams` | +| `saveThreadCodexParams` | `saveThreadOpenCodeParams` | +| `CodexArgsOption` | `OpenCodeArgsOption` | +| `CodexArgsRecognizedSegment` | `OpenCodeArgsRecognizedSegment` | +| `ParsedCodexArgsProfile` | `ParsedOpenCodeArgsProfile` | +| `normalizeCodexArgs` | `normalizeOpenCodeArgs` | +| `normalizeCodexArgsInput` | `normalizeOpenCodeArgsInput` | +| `parseCodexArgsProfile` | `parseOpenCodeArgsProfile` | +| `getCodexConfigPath` | `getOpenCodeConfigPath` | +| `runCodexDoctor` | `runOpenCodeCheck` | +| `runCodexUpdate` | `runOpenCodeUpdate` | +| `runCodexLogin` | `runOpenCodeLogin` | +| `cancelCodexLogin` | `cancelOpenCodeLogin` | +| `setCodexFeatureFlag` | `setOpenCodeFeatureFlag` | +| `setWorkspaceRuntimeCodexArgs` | `setWorkspaceRuntimeOpenCodeArgs` | +| `getConfigModel` | `getOpenCodeConfigModel` | + +### localStorage Keys + +| Ancien | Nouveau | +|--------|---------| +| `codexmonitor.threadLastUserActivity` | `opencodemonitor.threadLastUserActivity` | +| `codexmonitor.pinnedThreads` | `opencodemonitor.pinnedThreads` | +| `codexmonitor.threadCustomNames` | `opencodemonitor.threadCustomNames` | +| `codexmonitor.threadCodexParams` | `opencodemonitor.threadOpenCodeParams` | +| `codexmonitor.detachedReviewLinks` | `opencodemonitor.detachedReviewLinks` | +| `codexmonitor.sidebarWidth` | `opencodemonitor.sidebarWidth` | +| `codexmonitor.rightPanelWidth` | `opencodemonitor.rightPanelWidth` | +| `codexmonitor.chatDiffSplitPositionPercent` | `opencodemonitor.chatDiffSplitPositionPercent` | +| `codexmonitor.planPanelHeight` | `opencodemonitor.planPanelHeight` | +| `codexmonitor.terminalPanelHeight` | `opencodemonitor.terminalPanelHeight` | +| `codexmonitor.debugPanelHeight` | `opencodemonitor.debugPanelHeight` | +| `codexmonitor.sidebarCollapsed` | `opencodemonitor.sidebarCollapsed` | +| `codexmonitor.rightPanelCollapsed` | `opencodemonitor.rightPanelCollapsed` | +| `codexmonitor.promptHistory.*` | `opencodemonitor.promptHistory.*` | +| `codexmonitor.pendingPostUpdateVersion` | `opencodemonitor.pendingPostUpdateVersion` | + +### Événements + +| Ancien | Nouveau | +|--------|---------| +| `codex/backgroundThread` | `opencode/backgroundThread` | +| `codex/connected` | `opencode/connected` | +| `codex/event/skills_update_available` | `opencode/event/skills_update_available` | +| `codex/stderr` | `opencode/stderr` | + +### Autres + +| Ancien | Nouveau | +|--------|---------| +| `"codex"` (tab id) | `"opencode"` (tab id) | +| `Ask Codex to do something...` | `Ask OpenCode to do something...` | +| `Monitor the situation of your Codex agents` | `Monitor your OpenCode agents` | +| `Made with ♥ by Codex & Dimillian` | `Made with ♥ by Dimillian` | +| `www.codexmonitor.app` | `www.opencodemonitor.app` | +| `Dimillian/CodexMonitor` (GitHub) | `Dimillian/OpenCodeMonitor` | +| `codexmonitor.key` (signing) | `opencodemonitor.key` | +| `Codex Monitor.app` | `OpenCode Monitor.app` | +| `CodexMonitor.zip` | `OpenCodeMonitor.zip` | +| `gpt-5-codex` (default model) | Modèle par défaut OpenCode | +| `DEFAULT_AGENT_MODEL: "gpt-5-codex"` | Modèle par défaut OpenCode | +| `codex/` (branch prefix) | `opencode/` (branch prefix) | +| `__codex_monitor_page_start__` | `__opencode_monitor_page_start__` | diff --git a/migration-plan/04-rust-backend-plan.md b/migration-plan/04-rust-backend-plan.md new file mode 100644 index 0000000000..da99299489 --- /dev/null +++ b/migration-plan/04-rust-backend-plan.md @@ -0,0 +1,225 @@ +# Plan Backend Rust + +## Structure des Fichiers Après Migration + +``` +src-tauri/src/ +├── opencode/ # (ex: codex/) +│ ├── mod.rs # Tauri commands → appels HTTP +│ ├── args.rs # Résolution d'arguments opencode +│ ├── config.rs # Lecture/écriture opencode.json +│ └── home.rs # Résolution OPENCODE_CONFIG_DIR +├── backend/ +│ ├── app_server.rs # SUPPRIMER (remplacé par opencode_server.rs) +│ ├── opencode_server.rs # NOUVEAU: OpenCodeSession (HTTP client) +│ ├── process_core.rs # (inchangé: tokio process utils) +│ └── events.rs # Adapter EventSink +├── shared/ +│ ├── mod.rs # Renommer modules +│ ├── opencode_core.rs # (ex: codex_core.rs) Appels HTTP +│ ├── opencode_aux_core.rs # (ex: codex_aux_core.rs) +│ ├── opencode_update_core.rs # (ex: codex_update_core.rs) +│ ├── config_toml_core.rs # SUPPRIMER ou adapter +│ ├── settings_core.rs # Adapter (plus de sync config.toml) +│ ├── agents_config_core.rs # Adapter au format OpenCode +│ ├── prompts_core.rs # Adapter chemins +│ ├── files_core.rs # Adapter chemins +│ ├── local_usage_core.rs # Adapter chemins +│ └── ...autres modules # Ajustements mineurs +├── bin/ +│ ├── opencode_monitor_daemon.rs # (ex: codex_monitor_daemon.rs) +│ ├── opencode_monitor_daemonctl # (ex: codex_monitor_daemonctl.rs) +│ └── opencode_monitor_daemon/ # (ex: codex_monitor_daemon/) +│ ├── rpc.rs +│ ├── dispatcher.rs +│ ├── opencode.rs # RPC methods pour OpenCode +│ ├── workspace.rs +│ ├── git.rs +│ ├── prompts.rs +│ └── daemon.rs +├── lib.rs # Renommer imports de modules +├── state.rs # Renommer types +├── types.rs # Renommer champs +└── ...autres fichiers # Renommer références +``` + +## Étape 1: Renommage des Modules et Fichiers + +```bash +# Déplacer/renommer les dossiers +mv src-tauri/src/codex src-tauri/src/opencode +mv src-tauri/src/bin/codex_monitor_daemon.rs src-tauri/src/bin/opencode_monitor_daemon.rs +mv src-tauri/src/bin/codex_monitor_daemonctl.rs src-tauri/src/bin/opencode_monitor_daemonctl.rs +mv src-tauri/src/bin/codex_monitor_daemon src-tauri/src/bin/opencode_monitor_daemon + +# Renommer les fichiers dans le nouveau dossier opencode/ +mv src-tauri/src/opencode/config.rs src-tauri/src/opencode/config.rs # déjà bon +mv src-tauri/src/opencode/args.rs src-tauri/src/opencode/args.rs # déjà bon +mv src-tauri/src/opencode/home.rs src-tauri/src/opencode/home.rs # déjà bon + +# Renommer les modules shared +mv src-tauri/src/shared/codex_core.rs src-tauri/src/shared/opencode_core.rs +mv src-tauri/src/shared/codex_aux_core.rs src-tauri/src/shared/opencode_aux_core.rs +mv src-tauri/src/shared/codex_update_core.rs src-tauri/src/shared/opencode_update_core.rs +``` + +## Étape 2: Réécriture du Calque de Communication + +### Nouveau fichier: `backend/opencode_server.rs` + +Remplacer `WorkspaceSession` (JSON-RPC stdio) par `OpenCodeSession` (HTTP): + +```rust +// Architecture de OpenCodeSession +pub(crate) struct OpenCodeSession { + process: tokio::process::Child, + base_url: String, // http://127.0.0.1:{port} + client: reqwest::Client, // HTTP client + // ... channels pour événements +} + +pub(crate) async fn spawn_opencode_session( + entry: &WorkspaceEntry, + default_bin: Option, + opencode_args: Option, + app_handle: AppHandle, + opencode_home: Option, +) -> Arc { + // 1. Vérifier installation: opencode --version + // 2. Construire commande: opencode serve --port {auto} --hostname 127.0.0.1 + // 3. Lire le port depuis stdout (opencode imprime le port) + // 4. Initialiser le client HTTP + // 5. Ping l'API /health pour confirmer + // 6. Retourner la session +} +``` + +### API HTTP OpenCode à utiliser + +Basé sur `opencode_ai_llms.txt`: + +| Méthode | Endpoint / Commande | +|---------|-------------------| +| POST | `/session/:id/init` | +| GET | `/session/:id/children` | +| GET | `/config` | +| GET | `/config/providers` | +| CLI | `opencode run "prompt"` (pour prompts one-shot) | +| CLI | `opencode github install` (GitHub agent) | + +### Nouveau fichier: `shared/opencode_core.rs` + +```rust +// Exemple de structure des appels HTTP + +pub(crate) async fn start_session_core( + sessions: &HashMap>, + workspace_id: &str, +) -> Result { + let session = sessions.get(workspace_id).ok_or("Session not found")?; + let resp = session.client + .post(format!("{}/session", session.base_url)) + .json(&serde_json::json!({ + "model": "anthropic/claude-sonnet-4-5", + })) + .send() + .await + .map_err(|e| format!("HTTP error: {e}"))?; + // ... parsing réponse +} + +pub(crate) async fn send_message_core( + sessions: &HashMap>, + workspace_id: &str, + thread_id: &str, + message: &str, +) -> Result<(), String> { + let session = sessions.get(workspace_id).ok_or("Session not found")?; + // Utiliser opencode run pour envoyer le message dans la session + // ou POST à l'API session/:id/turn + todo!("Implémenter selon l'API OpenCode réelle") +} +``` + +### Nouveau fichier: `shared/opencode_aux_core.rs` + +```rust +pub(crate) async fn opencode_check_core( + settings: &AppSettings, + opencode_bin: Option, + opencode_args: Option, +) -> OpenCodeCheckResult { + // opencode --version au lieu de codex --version + // opencode serve --help au lieu de codex app-server --help +} + +pub(crate) async fn generate_commit_message_core( + // Utiliser opencode run avec un prompt dédié + // au lieu de background thread codex +) -> Result { + // Lancer: opencode run "Generate a git commit message..." + // Récupérer la sortie +} +``` + +## Étape 3: Mise à Jour de Cargo.toml + +```toml +[package] +name = "opencode-monitor" # au lieu de "codex-monitor" + +[[bin]] +name = "opencode-monitor" # au lieu de "codex-monitor" + +[[bin]] +name = "opencode-monitor-daemon" # au lieu de "codex-monitor-daemon" + +[[bin]] +name = "opencode-monitor-daemonctl" # au lieu de "codex-monitor-daemonctl" + +[lib] +name = "opencode_monitor_lib" # au lieu de "codex_monitor_lib" +``` + +## Étape 4: Mise à Jour de lib.rs + +```rust +// Renommer les mod imports +mod opencode; // au lieu de mod codex; +// ... +use opencode::... // au lieu de use codex::... + +// Renommer les commandes Tauri +// "codex_doctor" → "opencode_check" +// "codex_update" → "opencode_update" +// etc. +``` + +## Étape 5: Adaptation des Autres Modules + +| Fichier | Changement | +|---------|------------| +| `state.rs` | `codex_login_cancels` → `opencode_login_cancels`, `sessions` type change | +| `types.rs` | Renommer champs `codex_bin` → `opencode_bin`, `codex_args` → `opencode_args` | +| `tray.rs` | Renommer tooltip | +| `storage.rs` | Chemins de données | +| `workspaces/` | Adapter les appels à `spawn_opencode_session` | +| `files/` | Adapter les chemins CODEX_HOME | +| `tailscale/` | Renommer nom du daemon | +| `remote_backend/` | Adapter au nouveau protocole | +| `settings/` | Adapter les commandes Tauri | +| `prompts/` | Adapter les chemins | +| `menu.rs` | Renommer les références | + +## Fichier Clé: `backend/app_server.rs` + +C'est le fichier le plus impacté (~1100 lignes). Il doit être réécrit pour: + +1. Lancer `opencode serve` au lieu de `codex app-server` +2. Utiliser reqwest HTTP client au lieu de JSON-RPC stdio parsing +3. Adapter le système d'initialization (pas de `initialize` JSON-RPC) +4. Adapter le routage des événements (pas de notifications JSON-RPC push) +5. Remplacer le système de pending requests one-shot par des appels HTTP directs + +**Approche recommandée**: Ne pas modifier `app_server.rs` — créer `opencode_server.rs` +et supprimer l'ancien fichier. C'est une réécriture complète. diff --git a/migration-plan/05-frontend-plan.md b/migration-plan/05-frontend-plan.md new file mode 100644 index 0000000000..932a7f0beb --- /dev/null +++ b/migration-plan/05-frontend-plan.md @@ -0,0 +1,286 @@ +# Plan Frontend TypeScript/React + +## 1. Types Partagés (`src/types.ts`) + +```typescript +// Ancien +export interface AppSettings { + codexBin: string | null; // → opencodeBin + codexArgs: string | null; // → opencodeArgs + // ... +} + +// Nouveau +export interface AppSettings { + opencodeBin: string | null; + opencodeArgs: string | null; + // ... +} +``` + +### Types à renommer + +| Ancien | Nouveau | +|--------|---------| +| `CodexFeatureStage` | `OpenCodeFeatureStage` | +| `CodexFeature` | `OpenCodeFeature` | +| `CodexDoctorResult` | `OpenCodeCheckResult` | +| `CodexUpdateMethod` | `OpenCodeUpdateMethod` | +| `CodexUpdateResult` | `OpenCodeUpdateResult` | + +## 2. Services IPC (`src/services/tauri.ts`) + +```typescript +// Ancien +export async function getCodexConfigPath(): Promise { + return invoke("get_codex_config_path"); +} +export async function runCodexDoctor(codexBin, codexArgs): Promise { + return invoke("codex_doctor", { codexBin, codexArgs }); +} +export async function runCodexLogin(workspaceId) { + return invoke("codex_login", { workspaceId }); +} +export async function cancelCodexLogin(workspaceId) { + return invoke("codex_login_cancel", { workspaceId }); +} +export async function setCodexFeatureFlag(featureKey, enabled) { + return invoke("set_codex_feature_flag", { featureKey, enabled }); +} +export async function setWorkspaceRuntimeCodexArgs(workspaceId, codexArgs) { + return invoke("set_workspace_runtime_codex_args", { workspaceId, codexArgs }); +} + +// Nouveau +export async function getOpenCodeConfigPath(): Promise { + return invoke("get_opencode_config_path"); +} +export async function runOpenCodeCheck(opencodeBin, opencodeArgs): Promise { + return invoke("opencode_check", { opencodeBin, opencodeArgs }); +} +// etc. +``` + +### Fonctions IPC à renommer (liste complète) + +| Ancienne | Nouvelle | +|----------|----------| +| `getCodexConfigPath` | `getOpenCodeConfigPath` | +| `readGlobalCodexConfigToml` | `readGlobalOpenCodeConfigJson` | +| `writeGlobalCodexConfigToml` | `writeGlobalOpenCodeConfigJson` | +| `setWorkspaceRuntimeCodexArgs` | `setWorkspaceRuntimeOpenCodeArgs` | +| `setCodexFeatureFlag` | `setOpenCodeFeatureFlag` | +| `runCodexLogin` | `runOpenCodeLogin` | +| `cancelCodexLogin` | `cancelOpenCodeLogin` | +| `runCodexDoctor` | `runOpenCodeCheck` | +| `runCodexUpdate` | `runOpenCodeUpdate` | + +## 3. Événements (`src/services/events.ts`, `src/utils/appServerEvents.ts`) + +```typescript +// Ancien +export const APP_SERVER_EVENT_METHODS = { + BACKGROUND: "codex/backgroundThread", + CONNECTED: "codex/connected", + SKILLS_UPDATE: "codex/event/skills_update_available", +} as const; + +// Nouveau +export const APP_SERVER_EVENT_METHODS = { + BACKGROUND: "opencode/backgroundThread", + CONNECTED: "opencode/connected", + SKILLS_UPDATE: "opencode/event/skills_update_available", +} as const; +``` + +## 4. Utilitaires Thread + +### `src/features/threads/utils/threadStorage.ts` + +```typescript +// Clés localStorage +STORAGE_KEY_THREAD_CODEX_PARAMS = "codexmonitor.threadCodexParams" +// → "opencodemonitor.threadOpenCodeParams" + +// Type +export type ThreadCodexParams = { + // → ThreadOpenCodeParams + codexArgsOverride: string | null | undefined; + // → opencodeArgsOverride +}; + +export function makeThreadCodexParamsKey(workspaceId: string, threadId: string): string { + // → makeThreadOpenCodeParamsKey +} +``` + +### `src/features/threads/utils/codexArgsProfiles.ts` + +Migrer les profiles d'arguments Codex → OpenCode. OpenCode a une interface CLI +différente: `opencode [project]`, `opencode run`, `opencode serve`, etc. + +Les flags ignorés (`--model`, `--sandbox`) doivent être adaptés aux flags OpenCode. + +### `src/features/threads/utils/threadCodexParamsSeed.ts` + +Renommer tous les types et fonctions: +- `ThreadCodexParams` → `ThreadOpenCodeParams` +- `ThreadCodexSeedPatch` → `ThreadOpenCodeSeedPatch` +- `ResolvedThreadCodexState` → `ResolvedThreadOpenCodeState` +- `resolveWorkspaceRuntimeCodexArgsOverride` → `resolveWorkspaceRuntimeOpenCodeArgsOverride` + +### `src/features/threads/utils/threadCodexMetadata.ts` + +```typescript +// extractThreadCodexMetadata → extractThreadOpenCodeMetadata +// Modèle par défaut: "gpt-5-codex" → modèle par défaut OpenCode +``` + +## 5. Hooks Thread + +### `src/features/threads/hooks/useThreadCodexParams.ts` + +Renommer: +- `STORAGE_KEY_THREAD_CODEX_PARAMS` +- `ThreadCodexParams`, `ThreadCodexParamsMap` +- `useThreadCodexParams` +- `getThreadCodexParams`, `patchThreadCodexParams`, `deleteThreadCodexParams` +- `codexArgsOverride` dans les types + +### `src/features/threads/hooks/useThreads.ts` + +Renommer: +- `ensureWorkspaceRuntimeCodexArgs` → `ensureWorkspaceRuntimeOpenCodeArgs` +- `shouldPreflightRuntimeCodexArgsForSend` → `shouldPreflightRuntimeOpenCodeArgsForSend` +- `onThreadCodexMetadataDetected` → `onThreadOpenCodeMetadataDetected` +- `thread/runtime-codex-args` → `thread/runtime-opencode-args` + +### `src/features/threads/hooks/useThreadEventHandlers.ts` + +```typescript +// codex/stderr → opencode/stderr +const inferredSource = method === "opencode/stderr" ? "stderr" : "event"; +``` + +## 6. Composants Principaux + +### `src/App.tsx` + +Mettre à jour imports, références à Codex. + +### `src/features/app/components/MainApp.tsx` + +Renommer hooks et état: +- `useMainAppThreadCodexState` → `useMainAppThreadOpenCodeState` +- `useThreadCodexBootstrapOrchestration` → `useThreadOpenCodeBootstrapOrchestration` +- `useThreadCodexSyncOrchestration` → `useThreadOpenCodeSyncOrchestration` +- `preferredCodexArgsOverride` → `preferredOpenCodeArgsOverride` +- `selectedCodexArgsOverride` → `selectedOpenCodeArgsOverride` +- `codexArgsOptions` → `opencodeArgsOptions` +- `compactEmptyCodexNode` → `compactEmptyOpenCodeNode` +- `showCompactCodexThreadActions` → `showCompactOpenCodeThreadActions` +- `activeTab = "codex"` → `activeTab = "opencode"` +- `setActiveTab("codex")` → `setActiveTab("opencode")` + +### `src/features/app/components/TabBar.tsx` + +```tsx +// Ancien +{ id: "codex", label: "Codex", icon: }, + +// Nouveau +{ id: "opencode", label: "OpenCode", icon: }, +``` + +### `src/features/app/components/TabletNav.tsx` + +Même changement pour le type `TabletNavTab` et les labels. + +### `src/features/composer/components/Composer.tsx` + +```tsx +// Props renommées +codexArgsOptions → opencodeArgsOptions +selectedCodexArgsOverride → selectedOpenCodeArgsOverride +onSelectCodexArgsOverride → onSelectOpenCodeArgsOverride +``` + +### `src/features/composer/components/ComposerInput.tsx` + +```tsx +// Placeholder +"Ask Codex to do something..." → "Ask OpenCode to do something..." +``` + +### `src/features/composer/components/ComposerMetaBar.tsx` + +```tsx +// Imports +import type { CodexArgsOption } from "../../threads/utils/codexArgsProfiles"; +// → import type { OpenCodeArgsOption } from "../../threads/utils/opencodeArgsProfiles"; +``` + +## 7. Paramètres (Settings) + +### `src/features/settings/components/sections/SettingsCodexSection.tsx` + +Renommer le composant en `SettingsOpenCodeSection.tsx`, titres et descriptions. + +### `src/features/settings/hooks/useSettingsCodexSection.ts` + +Renommer le hook et les appels IPC. + +### `src/features/settings/hooks/useGlobalCodexConfigToml.ts` + +Adapter au format JSON d'OpenCode au lieu de TOML. + +## 8. Hooks et Services Divers + +| Fichier | Changement | +|---------|------------| +| `src/features/workspaces/hooks/useWorktreePrompt.ts` | `codex/` → `opencode/` branch prefix | +| `src/features/workspaces/hooks/useWorkspaceSelection.ts` | `tab: "codex"` → `tab: "opencode"` | +| `src/features/layout/hooks/layoutNodes/types.ts` | `compactEmptyCodexNode` → `compactEmptyOpenCodeNode` | +| `src/features/layout/hooks/layoutNodes/buildSecondaryNodes.tsx` | Renommer | +| `src/features/update/utils/postUpdateRelease.ts` | GitHub URLs | +| `src/features/prompts/components/PromptPanel.tsx` | `CODEX_HOME/prompts` → `OPENCODE_CONFIG_DIR/prompts` | +| `src/features/git/hooks/usePullRequestComposer.ts` | `tab: "codex"` → `tab: "opencode"` | +| `src/features/git/hooks/useAutoExitEmptyDiff.ts` | `tab: "codex"` → `tab: "opencode"` | +| `src/features/about/components/AboutView.tsx` | Texte, GitHub URL | +| `src/features/skills/hooks/useSkills.test.tsx` | Event names dans les tests | +| `src/features/app/components/WorktreeCard.tsx` | Texte tooltip | +| `src/features/app/components/WorkspaceCard.tsx` | Texte tooltip | +| `vite.config.ts` | `.codex-worktrees/` → `.opencode-worktrees/` | + +## 9. localStorage Keys + +Toutes les clés `codexmonitor.*` → `opencodemonitor.*` dans: + +- `src/features/threads/utils/threadStorage.ts` +- `src/features/layout/hooks/useResizablePanels.ts` +- `src/features/layout/hooks/useSidebarToggles.tsx` +- `src/features/composer/hooks/usePromptHistory.test.tsx` +- `src/features/update/utils/postUpdateRelease.ts` + +## 10. Fichiers de Test + +Tous les fichiers `.test.ts` et `.test.tsx` qui référencent Codex doivent être mis à jour: + +- `src/services/tauri.test.ts` +- `src/utils/appServerEvents.test.ts` +- `src/utils/codexArgsInput.test.ts` +- `src/utils/threadItems.test.ts` +- `src/features/threads/utils/threadCodexParamsSeed.test.ts` +- `src/features/threads/utils/threadCodexMetadata.test.ts` +- `src/features/threads/utils/codexArgsProfiles.test.ts` +- `src/features/threads/hooks/useThreadCodexParams.test.tsx` +- `src/features/threads/hooks/useThreads.integration.test.tsx` +- `src/features/threads/hooks/useThreadMessaging.test.tsx` +- `src/features/threads/hooks/useThreadActions.test.tsx` +- `src/features/threads/hooks/useThreadItemEvents.test.ts` +- `src/features/settings/hooks/useUpdater.test.ts` +- `src/features/layout/hooks/useResizablePanels.test.ts` +- `src/features/composer/hooks/usePromptHistory.test.tsx` +- `src/features/skills/hooks/useSkills.test.tsx` +- `src/features/prompts/hooks/useCustomPrompts.test.tsx` +- `src/features/update/components/UpdateToast.test.tsx` diff --git a/migration-plan/06-config-adaptation.md b/migration-plan/06-config-adaptation.md new file mode 100644 index 0000000000..808a1bef5f --- /dev/null +++ b/migration-plan/06-config-adaptation.md @@ -0,0 +1,167 @@ +# Adaptation du Système de Configuration + +## Différence Fondamentale + +| Aspect | Codex | OpenCode | +|--------|-------|----------| +| Format | `config.toml` (TOML) | `opencode.json` (JSON/JSONC) | +| Emplacement | `$CODEX_HOME/config.toml` (`~/.codex/`) | `~/.config/opencode/opencode.json` | +| Features | `[features]` section | Pas équivalent direct | +| Personnalité | `personality = "pragmatic"` | Configurable dans `opencode.json` | +| Agents | `.codex/agents/config.toml` | `subagents` dans `opencode.json` | +| Auth | `auth.json` séparé | Providers dans `opencode.json` + keyring | + +## 1. Fichier `opencode/config.rs` + +### Nouvelle Structure + +```rust +pub(crate) fn read_opencode_config() -> Result, String> { + let config_dir = resolve_opencode_config_dir(); + let config_path = config_dir.join("opencode.json"); + // Lire et parser le JSON +} + +pub(crate) fn write_opencode_config(config: &OpenCodeConfig) -> Result<(), String> { + let config_dir = resolve_opencode_config_dir(); + let config_path = config_dir.join("opencode.json"); + // Écrire le JSON formaté +} + +pub(crate) fn read_model() -> Result, String> { + // Lire "model" depuis opencode.json +} + +pub(crate) fn read_feature_flags() -> Result { + // OpenCode n'a pas de feature flags équivalents + // Retourner des valeurs par défaut +} +``` + +### Mapping des Paramètres + +| Paramètre Codex | Paramètre OpenCode | +|-----------------|-------------------| +| `model` | `model` (même clé) | +| `personality` | (non supporté) | +| `features.steer` | (géré par OpenCode automatiquement) | +| `features.collaboration_modes` | (non supporté) | +| `features.unified_exec` | (non supporté) | +| `features.apps` | (plugins MCP) | +| `review_model` | (non supporté) | +| `model_provider` | Provider dans `opencode.json` | +| `service_tier` | (non supporté) | +| `developer_instructions` | `instructions` (fichiers) | +| `commit_attribution` | (non supporté) | + +## 2. Fichier `opencode/home.rs` + +```rust +pub(crate) fn resolve_default_opencode_home() -> Option { + // Priorité: + // 1. $OPENCODE_CONFIG_DIR env var + // 2. $XDG_CONFIG_HOME/opencode (Linux) + // 3. ~/.config/opencode (fallback) + // 4. ~/Library/Application Support/opencode (macOS) + // 5. %APPDATA%/opencode (Windows) +} + +pub(crate) fn resolve_workspace_opencode_home( + entry: &WorkspaceEntry, + app_settings: Option<&AppSettings>, +) -> Option { + // Similaire à resolve_workspace_codex_home mais avec le nouveau chemin +} + +pub(crate) fn opencode_config_path() -> PathBuf { + resolve_default_opencode_home().map(|h| h.join("opencode.json")) +} +``` + +## 3. Fichier `shared/settings_core.rs` + +Adapter pour ne plus synchroniser les feature flags avec `config.toml`: + +```rust +pub(crate) fn get_app_settings_core() -> Result { + // Lire les settings depuis settings.json (inchangé) + // MAIS: ne plus lire config.toml pour les features flags +} + +pub(crate) fn update_app_settings_core(settings: AppSettings) -> Result { + // Écrire les settings + // MAIS: ne plus écrire dans config.toml + // Optionnel: synchroniser certaines valeurs dans opencode.json +} +``` + +## 4. Fichier `shared/config_toml_core.rs` + +**Option A**: Supprimer le fichier (si OpenCode ne supporte pas config.toml). + +**Option B**: Garder pour compatibilité avec les utilisateurs qui ont encore Codex +installé, mais le rendre optionnel. + +**Recommandation**: Supprimer. OpenCode utilise `opencode.json`, pas `config.toml`. + +## 5. Fichier `shared/agents_config_core.rs` + +OpenCode a un concept de sub-agents différent. Vérifier la documentation OpenCode +pour savoir comment configurer les sub-agents. + +```rust +// Structure probable pour OpenCode (à vérifier avec ctx7) +// opencode.json: +// { +// "subagents": { +// "explorer": { +// "model": "anthropic/claude-sonnet-4-5", +// "instructions": "..." +// } +// } +// } + +pub(crate) fn collect_agents(opencode_home: &Path) -> Result, String> { + let config_path = opencode_home.join("opencode.json"); + // Lire et parser les sub-agents depuis le JSON +} +``` + +## 6. Fichier `shared/account.rs` + +```rust +pub(crate) fn read_auth_account(opencode_home: Option) -> Option { + let opencode_home = opencode_home?; + // OpenCode stocke l'auth dans opencode.json ou via keyring OS + // À adapter selon la doc OpenCode + let auth_path = opencode_home.join("opencode.json"); + // ... +} +``` + +## 7. Fichiers de Prompts + +```rust +// shared/prompts_core.rs + +// Ancien: ~/.codex/prompts/ +// Nouveau: ~/.config/opencode/prompts/ + +pub(crate) fn global_prompts_dir() -> Option { + resolve_default_opencode_home().map(|h| h.join("prompts")) +} +``` + +## Résumé: Changements dans les Fichiers + +| Fichier | Action | +|---------|--------| +| `codex/config.rs` → `opencode/config.rs` | Réécrire: TOML → JSON | +| `codex/home.rs` → `opencode/home.rs` | Réécrire: ~/.codex → ~/.config/opencode | +| `shared/config_toml_core.rs` | Supprimer | +| `shared/settings_core.rs` | Adapter: enlever sync config.toml | +| `shared/agents_config_core.rs` | Adapter: format JSON au lieu de TOML | +| `shared/account.rs` | Adapter: auth depuis opencode.json | +| `shared/prompts_core.rs` | Adapter: nouveaux chemins | +| `shared/files_core.rs` | Adapter: nouveaux chemins | +| `shared/local_usage_core.rs` | Adapter: nouveaux chemins | diff --git a/migration-plan/07-daemon-rpc-plan.md b/migration-plan/07-daemon-rpc-plan.md new file mode 100644 index 0000000000..c0ca364873 --- /dev/null +++ b/migration-plan/07-daemon-rpc-plan.md @@ -0,0 +1,193 @@ +# Plan Daemon RPC + +## Architecture Actuelle + +``` +┌──────────────┐ TCP JSON-RPC ┌──────────────────────────┐ +│ Tauri App │ ◄──────────────────► │ codex-monitor-daemon │ +│ (Remote) │ std: JSON-RPC │ │ +│ │ │ ┌────────────────────┐ │ +│ │ │ │ codex app-server │ │ +│ │ │ │ (stdin/stdout) │ │ +│ │ │ └────────────────────┘ │ +└──────────────┘ └──────────────────────────┘ +``` + +## Architecture Cible + +``` +┌──────────────┐ TCP JSON-RPC ┌──────────────────────────┐ +│ Tauri App │ ◄──────────────────► │ opencode-monitor-daemon │ +│ (Remote) │ (adapté) │ │ +│ │ │ ┌────────────────────┐ │ +│ │ │ │ opencode serve │ │ +│ │ │ │ (HTTP REST API) │ │ +│ │ │ └────────────────────┘ │ +└──────────────┘ └──────────────────────────┘ +``` + +## 1. Renommage des Binaires + +| Ancien | Nouveau | +|--------|---------| +| `codex-monitor-daemon` | `opencode-monitor-daemon` | +| `codex-monitor-daemonctl` | `opencode-monitor-daemonctl` | +| `codex_monitor_daemon` (source) | `opencode_monitor_daemon` | +| `codex_monitor_daemonctl` (source) | `opencode_monitor_daemonctl` | +| `CODEX_MONITOR_DAEMON_TOKEN` | `OPENCODE_MONITOR_DAEMON_TOKEN` | +| `CODEX_MONITOR_DAEMON_PATH` | `OPENCODE_MONITOR_DAEMON_PATH` | +| `EXPECTED_DAEMON_NAME: "codex-monitor-daemon"` | `"opencode-monitor-daemon"` | + +## 2. Adaptation du Fichier Principal `bin/opencode_monitor_daemon.rs` + +### Ancien: Lance `codex app-server` (JSON-RPC stdio) +### Nouveau: Lance `opencode serve` (HTTP REST) + +Les changements principaux: + +```rust +// Ancien (codex) +fn spawn_workspace_session(entry, bin, args, ...) { + let mut cmd = tokio::process::Command("codex"); + cmd.args(["app-server"]) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + // JSON-RPC over stdio +} + +// Nouveau (opencode) +fn spawn_opencode_session(entry, bin, args, ...) { + let mut cmd = tokio::process::Command("opencode"); + cmd.args(["serve", "--port", "0", "--hostname", "127.0.0.1"]) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + // Lire le port depuis stdout + // Utiliser reqwest HTTP client pour la communication +} +``` + +### Auth + +```rust +// Ancien +let token = env::var("CODEX_MONITOR_DAEMON_TOKEN"); + +// Nouveau +let token = env::var("OPENCODE_MONITOR_DAEMON_TOKEN"); +``` + +## 3. Adaptation du Daemonctl + +### `bin/opencode_monitor_daemonctl.rs` + +```rust +// Ancien +const EXPECTED_DAEMON_NAME: &str = "codex-monitor-daemon"; +const APP_IDENTIFIER: &str = "com.dimillian.codexmonitor"; + +// Nouveau +const EXPECTED_DAEMON_NAME: &str = "opencode-monitor-daemon"; +const APP_IDENTIFIER: &str = "com.dimillian.opencodemonitor"; +``` + +### Commandes daemonctl + +```rust +// Ancien: ./codex-monitor-daemonctl start +// Nouveau: ./opencode-monitor-daemonctl start + +// Ancien: cargo run --bin codex_monitor_daemonctl +// Nouveau: cargo run --bin opencode_monitor_daemonctl +``` + +## 4. Adaptation du RPC Layer + +### `bin/opencode_monitor_daemon/rpc.rs` + +```rust +// Ancien (codex.rs handler) +"get_codex_config_path" => { + settings_core::get_codex_config_path_core() +} +"set_codex_feature_flag" => { + state.set_codex_feature_flag(feature_key, enabled) +} +"codex_login" => { + state.codex_login(workspace_id) +} + +// Nouveau (opencode.rs handler) +"get_opencode_config_path" => { + settings_core::get_opencode_config_path_core() +} +"set_opencode_feature_flag" => { + state.set_opencode_feature_flag(feature_key, enabled) +} +"opencode_login" => { + state.opencode_login(workspace_id) +} +``` + +### `bin/opencode_monitor_daemon/rpc/codex.rs` → `opencode.rs` + +Adapter les method handlers pour le nouveau protocole OpenCode: +- Les appels JSON-RPC deviennent des appels HTTP +- Les réponses asynchrones deviennent des réponses HTTP synchrones (ou avec polling) +- Les événements push doivent être gérés différemment + +## 5. Adaptation du Remote Backend + +### `remote_backend/transport.rs` et `tcp_transport.rs` + +Le transport TCP peut rester largement inchangé — il encapsule juste des messages +JSON-RPC. C'est le contenu des messages qui change. + +### `remote_backend/protocol.rs` + +Adapter les méthodes RPC pour correspondre au nouveau protocole OpenCode. + +### `remote_backend/mod.rs` + +```rust +// Ancien +"set_workspace_runtime_codex_args" + +// Nouveau +"set_workspace_runtime_opencode_args" +``` + +## 6. Adaptation du Module Tailscale + +### `tailscale/daemon_commands.rs` + +```rust +// Ancien +const EXPECTED_DAEMON_NAME: &str = "codex-monitor-daemon"; + +// Nouveau +const EXPECTED_DAEMON_NAME: &str = "opencode-monitor-daemon"; +``` + +### `tailscale/core.rs` + +Mettre à jour les chemins de binaires dans les tests. + +## 7. Tableau Récapitulatif + +| Fichier | Changement | +|---------|------------| +| `bin/codex_monitor_daemon.rs` | Renommer + adapter spawn pour `opencode serve` | +| `bin/codex_monitor_daemonctl.rs` | Renommer + adapter noms | +| `bin/codex_monitor_daemon/rpc.rs` | Renommer | +| `bin/codex_monitor_daemon/rpc/codex.rs` | Renommer + adapter method handlers | +| `bin/codex_monitor_daemon/rpc/dispatcher.rs` | Mettre à jour dispatch | +| `bin/codex_monitor_daemon/rpc/workspace.rs` | Renommer méthodes | +| `bin/codex_monitor_daemon/rpc/daemon.rs` | (inchangé) | +| `bin/codex_monitor_daemon/rpc/git.rs` | (inchangé) | +| `bin/codex_monitor_daemon/rpc/prompts.rs` | Adapter chemins | +| `remote_backend/mod.rs` | Adapter noms de méthodes | +| `remote_backend/transport.rs` | (inchangé) | +| `remote_backend/tcp_transport.rs` | (inchangé) | +| `tailscale/daemon_commands.rs` | Renommer daemon name | +| `tailscale/core.rs` | Adapter chemins | diff --git a/migration-plan/08-docs-scripts-ci.md b/migration-plan/08-docs-scripts-ci.md new file mode 100644 index 0000000000..8f65213ab1 --- /dev/null +++ b/migration-plan/08-docs-scripts-ci.md @@ -0,0 +1,234 @@ +# Documentation, Scripts et CI/CD + +## 1. README.md + +Réécrire `README.md` avec les références OpenCode: + +```markdown +# OpenCodeMonitor + +OpenCodeMonitor is a Tauri app for orchestrating multiple OpenCode agents across +local workspaces. It provides a sidebar to manage projects, a home screen for +quick actions, and a conversation view backed by the OpenCode serve API. +``` + +### Sections à mettre à jour + +| Ligne | Ancien | Nouveau | +|-------|--------|---------| +| 1 | `# CodexMonitor` | `# OpenCodeMonitor` | +| 3 | Badge gitcgr (CodexMonitor) | Badge gitcgr (OpenCodeMonitor) | +| 7 | `CodexMonitor is a Tauri app for orchestrating multiple Codex agents` | `OpenCodeMonitor is a Tauri app for orchestrating multiple OpenCode agents` | +| 14 | `Spawn one codex app-server per workspace` | `Spawn one opencode serve per workspace` | +| 17 | `Optional remote backend (daemon) mode for running Codex on another machine` | `Optional remote backend (daemon) mode for running OpenCode on another machine` | +| 55 | `Codex CLI installed and available as codex in PATH` | `OpenCode CLI installed and available as opencode in PATH` | +| 114-130 | `codex_monitor_daemon`, `codex_monitor_daemonctl` | `opencode_monitor_daemon`, `opencode_monitor_daemonctl` | +| 279-301 | `codex_monitor_daemon.rs`, `codex/` | `opencode_monitor_daemon.rs`, `opencode/` | +| 293 | `~/.codex` | `~/.config/opencode` | +| 299 | `codex app-server` | `opencode serve` | + +### Nouvelles sections à ajouter + +```markdown +## Prerequisites + +- OpenCode CLI installed as `opencode` in PATH +- Run `opencode` at least once to configure your provider +``` + +## 2. Documentation (`docs/`) + +### `docs/codebase-map.md` + +Mettre à jour tous les chemins et noms de modules. + +| Ancien | Nouveau | +|--------|---------| +| `codex_monitor_daemon/rpc.rs` | `opencode_monitor_daemon/rpc.rs` | +| `src-tauri/src/codex/` | `src-tauri/src/opencode/` | +| `bin/codex_monitor_daemon/` | `bin/opencode_monitor_daemon/` | +| `shared/codex_core.rs` | `shared/opencode_core.rs` | +| `shared/codex_aux_core.rs` | `shared/opencode_aux_core.rs` | +| `shared/codex_update_core.rs` | `shared/opencode_update_core.rs` | + +### `docs/app-server-events.md` + +| Ancien | Nouveau | +|--------|---------| +| `CodexMonitor` | `OpenCodeMonitor` | +| `codex/backgroundThread` | `opencode/backgroundThread` | +| `codex/connected` | `opencode/connected` | +| `codex/event/skills_update_available` | `opencode/event/skills_update_available` | +| `codex_core.rs` | `opencode_core.rs` | +| `codex/mod.rs` | `opencode/mod.rs` | +| `codex_monitor_daemon.rs` | `opencode_monitor_daemon.rs` | + +Note: La section "Where To Look In ../Codex" doit être réécrite car OpenCode +est un projet différent (anomalyco/opencode). + +### `docs/multi-agent-sync-runbook.md` + +Ce fichier référençait `../Codex` comme upstream (le repo OpenAI Codex). +Doit être réécrit pour pointer vers la doc OpenCode: `https://opencode.ai/docs`. + +### `docs/mobile-ios-tailscale-blueprint.md` + +| Ancien | Nouveau | +|--------|---------| +| `CodexMonitor iOS Remote Blueprint` | `OpenCodeMonitor iOS Remote Blueprint` | +| `codex_monitor_daemon` | `opencode_monitor_daemon` | +| `codex_monitor_daemonctl` | `opencode_monitor_daemonctl` | +| `com.dimillian.codexmonitor` | `com.dimillian.opencodemonitor` | + +### `docs/index.html` + +Réécrire complètement le site web de documentation: + +- Titre: `Codex Monitor` → `OpenCode Monitor` +- Description: "Orchestrate Codex agents" → "Orchestrate OpenCode agents" +- URLs GitHub: `Dimillian/CodexMonitor` → `Dimillian/OpenCodeMonitor` +- Meta tags, OG tags, Twitter cards +- Testimonials, screenshots, footer + +### `docs/changelog.html` + +- `Codex Monitor` → `OpenCode Monitor` +- URLs mises à jour + +### `docs/CNAME` + +- `www.codexmonitor.app` → `www.opencodemonitor.app` + +## 3. Scripts (`scripts/`) + +### `scripts/build_run_ios_device.sh` + +```bash +# Ancien +BUNDLE_ID="com.dimillian.codexmonitor.ios" +APP_PATH=".../Codex Monitor.app" + +# Nouveau +BUNDLE_ID="com.dimillian.opencodemonitor.ios" +APP_PATH=".../OpenCode Monitor.app" +``` + +### `scripts/build_run_ios.sh` + +```bash +# Mêmes changements que ci-dessus +BUNDLE_ID="com.dimillian.opencodemonitor.ios" +``` + +### `scripts/release_testflight_ios.sh` + +```bash +# Ancien +BETA_DESCRIPTION="Codex Monitor iOS beta build..." +BUNDLE_ID="com.dimillian.codexmonitor.ios" +IPA_PATH=".../Codex Monitor.ipa" + +# Nouveau +BETA_DESCRIPTION="OpenCode Monitor iOS beta build..." +BUNDLE_ID="com.dimillian.opencodemonitor.ios" +IPA_PATH=".../OpenCode Monitor.ipa" +``` + +### `scripts/macos-fix-openssl.sh` + +```bash +# Ancien +app_path=".../Codex Monitor.app" +bin_path=".../codex-monitor" +daemon_path=".../codex_monitor_daemon" +daemonctl_path=".../codex_monitor_daemonctl" + +# Nouveau +app_path=".../OpenCode Monitor.app" +bin_path=".../opencode-monitor" +daemon_path=".../opencode_monitor_daemon" +daemonctl_path=".../opencode_monitor_daemonctl" +``` + +## 4. CI/CD (`.github/workflows/`) + +### `.github/workflows/release.yml` + +| Ancien | Nouveau | +|--------|---------| +| `codexmonitor.key` (signing key) | `opencodemonitor.key` | +| `codex_monitor_daemon` (build) | `opencode_monitor_daemon` | +| `codex_monitor_daemonctl` (build) | `opencode_monitor_daemonctl` | +| `Codex Monitor.app` | `OpenCode Monitor.app` | +| `CodexMonitor.zip` | `OpenCodeMonitor.zip` | +| `CodexMonitor_${VERSION}_aarch64.dmg` | `OpenCodeMonitor_${VERSION}_aarch64.dmg` | +| `CodexMonitor.app.tar.gz.sig` | `OpenCodeMonitor.app.tar.gz.sig` | +| `CodexMonitor/releases` | `OpenCodeMonitor/releases` | +| `Cargo.lock` package `codex-monitor` | `opencode-monitor` | +| `codex-monitor_iOS/Info.plist` | `opencode-monitor_iOS/Info.plist` | + +### `.github/workflows/ci.yml` + +- Aucune référence directe à "codex". Ajuster si nécessaire. + +## 5. Autres Fichiers + +### `AGENTS.md` + +```markdown +# Ancien +# CodexMonitor Agent Guide +CodexMonitor is a Tauri app that orchestrates Codex agents across local workspaces. + +# Nouveau +# OpenCodeMonitor Agent Guide +OpenCodeMonitor is a Tauri app that orchestrates OpenCode agents across local workspaces. +``` + +### `REMOTE_BACKEND_POC.md` + +Mettre à jour les noms de binaires et les chemins. + +### `flake.nix` + +```nix +# Ancien +description = "CodexMonitor Tauri app for orchestrating Codex agents"; +pname = "codex-monitor-frontend"; +pname = "codex-monitor"; +cp "$target_dir/release/codex-monitor" $out/bin/ + +# Nouveau +description = "OpenCodeMonitor Tauri app for orchestrating OpenCode agents"; +pname = "opencode-monitor-frontend"; +pname = "opencode-monitor"; +cp "$target_dir/release/opencode-monitor" $out/bin/ +``` + +### `package.json` + +```json +{ + "name": "opencode-monitor", + // au lieu de "codex-monitor" +} +``` + +### `.vscode/extensions.json` + +Aucun changement nécessaire. + +### `.github/FUNDING.yml` + +Aucun changement nécessaire. + +## 6. Doctor Scripts + +### `scripts/doctor.sh` + +Mettre à jour les messages et chemins. Vérifier que `opencode` est dans le PATH +au lieu de `codex`. + +### `scripts/doctor.mjs` + +Adapter pour vérifier l'installation d'OpenCode au lieu de Codex. diff --git a/migration-plan/09-optimizations.md b/migration-plan/09-optimizations.md new file mode 100644 index 0000000000..7d5e90ff52 --- /dev/null +++ b/migration-plan/09-optimizations.md @@ -0,0 +1,127 @@ +# Optimisations Post-Migration + +Cette section liste les optimisations possibles après la migration fonctionnelle +vers OpenCode. Certaines sont spécifiques à OpenCode, d'autres sont des +améliorations générales. + +## 1. Utiliser l'API HTTP REST d'OpenCode + +Contrairement à Codex qui utilisait un protocole JSON-RPC propriétaire sur stdio, +OpenCode expose une API HTTP REST. Cela permet: + +- **Moins de code boilerplate**: Plus besoin de parser des lignes JSON-RPC, + gérer des IDs de requêtes, des channels one-shot, etc. +- **Timeouts standard**: HTTP a des timeouts natifs. +- **Parallelisme**: Possibilité d'envoyer plusieurs requêtes simultanément. +- **Instrumentation**: Métriques HTTP standard (latence, status codes). + +```rust +// Au lieu de: +let (tx, rx) = oneshot::channel(); +pending.insert(request_id, tx); +stdin.write_line(json!({"id": request_id, "method": method, "params": params})); +let response = rx.await.map_err(|_| "timeout")?; + +// On peut faire: +let response = client + .post(format!("{}/session/{}/start", base_url, session_id)) + .json(¶ms) + .timeout(Duration::from_secs(300)) + .send() + .await?; +``` + +## 2. Remplacer `opencode serve` par SDK si disponible + +Si OpenCode propose un SDK npm/rust, l'utiliser au lieu de lancer un sous-processus: + +```typescript +// Au lieu de spawn opencode serve + HTTP +// Utiliser le SDK OpenCode directement +import { createOpencode } from "@opencode-ai/sdk"; +const { client } = await createOpencode(); +``` + +L'`opencode_ai_llms.txt` mentionne `@opencode-ai/sdk`. Cela permettrait +d'éliminer complètement la gestion de processus enfant. + +## 3. Simplifier le Système d'Événements + +Codex utilisait un système complexe d'événements push JSON-RPC. OpenCode +pourrait simplifier cela: + +- **Polling HTTP**: Remplacer les événements push par du polling périodique + sur l'API REST. +- **Webhooks/SSE**: Si OpenCode supporte Server-Sent Events, les utiliser. + +## 4. Nettoyer le Code Mort + +Après la migration, plusieurs modules et fonctions deviendront obsolètes: + +- `backend/app_server.rs`: Remplacé par `opencode_server.rs` +- `shared/codex_core.rs`: Remplacé par `opencode_core.rs` +- `shared/codex_aux_core.rs`: Remplacé par `opencode_aux_core.rs` +- `shared/codex_update_core.rs`: Remplacé par `opencode_update_core.rs` +- `shared/config_toml_core.rs`: Supprimé +- Fonctions `codex_login`/`codex_login_cancel`: À adapter ou supprimer +- Fonctions `set_codex_feature_flag`: À adapter ou supprimer + +## 5. Simplifier les Agents + +OpenCode n'a probablement pas le même système d'agents que Codex (multi-agent, +collaboration modes). Simplifier l'UI et la logique des agents pour correspondre +à ce qu'OpenCode supporte réellement. + +## 6. Améliorer la Résilience + +Avec HTTP: + +- **Retry automatique**: Utiliser `reqwest::Client` avec retry policy. +- **Circuit breaker**: Détecter si `opencode serve` est en panne et réessayer. +- **Health check**: `GET /health` si disponible. +- **Graceful shutdown**: `POST /shutdown` si disponible. + +## 7. Unifier le Mode Local et Remote + +Avec Codex, le mode local utilisait stdio et le mode remote utilisait TCP. +Les deux avaient des chemins de code différents. + +Avec OpenCode, les deux modes peuvent utiliser HTTP: +- Local: `http://127.0.0.1:{port}` (process enfant) +- Remote: `http://{host}:{port}` (daemon TCP) + +Le code du client HTTP peut être partagé à 100%. + +## 8. Réduire les Dépendances + +Vérifier les dépendances devenues inutiles après la migration: + +- `tokio-tungstenite`: Probablement plus nécessaire (était pour WebSocket) +- Réduire l'utilisation de `serde_json` si le format change +- Vérifier si `git2` avec vendored est toujours nécessaire + +## 9. Améliorer les Tests + +- Écrire des tests d'intégration avec un mock HTTP server +- Tester la résilience (timeouts, erreurs réseau) +- Tester la migration des données (localStorage, settings.json) + +## 10. Monitoring et Observabilité + +- Ajouter des métriques sur les appels API OpenCode +- Logger les performances (latence des appels) +- Dashboard de statut pour les sessions OpenCode + +## Priorité des Optimisations + +| Optimisation | Impact | Effort | Priorité | +|-------------|--------|--------|----------| +| 1. API HTTP REST | Élevé | Moyen | Haute | +| 2. SDK OpenCode | Très élevé | Faible | Haute | +| 3. Nettoyage code mort | Moyen | Faible | Haute | +| 4. Unifier local/remote | Moyen | Faible | Haute | +| 5. Résilience HTTP | Moyen | Faible | Moyenne | +| 6. Agents simplifiés | Moyen | Faible | Moyenne | +| 7. Tests améliorés | Moyen | Moyen | Moyenne | +| 8. Monitoring | Faible | Faible | Basse | +| 9. Réduire dépendances | Faible | Faible | Basse | diff --git a/migration-plan/10-testing-strategy.md b/migration-plan/10-testing-strategy.md new file mode 100644 index 0000000000..df4bb99524 --- /dev/null +++ b/migration-plan/10-testing-strategy.md @@ -0,0 +1,197 @@ +# Stratégie de Test et Validation + +## Principe Général + +La migration doit être validée à chaque étape. Utiliser les outils de test +existants du projet: + +```bash +npm run typecheck # Vérification TypeScript +npm run test # Tests unitaires frontend +npm run lint # Linting +cd src-tauri && cargo check # Vérification Rust +cd src-tauri && cargo test # Tests Rust +npm run tauri:dev # Test manuel +``` + +## Phase 1: Renommage Mécanique + +### Tests de régression + +```bash +# Après chaque renommage en masse: +npm run typecheck # Doit passer (pas de breaking TS) +cd src-tauri && cargo check # Doit passer (pas de breaking Rust) +npm run test # Les tests existants doivent toujours passer +cd src-tauri && cargo test # Idem +``` + +### Vérifications manuelles + +```bash +# Compter les références résiduelles à "codex" (doit être 0) +rg -i "codex" --include="*.rs" --include="*.ts" --include="*.tsx" \ + --include="*.json" --include="*.toml" --include="*.md" \ + --include="*.html" --include="*.sh" --include="*.yml" \ + --include="*.yaml" --include="*.nix" \ + --exclude-dir=node_modules --exclude-dir=target \ + --exclude-dir=.git --exclude="package-lock.json" \ + | grep -v "opencode" | grep -v "codec" | grep -v "unicode" +``` + +## Phase 2: Réécriture du Backend HTTP + +### Stratégie de test + +| Niveau | Méthode | Outil | +|--------|---------|-------| +| Unité | Tester les fonctions HTTP individuelles | `cargo test` | +| Intégration | Mock HTTP server pour simuler OpenCode | `wiremock` ou `httpmock` | +| Intégration | Tester avec un vrai `opencode serve` | Script shell | +| E2E | Tauri app complète | Test manuel | + +### Test avec mock HTTP + +```rust +// Ajouter wiremock dans Cargo.toml (dev-dependencies) +#[cfg(test)] +mod tests { + use wiremock::MockServer; + + #[tokio::test] + async fn test_start_session() { + let mock_server = MockServer::start().await; + let base_url = mock_server.uri(); + + // Configurer le mock + Mock::given(method("POST")) + .and(path("/session")) + .respond_with(ResponseTemplate::new(200) + .set_body_json(json!({"id": "session-1"}))) + .mount(&mock_server) + .await; + + // Tester la fonction + let result = start_session_core(&base_url).await; + assert!(result.is_ok()); + } +} +``` + +### Approche pour les tests d'intégration réels + +```bash +# 1. Démarrer opencode serve en arrière-plan +opencode serve --port 9999 --hostname 127.0.0.1 & +OPENCODE_PID=$! + +# 2. Lancer les tests Rust qui pointent sur ce serveur +OPENCODE_TEST_URL="http://127.0.0.1:9999" cargo test --test integration + +# 3. Arrêter le serveur +kill $OPENCODE_PID +``` + +## Phase 3: Frontend + +```bash +# Tests TypeScript (doivent tous passer) +npm run test + +# Type checking +npm run typecheck + +# Vérifier que les imports sont corrects +npx tsc --noEmit + +# Test manuel dans le navigateur +npm run dev +``` + +### Points de vérification frontend + +- [ ] Les types `AppSettings` sont correctement mis à jour +- [ ] Les appels IPC pointent vers les bonnes commandes Tauri +- [ ] Les clés localStorage sont mises à jour (anciennes données ignorées) +- [ ] Les noms d'événements sont corrects +- [ ] Les noms de tabs sont mis à jour ("Codex" → "OpenCode") +- [ ] Les labels et placeholders sont mis à jour +- [ ] Les imports utilisent les nouveaux chemins +- [ ] Les tests passent + +## Phase 4: Configuration + +```bash +# Tester la migration des settings +# Vérifier que l'ancien ~/.codex/ n'est plus utilisé +# Vérifier que ~/.config/opencode/opencode.json est correctement parsé +cd src-tauri && cargo test -- opencode_config +``` + +## Phase 5: Daemon + +```bash +# Build les binaires +cargo build --bin opencode_monitor_daemon --bin opencode_monitor_daemonctl + +# Tester le daemon +./target/debug/opencode_monitor_daemonctl status + +# Tests Rust +cargo test --bin opencode_monitor_daemon +``` + +## Phase 6: Documentation et CI + +- [ ] `cargo doc --no-deps` ne produit pas d'erreurs +- [ ] Les workflows GitHub sont valides (vérifier avec `actionlint`) +- [ ] Les scripts shell ne contiennent plus de références à "codex" + +## Phase 7: Tests de Non-Régression Fonctionnels + +### Checklist fonctionnelle + +- [ ] L'application se lance et affiche la UI +- [ ] Les workspaces peuvent être ajoutés et configurés +- [ ] Les sessions OpenCode sont créées et listées +- [ ] Les messages peuvent être envoyés et reçus +- [ ] Le mode remote fonctionne (daemon TCP) +- [ ] Les paramètres sont persistés et chargés +- [ ] Les prompts personnalisés fonctionnent +- [ ] Les branches worktree sont créées correctement +- [ ] Le système de notification (tray) fonctionne +- [ ] Les raccourcis claviers sont fonctionnels +- [ ] Le panneau git affiche les changements +- [ ] Le panneau de terminal fonctionne +- [ ] Les mises à jour automatiques fonctionnent (si configurées) + +## Validation Continue + +Ajouter une GitHub Action qui valide la migration: + +```yaml +name: Migration Validation + +on: + push: + branches: [main] + pull_request: + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: npm install + - run: npm run typecheck + - run: npm run test + - run: npm run lint + - name: Check no "codex" references remain + run: | + ! rg -i "codex" --include="*.rs" --include="*.ts" --include="*.tsx" \ + --exclude-dir=node_modules --exclude-dir=target --exclude-dir=.git \ + | grep -v "opencode" | grep -v "codec" | grep -v "unicode" \ + | grep "codex" + - run: cargo check --manifest-path src-tauri/Cargo.toml + - run: cargo test --manifest-path src-tauri/Cargo.toml +``` diff --git a/migration-plan/11-execution-order.md b/migration-plan/11-execution-order.md new file mode 100644 index 0000000000..33fb205fd1 --- /dev/null +++ b/migration-plan/11-execution-order.md @@ -0,0 +1,231 @@ +# Ordre d'Exécution Recommandé + +## Légende + +- **Durée**: Estimation basse/haute en heures de travail effectif +- **Risque**: Faible/Moyen/Élevé (impact sur la stabilité du projet) +- **Dépendances**: Étapes qui doivent être faites avant + +--- + +## Phase 0: Préparation (1h) + +```bash +# 1. Sauvegarder l'état actuel +git checkout -b migration/opencode-prep +git tag pre-migration-$(date +%Y%m%d) + +# 2. Vérifier l'installation OpenCode +opencode --version + +# 3. Étudier la doc OpenCode +opencode ai docs # si dispo, ou lire https://opencode.ai/docs + +# 4. Lire les fichiers de référence +# - opencode_ai_llms.txt (déjà lu) +# - developers_openai_codex_llms.txt (déjà lu) +``` + +--- + +## Phase 1: Renommage Projet et Binaires (4-6h) ⚠️ Risque: Faible + +**Objectif**: Renommer le projet, les binaires, les packages sans changer la logique. + +### Ordre + +1. **Cargo.toml** — Renommer le crate et les binaires +2. **package.json** — Renommer le package npm +3. **lib.rs** — Renommer les modules imports +4. **Fichiers Rust** — Renommer modules `codex/` → `opencode/`, `codex_core` → `opencode_core`, etc. +5. **Fichiers TypeScript** — Renommer types, fonctions, imports +6. **Chemins** — Renommer dossiers et fichiers (via git mv) +7. **Validation**: `cargo check`, `npm run typecheck`, `npm run test` + +✅ **Checkpoint**: Le projet compile et les tests passent (même si la logique Codex +est encore utilisée). + +--- + +## Phase 2: Rewrite du Calque de Communication (8-16h) ⚠️ Risque: Élevé + +**Objectif**: Remplacer le JSON-RPC stdio de Codex par l'API HTTP REST d'OpenCode. + +### Sous-étapes + +#### 2a. Créer `backend/opencode_server.rs` (4-6h) +- Lancer `opencode serve` au lieu de `codex app-server` +- Implémenter `OpenCodeSession` avec reqwest HTTP client +- Lire le port depuis la sortie stdout +- Implémenter health check +- **Test**: `cargo test` + test manuel avec `opencode serve` + +#### 2b. Réécrire `shared/opencode_core.rs` (3-5h) +- Adapter tous les appels JSON-RPC → HTTP REST +- start_session, send_message, list_sessions, etc. +- Remplacer les oneshot channels par des appels HTTP directs +- **Test**: Tests unitaires avec mock HTTP + tests d'intégration + +#### 2c. Réécrire `shared/opencode_aux_core.rs` (2-3h) +- `opencode_check_core` (ex: codex_doctor) +- Background prompts via `opencode run` au lieu de threads cachés +- Génération de commit messages, run metadata +- **Test**: Tests manuels + +#### 2d. Réécrire `codex/mod.rs` → `opencode/mod.rs` (1-2h) +- Adapter les Tauri commands +- **Test**: `cargo check` + +✅ **Checkpoint**: Les opérations de base fonctionnent (création session, envoi message). + +--- + +## Phase 3: Configuration (4-8h) ⚠️ Risque: Moyen + +**Objectif**: Remplacer la config TOML par la config JSON OpenCode. + +### Sous-étapes + +1. **`opencode/config.rs`** — Lire/écrire `opencode.json` +2. **`opencode/home.rs`** — Résoudre `~/.config/opencode/` +3. **`shared/settings_core.rs`** — Adapter la synchronisation +4. **Supprimer** `shared/config_toml_core.rs` +5. **`shared/agents_config_core.rs`** — Adapter +6. **`shared/account.rs`** — Adapter l'auth +7. **`shared/prompts_core.rs`**, **`shared/files_core.rs`** — Nouveaux chemins +8. **Validation**: Tests de lecture/écriture de config + +✅ **Checkpoint**: Les settings sont chargés depuis opencode.json. + +--- + +## Phase 4: Frontend (4-8h) ⚠️ Risque: Moyen + +**Objectif**: Mettre à jour toute la couche frontend. + +### Ordre recommandé + +1. **`src/types.ts`** — Renommer les types (plus risqué, beaucoup de dépendances) +2. **`src/services/tauri.ts`** — Renommer les wrappers IPC +3. **`src/services/events.ts`** — Mettre à jour les noms d'événements +4. **Utils thread** — `codexArgsProfiles.ts`, `codexArgsInput.ts`, `threadStorage.ts` +5. **Hooks thread** — `useThreadCodexParams.ts`, `useThreads.ts`, etc. +6. **Composants app** — `MainApp.tsx`, `TabBar.tsx`, `TabletNav.tsx` +7. **Composants composer** — `Composer.tsx`, `ComposerInput.tsx`, `ComposerMetaBar.tsx` +8. **Paramètres** — `SettingsCodexSection.tsx`, `useSettingsCodexSection.ts` +9. **Mettre à jour les clés localStorage** +10. **Fichiers de test** — Adapter les tests + +✅ **Checkpoint**: `npm run typecheck` et `npm run test` passent. + +--- + +## Phase 5: Daemon RPC (4-8h) ⚠️ Risque: Élevé + +**Objectif**: Adapter le daemon TCP au nouveau protocole. + +### Ordre + +1. Renommer les binaires daemon +2. Adapter `bin/opencode_monitor_daemon.rs` pour lancer `opencode serve` +3. Adapter `bin/opencode_monitor_daemonctl.rs` +4. Adapter les handlers RPC +5. Adapter `remote_backend/` +6. Adapter `tailscale/` + +✅ **Checkpoint**: `cargo build` et le mode remote fonctionne. + +--- + +## Phase 6: Documentation, Scripts, CI (2-4h) ⚠️ Risque: Faible + +**Objectif**: Mettre à jour tous les fichiers non-code. + +### Ordre + +1. `README.md` +2. `docs/*.md` +3. `docs/index.html`, `docs/changelog.html`, `docs/CNAME` +4. `scripts/*.sh` +5. `.github/workflows/release.yml` +6. `flake.nix` +7. `AGENTS.md`, `REMOTE_BACKEND_POC.md` + +✅ **Checkpoint**: Aucune référence résiduelle à "codex" dans les fichiers +(voir commande `rg` dans le plan de test). + +--- + +## Phase 7: Optimisations (4-8h) ⚠️ Risque: Moyen + +**Objectif**: Améliorer le code après la migration. + +### Ordre + +1. Nettoyer le code mort (anciens modules, fonctions dépréciées) +2. Simplifier le système d'agents +3. Ajouter résilience HTTP (retry, timeouts) +4. Explorer l'utilisation du SDK OpenCode (`@opencode-ai/sdk`) +5. Réduire les dépendances inutiles + +✅ **Checkpoint**: Code propre, performant, maintenable. + +--- + +## Phase 8: Tests Finaux (2-4h) ⚠️ Risque: Faible + +**Objectif**: Validation complète. + +1. Exécuter la checklist fonctionnelle (voir `10-testing-strategy.md`) +2. Test manuel de l'application complète +3. Test du daemon en mode remote +4. Test sur macOS, Linux, Windows +5. Test iOS (simulateur) +6. Build release avec `npm run tauri:build` + +--- + +## Résumé du Planning + +| Phase | Description | Durée | Risque | Dépendances | +|-------|-------------|-------|--------|-------------| +| 0 | Préparation | 1h | Faible | - | +| 1 | Renommage | 4-6h | Faible | - | +| 2 | Calque communication | 8-16h | **Élevé** | Phase 1 | +| 3 | Configuration | 4-8h | Moyen | Phase 1 | +| 4 | Frontend | 4-8h | Moyen | Phase 1, 2 | +| 5 | Daemon RPC | 4-8h | **Élevé** | Phase 1, 2, 3 | +| 6 | Docs/CI | 2-4h | Faible | Phase 1 | +| 7 | Optimisations | 4-8h | Moyen | Phase 2, 3, 4, 5 | +| 8 | Tests finaux | 2-4h | Faible | Toutes | +| **Total** | | **29-55h** | | | + +## Approche Recommandée + +### Par lots (recommandé) + +Travailler par phases dans l'ordre, avec validation entre chaque. + +### Par feature (alternatif) + +Implémenter feature par feature: +1. Communication: fonctionnelle mais avec les anciens noms +2. Renommage: une fois que tout fonctionne + +**Non recommandé** car le renommage en masse est moins risqué quand le code +est déjà fonctionnel, et les conflits de merge seront nombreux. + +### Branches Git + +```bash +git checkout -b migration/phase-1-rename +git checkout -b migration/phase-2-http +git checkout -b migration/phase-3-config +git checkout -b migration/phase-4-frontend +git checkout -b migration/phase-5-daemon +git checkout -b migration/phase-6-docs +git checkout -b migration/phase-7-optimizations +git checkout -b migration/phase-8-testing +``` + +Chaque phase est mergée dans `main` après validation. diff --git a/opencode_ai_llms.txt b/opencode_ai_llms.txt new file mode 100644 index 0000000000..e4ecc695e5 --- /dev/null +++ b/opencode_ai_llms.txt @@ -0,0 +1,1401 @@ +### Install OpenCode via script + +Source: https://opencode.ai/docs + +The recommended method for installing OpenCode on supported systems. + +```bash +curl -fsSL https://opencode.ai/install | bash +``` + +-------------------------------- + +### Install OpenCode on Windows + +Source: https://opencode.ai/docs + +Installation commands for Windows environments. + +```bash +choco install opencode +``` + +```bash +scoop install opencode +``` + +```bash +npm install -g opencode-ai +``` + +```bash +mise use -g github:anomalyco/opencode +``` + +```bash +docker run -it --rm ghcr.io/anomalyco/opencode +``` + +-------------------------------- + +### Install OpenCode via Homebrew + +Source: https://opencode.ai/docs + +Installation command for macOS and Linux users using Homebrew. + +```bash +brew install anomalyco/tap/opencode +``` + +-------------------------------- + +### Server Configuration Example (opencode.json) + +Source: https://opencode.ai/docs/config + +Example of an opencode.json file for configuring server settings. This includes port, hostname, mDNS discovery, and CORS origins for the `opencode serve` and `opencode web` commands. + +```json +{ + "$schema": "https://opencode.ai/config.json", + "server": { + "port": 4096, + "hostname": "0.0.0.0", + "mdns": true, + "mdnsDomain": "myproject.local", + "cors": ["http://localhost:5173"] + } +} +``` + +-------------------------------- + +### Start OpenCode Backend Server + +Source: https://opencode.ai/docs/cli + +Starts the OpenCode backend server for web and mobile access on a specified port and hostname. + +```bash +opencode web --port 4096 --hostname 0.0.0.0 +``` + +-------------------------------- + +### Install GitHub Agent + +Source: https://opencode.ai/docs/cli + +Installs the GitHub agent in a repository, setting up necessary GitHub Actions workflows and guiding through configuration. + +```bash +opencode github install +``` + +-------------------------------- + +### Start OpenCode TUI with Project + +Source: https://opencode.ai/docs/cli + +Start the OpenCode terminal user interface (TUI) and specify a project. + +```bash +opencode [project] +``` + +-------------------------------- + +### TUI Configuration Example (tui.json) + +Source: https://opencode.ai/docs/config + +Example of a tui.json file for customizing the TUI experience. Settings like scroll speed, acceleration, diff style, and mouse support can be configured here. + +```json +{ + "$schema": "https://opencode.ai/tui.json", + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": true + }, + "diff_style": "auto", + "mouse": true +} +``` + +-------------------------------- + +### OpenCode Plugin Install Commands + +Source: https://opencode.ai/docs/cli + +Installs a plugin and updates the configuration. The 'plug' alias can also be used. + +```bash +opencode plugin +``` + +```bash +opencode plug +``` + +-------------------------------- + +### Access Windows files from WSL + +Source: https://opencode.ai/docs/windows-wsl + +Demonstrates how to navigate to Windows directories from within the WSL terminal. Windows drives are mounted under the `/mnt/` directory, allowing seamless file access. + +```bash +cd /mnt/c/Users/YourName/project +opencode +``` + +-------------------------------- + +### Install OpenCode CLI + +Source: https://opencode.ai/docs/github + +Command to install OpenCode in a GitHub repository. This command initiates an interactive setup process for the GitHub app, workflow, and secrets. + +```bash +opencode github install +``` + +-------------------------------- + +### Run OpenCode web client in WSL + +Source: https://opencode.ai/docs/windows-wsl + +Launches the OpenCode web client from within the WSL terminal, making it accessible via a browser on your Windows machine. Binding to `0.0.0.0` allows connections from your Windows host. + +```bash +opencode web --hostname 0.0.0.0 +``` + +-------------------------------- + +### Start OpenCode TUI + +Source: https://opencode.ai/docs/tui + +Run OpenCode to start the TUI for the current directory. You can also specify a project path. + +```bash +opencode +``` + +```bash +opencode /path/to/project +``` + +-------------------------------- + +### Configure LSP Server Environment Variables + +Source: https://opencode.ai/docs/lsp + +Use the `env` property to set environment variables for an LSP server when it starts. This example sets `RUST_LOG` for `rust-analyzer`. + +```json +{ + "$schema": "https://opencode.ai/config.json", + "lsp": { + "rust": { + "command": ["rust-analyzer"], + "env": { + "RUST_LOG": "debug" + } + } + } +} +``` + +-------------------------------- + +### Start Headless OpenCode Server + +Source: https://opencode.ai/docs/cli + +Start a headless OpenCode server for API access. This starts an HTTP server that provides API access to opencode functionality without the TUI interface. Set `OPENCODE_SERVER_PASSWORD` to enable HTTP basic auth. + +```bash +opencode serve +``` + +-------------------------------- + +### Install OpenCode on Arch Linux + +Source: https://opencode.ai/docs + +Commands for installing OpenCode on Arch Linux systems. + +```bash +sudo pacman -S opencode # Arch Linux (Stable) +paru -S opencode-bin # Arch Linux (Latest from AUR) +``` + +-------------------------------- + +### Install OpenCode AI SDK + +Source: https://opencode.ai/docs/sdk + +Install the OpenCode AI SDK package using npm. This is the first step to integrating the SDK into your project. + +```bash +npm install @opencode-ai/sdk +``` + +-------------------------------- + +### Install Clipboard Utilities for Linux (Wayland) + +Source: https://opencode.ai/docs/troubleshooting + +Installs the `wl-clipboard` utility required for copy/paste functionality in OpenCode on Linux systems utilizing the Wayland display server. This ensures seamless integration with the Wayland clipboard protocols. + +```bash +apt install -y wl-clipboard +``` + +-------------------------------- + +### TUI Configuration Example (tui.json) + +Source: https://opencode.ai/docs/tui + +Customize TUI behavior including theme, keymaps, and scrolling. Keymap settings are merged with defaults, so only specify changes. + +```json +{ + "$schema": "https://opencode.ai/tui.json", + "theme": "opencode", + "keymap": { + "leader": "ctrl+x", + "leader_timeout": 2000, + "sections": { + "global": { + "command.palette.show": "ctrl+p" + } + } + }, + "scroll_speed": 3, + "scroll_acceleration": { + "enabled": false + }, + "diff_style": "auto", + "mouse": true +} +``` + +-------------------------------- + +### Install OpenCode via package managers + +Source: https://opencode.ai/docs + +Commands for installing the OpenCode CLI using various Node.js package managers. + +```bash +npm install -g opencode-ai +``` + +```bash +bun install -g opencode-ai +``` + +```bash +pnpm install -g opencode-ai +``` + +```bash +yarn global add opencode-ai +``` + +-------------------------------- + +### macOS Managed Preferences .mobileconfig Example + +Source: https://opencode.ai/docs/config + +Example XML structure for a .mobileconfig file to manage OpenCode settings on macOS. Deploy this via MDM to enforce configurations like sharing and server settings. + +```xml + + + + + PayloadContent + + + PayloadType + ai.opencode.managed + PayloadIdentifier + com.example.opencode.config + PayloadUUID + GENERATE-YOUR-OWN-UUID + PayloadVersion + 1 + share + disabled + server + + hostname + 127.0.0.1 + + permission + + * + ask + bash + + * + ask + rm -rf * + deny + + + + + PayloadType + Configuration + PayloadIdentifier + com.example.opencode + PayloadUUID + GENERATE-YOUR-OWN-UUID + PayloadVersion + 1 + + +``` + +-------------------------------- + +### OpenCode Web Server Command + +Source: https://opencode.ai/docs/cli + +Starts a headless OpenCode server with a web interface. Flags control port, hostname, mDNS, and CORS. + +```bash +opencode web +``` + +-------------------------------- + +### Basic OpenCode Configuration (JSONC) + +Source: https://opencode.ai/docs/config + +This is a basic example of an OpenCode configuration file using JSONC format, which allows comments. It specifies the model to use and enables auto-updates. + +```jsonc +{ + "$schema": "https://opencode.ai/config.json", + "model": "anthropic/claude-sonnet-4-5", + "autoupdate": true, + "server": { + "port": 4096, + }, +} +``` + +-------------------------------- + +### Provide feedback on plan + +Source: https://opencode.ai/docs + +Example of providing additional context or references to the agent. + +```text +We'd like to design this new screen using a design I've used before. +[Image #1] Take a look at this image and use it as a reference. +``` + +-------------------------------- + +### Example AGENTS.md Content + +Source: https://opencode.ai/docs/rules + +This markdown file provides project-specific guidance for opencode, including structure, code standards, and monorepo conventions. + +```markdown +# SST v3 Monorepo Project + +This is an SST v3 monorepo with TypeScript. The project uses bun workspaces for package management. + +## Project Structure + +- `packages/` - Contains all workspace packages (functions, core, web, etc.) +- `infra/` - Infrastructure definitions split by service (storage.ts, api.ts, web.ts) +- `sst.config.ts` - Main SST configuration with dynamic imports + +## Code Standards + +- Use TypeScript with strict mode enabled +- Shared code goes in `packages/core/` with proper exports configuration +- Functions go in `packages/functions/` +- Infrastructure should be split into logical files in `infra/` + +## Monorepo Conventions + +- Import shared modules using workspace names: `@my-app/core/example` +``` + +-------------------------------- + +### Advanced Keybinding with Event Handling + +Source: https://opencode.ai/docs/keybinds + +This example illustrates advanced keybinding configuration using an object, allowing for specific event handling like preventing default behavior. Use this for more complex shortcut requirements. + +```json +{ + "$schema": "https://opencode.ai/tui.json", + "keymap": { + "sections": { + "prompt": { + "prompt.paste": { + "key": "ctrl+v", + "preventDefault": false + } + } + } + } +} +``` + +-------------------------------- + +### Ask questions + +Source: https://opencode.ai/docs + +Example of querying the codebase using the @ symbol for file fuzzy searching. + +```text +How is authentication handled in @packages/functions/src/api/index.ts +``` + +-------------------------------- + +### Skill File Structure and Example + +Source: https://opencode.ai/docs/skills + +Defines the expected directory structure for agent skills and provides an example of a `SKILL.md` file, including YAML frontmatter and markdown content. + +```markdown +--- +name: git-release +description: Create consistent releases and changelogs +license: MIT +compatibility: opencode +metadata: + audience: maintainers + workflow: github +--- + +## What I do + +- Draft release notes from merged PRs +- Propose a version bump +- Provide a copy-pasteable `gh release create` command + +## When to use me + +Use this when you are preparing a tagged release. Ask clarifying questions if the target versioning scheme is unclear. + +``` + +-------------------------------- + +### Run OpenCode Command + +Source: https://opencode.ai/docs/cli + +Execute OpenCode commands programmatically by providing the command as an argument. This example runs a command to explain JavaScript closures. + +```bash +opencode run "Explain how closures work in JavaScript" +``` + +-------------------------------- + +### Configure ignore patterns + +Source: https://opencode.ai/docs/tools + +Create a .ignore file in the project root to specify paths that should be included in searches, overriding .gitignore rules. This example includes node_modules, dist, and build directories. + +```text +!node_modules/ +!dist/ +!build/ +``` + +-------------------------------- + +### Configure Model Instructions + +Source: https://opencode.ai/docs/config + +Provide custom instructions to the model by specifying paths to instruction files or glob patterns. This helps guide the model's behavior. + +```json +{ + "$schema": "https://opencode.ai/config.json", + "instructions": ["CONTRIBUTING.md", "docs/guidelines.md", ".cursor/rules/*.md"] +} +``` + +-------------------------------- + +### Disable Multiple Tools with Wildcards (Deprecated) + +Source: https://opencode.ai/docs/agents + +This example demonstrates using wildcards in the legacy 'tools' configuration to disable multiple tools at once. Agent-specific configurations take precedence over global settings. + +```json +{ + "$schema": "https://opencode.ai/config.json", + "agent": { + "readonly": { + "tools": { + "mymcp_*": false, + "write": false, + "edit": false + } + } + } +} +``` + +-------------------------------- + +### Secure OpenCode server with a password in WSL + +Source: https://opencode.ai/docs/windows-wsl + +Starts the OpenCode server with network access enabled and sets an environment variable for password protection. This is crucial for securing the server when accessible from outside the WSL environment. + +```bash +OPENCODE_SERVER_PASSWORD=your-password opencode serve --hostname 0.0.0.0 +``` + +-------------------------------- + +### Initialize project + +Source: https://opencode.ai/docs + +Commands to navigate to a project and initialize OpenCode. + +```bash +cd /path/to/project +``` + +```bash +opencode +``` + +```bash +/init +``` + +-------------------------------- + +### Skill Tool Description Example + +Source: https://opencode.ai/docs/skills + +Illustrates how OpenCode represents available skills in its tool description, including the skill name and a brief description. + +```xml + + + git-release + Create consistent releases and changelogs + + + +``` + +-------------------------------- + +### Run OpenCode server in WSL for Desktop App Connection + +Source: https://opencode.ai/docs/windows-wsl + +Starts the OpenCode server within WSL, configured to listen on all network interfaces (`0.0.0.0`) and a specified port. This allows the OpenCode Desktop app on Windows to connect to the WSL-based server. + +```bash +opencode serve --hostname 0.0.0.0 --port 4096 +``` + +-------------------------------- + +### Customize Session Keybindings + +Source: https://opencode.ai/docs/keybinds + +This example shows how to configure multiple keybindings for a single command, disable a command, or use comma-separated shortcuts. It also demonstrates using an array for multiple key sequences for a command. + +```json +{ + "$schema": "https://opencode.ai/tui.json", + "keymap": { + "sections": { + "session": { + "session.compact": "none", + "session.export": "x,ctrl+shift+x", + "session.copy": ["y", "ctrl+shift+c"] + } + } + } +} +``` + +-------------------------------- + +### Connect to OpenAI + +Source: https://opencode.ai/docs/providers + +Use the `/connect` command and select OpenAI. Authenticate via browser for ChatGPT Plus/Pro or manually enter your API key. + +```txt +/connect +``` + +```txt +┌ Select auth method +│ +│ ChatGPT Plus/Pro +│ Manually enter API Key +└ +``` + +```txt +/models +``` + +-------------------------------- + +### Setup Virtual Framebuffer for Headless Linux + +Source: https://opencode.ai/docs/troubleshooting + +Configures a virtual display buffer (`Xvfb`) for running OpenCode in headless Linux environments where a physical display is not available. This setup is necessary for enabling copy/paste functionality in such scenarios by simulating a graphical environment. + +```bash +apt install -y xvfb +# and run: +Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & +export DISPLAY=:99.0 +``` + +-------------------------------- + +### Connect to Ollama Cloud + +Source: https://opencode.ai/docs/providers + +Use the `/connect` command and select Ollama Cloud. Ensure you pull model information locally before using cloud models. + +```txt +/connect +``` + +```txt +┌ API key +│ +│ +└ enter +``` + +```bash +ollama pull gpt-oss:20b-cloud +``` + +```txt +/models +``` + +-------------------------------- + +### Install Clipboard Utilities for Linux (X11) + +Source: https://opencode.ai/docs/troubleshooting + +Installs necessary clipboard utilities for OpenCode's copy/paste functionality on Linux systems using the X11 display server. Users can choose between `xclip` or `xsel`. These tools enable the application to interact with the system clipboard. + +```bash +apt install -y xclip +# or +apt install -y xsel +``` + +-------------------------------- + +### Configure MCP Server Globally (JSON) + +Source: https://opencode.ai/docs/mcp-servers + +This JSON configuration shows a basic setup for enabling or disabling MCP servers globally. It includes an example of a local MCP server and how to toggle its tool availability. + +```json +{ + "$schema": "https://opencode.ai/config.json", + "mcp": { + "my-mcp-foo": { + "type": "local", + "command": ["bun", "x", "my-mcp-command-foo"] + }, + "my-mcp-bar": { + "type": "local", + "command": ["bun", "x", "my-mcp-command-bar"] + } + }, + "tools": { + "my-mcp-foo": false + } +} +``` + +-------------------------------- + +### Connect to GitHub Copilot + +Source: https://opencode.ai/docs/providers + +Initiate the connection to GitHub Copilot by running the /connect command. Follow the on-screen instructions to authorize via github.com/login/device. + +```bash +/connect +``` + +```txt +┌ Login with GitHub Copilot +│ +│ https://github.com/login/device +│ +│ Enter code: 8F43-6FCF +│ +└ Waiting for authorization... +``` + +```bash +/models +``` + +-------------------------------- + +### Manage Projects with JavaScript + +Source: https://opencode.ai/docs/sdk + +Provides examples for interacting with project-related APIs: `project.list()` to retrieve all projects and `project.current()` to get the currently active project. Both methods return arrays or single objects conforming to the Project type. + +```javascript +// List all projects +const projects = await client.project.list() + +// Get current project +const currentProject = await client.project.current() +``` + +-------------------------------- + +### Reset OpenCode Desktop App Data (Linux/macOS) + +Source: https://opencode.ai/docs/troubleshooting + +This command removes the OpenCode application data directory on Linux and macOS systems. This is a last resort for resolving issues when the application won't start or settings cannot be cleared through the UI. It deletes configuration files and UI state. + +```bash +rm -rf ~/.local/share/opencode +``` + +-------------------------------- + +### Define manual instructions in AGENTS.md + +Source: https://opencode.ai/docs/rules + +Reference external files using the @ syntax to provide project-specific rules and guidelines. Use lazy loading for these references to maintain performance. + +```markdown +# TypeScript Project Rules + +## External File Loading + +CRITICAL: When you encounter a file reference (e.g., @rules/general.md), use your Read tool to load it on a need-to-know basis. They're relevant to the SPECIFIC task at hand. + +Instructions: + +- Do NOT preemptively load all references - use lazy loading based on actual need +- When loaded, treat content as mandatory instructions that override defaults +- Follow references recursively when needed + +## Development Guidelines + +For TypeScript code style and best practices: @docs/typescript-guidelines.md +For React component architecture and hooks patterns: @docs/react-patterns.md +For REST API design and error handling: @docs/api-standards.md +For testing strategies and coverage requirements: @test/testing-guidelines.md + +## General Guidelines + +Read the following file immediately as it's relevant to all workflows: @rules/general-guidelines.md. +``` + +-------------------------------- + +### Clear OpenCode Cache on Linux + +Source: https://opencode.ai/docs/troubleshooting + +Provides the command to remove the OpenCode cache directory on Linux systems. Clearing the cache is a crucial step for resolving issues related to corrupted application data or stuck plugin installations. This command forcefully removes the specified directory and its contents. + +```bash +rm -rf ~/.cache/opencode +``` + +-------------------------------- + +### Prompt Example for Local MCP Server + +Source: https://opencode.ai/docs/mcp-servers + +Demonstrates how to invoke a configured local MCP server, `mcp_everything`, within a prompt. This shows the practical application of adding and enabling MCP tools for LLM interaction. + +```txt +use the mcp_everything tool to add the number 3 and 4 +``` + +-------------------------------- + +### Connect to OpenCode Zen + +Source: https://opencode.ai/docs/providers + +Initiate the connection process for OpenCode Zen via the TUI. Follow the provided URL to authenticate and obtain an API key. + +```txt +/connect +``` + +```txt +┌ API key +│ +│ +└ enter +``` + +```txt +/models +``` + +-------------------------------- + +### Configure TUI Keymap in tui.json + +Source: https://opencode.ai/docs/keybinds + +This example demonstrates the structure of the `keymap` configuration in `tui.json`, including setting a leader key, leader timeout, and defining keybindings for global, session, and input sections. Use this to customize your TUI shortcuts. + +```json +{ + "$schema": "https://opencode.ai/tui.json", + "keymap": { + "leader": "ctrl+x", + "leader_timeout": 2000, + "sections": { + "global": { + "command.palette.show": "ctrl+p", + "session.new": "n", + "session.list": "l" + }, + "session": { + "session.compact": "c", + "session.undo": "u", + "session.redo": "r" + }, + "input": { + "input.submit": "return", + "input.newline": ["shift+return", "ctrl+return", "alt+return", "ctrl+j"] + } + } + } +} +``` + +-------------------------------- + +### Connect to SAP AI Core + +Source: https://opencode.ai/docs/providers + +Use the `/connect` command and search for SAP AI Core. You will need to provide your service key JSON. + +```txt +/connect +``` + +```txt +┌ Service key +│ +│ +└ enter +``` + +```bash +AICORE_SERVICE_KEY='{"clientid":"...","clientsecret":"...","url":"...","serviceurls":{"AI_API_URL":"..."}}' opencode +``` + +```bash +export AICORE_SERVICE_KEY='{"clientid":"...","clientsecret":"...","url":"...","serviceurls":{"AI_API_URL":"..."}}' +``` + +```bash +AICORE_DEPLOYMENT_ID=your-deployment-id AICORE_RESOURCE_GROUP=your-resource-group opencode +``` + +```txt +/models +``` + +-------------------------------- + +### Initialize LSP Configuration Object + +Source: https://opencode.ai/docs/lsp + +Use an empty object for `lsp` to keep built-in servers enabled while allowing for custom configurations or overrides. + +```json +{ + "$schema": "https://opencode.ai/config.json", + "lsp": {} +} +``` + +-------------------------------- + +### Start OpenCode TUI + +Source: https://opencode.ai/docs/cli + +Run the OpenCode CLI without arguments to start the terminal user interface (TUI). + +```bash +opencode +``` + +-------------------------------- + +### GET /session/:id/children + +Source: https://opencode.ai/docs/server + +Retrieves the child sessions of a given session. This endpoint is used to get the sessions that are children of a specific session. + +```APIDOC +## GET /session/:id/children + +### Description +Gets a session's child sessions. + +### Method +GET + +### Endpoint +/session/:id/children + +### Parameters +#### Path Parameters +- **id** (string) - Required - The ID of the parent session. + +### Request Example +No request body. + +### Response +#### Success Response (200) +- **Session[]** - An array of child Session objects. + +#### Response Example +[ + { + "id": "childSession1", + "title": "Child Session Title", + // ... other session properties + } +] + +``` + +-------------------------------- + +### Add Custom Provider via CLI + +Source: https://opencode.ai/docs/providers + +Steps to add a custom provider using the `/connect` command, including selecting 'Other', entering a provider ID, and providing an API key. + +```bash +$ /connect + +┌ Add credential +│ +◆ Select provider +│ ... +│ ● Other +└ +``` + +```bash +$ /connect + +┌ Add credential +│ +◇ Enter provider id +│ myprovider +└ +``` + +```bash +$ /connect + +┌ Add credential +│ +▲ This only stores a credential for myprovider - you will need to configure it in opencode.json, check the docs for examples. +│ +◇ Enter your API key +│ sk-... +└ +``` + +-------------------------------- + +### Install and Configure opencode-helicone-session Plugin + +Source: https://opencode.ai/docs/providers + +Install the session tracking plugin to automatically log OpenCode conversations as sessions in Helicone. This plugin injects necessary headers for session management. + +```bash +npm install -g opencode-helicone-session +``` + +```json +{ + "plugin": ["opencode-helicone-session"] +} +``` + +-------------------------------- + +### Create Opencode Client Instance + +Source: https://opencode.ai/docs/sdk + +Create a new instance of the OpenCode client, which also starts a server. This method can be configured with various options like hostname, port, and timeout. It returns an object containing the client and server instances. + +```javascript +import { createOpencode } from "@opencode-ai/sdk" + +const { client } = await createOpencode() +``` + +-------------------------------- + +### Retrieve Configuration and Providers with JavaScript + +Source: https://opencode.ai/docs/sdk + +Illustrates how to fetch general configuration details using `config.get()` and a list of available providers along with their default models using `config.providers()`. The latter returns both providers and default model mappings. + +```javascript +const config = await client.config.get() + +const { providers, default: defaults } = await client.config.providers() +``` + +-------------------------------- + +### OpenCode Configuration Example (JSON) + +Source: https://opencode.ai/docs/enterprise + +An example JSON configuration file for OpenCode, specifying schema and sharing settings. The 'share' property is set to 'disabled' by default. + +```json +{ + "$schema": "https://opencode.ai/config.json", + "share": "disabled" +} +``` + +-------------------------------- + +### Enable Skill Tool + +Source: https://opencode.ai/docs/tools + +Configure the 'skill' tool permission to 'allow' in opencode.json to enable loading and returning the content of skill files (SKILL.md). + +```json +{ + "$schema": "https://opencode.ai/config.json", + "permission": { + "skill": "allow" + } +} +``` + +-------------------------------- + +### POST /session/:id/init + +Source: https://opencode.ai/docs/server + +Initializes the session by analyzing the app and creating `AGENTS.md`. Requires a request body with messageID, providerID, and modelID. + +```APIDOC +## POST /session/:id/init + +### Description +Analyze app and create `AGENTS.md`. + +### Method +POST + +### Endpoint +/session/:id/init + +### Parameters +#### Path Parameters +- **id** (string) - Required - The ID of the session. + +#### Request Body +- **messageID** (string) - Required - The ID of the message. +- **providerID** (string) - Required - The ID of the provider. +- **modelID** (string) - Required - The ID of the model. + +### Request Example +{ + "messageID": "message1", + "providerID": "provider1", + "modelID": "model1" +} + +### Response +#### Success Response (200) +- **boolean** - True if the initialization was successful. + +#### Response Example +true + +``` + +-------------------------------- + +### Define feature plan + +Source: https://opencode.ai/docs + +Example prompt for describing a new feature to the agent. + +```text +When a user deletes a note, we'd like to flag it as deleted in the database. +Then create a screen that shows all the recently deleted notes. +From this screen, the user can undelete a note or permanently delete it. +``` + +-------------------------------- + +### Reset OpenCode Desktop App Data (Windows) + +Source: https://opencode.ai/docs/troubleshooting + +This instruction guides users to manually delete the OpenCode application data directory on Windows. This action is recommended as a last resort for troubleshooting startup or settings issues when in-app options are unavailable. It clears stored configurations and UI states. + +```batch +Press WIN+R and delete: %USERPROFILE%\.local\share\opencode +``` + +-------------------------------- + +### Configure LSP Server Initialization Options + +Source: https://opencode.ai/docs/lsp + +Pass custom initialization options to an LSP server using the `initialization` property. These options are sent during the LSP `initialize` request and are server-specific. + +```json +{ + "$schema": "https://opencode.ai/config.json", + "lsp": { + "custom-lsp": { + "command": ["custom-lsp-server", "--stdio"], + "extensions": [".custom"], + "initialization": { + "preferences": { + "importModuleSpecifierPreference": "relative" + } + } + } + } +} +``` + +-------------------------------- + +### Prompt OpenCode TUI + +Source: https://opencode.ai/docs/tui + +Once inside the TUI, you can prompt the LLM with a message to get information about your codebase. + +```text +Give me a quick summary of the codebase. +``` + +-------------------------------- + +### Clear OpenCode Provider Package Cache (Windows) + +Source: https://opencode.ai/docs/troubleshooting + +This instruction guides users to manually delete the OpenCode provider package cache on Windows. This action helps resolve AI_APICallError issues caused by outdated or corrupted provider packages. Restarting OpenCode after clearing the cache will prompt it to download the latest packages. + +```batch +Press WIN+R and delete: %USERPROFILE%\.cache\opencode +``` + +-------------------------------- + +### Configure Opencode Client with Options + +Source: https://opencode.ai/docs/sdk + +Instantiate the OpenCode client with custom configuration options. This allows overriding default settings such as hostname, port, and specifying a particular model. The example demonstrates setting a model and logging the server URL before closing the server. + +```javascript +import { createOpencode } from "@opencode-ai/sdk" + +const opencode = await createOpencode({ + hostname: "127.0.0.1", + port: 4096, + config: { + model: "anthropic/claude-3-5-sonnet-20241022", + }, +}) + +console.log(`Server running at ${opencode.server.url}`) + +opencode.server.close() +``` + +-------------------------------- + +### Execute Shell Commands + +Source: https://opencode.ai/docs/tui + +Start a message with '!' to execute a shell command. The output of the command will be added to the conversation as a tool result. + +```bash +!ls -la +``` + +-------------------------------- + +### Config API + +Source: https://opencode.ai/docs/sdk + +Manages configuration settings, including getting general config and listing providers. + +```APIDOC +## GET /config + +### Description +Retrieves the general configuration information. + +### Method +GET + +### Endpoint +/config + +### Parameters +#### Query Parameters +None + +#### Request Body +None + +### Response +#### Success Response (200) +- **config** (Config) - The configuration object. + +#### Response Example +```json +{ + "setting1": "value1", + "setting2": 123 +} +``` + +## GET /config/providers + +### Description +Lists available providers and their default models. + +### Method +GET + +### Endpoint +/config/providers + +### Parameters +#### Query Parameters +None + +#### Request Body +None + +### Response +#### Success Response (200) +- **providers** (Provider[]) - An array of available providers. +- **default** (object) - An object mapping provider keys to their default model names. + +#### Response Example +```json +{ + "providers": [ + { + "name": "OpenAI", + "models": ["gpt-3.5-turbo", "gpt-4"] + } + ], + "default": { + "openai": "gpt-3.5-turbo" + } +} +``` +``` \ No newline at end of file diff --git a/package.json b/package.json index 1855e62fb1..4b74554920 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "codex-monitor", + "name": "opencode-monitor", "private": true, "version": "0.7.68", "type": "module", diff --git a/scripts/macos-fix-openssl.sh b/scripts/macos-fix-openssl.sh index 9ede8e0c2f..59a9557ef7 100755 --- a/scripts/macos-fix-openssl.sh +++ b/scripts/macos-fix-openssl.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -app_path="${1:-src-tauri/target/release/bundle/macos/Codex Monitor.app}" +app_path="${1:-src-tauri/target/release/bundle/macos/OpenCode Monitor.app}" identity="${CODESIGN_IDENTITY:-}" entitlements_path="${ENTITLEMENTS_PATH:-src-tauri/Entitlements.plist}" @@ -44,11 +44,11 @@ fi libssl="${openssl_prefix}/lib/libssl.3.dylib" libcrypto="${openssl_prefix}/lib/libcrypto.3.dylib" frameworks_dir="${app_path}/Contents/Frameworks" -bin_path="${app_path}/Contents/MacOS/codex-monitor" -daemon_path="${app_path}/Contents/MacOS/codex_monitor_daemon" -daemonctl_path="${app_path}/Contents/MacOS/codex_monitor_daemonctl" -daemon_source="${DAEMON_BINARY_PATH:-src-tauri/target/release/codex_monitor_daemon}" -daemonctl_source="${DAEMONCTL_BINARY_PATH:-src-tauri/target/release/codex_monitor_daemonctl}" +bin_path="${app_path}/Contents/MacOS/opencode-monitor" +daemon_path="${app_path}/Contents/MacOS/opencode_monitor_daemon" +daemonctl_path="${app_path}/Contents/MacOS/opencode_monitor_daemonctl" +daemon_source="${DAEMON_BINARY_PATH:-src-tauri/target/release/opencode_monitor_daemon}" +daemonctl_source="${DAEMONCTL_BINARY_PATH:-src-tauri/target/release/opencode_monitor_daemonctl}" sync_embedded_binary() { local source_path="$1" diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 94b401cd45..968a35357f 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -603,45 +603,6 @@ dependencies = [ "objc", ] -[[package]] -name = "codex-monitor" -version = "0.7.68" -dependencies = [ - "base64 0.22.1", - "block2", - "chrono", - "cpal", - "fix-path-env", - "futures-util", - "git2", - "ignore", - "libc", - "objc2", - "objc2-app-kit", - "objc2-av-foundation", - "objc2-foundation", - "portable-pty", - "reqwest 0.12.28", - "serde", - "serde_json", - "sha2", - "shell-words", - "tauri", - "tauri-build", - "tauri-plugin-dialog", - "tauri-plugin-liquid-glass", - "tauri-plugin-notification", - "tauri-plugin-opener", - "tauri-plugin-process", - "tauri-plugin-updater", - "tauri-plugin-window-state", - "tokio", - "tokio-tungstenite", - "toml_edit 0.20.2", - "uuid", - "whisper-rs", -] - [[package]] name = "combine" version = "4.6.7" @@ -3066,6 +3027,45 @@ dependencies = [ "pathdiff", ] +[[package]] +name = "opencode-monitor" +version = "0.7.68" +dependencies = [ + "base64 0.22.1", + "block2", + "chrono", + "cpal", + "fix-path-env", + "futures-util", + "git2", + "ignore", + "libc", + "objc2", + "objc2-app-kit", + "objc2-av-foundation", + "objc2-foundation", + "portable-pty", + "reqwest 0.12.28", + "serde", + "serde_json", + "sha2", + "shell-words", + "tauri", + "tauri-build", + "tauri-plugin-dialog", + "tauri-plugin-liquid-glass", + "tauri-plugin-notification", + "tauri-plugin-opener", + "tauri-plugin-process", + "tauri-plugin-updater", + "tauri-plugin-window-state", + "tokio", + "tokio-tungstenite", + "toml_edit 0.20.2", + "uuid", + "whisper-rs", +] + [[package]] name = "openssl-probe" version = "0.1.6" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 44a1538206..3f12fa9009 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,10 +1,10 @@ [package] -name = "codex-monitor" +name = "opencode-monitor" version = "0.7.68" -description = "A Tauri App" +description = "OpenCode Monitor - Tauri app for orchestrating OpenCode agents" authors = ["you"] edition = "2021" -default-run = "codex-monitor" +default-run = "opencode-monitor" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -15,7 +15,7 @@ custom-protocol = ["tauri/custom-protocol"] # The `_lib` suffix may seem redundant but it is necessary # to make the lib name unique and wouldn't conflict with the bin name. # This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519 -name = "codex_monitor_lib" +name = "opencode_monitor_lib" crate-type = ["staticlib", "cdylib", "rlib"] [build-dependencies] diff --git a/src-tauri/gen/apple/Sources/codex-monitor/bindings/bindings.h b/src-tauri/gen/apple/Sources/opencode-monitor/bindings/bindings.h similarity index 100% rename from src-tauri/gen/apple/Sources/codex-monitor/bindings/bindings.h rename to src-tauri/gen/apple/Sources/opencode-monitor/bindings/bindings.h diff --git a/src-tauri/gen/apple/Sources/codex-monitor/main.mm b/src-tauri/gen/apple/Sources/opencode-monitor/main.mm similarity index 100% rename from src-tauri/gen/apple/Sources/codex-monitor/main.mm rename to src-tauri/gen/apple/Sources/opencode-monitor/main.mm diff --git a/src-tauri/gen/apple/codex-monitor.xcodeproj/project.pbxproj b/src-tauri/gen/apple/opencode-monitor.xcodeproj/project.pbxproj similarity index 92% rename from src-tauri/gen/apple/codex-monitor.xcodeproj/project.pbxproj rename to src-tauri/gen/apple/opencode-monitor.xcodeproj/project.pbxproj index b612cdd580..84dfb3c413 100644 --- a/src-tauri/gen/apple/codex-monitor.xcodeproj/project.pbxproj +++ b/src-tauri/gen/apple/opencode-monitor.xcodeproj/project.pbxproj @@ -22,13 +22,13 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 022C9B9709B6E33626712962 /* codex-monitor_iOS.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = "codex-monitor_iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 022C9B9709B6E33626712962 /* opencode-monitor_iOS.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = "opencode-monitor_iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 08DA73A3B0441143BDAB249C /* mod.rs */ = {isa = PBXFileReference; path = mod.rs; sourceTree = ""; }; 08E90DC456838C95694EF8D8 /* app_server.rs */ = {isa = PBXFileReference; path = app_server.rs; sourceTree = ""; }; 0C5D9C058CAABA28654FB273 /* storage.rs */ = {isa = PBXFileReference; path = storage.rs; sourceTree = ""; }; 0DBD88931E2EB5866EE47EF6 /* mod.rs */ = {isa = PBXFileReference; path = mod.rs; sourceTree = ""; }; 12A2D65E6D9051B27D1CA5E5 /* commands.rs */ = {isa = PBXFileReference; path = commands.rs; sourceTree = ""; }; - 193ABFDFCFD507D463E1A29A /* codex_aux_core.rs */ = {isa = PBXFileReference; path = codex_aux_core.rs; sourceTree = ""; }; + 193ABFDFCFD507D463E1A29A /* opencode_aux_core.rs */ = {isa = PBXFileReference; path = opencode_aux_core.rs; sourceTree = ""; }; 2966B8A4BD316FB016FEA54E /* prompts.rs */ = {isa = PBXFileReference; path = prompts.rs; sourceTree = ""; }; 2C3BE9ABFD193F068D2BBA5A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 2EE9CACCF7CD2CF0BA7A20A5 /* rules.rs */ = {isa = PBXFileReference; path = rules.rs; sourceTree = ""; }; @@ -65,7 +65,7 @@ 9D954D38686C4132856A59E4 /* tcp_transport.rs */ = {isa = PBXFileReference; path = tcp_transport.rs; sourceTree = ""; }; 9E58DB47DA7B47D628EADE5D /* args.rs */ = {isa = PBXFileReference; path = args.rs; sourceTree = ""; }; 9E5C2A555AC05BDC3564838B /* local_usage_core.rs */ = {isa = PBXFileReference; path = local_usage_core.rs; sourceTree = ""; }; - A35E6BC600DBB2FF9C6EABCD /* codex_monitor_daemon.rs */ = {isa = PBXFileReference; path = codex_monitor_daemon.rs; sourceTree = ""; }; + A35E6BC600DBB2FF9C6EABCD /* opencode_monitor_daemon.rs */ = {isa = PBXFileReference; path = opencode_monitor_daemon.rs; sourceTree = ""; }; A677124A2706E5BF201E0FEB /* mod.rs */ = {isa = PBXFileReference; path = mod.rs; sourceTree = ""; }; AA0D64CE30289CCE13E59F0F /* worktree_core.rs */ = {isa = PBXFileReference; path = worktree_core.rs; sourceTree = ""; }; AE51BE7D07536FD61C56B291 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; @@ -81,7 +81,7 @@ C87A6117F01777AC322C19B0 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; D05DC45BD60F3A9C1A3B0663 /* policy.rs */ = {isa = PBXFileReference; path = policy.rs; sourceTree = ""; }; D3469462193DAA7437CF3971 /* state.rs */ = {isa = PBXFileReference; path = state.rs; sourceTree = ""; }; - D5066E0D8C3EBB3BF6522255 /* codex_core.rs */ = {isa = PBXFileReference; path = codex_core.rs; sourceTree = ""; }; + D5066E0D8C3EBB3BF6522255 /* opencode_core.rs */ = {isa = PBXFileReference; path = opencode_core.rs; sourceTree = ""; }; DA6F8CA66C86156DDE024DBD /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; DA7D0B551D09725FFEF6A5F7 /* git.rs */ = {isa = PBXFileReference; path = git.rs; sourceTree = ""; }; DBB890CC58633E8FD68707DF /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; @@ -96,7 +96,7 @@ F21403CBF1CB75B77D6CD4D8 /* window.rs */ = {isa = PBXFileReference; path = window.rs; sourceTree = ""; }; F232CF7BE0BAFB0DDA272197 /* menu.rs */ = {isa = PBXFileReference; path = menu.rs; sourceTree = ""; }; F735BFAFC67E7F8010E2186A /* tests.rs */ = {isa = PBXFileReference; path = tests.rs; sourceTree = ""; }; - F7E7F50DDC0E32C36762F226 /* codex-monitor_iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "codex-monitor_iOS.entitlements"; sourceTree = ""; }; + F7E7F50DDC0E32C36762F226 /* opencode-monitor_iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "opencode-monitor_iOS.entitlements"; sourceTree = ""; }; FB7082DA519893791E84DA90 /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; path = assets; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ @@ -130,13 +130,13 @@ path = files; sourceTree = ""; }; - 01096FE16EA19E6A2C83F468 /* codex-monitor_iOS */ = { + 01096FE16EA19E6A2C83F468 /* opencode-monitor_iOS */ = { isa = PBXGroup; children = ( - F7E7F50DDC0E32C36762F226 /* codex-monitor_iOS.entitlements */, + F7E7F50DDC0E32C36762F226 /* opencode-monitor_iOS.entitlements */, DF8059D941E42CC381E36993 /* Info.plist */, ); - path = "codex-monitor_iOS"; + path = "opencode-monitor_iOS"; sourceTree = ""; }; 1520D0382B1D17E080470F05 = { @@ -145,7 +145,7 @@ FB7082DA519893791E84DA90 /* assets */, 3F381072CFEA46313C66A851 /* Assets.xcassets */, DA6F8CA66C86156DDE024DBD /* LaunchScreen.storyboard */, - 01096FE16EA19E6A2C83F468 /* codex-monitor_iOS */, + 01096FE16EA19E6A2C83F468 /* opencode-monitor_iOS */, A47AFF5CADEC3443E0C5670C /* Externals */, 82525E4385E90833CF61C7A8 /* Sources */, 8B6C2150457718F38C7FCA0B /* src */, @@ -201,8 +201,8 @@ isa = PBXGroup; children = ( E0D2C9BCD8F60877A6C907AE /* account.rs */, - 193ABFDFCFD507D463E1A29A /* codex_aux_core.rs */, - D5066E0D8C3EBB3BF6522255 /* codex_core.rs */, + 193ABFDFCFD507D463E1A29A /* opencode_aux_core.rs */, + D5066E0D8C3EBB3BF6522255 /* opencode_core.rs */, DFDE9F291B67662882DA2A57 /* files_core.rs */, 509A692853CBF38B70F4C5D8 /* git_core.rs */, 80C8B0127080EFDC77615869 /* git_ui_core.rs */, @@ -228,7 +228,7 @@ 74B7A9B5A8090991AAF921E0 /* bin */ = { isa = PBXGroup; children = ( - A35E6BC600DBB2FF9C6EABCD /* codex_monitor_daemon.rs */, + A35E6BC600DBB2FF9C6EABCD /* opencode_monitor_daemon.rs */, ); path = bin; sourceTree = ""; @@ -236,7 +236,7 @@ 82525E4385E90833CF61C7A8 /* Sources */ = { isa = PBXGroup; children = ( - BD87CFB69FD8CF92388BEE5D /* codex-monitor */, + BD87CFB69FD8CF92388BEE5D /* opencode-monitor */, ); path = Sources; sourceTree = ""; @@ -271,7 +271,7 @@ F21403CBF1CB75B77D6CD4D8 /* window.rs */, A129D8219A1A13FA984555C6 /* backend */, 74B7A9B5A8090991AAF921E0 /* bin */, - 97E70EBFACB0FDAD50E1332C /* codex */, + 97E70EBFACB0FDAD50E1332C /* opencode */, 8A851D3110FA91F307B978D2 /* dictation */, 00C678587D406CBBBC7DB473 /* files */, 41BDAF45DFACDE58DB7F6CF9 /* git */, @@ -285,7 +285,7 @@ path = ../../src; sourceTree = ""; }; - 97E70EBFACB0FDAD50E1332C /* codex */ = { + 97E70EBFACB0FDAD50E1332C /* opencode */ = { isa = PBXGroup; children = ( 9E58DB47DA7B47D628EADE5D /* args.rs */, @@ -293,7 +293,7 @@ 334BA14E59A5FC1AF3CAA943 /* home.rs */, 920E0860F7C1C1530051CF92 /* mod.rs */, ); - path = codex; + path = opencode; sourceTree = ""; }; A129D8219A1A13FA984555C6 /* backend */ = { @@ -321,13 +321,13 @@ path = settings; sourceTree = ""; }; - BD87CFB69FD8CF92388BEE5D /* codex-monitor */ = { + BD87CFB69FD8CF92388BEE5D /* opencode-monitor */ = { isa = PBXGroup; children = ( 8B631803A68708BDF5FC92AF /* main.mm */, 1C8CA1237FC96B6623A1D1E8 /* bindings */, ); - path = "codex-monitor"; + path = "opencode-monitor"; sourceTree = ""; }; BF709576DB015EF813732D22 /* workspaces */ = { @@ -348,7 +348,7 @@ C10744B9FE87EBD6824B6DCA /* Products */ = { isa = PBXGroup; children = ( - 022C9B9709B6E33626712962 /* codex-monitor_iOS.app */, + 022C9B9709B6E33626712962 /* opencode-monitor_iOS.app */, ); name = Products; sourceTree = ""; @@ -356,9 +356,9 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 09F7A9973F81CD1301FD1481 /* codex-monitor_iOS */ = { + 09F7A9973F81CD1301FD1481 /* opencode-monitor_iOS */ = { isa = PBXNativeTarget; - buildConfigurationList = 4245402F66C53104E9663F2B /* Build configuration list for PBXNativeTarget "codex-monitor_iOS" */; + buildConfigurationList = 4245402F66C53104E9663F2B /* Build configuration list for PBXNativeTarget "opencode-monitor_iOS" */; buildPhases = ( 3A3448A587D98E369778B54B /* Build Rust Code */, 77CD29A54DE8CA310796629E /* Sources */, @@ -369,11 +369,11 @@ ); dependencies = ( ); - name = "codex-monitor_iOS"; + name = "opencode-monitor_iOS"; packageProductDependencies = ( ); - productName = "codex-monitor_iOS"; - productReference = 022C9B9709B6E33626712962 /* codex-monitor_iOS.app */; + productName = "opencode-monitor_iOS"; + productReference = 022C9B9709B6E33626712962 /* opencode-monitor_iOS.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -385,7 +385,7 @@ BuildIndependentTargetsInParallel = YES; LastUpgradeCheck = 1430; }; - buildConfigurationList = 4D2F35D5D2B53F099DB9297F /* Build configuration list for PBXProject "codex-monitor" */; + buildConfigurationList = 4D2F35D5D2B53F099DB9297F /* Build configuration list for PBXProject "opencode-monitor" */; compatibilityVersion = "Xcode 14.0"; developmentRegion = en; hasScannedForEncodings = 0; @@ -399,7 +399,7 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 09F7A9973F81CD1301FD1481 /* codex-monitor_iOS */, + 09F7A9973F81CD1301FD1481 /* opencode-monitor_iOS */, ); }; /* End PBXProject section */ @@ -461,7 +461,7 @@ arm64, ); ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = "codex-monitor_iOS/codex-monitor_iOS.entitlements"; + CODE_SIGN_ENTITLEMENTS = "opencode-monitor_iOS/opencode-monitor_iOS.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; ENABLE_BITCODE = NO; "EXCLUDED_ARCHS[sdk=iphoneos*]" = x86_64; @@ -469,7 +469,7 @@ "$(inherited)", "\".\"", ); - INFOPLIST_FILE = "codex-monitor_iOS/Info.plist"; + INFOPLIST_FILE = "opencode-monitor_iOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -481,8 +481,8 @@ ); "LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(DT_TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(DT_TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; "LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(DT_TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(DT_TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; - PRODUCT_BUNDLE_IDENTIFIER = com.dimillian.codexmonitor.ios; - PRODUCT_NAME = "Codex Monitor"; + PRODUCT_BUNDLE_IDENTIFIER = com.dimillian.opencodemonitor.ios; + PRODUCT_NAME = "OpenCode Monitor"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALID_ARCHS = arm64; @@ -498,7 +498,7 @@ arm64, ); ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = "codex-monitor_iOS/codex-monitor_iOS.entitlements"; + CODE_SIGN_ENTITLEMENTS = "opencode-monitor_iOS/opencode-monitor_iOS.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; ENABLE_BITCODE = NO; "EXCLUDED_ARCHS[sdk=iphoneos*]" = x86_64; @@ -506,7 +506,7 @@ "$(inherited)", "\".\"", ); - INFOPLIST_FILE = "codex-monitor_iOS/Info.plist"; + INFOPLIST_FILE = "opencode-monitor_iOS/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -518,8 +518,8 @@ ); "LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(DT_TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(DT_TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; "LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(DT_TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(DT_TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; - PRODUCT_BUNDLE_IDENTIFIER = com.dimillian.codexmonitor.ios; - PRODUCT_NAME = "Codex Monitor"; + PRODUCT_BUNDLE_IDENTIFIER = com.dimillian.opencodemonitor.ios; + PRODUCT_NAME = "OpenCode Monitor"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALID_ARCHS = arm64; @@ -649,7 +649,7 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 4245402F66C53104E9663F2B /* Build configuration list for PBXNativeTarget "codex-monitor_iOS" */ = { + 4245402F66C53104E9663F2B /* Build configuration list for PBXNativeTarget "opencode-monitor_iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 8ABC0B8E4F1EE76167F9E08F /* debug */, @@ -658,7 +658,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = debug; }; - 4D2F35D5D2B53F099DB9297F /* Build configuration list for PBXProject "codex-monitor" */ = { + 4D2F35D5D2B53F099DB9297F /* Build configuration list for PBXProject "opencode-monitor" */ = { isa = XCConfigurationList; buildConfigurations = ( F9C2416A9640DD1FA341DC22 /* debug */, diff --git a/src-tauri/gen/apple/codex-monitor.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/src-tauri/gen/apple/opencode-monitor.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from src-tauri/gen/apple/codex-monitor.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to src-tauri/gen/apple/opencode-monitor.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/src-tauri/gen/apple/codex-monitor.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/src-tauri/gen/apple/opencode-monitor.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from src-tauri/gen/apple/codex-monitor.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to src-tauri/gen/apple/opencode-monitor.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/src-tauri/gen/apple/codex-monitor.xcodeproj/xcshareddata/xcschemes/codex-monitor_iOS.xcscheme b/src-tauri/gen/apple/opencode-monitor.xcodeproj/xcshareddata/xcschemes/opencode-monitor_iOS.xcscheme similarity index 84% rename from src-tauri/gen/apple/codex-monitor.xcodeproj/xcshareddata/xcschemes/codex-monitor_iOS.xcscheme rename to src-tauri/gen/apple/opencode-monitor.xcodeproj/xcshareddata/xcschemes/opencode-monitor_iOS.xcscheme index 3eb5f02ad8..20894337f5 100644 --- a/src-tauri/gen/apple/codex-monitor.xcodeproj/xcshareddata/xcschemes/codex-monitor_iOS.xcscheme +++ b/src-tauri/gen/apple/opencode-monitor.xcodeproj/xcshareddata/xcschemes/opencode-monitor_iOS.xcscheme @@ -15,9 +15,9 @@ + BuildableName = "OpenCode Monitor.app" + BlueprintName = "opencode-monitor_iOS" + ReferencedContainer = "container:opencode-monitor.xcodeproj"> @@ -31,9 +31,9 @@ + BuildableName = "OpenCode Monitor.app" + BlueprintName = "opencode-monitor_iOS" + ReferencedContainer = "container:opencode-monitor.xcodeproj"> @@ -66,9 +66,9 @@ + BuildableName = "OpenCode Monitor.app" + BlueprintName = "opencode-monitor_iOS" + ReferencedContainer = "container:opencode-monitor.xcodeproj"> @@ -95,9 +95,9 @@ + BuildableName = "OpenCode Monitor.app" + BlueprintName = "opencode-monitor_iOS" + ReferencedContainer = "container:opencode-monitor.xcodeproj"> diff --git a/src-tauri/gen/apple/codex-monitor_iOS/Info.plist b/src-tauri/gen/apple/opencode-monitor_iOS/Info.plist similarity index 95% rename from src-tauri/gen/apple/codex-monitor_iOS/Info.plist rename to src-tauri/gen/apple/opencode-monitor_iOS/Info.plist index cfee2cc61e..ed3ec0095f 100644 --- a/src-tauri/gen/apple/codex-monitor_iOS/Info.plist +++ b/src-tauri/gen/apple/opencode-monitor_iOS/Info.plist @@ -11,7 +11,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - Codex Monitor + OpenCode Monitor CFBundlePackageType APPL CFBundleShortVersionString @@ -45,7 +45,7 @@ fetch CFBundleDisplayName - Codex Monitor + OpenCode Monitor NSMicrophoneUsageDescription Allow access to the microphone for dictation. diff --git a/src-tauri/gen/apple/codex-monitor_iOS/codex-monitor_iOS.entitlements b/src-tauri/gen/apple/opencode-monitor_iOS/opencode-monitor_iOS.entitlements similarity index 100% rename from src-tauri/gen/apple/codex-monitor_iOS/codex-monitor_iOS.entitlements rename to src-tauri/gen/apple/opencode-monitor_iOS/opencode-monitor_iOS.entitlements diff --git a/src-tauri/gen/apple/project.yml b/src-tauri/gen/apple/project.yml index fa830dc7f7..37e7f7b5ab 100644 --- a/src-tauri/gen/apple/project.yml +++ b/src-tauri/gen/apple/project.yml @@ -1,6 +1,6 @@ -name: codex-monitor +name: opencode-monitor options: - bundleIdPrefix: com.dimillian.codexmonitor + bundleIdPrefix: com.dimillian.opencodemonitor deploymentTarget: iOS: 14.0 fileGroups: [../../src] @@ -10,8 +10,8 @@ configs: settingGroups: app: base: - PRODUCT_NAME: Codex Monitor - PRODUCT_BUNDLE_IDENTIFIER: com.dimillian.codexmonitor + PRODUCT_NAME: OpenCode Monitor + PRODUCT_BUNDLE_IDENTIFIER: com.dimillian.opencodemonitor targetTemplates: app: type: application @@ -24,20 +24,20 @@ targetTemplates: settings: groups: [app] targets: - codex-monitor_iOS: + opencode-monitor_iOS: type: application platform: iOS sources: - path: Sources - path: Assets.xcassets - path: Externals - - path: codex-monitor_iOS + - path: opencode-monitor_iOS - path: assets buildPhase: resources type: folder - path: LaunchScreen.storyboard info: - path: codex-monitor_iOS/Info.plist + path: opencode-monitor_iOS/Info.plist properties: LSRequiresIPhoneOS: true UILaunchStoryboardName: LaunchScreen @@ -56,7 +56,7 @@ targets: CFBundleShortVersionString: 0.7.45 CFBundleVersion: "0.7.45" entitlements: - path: codex-monitor_iOS/codex-monitor_iOS.entitlements + path: opencode-monitor_iOS/opencode-monitor_iOS.entitlements scheme: environmentVariables: RUST_BACKTRACE: full diff --git a/src-tauri/src/backend/app_server.rs b/src-tauri/src/backend/app_server.rs index 9dce23cc2f..d688d63a01 100644 --- a/src-tauri/src/backend/app_server.rs +++ b/src-tauri/src/backend/app_server.rs @@ -13,7 +13,7 @@ use tokio::sync::{mpsc, oneshot, Mutex}; use tokio::time::timeout; use crate::backend::events::{AppServerEvent, EventSink}; -use crate::codex::args::parse_codex_args; +use crate::opencode::args::parse_opencode_args; use crate::shared::process_core::{kill_child_process_tree, tokio_command}; use crate::types::WorkspaceEntry; @@ -389,7 +389,7 @@ fn should_suppress_hidden_thread_event( !has_result_or_error && !matches!( method_name, - Some("thread/archived") | Some("codex/backgroundThread") + Some("thread/archived") | Some("opencode/backgroundThread") ) } @@ -419,8 +419,8 @@ pub(crate) struct RequestContext { fn build_initialize_params(client_version: &str) -> Value { json!({ "clientInfo": { - "name": "codex_monitor", - "title": "Codex Monitor", + "name": "opencode_monitor", + "title": "OpenCode Monitor", "version": client_version }, "capabilities": { @@ -432,7 +432,7 @@ fn build_initialize_params(client_version: &str) -> Value { const REQUEST_TIMEOUT: Duration = Duration::from_secs(300); pub(crate) struct WorkspaceSession { - pub(crate) codex_args: Option, + pub(crate) opencode_args: Option, pub(crate) child: Mutex, pub(crate) stdin: Mutex, pub(crate) pending: Mutex>>, @@ -560,7 +560,7 @@ impl WorkspaceSession { } } -pub(crate) fn build_codex_path_env(codex_bin: Option<&str>) -> Option { +pub(crate) fn build_opencode_path_env(opencode_bin: Option<&str>) -> Option { let mut paths: Vec = env::var_os("PATH") .map(|value| env::split_paths(&value).collect()) .unwrap_or_default(); @@ -622,7 +622,7 @@ pub(crate) fn build_codex_path_env(codex_bin: Option<&str>) -> Option { } } - if let Some(bin_path) = codex_bin.filter(|value| !value.trim().is_empty()) { + if let Some(bin_path) = opencode_bin.filter(|value| !value.trim().is_empty()) { if let Some(parent) = Path::new(bin_path).parent() { extras.push(parent.to_path_buf()); } @@ -643,18 +643,18 @@ pub(crate) fn build_codex_path_env(codex_bin: Option<&str>) -> Option { .map(|joined| joined.to_string_lossy().to_string()) } -pub(crate) fn build_codex_command_with_bin( - codex_bin: Option, - codex_args: Option<&str>, +pub(crate) fn build_opencode_command_with_bin( + opencode_bin: Option, + opencode_args: Option<&str>, args: Vec, ) -> Result { - let bin = codex_bin + let bin = opencode_bin .clone() .filter(|value| !value.trim().is_empty()) - .unwrap_or_else(|| "codex".into()); + .unwrap_or_else(|| "opencode".into()); - let path_env = build_codex_path_env(codex_bin.as_deref()); - let mut command_args = parse_codex_args(codex_args)?; + let path_env = build_opencode_path_env(opencode_bin.as_deref()); + let mut command_args = parse_opencode_args(opencode_args)?; command_args.extend(args); #[cfg(target_os = "windows")] @@ -697,24 +697,24 @@ pub(crate) fn build_codex_command_with_bin( Ok(command) } -pub(crate) async fn check_codex_installation( - codex_bin: Option, +pub(crate) async fn check_opencode_installation( + opencode_bin: Option, ) -> Result, String> { - let mut command = build_codex_command_with_bin(codex_bin, None, vec!["--version".to_string()])?; + let mut command = build_opencode_command_with_bin(opencode_bin, None, vec!["--version".to_string()])?; command.stdout(std::process::Stdio::piped()); command.stderr(std::process::Stdio::piped()); let output = match timeout(Duration::from_secs(5), command.output()).await { Ok(result) => result.map_err(|e| { if e.kind() == ErrorKind::NotFound { - "Codex CLI not found. Install Codex and ensure `codex` is on your PATH.".to_string() + "OpenCode CLI not found. Install OpenCode and ensure `opencode` is on your PATH.".to_string() } else { e.to_string() } })?, Err(_) => { return Err( - "Timed out while checking Codex CLI. Make sure `codex --version` runs in Terminal." + "Timed out while checking OpenCode CLI. Make sure `opencode --version` runs in Terminal." .to_string(), ); } @@ -730,11 +730,11 @@ pub(crate) async fn check_codex_installation( }; if detail.is_empty() { return Err( - "Codex CLI failed to start. Try running `codex --version` in Terminal.".to_string(), + "OpenCode CLI failed to start. Try running `opencode --version` in Terminal.".to_string(), ); } return Err(format!( - "Codex CLI failed to start: {detail}. Try running `codex --version` in Terminal." + "OpenCode CLI failed to start: {detail}. Try running `opencode --version` in Terminal." )); } @@ -748,23 +748,23 @@ pub(crate) async fn check_codex_installation( pub(crate) async fn spawn_workspace_session( entry: WorkspaceEntry, - default_codex_bin: Option, - codex_args: Option, - codex_home: Option, + default_opencode_bin: Option, + opencode_args: Option, + opencode_home: Option, client_version: String, event_sink: E, ) -> Result, String> { - let codex_bin = default_codex_bin; - let _ = check_codex_installation(codex_bin.clone()).await?; + let opencode_bin = default_opencode_bin; + let _ = check_opencode_installation(opencode_bin.clone()).await?; - let mut command = build_codex_command_with_bin( - codex_bin, - codex_args.as_deref(), + let mut command = build_opencode_command_with_bin( + opencode_bin, + opencode_args.as_deref(), vec!["app-server".to_string()], )?; command.current_dir(&entry.path); - if let Some(path) = codex_home.as_ref() { - command.env("CODEX_HOME", path); + if let Some(path) = opencode_home.as_ref() { + command.env("OPENCODE_CONFIG_DIR", path); } command.stdin(std::process::Stdio::piped()); command.stdout(std::process::Stdio::piped()); @@ -776,7 +776,7 @@ pub(crate) async fn spawn_workspace_session( let stderr = child.stderr.take().ok_or("missing stderr")?; let session = Arc::new(WorkspaceSession { - codex_args, + opencode_args, child: Mutex::new(child), stdin: Mutex::new(stdin), pending: Mutex::new(HashMap::new()), @@ -808,7 +808,7 @@ pub(crate) async fn spawn_workspace_session( let payload = AppServerEvent { workspace_id: fallback_workspace_id.clone(), message: json!({ - "method": "codex/parseError", + "method": "opencode/parseError", "params": { "error": err.to_string(), "raw": line }, }), }; @@ -896,7 +896,7 @@ pub(crate) async fn spawn_workspace_session( .unwrap_or_else(|| fallback_workspace_id.clone()); if let Some(ref tid) = thread_id { - if method_name == Some("codex/backgroundThread") { + if method_name == Some("opencode/backgroundThread") { let action = value .get("params") .and_then(|params| params.get("action")) @@ -912,7 +912,7 @@ pub(crate) async fn spawn_workspace_session( let payload = AppServerEvent { workspace_id: routed_workspace_id.clone(), message: json!({ - "method": "codex/backgroundThread", + "method": "opencode/backgroundThread", "params": { "threadId": tid, "action": "hide" @@ -1062,7 +1062,7 @@ pub(crate) async fn spawn_workspace_session( let payload = AppServerEvent { workspace_id: workspace_id.clone(), message: json!({ - "method": "codex/stderr", + "method": "opencode/stderr", "params": { "message": line }, }), }; @@ -1082,7 +1082,7 @@ pub(crate) async fn spawn_workspace_session( let mut child = session.child.lock().await; kill_child_process_tree(&mut child).await; return Err( - "Codex app-server did not respond to initialize. Check that `codex app-server` works in Terminal." + "OpenCode serve did not respond to initialize. Check that `opencode serve` works in Terminal." .to_string(), ); } @@ -1093,7 +1093,7 @@ pub(crate) async fn spawn_workspace_session( let payload = AppServerEvent { workspace_id: entry.id.clone(), message: json!({ - "method": "codex/connected", + "method": "opencode/connected", "params": { "workspaceId": entry.id.clone() } }), }; @@ -1241,9 +1241,9 @@ mod tests { #[test] fn resolve_workspace_for_cwd_normalizes_windows_paths() { let mut roots = HashMap::new(); - roots.insert("ws-1".to_string(), normalize_root_path("C:\\Dev\\Codex")); + roots.insert("ws-1".to_string(), normalize_root_path("C:\\Dev\\OpenCode")); assert_eq!( - resolve_workspace_for_cwd("c:/dev/codex", &roots), + resolve_workspace_for_cwd("c:/dev/opencode", &roots), Some("ws-1".to_string()) ); } @@ -1251,7 +1251,7 @@ mod tests { #[test] fn resolve_workspace_for_cwd_normalizes_windows_namespace_paths() { let mut roots = HashMap::new(); - roots.insert("ws-1".to_string(), normalize_root_path("C:\\Dev\\Codex")); + roots.insert("ws-1".to_string(), normalize_root_path("C:\\Dev\\OpenCode")); assert_eq!( resolve_workspace_for_cwd("\\\\?\\C:\\Dev\\Codex", &roots), Some("ws-1".to_string()) @@ -1269,9 +1269,9 @@ mod tests { #[test] fn resolve_workspace_for_cwd_matches_nested_paths() { let mut roots = HashMap::new(); - roots.insert("ws-1".to_string(), normalize_root_path("/tmp/codex")); + roots.insert("ws-1".to_string(), normalize_root_path("/tmp/opencode")); assert_eq!( - resolve_workspace_for_cwd("/tmp/codex/subdir/project", &roots), + resolve_workspace_for_cwd("/tmp/opencode/subdir/project", &roots), Some("ws-1".to_string()) ); } @@ -1279,13 +1279,13 @@ mod tests { #[test] fn resolve_workspace_for_cwd_prefers_longest_matching_root() { let mut roots = HashMap::new(); - roots.insert("ws-parent".to_string(), normalize_root_path("/tmp/codex")); + roots.insert("ws-parent".to_string(), normalize_root_path("/tmp/opencode")); roots.insert( "ws-child".to_string(), - normalize_root_path("/tmp/codex/subdir"), + normalize_root_path("/tmp/opencode/subdir"), ); assert_eq!( - resolve_workspace_for_cwd("/tmp/codex/subdir/project", &roots), + resolve_workspace_for_cwd("/tmp/opencode/subdir/project", &roots), Some("ws-child".to_string()) ); } @@ -1381,7 +1381,7 @@ mod tests { false )); assert!(!should_suppress_hidden_thread_event( - Some("codex/backgroundThread"), + Some("opencode/backgroundThread"), false )); } diff --git a/src-tauri/src/bin/codex_monitor_daemon.rs b/src-tauri/src/bin/opencode_monitor_daemon.rs similarity index 90% rename from src-tauri/src/bin/codex_monitor_daemon.rs rename to src-tauri/src/bin/opencode_monitor_daemon.rs index 59bfc00bc8..4762dd6325 100644 --- a/src-tauri/src/bin/codex_monitor_daemon.rs +++ b/src-tauri/src/bin/opencode_monitor_daemon.rs @@ -1,12 +1,12 @@ #[allow(dead_code)] #[path = "../backend/mod.rs"] mod backend; -#[path = "../codex/args.rs"] -mod codex_args; -#[path = "../codex/config.rs"] -mod codex_config; -#[path = "../codex/home.rs"] -mod codex_home; +#[path = "../opencode/args.rs"] +mod opencode_args; +#[path = "../opencode/config.rs"] +mod opencode_config; +#[path = "../opencode/home.rs"] +mod opencode_home; #[path = "../files/io.rs"] mod file_io; #[path = "../files/ops.rs"] @@ -15,7 +15,7 @@ mod file_ops; mod file_policy; #[path = "../git_utils.rs"] mod git_utils; -#[path = "codex_monitor_daemon/rpc.rs"] +#[path = "opencode_monitor_daemon/rpc.rs"] mod rpc; #[path = "../rules.rs"] mod rules; @@ -23,7 +23,7 @@ mod rules; mod shared; #[path = "../storage.rs"] mod storage; -#[path = "codex_monitor_daemon/transport.rs"] +#[path = "opencode_monitor_daemon/transport.rs"] mod transport; #[allow(dead_code)] #[path = "../types.rs"] @@ -36,15 +36,15 @@ mod workspace_macos; mod workspace_settings; // Provide feature-style module paths for shared cores when compiled in the daemon. -mod codex { +mod opencode { pub(crate) mod args { - pub(crate) use crate::codex_args::*; + pub(crate) use crate::opencode_args::*; } pub(crate) mod config { - pub(crate) use crate::codex_config::*; + pub(crate) use crate::opencode_config::*; } pub(crate) mod home { - pub(crate) use crate::codex_home::*; + pub(crate) use crate::opencode_home::*; } } @@ -77,11 +77,11 @@ use tokio::sync::{broadcast, mpsc, Mutex, Semaphore}; use backend::app_server::{spawn_workspace_session, WorkspaceSession}; use backend::events::{AppServerEvent, EventSink, TerminalExit, TerminalOutput}; -use shared::codex_core::CodexLoginCancelState; +use shared::opencode_core::OpenCodeLoginCancelState; use shared::process_core::kill_child_process_tree; use shared::prompts_core::{self, CustomPromptEntry}; use shared::{ - agents_config_core, codex_aux_core, codex_core, files_core, git_core, git_ui_core, + agents_config_core, opencode_aux_core, opencode_core, files_core, git_core, git_ui_core, local_usage_core, settings_core, workspaces_core, worktree_core, }; use storage::{read_settings, read_workspaces}; @@ -94,21 +94,21 @@ use workspace_settings::apply_workspace_settings_update; const DEFAULT_LISTEN_ADDR: &str = "127.0.0.1:4732"; const MAX_IN_FLIGHT_RPC_PER_CONNECTION: usize = 32; -const DAEMON_NAME: &str = "codex-monitor-daemon"; +const DAEMON_NAME: &str = "opencode-monitor-daemon"; fn spawn_with_client( event_sink: DaemonEventSink, client_version: String, entry: WorkspaceEntry, default_bin: Option, - codex_args: Option, - codex_home: Option, + opencode_args: Option, + opencode_home: Option, ) -> impl std::future::Future, String>> { spawn_workspace_session( entry, default_bin, - codex_args, - codex_home, + opencode_args, + opencode_home, client_version, event_sink, ) @@ -156,7 +156,7 @@ struct DaemonState { settings_path: PathBuf, app_settings: Mutex, event_sink: DaemonEventSink, - codex_login_cancels: Mutex>, + opencode_login_cancels: Mutex>, daemon_binary_path: Option, } @@ -183,7 +183,7 @@ impl DaemonState { settings_path, app_settings: Mutex::new(app_settings), event_sink, - codex_login_cancels: Mutex::new(HashMap::new()), + opencode_login_cancels: Mutex::new(HashMap::new()), daemon_binary_path, } } @@ -259,14 +259,14 @@ impl DaemonState { &self.sessions, &self.app_settings, &self.storage_path, - move |entry, default_bin, codex_args, codex_home| { + move |entry, default_bin, opencode_args, opencode_home| { spawn_with_client( self.event_sink.clone(), client_version.clone(), entry, default_bin, - codex_args, - codex_home, + opencode_args, + opencode_home, ) }, ) @@ -289,14 +289,14 @@ impl DaemonState { &self.sessions, &self.app_settings, &self.storage_path, - move |entry, default_bin, codex_args, codex_home| { + move |entry, default_bin, opencode_args, opencode_home| { spawn_with_client( self.event_sink.clone(), client_version.clone(), entry, default_bin, - codex_args, - codex_home, + opencode_args, + opencode_home, ) }, ) @@ -337,14 +337,14 @@ impl DaemonState { |root, args| { workspaces_core::run_git_command_unit(root, args, git_core::run_git_command_owned) }, - move |entry, default_bin, codex_args, codex_home| { + move |entry, default_bin, opencode_args, opencode_home| { spawn_with_client( self.event_sink.clone(), client_version.clone(), entry, default_bin, - codex_args, - codex_home, + opencode_args, + opencode_home, ) }, ) @@ -438,14 +438,14 @@ impl DaemonState { |root, args| { workspaces_core::run_git_command_unit(root, args, git_core::run_git_command_owned) }, - move |entry, default_bin, codex_args, codex_home| { + move |entry, default_bin, opencode_args, opencode_home| { spawn_with_client( self.event_sink.clone(), client_version.clone(), entry, default_bin, - codex_args, - codex_home, + opencode_args, + opencode_home, ) }, ) @@ -511,14 +511,14 @@ impl DaemonState { |workspaces, workspace_id, next_settings| { apply_workspace_settings_update(workspaces, workspace_id, next_settings) }, - move |entry, default_bin, codex_args, codex_home| { + move |entry, default_bin, opencode_args, opencode_home| { spawn_with_client( self.event_sink.clone(), client_version.clone(), entry, default_bin, - codex_args, - codex_home, + opencode_args, + opencode_home, ) }, ) @@ -539,40 +539,40 @@ impl DaemonState { &self.workspaces, &self.sessions, &self.app_settings, - move |entry, default_bin, codex_args, codex_home| { + move |entry, default_bin, opencode_args, opencode_home| { spawn_with_client( self.event_sink.clone(), client_version.clone(), entry, default_bin, - codex_args, - codex_home, + opencode_args, + opencode_home, ) }, ) .await } - async fn set_workspace_runtime_codex_args( + async fn set_workspace_runtime_opencode_args( &self, workspace_id: String, - codex_args: Option, + opencode_args: Option, client_version: String, - ) -> Result { - workspaces_core::set_workspace_runtime_codex_args_core( + ) -> Result { + workspaces_core::set_workspace_runtime_opencode_args_core( workspace_id, - codex_args, + opencode_args, &self.workspaces, &self.sessions, &self.app_settings, - move |entry, default_bin, next_args, codex_home| { + move |entry, default_bin, next_args, opencode_home| { spawn_with_client( self.event_sink.clone(), client_version.clone(), entry, default_bin, next_args, - codex_home, + opencode_home, ) }, ) @@ -588,12 +588,12 @@ impl DaemonState { .await } - async fn set_codex_feature_flag( + async fn set_opencode_feature_flag( &self, feature_key: String, enabled: bool, ) -> Result<(), String> { - codex_config::write_feature_enabled(feature_key.as_str(), enabled) + opencode_config::write_feature_enabled(feature_key.as_str(), enabled) } async fn get_agents_settings(&self) -> Result { @@ -681,7 +681,7 @@ impl DaemonState { } async fn start_thread(&self, workspace_id: String) -> Result { - codex_core::start_thread_core(&self.sessions, &self.workspaces, workspace_id).await + opencode_core::start_thread_core(&self.sessions, &self.workspaces, workspace_id).await } async fn resume_thread( @@ -689,7 +689,7 @@ impl DaemonState { workspace_id: String, thread_id: String, ) -> Result { - codex_core::resume_thread_core(&self.sessions, workspace_id, thread_id).await + opencode_core::resume_thread_core(&self.sessions, workspace_id, thread_id).await } async fn read_thread( @@ -697,7 +697,7 @@ impl DaemonState { workspace_id: String, thread_id: String, ) -> Result { - codex_core::read_thread_core(&self.sessions, workspace_id, thread_id).await + opencode_core::read_thread_core(&self.sessions, workspace_id, thread_id).await } async fn thread_live_subscribe( @@ -705,7 +705,7 @@ impl DaemonState { workspace_id: String, thread_id: String, ) -> Result { - codex_core::thread_live_subscribe_core( + opencode_core::thread_live_subscribe_core( &self.sessions, workspace_id.clone(), thread_id.clone(), @@ -734,7 +734,7 @@ impl DaemonState { workspace_id: String, thread_id: String, ) -> Result { - codex_core::thread_live_unsubscribe_core( + opencode_core::thread_live_unsubscribe_core( &self.sessions, workspace_id.clone(), thread_id.clone(), @@ -755,7 +755,7 @@ impl DaemonState { } async fn fork_thread(&self, workspace_id: String, thread_id: String) -> Result { - codex_core::fork_thread_core(&self.sessions, workspace_id, thread_id).await + opencode_core::fork_thread_core(&self.sessions, workspace_id, thread_id).await } async fn list_threads( @@ -765,7 +765,7 @@ impl DaemonState { limit: Option, sort_key: Option, ) -> Result { - codex_core::list_threads_core(&self.sessions, workspace_id, cursor, limit, sort_key) + opencode_core::list_threads_core(&self.sessions, workspace_id, cursor, limit, sort_key) .await } @@ -775,7 +775,7 @@ impl DaemonState { cursor: Option, limit: Option, ) -> Result { - codex_core::list_mcp_server_status_core(&self.sessions, workspace_id, cursor, limit).await + opencode_core::list_mcp_server_status_core(&self.sessions, workspace_id, cursor, limit).await } async fn archive_thread( @@ -783,7 +783,7 @@ impl DaemonState { workspace_id: String, thread_id: String, ) -> Result { - codex_core::archive_thread_core(&self.sessions, workspace_id, thread_id).await + opencode_core::archive_thread_core(&self.sessions, workspace_id, thread_id).await } async fn compact_thread( @@ -791,7 +791,7 @@ impl DaemonState { workspace_id: String, thread_id: String, ) -> Result { - codex_core::compact_thread_core(&self.sessions, workspace_id, thread_id).await + opencode_core::compact_thread_core(&self.sessions, workspace_id, thread_id).await } async fn set_thread_name( @@ -800,7 +800,7 @@ impl DaemonState { thread_id: String, name: String, ) -> Result { - codex_core::set_thread_name_core(&self.sessions, workspace_id, thread_id, name).await + opencode_core::set_thread_name_core(&self.sessions, workspace_id, thread_id, name).await } async fn send_user_message( @@ -816,7 +816,7 @@ impl DaemonState { app_mentions: Option>, collaboration_mode: Option, ) -> Result { - codex_core::send_user_message_core( + opencode_core::send_user_message_core( &self.sessions, &self.workspaces, workspace_id, @@ -842,7 +842,7 @@ impl DaemonState { images: Option>, app_mentions: Option>, ) -> Result { - codex_core::turn_steer_core( + opencode_core::turn_steer_core( &self.sessions, workspace_id, thread_id, @@ -860,7 +860,7 @@ impl DaemonState { thread_id: String, turn_id: String, ) -> Result { - codex_core::turn_interrupt_core(&self.sessions, workspace_id, thread_id, turn_id).await + opencode_core::turn_interrupt_core(&self.sessions, workspace_id, thread_id, turn_id).await } async fn start_review( @@ -870,12 +870,12 @@ impl DaemonState { target: Value, delivery: Option, ) -> Result { - codex_core::start_review_core(&self.sessions, workspace_id, thread_id, target, delivery) + opencode_core::start_review_core(&self.sessions, workspace_id, thread_id, target, delivery) .await } async fn model_list(&self, workspace_id: String) -> Result { - codex_core::model_list_core(&self.sessions, workspace_id).await + opencode_core::model_list_core(&self.sessions, workspace_id).await } async fn experimental_feature_list( @@ -884,33 +884,33 @@ impl DaemonState { cursor: Option, limit: Option, ) -> Result { - codex_core::experimental_feature_list_core(&self.sessions, workspace_id, cursor, limit) + opencode_core::experimental_feature_list_core(&self.sessions, workspace_id, cursor, limit) .await } async fn collaboration_mode_list(&self, workspace_id: String) -> Result { - codex_core::collaboration_mode_list_core(&self.sessions, workspace_id).await + opencode_core::collaboration_mode_list_core(&self.sessions, workspace_id).await } async fn account_rate_limits(&self, workspace_id: String) -> Result { - codex_core::account_rate_limits_core(&self.sessions, workspace_id).await + opencode_core::account_rate_limits_core(&self.sessions, workspace_id).await } async fn account_read(&self, workspace_id: String) -> Result { - codex_core::account_read_core(&self.sessions, &self.workspaces, workspace_id).await + opencode_core::account_read_core(&self.sessions, &self.workspaces, workspace_id).await } - async fn codex_login(&self, workspace_id: String) -> Result { - codex_core::codex_login_core(&self.sessions, &self.codex_login_cancels, workspace_id).await + async fn opencode_login(&self, workspace_id: String) -> Result { + opencode_core::opencode_login_core(&self.sessions, &self.opencode_login_cancels, workspace_id).await } - async fn codex_login_cancel(&self, workspace_id: String) -> Result { - codex_core::codex_login_cancel_core(&self.sessions, &self.codex_login_cancels, workspace_id) + async fn opencode_login_cancel(&self, workspace_id: String) -> Result { + opencode_core::opencode_login_cancel_core(&self.sessions, &self.opencode_login_cancels, workspace_id) .await } async fn skills_list(&self, workspace_id: String) -> Result { - codex_core::skills_list_core(&self.sessions, &self.workspaces, workspace_id).await + opencode_core::skills_list_core(&self.sessions, &self.workspaces, workspace_id).await } async fn apps_list( @@ -920,7 +920,7 @@ impl DaemonState { limit: Option, thread_id: Option, ) -> Result { - codex_core::apps_list_core(&self.sessions, workspace_id, cursor, limit, thread_id).await + opencode_core::apps_list_core(&self.sessions, workspace_id, cursor, limit, thread_id).await } async fn respond_to_server_request( @@ -929,7 +929,7 @@ impl DaemonState { request_id: Value, result: Value, ) -> Result { - codex_core::respond_to_server_request_core( + opencode_core::respond_to_server_request_core( &self.sessions, workspace_id, request_id, @@ -944,11 +944,11 @@ impl DaemonState { workspace_id: String, command: Vec, ) -> Result { - codex_core::remember_approval_rule_core(&self.workspaces, workspace_id, command).await + opencode_core::remember_approval_rule_core(&self.workspaces, workspace_id, command).await } async fn get_config_model(&self, workspace_id: String) -> Result { - codex_core::get_config_model_core(&self.workspaces, workspace_id).await + opencode_core::get_config_model_core(&self.workspaces, workspace_id).await } async fn add_clone( @@ -966,14 +966,14 @@ impl DaemonState { &self.sessions, &self.app_settings, &self.storage_path, - |entry, default_bin, codex_args, codex_home| { + |entry, default_bin, opencode_args, opencode_home| { spawn_with_client( self.event_sink.clone(), client_version.clone(), entry, default_bin, - codex_args, - codex_home, + opencode_args, + opencode_home, ) }, ) @@ -1258,12 +1258,12 @@ impl DaemonState { .await } - async fn codex_doctor( + async fn opencode_doctor( &self, - codex_bin: Option, - codex_args: Option, + opencode_bin: Option, + opencode_args: Option, ) -> Result { - codex_aux_core::codex_doctor_core(&self.app_settings, codex_bin, codex_args).await + opencode_aux_core::opencode_doctor_core(&self.app_settings, opencode_bin, opencode_args).await } async fn generate_commit_message( @@ -1281,7 +1281,7 @@ impl DaemonState { let settings = self.app_settings.lock().await; settings.commit_message_prompt.clone() }; - codex_aux_core::generate_commit_message_core( + opencode_aux_core::generate_commit_message_core( &self.sessions, &self.workspaces, workspace_id, @@ -1300,7 +1300,7 @@ impl DaemonState { workspace_id: String, prompt: String, ) -> Result { - codex_aux_core::generate_run_metadata_core( + opencode_aux_core::generate_run_metadata_core( &self.sessions, &self.workspaces, workspace_id, @@ -1316,8 +1316,8 @@ impl DaemonState { &self, workspace_id: String, description: String, - ) -> Result { - codex_aux_core::generate_agent_description_core( + ) -> Result { + opencode_aux_core::generate_agent_description_core( &self.sessions, &self.workspaces, workspace_id, @@ -1366,7 +1366,7 @@ fn emit_background_thread_hide(event_sink: &DaemonEventSink, workspace_id: &str, event_sink.emit_app_server_event(AppServerEvent { workspace_id: workspace_id.to_string(), message: json!({ - "method": "codex/backgroundThread", + "method": "opencode/backgroundThread", "params": { "threadId": thread_id, "action": "hide" @@ -1486,20 +1486,20 @@ fn default_data_dir() -> PathBuf { if let Ok(xdg) = env::var("XDG_DATA_HOME") { let trimmed = xdg.trim(); if !trimmed.is_empty() { - return PathBuf::from(trimmed).join("codex-monitor-daemon"); + return PathBuf::from(trimmed).join("opencode-monitor-daemon"); } } let home = env::var("HOME").unwrap_or_else(|_| ".".to_string()); PathBuf::from(home) .join(".local") .join("share") - .join("codex-monitor-daemon") + .join("opencode-monitor-daemon") } fn usage() -> String { format!( "\ -USAGE:\n codex-monitor-daemon [--listen ] [--data-dir ] [--token | --insecure-no-auth]\n\n\ +USAGE:\n opencode-monitor-daemon [--listen ] [--data-dir ] [--token | --insecure-no-auth]\n\n\ OPTIONS:\n --listen Bind address (default: {DEFAULT_LISTEN_ADDR})\n --data-dir Data dir holding workspaces.json/settings.json\n --token Shared token required by TCP clients\n --insecure-no-auth Disable TCP auth (dev only)\n -h, --help Show this help\n" ) } @@ -1508,7 +1508,7 @@ fn parse_args() -> Result { let mut listen = DEFAULT_LISTEN_ADDR .parse::() .map_err(|err| err.to_string())?; - let mut token = env::var("CODEX_MONITOR_DAEMON_TOKEN") + let mut token = env::var("OPENCODE_MONITOR_DAEMON_TOKEN") .ok() .map(|value| value.trim().to_string()) .filter(|value| !value.is_empty()); @@ -1552,7 +1552,7 @@ fn parse_args() -> Result { if token.is_none() && !insecure_no_auth { return Err( - "Missing --token (or set CODEX_MONITOR_DAEMON_TOKEN). Use --insecure-no-auth for local dev only." + "Missing --token (or set OPENCODE_MONITOR_DAEMON_TOKEN). Use --insecure-no-auth for local dev only." .to_string(), ); } @@ -1596,7 +1596,7 @@ mod tests { .expect("time") .as_nanos(); let dir = std::env::temp_dir().join(format!( - "codex-monitor-{prefix}-{}-{unique}", + "opencode-monitor-{prefix}-{}-{unique}", std::process::id() )); std::fs::create_dir_all(&dir).expect("create temp dir"); @@ -1613,8 +1613,8 @@ mod tests { settings_path: data_dir.join("settings.json"), app_settings: Mutex::new(AppSettings::default()), event_sink: DaemonEventSink { tx }, - codex_login_cancels: Mutex::new(HashMap::new()), - daemon_binary_path: Some("/tmp/codex-monitor-daemon".to_string()), + opencode_login_cancels: Mutex::new(HashMap::new()), + daemon_binary_path: Some("/tmp/opencode-monitor-daemon".to_string()), } } @@ -1669,7 +1669,7 @@ mod tests { let stdin = child.stdin.take().expect("dummy child stdin"); Arc::new(WorkspaceSession { - codex_args: None, + opencode_args: None, child: Mutex::new(child), stdin: Mutex::new(stdin), pending: Mutex::new(HashMap::new()), @@ -1940,7 +1940,7 @@ fn main() { } }; eprintln!( - "codex-monitor-daemon listening on {} (data dir: {})", + "opencode-monitor-daemon listening on {} (data dir: {})", config.listen, state .storage_path diff --git a/src-tauri/src/bin/codex_monitor_daemon/rpc.rs b/src-tauri/src/bin/opencode_monitor_daemon/rpc.rs similarity index 99% rename from src-tauri/src/bin/codex_monitor_daemon/rpc.rs rename to src-tauri/src/bin/opencode_monitor_daemon/rpc.rs index a7ce318120..11ef1648fb 100644 --- a/src-tauri/src/bin/codex_monitor_daemon/rpc.rs +++ b/src-tauri/src/bin/opencode_monitor_daemon/rpc.rs @@ -1,7 +1,7 @@ use super::*; -#[path = "rpc/codex.rs"] -mod codex; +#[path = "rpc/opencode.rs"] +mod opencode; #[path = "rpc/daemon.rs"] mod daemon; #[path = "rpc/dispatcher.rs"] diff --git a/src-tauri/src/bin/codex_monitor_daemon/rpc/daemon.rs b/src-tauri/src/bin/opencode_monitor_daemon/rpc/daemon.rs similarity index 100% rename from src-tauri/src/bin/codex_monitor_daemon/rpc/daemon.rs rename to src-tauri/src/bin/opencode_monitor_daemon/rpc/daemon.rs diff --git a/src-tauri/src/bin/codex_monitor_daemon/rpc/dispatcher.rs b/src-tauri/src/bin/opencode_monitor_daemon/rpc/dispatcher.rs similarity index 89% rename from src-tauri/src/bin/codex_monitor_daemon/rpc/dispatcher.rs rename to src-tauri/src/bin/opencode_monitor_daemon/rpc/dispatcher.rs index 781b3d7bbc..1db80cb8a7 100644 --- a/src-tauri/src/bin/codex_monitor_daemon/rpc/dispatcher.rs +++ b/src-tauri/src/bin/opencode_monitor_daemon/rpc/dispatcher.rs @@ -14,7 +14,7 @@ pub(super) async fn dispatch_rpc_request( return result; } - if let Some(result) = codex::try_handle(state, method, params).await { + if let Some(result) = opencode::try_handle(state, method, params).await { return result; } diff --git a/src-tauri/src/bin/codex_monitor_daemon/rpc/git.rs b/src-tauri/src/bin/opencode_monitor_daemon/rpc/git.rs similarity index 100% rename from src-tauri/src/bin/codex_monitor_daemon/rpc/git.rs rename to src-tauri/src/bin/opencode_monitor_daemon/rpc/git.rs diff --git a/src-tauri/src/bin/codex_monitor_daemon/rpc/codex.rs b/src-tauri/src/bin/opencode_monitor_daemon/rpc/opencode.rs similarity index 96% rename from src-tauri/src/bin/codex_monitor_daemon/rpc/codex.rs rename to src-tauri/src/bin/opencode_monitor_daemon/rpc/opencode.rs index cc278938ea..c7803b8df5 100644 --- a/src-tauri/src/bin/codex_monitor_daemon/rpc/codex.rs +++ b/src-tauri/src/bin/opencode_monitor_daemon/rpc/opencode.rs @@ -16,8 +16,8 @@ pub(super) async fn try_handle( params: &Value, ) -> Option> { match method { - "get_codex_config_path" => { - let path = match settings_core::get_codex_config_path_core() { + "get_opencode_config_path" => { + let path = match settings_core::get_opencode_config_path_core() { Ok(value) => value, Err(err) => return Some(Err(err)), }; @@ -287,7 +287,7 @@ pub(super) async fn try_handle( }; Some(state.collaboration_mode_list(workspace_id).await) } - "set_codex_feature_flag" => { + "set_opencode_feature_flag" => { let feature_key = match parse_string(params, "featureKey") { Ok(value) => value, Err(err) => return Some(Err(err)), @@ -298,7 +298,7 @@ pub(super) async fn try_handle( }; Some( state - .set_codex_feature_flag(feature_key, enabled) + .set_opencode_feature_flag(feature_key, enabled) .await .map(|_| json!({ "ok": true })), ) @@ -399,19 +399,19 @@ pub(super) async fn try_handle( }; Some(state.account_read(workspace_id).await) } - "codex_login" => { + "opencode_login" => { let workspace_id = match parse_string(params, "workspaceId") { Ok(value) => value, Err(err) => return Some(Err(err)), }; - Some(state.codex_login(workspace_id).await) + Some(state.opencode_login(workspace_id).await) } - "codex_login_cancel" => { + "opencode_login_cancel" => { let workspace_id = match parse_string(params, "workspaceId") { Ok(value) => value, Err(err) => return Some(Err(err)), }; - Some(state.codex_login_cancel(workspace_id).await) + Some(state.opencode_login_cancel(workspace_id).await) } "skills_list" => { let workspace_id = match parse_string(params, "workspaceId") { @@ -473,10 +473,10 @@ pub(super) async fn try_handle( }; Some(state.remember_approval_rule(workspace_id, command).await) } - "codex_doctor" => { - let codex_bin = parse_optional_string(params, "codexBin"); - let codex_args = parse_optional_string(params, "codexArgs"); - Some(state.codex_doctor(codex_bin, codex_args).await) + "opencode_doctor" => { + let opencode_bin = parse_optional_string(params, "opencodeBin"); + let opencode_args = parse_optional_string(params, "opencodeArgs"); + Some(state.opencode_doctor(opencode_bin, opencode_args).await) } "generate_run_metadata" => { let workspace_id = match parse_string(params, "workspaceId") { diff --git a/src-tauri/src/bin/codex_monitor_daemon/rpc/prompts.rs b/src-tauri/src/bin/opencode_monitor_daemon/rpc/prompts.rs similarity index 100% rename from src-tauri/src/bin/codex_monitor_daemon/rpc/prompts.rs rename to src-tauri/src/bin/opencode_monitor_daemon/rpc/prompts.rs diff --git a/src-tauri/src/bin/codex_monitor_daemon/rpc/workspace.rs b/src-tauri/src/bin/opencode_monitor_daemon/rpc/workspace.rs similarity index 97% rename from src-tauri/src/bin/codex_monitor_daemon/rpc/workspace.rs rename to src-tauri/src/bin/opencode_monitor_daemon/rpc/workspace.rs index 3f18527f7b..e47f84a9ed 100644 --- a/src-tauri/src/bin/codex_monitor_daemon/rpc/workspace.rs +++ b/src-tauri/src/bin/opencode_monitor_daemon/rpc/workspace.rs @@ -122,13 +122,13 @@ pub(super) async fn try_handle( serialize_ok(state.connect_workspace(request.id, client_version.to_string())).await, ) } - "set_workspace_runtime_codex_args" => { + "set_workspace_runtime_opencode_args" => { let request = - parse_request_or_err!(params, workspace_rpc::SetWorkspaceRuntimeCodexArgsRequest); + parse_request_or_err!(params, workspace_rpc::SetWorkspaceRuntimeOpenCodeArgsRequest); Some( - serialize_result(state.set_workspace_runtime_codex_args( + serialize_result(state.set_workspace_runtime_opencode_args( request.workspace_id, - request.codex_args, + request.opencode_args, client_version.to_string(), )) .await, diff --git a/src-tauri/src/bin/codex_monitor_daemon/transport.rs b/src-tauri/src/bin/opencode_monitor_daemon/transport.rs similarity index 100% rename from src-tauri/src/bin/codex_monitor_daemon/transport.rs rename to src-tauri/src/bin/opencode_monitor_daemon/transport.rs diff --git a/src-tauri/src/bin/codex_monitor_daemonctl.rs b/src-tauri/src/bin/opencode_monitor_daemonctl.rs similarity index 98% rename from src-tauri/src/bin/codex_monitor_daemonctl.rs rename to src-tauri/src/bin/opencode_monitor_daemonctl.rs index f31c6aef95..a8d9c7fbc7 100644 --- a/src-tauri/src/bin/codex_monitor_daemonctl.rs +++ b/src-tauri/src/bin/opencode_monitor_daemonctl.rs @@ -22,12 +22,12 @@ use tokio::time::{sleep, timeout, Instant}; use types::{AppSettings, TailscaleDaemonCommandPreview, TcpDaemonState, TcpDaemonStatus}; -const EXPECTED_DAEMON_NAME: &str = "codex-monitor-daemon"; +const EXPECTED_DAEMON_NAME: &str = "opencode-monitor-daemon"; const EXPECTED_DAEMON_MODE: &str = "tcp"; const CURRENT_APP_VERSION: &str = env!("CARGO_PKG_VERSION"); const DEFAULT_LISTEN_ADDR: &str = "0.0.0.0:4732"; const REMOTE_TOKEN_PLACEHOLDER: &str = ""; -const APP_IDENTIFIER: &str = "com.dimillian.codexmonitor"; +const APP_IDENTIFIER: &str = "com.dimillian.opencode-monitor"; const DAEMON_RPC_TIMEOUT: Duration = Duration::from_millis(700); #[derive(Debug, Clone)] @@ -236,9 +236,9 @@ fn parse_args() -> Result { fn usage() -> String { format!( "\ -USAGE:\n codex-monitor-daemonctl [options]\n\n\ +USAGE:\n opencode-monitor-daemonctl [options]\n\n\ COMMANDS:\n start Start daemon (auto-restarts mismatched daemon if safe)\n stop Stop daemon\n status Show daemon status\n command-preview Print equivalent daemon start command\n\n\ -OPTIONS:\n --listen Bind/listen address (default derived from settings, fallback: {DEFAULT_LISTEN_ADDR})\n --token Remote backend token override\n --data-dir App data dir (contains settings.json/workspaces.json)\n --daemon-path Explicit path to codex-monitor-daemon binary\n --insecure-no-auth Start/probe daemon without auth token (dev only)\n --json Print JSON output\n -h, --help Show this help\n\n\ +OPTIONS:\n --listen Bind/listen address (default derived from settings, fallback: {DEFAULT_LISTEN_ADDR})\n --token Remote backend token override\n --data-dir App data dir (contains settings.json/workspaces.json)\n --daemon-path Explicit path to opencode-monitor-daemon binary\n --insecure-no-auth Start/probe daemon without auth token (dev only)\n --json Print JSON output\n -h, --help Show this help\n\n\ NOTES:\n - Defaults read token/host from /settings.json\n - If no --data-dir is provided, default app data dir is used for this platform\n" ) } @@ -314,7 +314,7 @@ fn resolve_listen_addr( fn resolve_token(token_arg: Option<&str>, settings: Option<&AppSettings>) -> Option { trim_non_empty(token_arg) - .or_else(|| trim_non_empty(env::var("CODEX_MONITOR_DAEMON_TOKEN").ok().as_deref())) + .or_else(|| trim_non_empty(env::var("OPENCODE_MONITOR_DAEMON_TOKEN").ok().as_deref())) .or_else(|| { settings.and_then(|value| trim_non_empty(value.remote_backend_token.as_deref())) }) @@ -1379,7 +1379,7 @@ mod tests { #[test] fn parses_pid_from_ss_output() { let output = r#"State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess -LISTEN 0 4096 0.0.0.0:4732 0.0.0.0:* users:(("codex-monitor-da",pid=12345,fd=7)) +LISTEN 0 4096 0.0.0.0:4732 0.0.0.0:* users:(("opencode-monitor-da",pid=12345,fd=7)) "#; assert_eq!(parse_ss_listener_pid(output, 4732), Some(12345)); assert_eq!(parse_ss_listener_pid(output, 9000), None); @@ -1389,7 +1389,7 @@ LISTEN 0 4096 0.0.0.0:4732 0.0.0.0:* users:(("codex-monitor-da",p fn parses_pid_from_netstat_output() { let output = r#"Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name -tcp 0 0 0.0.0.0:4732 0.0.0.0:* LISTEN 6789/codex-monitor-da +tcp 0 0 0.0.0.0:4732 0.0.0.0:* LISTEN 6789/opencode-monitor-da "#; assert_eq!(parse_netstat_listener_pid(output, 4732), Some(6789)); assert_eq!(parse_netstat_listener_pid(output, 9000), None); diff --git a/src-tauri/src/daemon_binary.rs b/src-tauri/src/daemon_binary.rs index 09f20e2219..3e8cd3a63d 100644 --- a/src-tauri/src/daemon_binary.rs +++ b/src-tauri/src/daemon_binary.rs @@ -2,9 +2,9 @@ use std::path::PathBuf; pub(crate) fn daemon_binary_candidates() -> &'static [&'static str] { if cfg!(windows) { - &["codex_monitor_daemon.exe", "codex-monitor-daemon.exe"] + &["opencode_monitor_daemon.exe", "opencode-monitor-daemon.exe"] } else { - &["codex_monitor_daemon", "codex-monitor-daemon"] + &["opencode_monitor_daemon", "opencode-monitor-daemon"] } } @@ -46,7 +46,7 @@ pub(crate) fn resolve_daemon_binary_path() -> Result { .ok_or_else(|| "Unable to resolve executable directory".to_string())?; let candidate_names = daemon_binary_candidates(); - if let Ok(explicit_raw) = std::env::var("CODEX_MONITOR_DAEMON_PATH") { + if let Ok(explicit_raw) = std::env::var("OPENCODE_MONITOR_DAEMON_PATH") { let explicit = explicit_raw.trim(); if !explicit.is_empty() { let explicit_path = PathBuf::from(explicit); @@ -95,6 +95,6 @@ mod tests { #[test] fn daemon_binary_candidates_prioritize_underscored_name() { - assert!(daemon_binary_candidates()[0].starts_with("codex_monitor_daemon")); + assert!(daemon_binary_candidates()[0].starts_with("opencode_monitor_daemon")); } } diff --git a/src-tauri/src/files/io.rs b/src-tauri/src/files/io.rs index f802c22e6c..86f90fe7b1 100644 --- a/src-tauri/src/files/io.rs +++ b/src-tauri/src/files/io.rs @@ -143,14 +143,14 @@ mod tests { use uuid::Uuid; fn temp_dir() -> PathBuf { - std::env::temp_dir().join(format!("codex-monitor-file-io-{}", Uuid::new_v4())) + std::env::temp_dir().join(format!("opencode-monitor-file-io-{}", Uuid::new_v4())) } #[test] fn read_returns_missing_when_root_absent() { let root = temp_dir(); let response = - read_text_file_within(&root, "AGENTS.md", true, "CODEX_HOME", "AGENTS.md", false) + read_text_file_within(&root, "AGENTS.md", true, "OPENCODE_CONFIG_DIR", "AGENTS.md", false) .expect("read should succeed"); assert!(!response.exists); assert!(response.content.is_empty()); @@ -164,13 +164,13 @@ mod tests { "AGENTS.md", "hello", true, - "CODEX_HOME", + "OPENCODE_CONFIG_DIR", "AGENTS.md", false, ) .expect("write should succeed"); let response = - read_text_file_within(&root, "AGENTS.md", false, "CODEX_HOME", "AGENTS.md", false) + read_text_file_within(&root, "AGENTS.md", false, "OPENCODE_CONFIG_DIR", "AGENTS.md", false) .expect("read should succeed"); assert!(response.exists); assert_eq!(response.content, "hello"); @@ -250,7 +250,7 @@ mod tests { symlink(&outside_file, &link_path).expect("create symlink"); let response = - read_text_file_within(&root, "AGENTS.md", false, "CODEX_HOME", "AGENTS.md", true) + read_text_file_within(&root, "AGENTS.md", false, "OPENCODE_CONFIG_DIR", "AGENTS.md", true) .expect("read should succeed"); assert!(response.exists); assert_eq!(response.content, "outside"); @@ -277,7 +277,7 @@ mod tests { "AGENTS.md", "updated", false, - "CODEX_HOME", + "OPENCODE_CONFIG_DIR", "AGENTS.md", true, ) @@ -307,7 +307,7 @@ mod tests { &root, "config.toml", false, - "CODEX_HOME", + "OPENCODE_CONFIG_DIR", "config.toml", false, ) diff --git a/src-tauri/src/files/mod.rs b/src-tauri/src/files/mod.rs index 5f40ecb2de..741e79cc39 100644 --- a/src-tauri/src/files/mod.rs +++ b/src-tauri/src/files/mod.rs @@ -5,7 +5,7 @@ use tauri::{AppHandle, State}; use self::io::TextFileResponse; use self::policy::{FileKind, FileScope}; use crate::remote_backend; -use crate::shared::codex_core; +use crate::shared::opencode_core; use crate::shared::files_core::{file_read_core, file_write_core}; use crate::state::AppState; @@ -101,13 +101,13 @@ pub(crate) async fn read_image_as_data_url( return Err("Image conversion is only supported in remote backend mode or on mobile runtimes".to_string()); } - let normalized = codex_core::normalize_file_path(trimmed_path); + let normalized = opencode_core::normalize_file_path(trimmed_path); if normalized.is_empty() { return Err("Image path is required".to_string()); } let _ = app; - codex_core::read_image_as_data_url_core(&normalized) + opencode_core::read_image_as_data_url_core(&normalized) } #[tauri::command] diff --git a/src-tauri/src/files/ops.rs b/src-tauri/src/files/ops.rs index 56ea7ed8b8..a98c128eca 100644 --- a/src-tauri/src/files/ops.rs +++ b/src-tauri/src/files/ops.rs @@ -44,7 +44,7 @@ mod tests { use super::{read_with_policy, write_with_policy}; fn temp_dir(prefix: &str) -> std::path::PathBuf { - let dir = std::env::temp_dir().join(format!("codex-monitor-{prefix}-{}", Uuid::new_v4())); + let dir = std::env::temp_dir().join(format!("opencode-monitor-{prefix}-{}", Uuid::new_v4())); if dir.exists() { let _ = fs::remove_dir_all(&dir); } diff --git a/src-tauri/src/files/policy.rs b/src-tauri/src/files/policy.rs index 6ab24ec1e1..732bae2f1b 100644 --- a/src-tauri/src/files/policy.rs +++ b/src-tauri/src/files/policy.rs @@ -37,14 +37,14 @@ pub(crate) fn policy_for(scope: FileScope, kind: FileKind) -> Result Ok(FilePolicy { filename: AGENTS_FILENAME, - root_context: "CODEX_HOME", + root_context: "OPENCODE_CONFIG_DIR", root_may_be_missing: true, create_root: true, allow_external_symlink_target: true, }), (FileScope::Global, FileKind::Config) => Ok(FilePolicy { filename: CONFIG_FILENAME, - root_context: "CODEX_HOME", + root_context: "OPENCODE_CONFIG_DIR", root_may_be_missing: true, create_root: true, allow_external_symlink_target: false, @@ -73,7 +73,7 @@ mod tests { fn global_agents_policy_creates_root() { let policy = policy_for(FileScope::Global, FileKind::Agents).expect("policy"); assert_eq!(policy.filename, "AGENTS.md"); - assert_eq!(policy.root_context, "CODEX_HOME"); + assert_eq!(policy.root_context, "OPENCODE_CONFIG_DIR"); assert!(policy.root_may_be_missing); assert!(policy.create_root); assert!(policy.allow_external_symlink_target); @@ -83,7 +83,7 @@ mod tests { fn global_config_policy_creates_root() { let policy = policy_for(FileScope::Global, FileKind::Config).expect("policy"); assert_eq!(policy.filename, "config.toml"); - assert_eq!(policy.root_context, "CODEX_HOME"); + assert_eq!(policy.root_context, "OPENCODE_CONFIG_DIR"); assert!(policy.root_may_be_missing); assert!(policy.create_root); assert!(!policy.allow_external_symlink_target); diff --git a/src-tauri/src/git_utils.rs b/src-tauri/src/git_utils.rs index 302778576c..286f9474d2 100644 --- a/src-tauri/src/git_utils.rs +++ b/src-tauri/src/git_utils.rs @@ -109,7 +109,7 @@ mod tests { #[test] fn checkout_branch_missing_does_not_change_head() { let root = std::env::temp_dir().join(format!( - "codex-monitor-git-utils-test-{}", + "opencode-monitor-git-utils-test-{}", uuid::Uuid::new_v4() )); fs::create_dir_all(&root).expect("create temp repo root"); diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 83e9dacae7..7965e512e8 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -7,7 +7,7 @@ use tauri::RunEvent; use tauri::WindowEvent; mod backend; -mod codex; +mod opencode; mod daemon_binary; mod dictation; mod event_sink; @@ -182,17 +182,17 @@ pub fn run() { .invoke_handler(tauri::generate_handler![ settings::get_app_settings, settings::update_app_settings, - settings::get_codex_config_path, + settings::get_opencode_config_path, files::file_read, files::file_write, files::read_image_as_data_url, files::write_text_file, - codex::get_config_model, + opencode::get_config_model, menu::menu_set_accelerators, tray::set_tray_recent_threads, tray::set_tray_session_usage, - codex::codex_doctor, - codex::codex_update, + opencode::opencode_doctor, + opencode::opencode_update, workspaces::list_workspaces, workspaces::is_workspace_path_dir, workspaces::add_workspace, @@ -207,28 +207,28 @@ pub fn run() { workspaces::rename_worktree_upstream, workspaces::apply_worktree_changes, workspaces::update_workspace_settings, - workspaces::set_workspace_runtime_codex_args, - codex::start_thread, - codex::send_user_message, - codex::turn_steer, - codex::turn_interrupt, - codex::start_review, - codex::respond_to_server_request, - codex::remember_approval_rule, - codex::generate_commit_message, - codex::generate_run_metadata, - codex::generate_agent_description, - codex::resume_thread, - codex::read_thread, - codex::thread_live_subscribe, - codex::thread_live_unsubscribe, - codex::fork_thread, - codex::list_threads, - codex::list_mcp_server_status, - codex::archive_thread, - codex::compact_thread, - codex::set_thread_name, - codex::collaboration_mode_list, + workspaces::set_workspace_runtime_opencode_args, + opencode::start_thread, + opencode::send_user_message, + opencode::turn_steer, + opencode::turn_interrupt, + opencode::start_review, + opencode::respond_to_server_request, + opencode::remember_approval_rule, + opencode::generate_commit_message, + opencode::generate_run_metadata, + opencode::generate_agent_description, + opencode::resume_thread, + opencode::read_thread, + opencode::thread_live_subscribe, + opencode::thread_live_unsubscribe, + opencode::fork_thread, + opencode::list_threads, + opencode::list_mcp_server_status, + opencode::archive_thread, + opencode::compact_thread, + opencode::set_thread_name, + opencode::collaboration_mode_list, workspaces::connect_workspace, git::get_git_status, git::init_git_repo, @@ -260,22 +260,22 @@ pub fn run() { git::list_git_branches, git::checkout_git_branch, git::create_git_branch, - codex::model_list, - codex::experimental_feature_list, - codex::set_codex_feature_flag, - codex::get_agents_settings, - codex::set_agents_core_settings, - codex::create_agent, - codex::update_agent, - codex::delete_agent, - codex::read_agent_config_toml, - codex::write_agent_config_toml, - codex::account_rate_limits, - codex::account_read, - codex::codex_login, - codex::codex_login_cancel, - codex::skills_list, - codex::apps_list, + opencode::model_list, + opencode::experimental_feature_list, + opencode::set_opencode_feature_flag, + opencode::get_agents_settings, + opencode::set_agents_core_settings, + opencode::create_agent, + opencode::update_agent, + opencode::delete_agent, + opencode::read_agent_config_toml, + opencode::write_agent_config_toml, + opencode::account_rate_limits, + opencode::account_read, + opencode::opencode_login, + opencode::opencode_login_cancel, + opencode::skills_list, + opencode::apps_list, prompts::prompts_list, prompts::prompts_create, prompts::prompts_update, diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 0b817d97c3..f06ff525b5 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -5,5 +5,5 @@ fn main() { if let Err(err) = fix_path_env::fix() { eprintln!("Failed to sync PATH from shell: {err}"); } - codex_monitor_lib::run() + opencode_monitor_lib::run() } diff --git a/src-tauri/src/menu.rs b/src-tauri/src/menu.rs index 470fc78142..5e2ace2ac7 100644 --- a/src-tauri/src/menu.rs +++ b/src-tauri/src/menu.rs @@ -336,7 +336,7 @@ pub(crate) fn handle_menu_event( return; } let _ = WebviewWindowBuilder::new(app, "about", WebviewUrl::App("index.html".into())) - .title("About Codex Monitor") + .title("About OpenCode Monitor") .resizable(false) .inner_size(360.0, 240.0) .center() diff --git a/src-tauri/src/codex/args.rs b/src-tauri/src/opencode/args.rs similarity index 67% rename from src-tauri/src/codex/args.rs rename to src-tauri/src/opencode/args.rs index 6560c64d93..bc04d41b6c 100644 --- a/src-tauri/src/codex/args.rs +++ b/src-tauri/src/opencode/args.rs @@ -1,29 +1,29 @@ use crate::types::{AppSettings, WorkspaceEntry}; -pub(crate) fn parse_codex_args(value: Option<&str>) -> Result, String> { +pub(crate) fn parse_opencode_args(value: Option<&str>) -> Result, String> { let raw = match value { Some(raw) if !raw.trim().is_empty() => raw.trim(), _ => return Ok(Vec::new()), }; shell_words::split(raw) - .map_err(|err| format!("Invalid Codex args: {err}")) + .map_err(|err| format!("Invalid OpenCode args: {err}")) .map(|args| args.into_iter().filter(|arg| !arg.is_empty()).collect()) } -pub(crate) fn resolve_workspace_codex_args( +pub(crate) fn resolve_workspace_opencode_args( _entry: &WorkspaceEntry, _parent_entry: Option<&WorkspaceEntry>, app_settings: Option<&AppSettings>, ) -> Option { if let Some(settings) = app_settings { - if let Some(value) = settings.codex_args.as_deref() { - return normalize_codex_args(value); + if let Some(value) = settings.opencode_args.as_deref() { + return normalize_opencode_args(value); } } None } -fn normalize_codex_args(value: &str) -> Option { +fn normalize_opencode_args(value: &str) -> Option { let trimmed = value.trim(); if trimmed.is_empty() { None @@ -34,33 +34,33 @@ fn normalize_codex_args(value: &str) -> Option { #[cfg(test)] mod tests { - use super::{parse_codex_args, resolve_workspace_codex_args}; + use super::{parse_opencode_args, resolve_workspace_opencode_args}; use crate::types::{AppSettings, WorkspaceEntry, WorkspaceKind, WorkspaceSettings}; #[test] fn parses_empty_args() { - assert!(parse_codex_args(None).expect("parse none").is_empty()); - assert!(parse_codex_args(Some(" ")) + assert!(parse_opencode_args(None).expect("parse none").is_empty()); + assert!(parse_opencode_args(Some(" ")) .expect("parse blanks") .is_empty()); } #[test] fn parses_simple_args() { - let args = parse_codex_args(Some("--profile personal --flag")).expect("parse args"); + let args = parse_opencode_args(Some("--profile personal --flag")).expect("parse args"); assert_eq!(args, vec!["--profile", "personal", "--flag"]); } #[test] fn parses_quoted_args() { - let args = parse_codex_args(Some("--path \"a b\" --name='c d'")).expect("parse args"); + let args = parse_opencode_args(Some("--path \"a b\" --name='c d'")).expect("parse args"); assert_eq!(args, vec!["--path", "a b", "--name=c d"]); } #[test] - fn resolves_workspace_codex_args_from_app_settings_only() { + fn resolves_workspace_opencode_args_from_app_settings_only() { let mut app_settings = AppSettings::default(); - app_settings.codex_args = Some("--profile app".to_string()); + app_settings.opencode_args = Some("--profile app".to_string()); let parent = WorkspaceEntry { id: "parent".to_string(), @@ -82,7 +82,7 @@ mod tests { settings: WorkspaceSettings::default(), }; - let resolved = resolve_workspace_codex_args(&child, Some(&parent), Some(&app_settings)); + let resolved = resolve_workspace_opencode_args(&child, Some(&parent), Some(&app_settings)); assert_eq!(resolved.as_deref(), Some("--profile app")); let main = WorkspaceEntry { @@ -94,7 +94,7 @@ mod tests { worktree: None, settings: WorkspaceSettings::default(), }; - let resolved_main = resolve_workspace_codex_args(&main, None, Some(&app_settings)); + let resolved_main = resolve_workspace_opencode_args(&main, None, Some(&app_settings)); assert_eq!(resolved_main.as_deref(), Some("--profile app")); } } diff --git a/src-tauri/src/codex/config.rs b/src-tauri/src/opencode/config.rs similarity index 87% rename from src-tauri/src/codex/config.rs rename to src-tauri/src/opencode/config.rs index 790821f22e..f940a02278 100644 --- a/src-tauri/src/codex/config.rs +++ b/src-tauri/src/opencode/config.rs @@ -19,7 +19,7 @@ pub(crate) fn read_apps_enabled() -> Result, String> { } pub(crate) fn read_personality() -> Result, String> { - let Some(root) = resolve_default_codex_home() else { + let Some(root) = resolve_default_opencode_home() else { return Ok(None); }; let (_, document) = config_toml_core::load_global_config_document(&root)?; @@ -54,7 +54,7 @@ pub(crate) fn write_feature_enabled(feature_key: &str, enabled: bool) -> Result< } pub(crate) fn write_personality(personality: &str) -> Result<(), String> { - let Some(root) = resolve_default_codex_home() else { + let Some(root) = resolve_default_opencode_home() else { return Ok(()); }; let (_, mut document) = config_toml_core::load_global_config_document(&root)?; @@ -64,7 +64,7 @@ pub(crate) fn write_personality(personality: &str) -> Result<(), String> { } fn read_feature_flag(key: &str) -> Result, String> { - let Some(root) = resolve_default_codex_home() else { + let Some(root) = resolve_default_opencode_home() else { return Ok(None); }; let (_, document) = config_toml_core::load_global_config_document(&root)?; @@ -72,7 +72,7 @@ fn read_feature_flag(key: &str) -> Result, String> { } fn write_feature_flag(key: &str, enabled: bool) -> Result<(), String> { - let Some(root) = resolve_default_codex_home() else { + let Some(root) = resolve_default_opencode_home() else { return Ok(()); }; let (_, mut document) = config_toml_core::load_global_config_document(&root)?; @@ -81,20 +81,20 @@ fn write_feature_flag(key: &str, enabled: bool) -> Result<(), String> { } pub(crate) fn config_toml_path() -> Option { - resolve_default_codex_home().map(|home| home.join("config.toml")) + resolve_default_opencode_home().map(|home| home.join("config.toml")) } -pub(crate) fn read_config_model(codex_home: Option) -> Result, String> { - let root = codex_home.or_else(resolve_default_codex_home); +pub(crate) fn read_config_model(opencode_home: Option) -> Result, String> { + let root = opencode_home.or_else(resolve_default_opencode_home); let Some(root) = root else { - return Err("Unable to resolve CODEX_HOME".to_string()); + return Err("Unable to resolve OPENCODE_CONFIG_DIR".to_string()); }; let (_, document) = config_toml_core::load_global_config_document(&root)?; Ok(config_toml_core::read_top_level_string(&document, "model")) } -fn resolve_default_codex_home() -> Option { - crate::codex::home::resolve_default_codex_home() +fn resolve_default_opencode_home() -> Option { + crate::opencode::home::resolve_default_opencode_home() } fn read_personality_from_document(document: &toml_edit::Document) -> Option { diff --git a/src-tauri/src/codex/home.rs b/src-tauri/src/opencode/home.rs similarity index 77% rename from src-tauri/src/codex/home.rs rename to src-tauri/src/opencode/home.rs index cd3e29e251..c263bfca57 100644 --- a/src-tauri/src/codex/home.rs +++ b/src-tauri/src/opencode/home.rs @@ -3,23 +3,23 @@ use std::path::PathBuf; use crate::types::WorkspaceEntry; -pub(crate) fn resolve_workspace_codex_home( +pub(crate) fn resolve_workspace_opencode_home( _entry: &WorkspaceEntry, _parent_entry: Option<&WorkspaceEntry>, ) -> Option { - resolve_default_codex_home() + resolve_default_opencode_home() } -pub(crate) fn resolve_default_codex_home() -> Option { - if let Ok(value) = env::var("CODEX_HOME") { - if let Some(path) = normalize_codex_home(&value) { +pub(crate) fn resolve_default_opencode_home() -> Option { + if let Ok(value) = env::var("OPENCODE_CONFIG_DIR") { + if let Some(path) = normalize_opencode_home(&value) { return Some(path); } } - resolve_home_dir().map(|home| home.join(".codex")) + resolve_home_dir().map(|home| home.join(".config/opencode")) } -fn normalize_codex_home(value: &str) -> Option { +fn normalize_opencode_home(value: &str) -> Option { let trimmed = value.trim(); if trimmed.is_empty() { return None; @@ -197,26 +197,26 @@ mod tests { } #[test] - fn workspace_codex_home_uses_default_resolution() { + fn workspace_opencode_home_uses_default_resolution() { let entry = workspace_entry(WorkspaceKind::Main, "/repo"); let _guard = ENV_LOCK.lock().expect("lock env"); - let prev_codex_home = std::env::var("CODEX_HOME").ok(); - std::env::set_var("CODEX_HOME", "/tmp/codex-global"); + let prev_opencode_home = std::env::var("OPENCODE_CONFIG_DIR").ok(); + std::env::set_var("OPENCODE_CONFIG_DIR", "/tmp/opencode-global"); - let resolved = resolve_workspace_codex_home(&entry, None); - assert_eq!(resolved, Some(PathBuf::from("/tmp/codex-global"))); + let resolved = resolve_workspace_opencode_home(&entry, None); + assert_eq!(resolved, Some(PathBuf::from("/tmp/opencode-global"))); - match prev_codex_home { - Some(value) => std::env::set_var("CODEX_HOME", value), - None => std::env::remove_var("CODEX_HOME"), + match prev_opencode_home { + Some(value) => std::env::set_var("OPENCODE_CONFIG_DIR", value), + None => std::env::remove_var("OPENCODE_CONFIG_DIR"), } } #[test] - fn codex_home_expands_tilde_and_env_vars() { + fn opencode_home_expands_tilde_and_env_vars() { let _guard = ENV_LOCK.lock().expect("lock env"); - let home_dir = std::env::temp_dir().join("codex-home-test"); + let home_dir = std::env::temp_dir().join("opencode-home-test"); let home_str = home_dir.to_string_lossy().to_string(); let prev_home = std::env::var("HOME").ok(); @@ -225,22 +225,22 @@ mod tests { let prev_appdata = std::env::var("APPDATA").ok(); std::env::set_var("APPDATA", "/tmp/appdata-root"); - let tilde = normalize_codex_home("~/.codex-api"); - assert_eq!(tilde, Some(home_dir.join(".codex-api"))); + let tilde = normalize_opencode_home("~/.config/opencode-api"); + assert_eq!(tilde, Some(home_dir.join(".config/opencode-api"))); - let dollar = normalize_codex_home("$HOME/.codex-api"); - assert_eq!(dollar, Some(home_dir.join(".codex-api"))); + let dollar = normalize_opencode_home("$HOME/.opencode-api"); + assert_eq!(dollar, Some(home_dir.join(".opencode-api"))); - let braces = normalize_codex_home("${HOME}/.codex-api"); - assert_eq!(braces, Some(home_dir.join(".codex-api"))); + let braces = normalize_opencode_home("${HOME}/.opencode-api"); + assert_eq!(braces, Some(home_dir.join(".opencode-api"))); - let appdata = normalize_codex_home("%APPDATA%/Codex"); - assert_eq!(appdata, Some(PathBuf::from("/tmp/appdata-root/Codex"))); + let appdata = normalize_opencode_home("%APPDATA%/OpenCode"); + assert_eq!(appdata, Some(PathBuf::from("/tmp/appdata-root/OpenCode"))); - let appdata_lower = normalize_codex_home("$appdata/Codex"); + let appdata_lower = normalize_opencode_home("$appdata/OpenCode"); assert_eq!( appdata_lower, - Some(PathBuf::from("/tmp/appdata-root/Codex")) + Some(PathBuf::from("/tmp/appdata-root/OpenCode")) ); match prev_home { diff --git a/src-tauri/src/codex/mod.rs b/src-tauri/src/opencode/mod.rs similarity index 87% rename from src-tauri/src/codex/mod.rs rename to src-tauri/src/opencode/mod.rs index e55d1e9eea..89d2392d4f 100644 --- a/src-tauri/src/codex/mod.rs +++ b/src-tauri/src/opencode/mod.rs @@ -14,7 +14,7 @@ use crate::backend::events::AppServerEvent; use crate::event_sink::TauriEventSink; use crate::remote_backend; use crate::shared::agents_config_core; -use crate::shared::codex_core::{self, insert_optional_nullable_string}; +use crate::shared::opencode_core::{self, insert_optional_nullable_string}; use crate::state::AppState; use crate::types::WorkspaceEntry; @@ -33,18 +33,18 @@ fn emit_thread_live_event(app: &AppHandle, workspace_id: &str, method: &str, par pub(crate) async fn spawn_workspace_session( entry: WorkspaceEntry, - default_codex_bin: Option, - codex_args: Option, + default_opencode_bin: Option, + opencode_args: Option, app_handle: AppHandle, - codex_home: Option, + opencode_home: Option, ) -> Result, String> { let client_version = app_handle.package_info().version.to_string(); let event_sink = TauriEventSink::new(app_handle); spawn_workspace_session_inner( entry, - default_codex_bin, - codex_args, - codex_home, + default_opencode_bin, + opencode_args, + opencode_home, client_version, event_sink, ) @@ -52,22 +52,22 @@ pub(crate) async fn spawn_workspace_session( } #[tauri::command] -pub(crate) async fn codex_doctor( - codex_bin: Option, - codex_args: Option, +pub(crate) async fn opencode_doctor( + opencode_bin: Option, + opencode_args: Option, state: State<'_, AppState>, ) -> Result { - crate::shared::codex_aux_core::codex_doctor_core(&state.app_settings, codex_bin, codex_args) + crate::shared::opencode_aux_core::opencode_doctor_core(&state.app_settings, opencode_bin, opencode_args) .await } #[tauri::command] -pub(crate) async fn codex_update( - codex_bin: Option, - codex_args: Option, +pub(crate) async fn opencode_update( + opencode_bin: Option, + opencode_args: Option, state: State<'_, AppState>, ) -> Result { - crate::shared::codex_update_core::codex_update_core(&state.app_settings, codex_bin, codex_args) + crate::shared::opencode_update_core::opencode_update_core(&state.app_settings, opencode_bin, opencode_args) .await } @@ -87,7 +87,7 @@ pub(crate) async fn start_thread( .await; } - codex_core::start_thread_core(&state.sessions, &state.workspaces, workspace_id).await + opencode_core::start_thread_core(&state.sessions, &state.workspaces, workspace_id).await } #[tauri::command] @@ -107,7 +107,7 @@ pub(crate) async fn resume_thread( .await; } - codex_core::resume_thread_core(&state.sessions, workspace_id, thread_id).await + opencode_core::resume_thread_core(&state.sessions, workspace_id, thread_id).await } #[tauri::command] @@ -127,7 +127,7 @@ pub(crate) async fn read_thread( .await; } - codex_core::read_thread_core(&state.sessions, workspace_id, thread_id).await + opencode_core::read_thread_core(&state.sessions, workspace_id, thread_id).await } #[tauri::command] @@ -147,7 +147,7 @@ pub(crate) async fn thread_live_subscribe( .await; } - codex_core::thread_live_subscribe_core( + opencode_core::thread_live_subscribe_core( &state.sessions, workspace_id.clone(), thread_id.clone(), @@ -187,7 +187,7 @@ pub(crate) async fn thread_live_unsubscribe( .await; } - codex_core::thread_live_unsubscribe_core( + opencode_core::thread_live_unsubscribe_core( &state.sessions, workspace_id.clone(), thread_id.clone(), @@ -223,7 +223,7 @@ pub(crate) async fn fork_thread( .await; } - codex_core::fork_thread_core(&state.sessions, workspace_id, thread_id).await + opencode_core::fork_thread_core(&state.sessions, workspace_id, thread_id).await } #[tauri::command] @@ -250,7 +250,7 @@ pub(crate) async fn list_threads( .await; } - codex_core::list_threads_core(&state.sessions, workspace_id, cursor, limit, sort_key).await + opencode_core::list_threads_core(&state.sessions, workspace_id, cursor, limit, sort_key).await } #[tauri::command] @@ -271,7 +271,7 @@ pub(crate) async fn list_mcp_server_status( .await; } - codex_core::list_mcp_server_status_core(&state.sessions, workspace_id, cursor, limit).await + opencode_core::list_mcp_server_status_core(&state.sessions, workspace_id, cursor, limit).await } #[tauri::command] @@ -291,7 +291,7 @@ pub(crate) async fn archive_thread( .await; } - codex_core::archive_thread_core(&state.sessions, workspace_id, thread_id).await + opencode_core::archive_thread_core(&state.sessions, workspace_id, thread_id).await } #[tauri::command] @@ -311,7 +311,7 @@ pub(crate) async fn compact_thread( .await; } - codex_core::compact_thread_core(&state.sessions, workspace_id, thread_id).await + opencode_core::compact_thread_core(&state.sessions, workspace_id, thread_id).await } #[tauri::command] @@ -332,7 +332,7 @@ pub(crate) async fn set_thread_name( .await; } - codex_core::set_thread_name_core(&state.sessions, workspace_id, thread_id, name).await + opencode_core::set_thread_name_core(&state.sessions, workspace_id, thread_id, name).await } #[tauri::command] @@ -381,7 +381,7 @@ pub(crate) async fn send_user_message( .await; } - codex_core::send_user_message_core( + opencode_core::send_user_message_core( &state.sessions, &state.workspaces, workspace_id, @@ -432,7 +432,7 @@ pub(crate) async fn turn_steer( .await; } - codex_core::turn_steer_core( + opencode_core::turn_steer_core( &state.sessions, workspace_id, thread_id, @@ -460,7 +460,7 @@ pub(crate) async fn collaboration_mode_list( .await; } - codex_core::collaboration_mode_list_core(&state.sessions, workspace_id).await + opencode_core::collaboration_mode_list_core(&state.sessions, workspace_id).await } #[tauri::command] @@ -481,7 +481,7 @@ pub(crate) async fn turn_interrupt( .await; } - codex_core::turn_interrupt_core(&state.sessions, workspace_id, thread_id, turn_id).await + opencode_core::turn_interrupt_core(&state.sessions, workspace_id, thread_id, turn_id).await } #[tauri::command] @@ -508,7 +508,7 @@ pub(crate) async fn start_review( .await; } - codex_core::start_review_core( + opencode_core::start_review_core( &state.sessions, workspace_id, thread_id, @@ -534,7 +534,7 @@ pub(crate) async fn model_list( .await; } - codex_core::model_list_core(&state.sessions, workspace_id).await + opencode_core::model_list_core(&state.sessions, workspace_id).await } #[tauri::command] @@ -559,11 +559,11 @@ pub(crate) async fn experimental_feature_list( .await; } - codex_core::experimental_feature_list_core(&state.sessions, workspace_id, cursor, limit).await + opencode_core::experimental_feature_list_core(&state.sessions, workspace_id, cursor, limit).await } #[tauri::command] -pub(crate) async fn set_codex_feature_flag( +pub(crate) async fn set_opencode_feature_flag( feature_key: String, enabled: bool, state: State<'_, AppState>, @@ -573,7 +573,7 @@ pub(crate) async fn set_codex_feature_flag( remote_backend::call_remote( &*state, app, - "set_codex_feature_flag", + "set_opencode_feature_flag", json!({ "featureKey": feature_key, "enabled": enabled @@ -728,7 +728,7 @@ pub(crate) async fn account_rate_limits( .await; } - codex_core::account_rate_limits_core(&state.sessions, workspace_id).await + opencode_core::account_rate_limits_core(&state.sessions, workspace_id).await } #[tauri::command] @@ -747,11 +747,11 @@ pub(crate) async fn account_read( .await; } - codex_core::account_read_core(&state.sessions, &state.workspaces, workspace_id).await + opencode_core::account_read_core(&state.sessions, &state.workspaces, workspace_id).await } #[tauri::command] -pub(crate) async fn codex_login( +pub(crate) async fn opencode_login( workspace_id: String, state: State<'_, AppState>, app: AppHandle, @@ -760,17 +760,17 @@ pub(crate) async fn codex_login( return remote_backend::call_remote( &*state, app, - "codex_login", + "opencode_login", json!({ "workspaceId": workspace_id }), ) .await; } - codex_core::codex_login_core(&state.sessions, &state.codex_login_cancels, workspace_id).await + opencode_core::opencode_login_core(&state.sessions, &state.opencode_login_cancels, workspace_id).await } #[tauri::command] -pub(crate) async fn codex_login_cancel( +pub(crate) async fn opencode_login_cancel( workspace_id: String, state: State<'_, AppState>, app: AppHandle, @@ -779,13 +779,13 @@ pub(crate) async fn codex_login_cancel( return remote_backend::call_remote( &*state, app, - "codex_login_cancel", + "opencode_login_cancel", json!({ "workspaceId": workspace_id }), ) .await; } - codex_core::codex_login_cancel_core(&state.sessions, &state.codex_login_cancels, workspace_id) + opencode_core::opencode_login_cancel_core(&state.sessions, &state.opencode_login_cancels, workspace_id) .await } @@ -805,7 +805,7 @@ pub(crate) async fn skills_list( .await; } - codex_core::skills_list_core(&state.sessions, &state.workspaces, workspace_id).await + opencode_core::skills_list_core(&state.sessions, &state.workspaces, workspace_id).await } #[tauri::command] @@ -832,7 +832,7 @@ pub(crate) async fn apps_list( .await; } - codex_core::apps_list_core(&state.sessions, workspace_id, cursor, limit, thread_id).await + opencode_core::apps_list_core(&state.sessions, workspace_id, cursor, limit, thread_id).await } #[tauri::command] @@ -854,7 +854,7 @@ pub(crate) async fn respond_to_server_request( return Ok(()); } - codex_core::respond_to_server_request_core(&state.sessions, workspace_id, request_id, result) + opencode_core::respond_to_server_request_core(&state.sessions, workspace_id, request_id, result) .await } @@ -864,7 +864,7 @@ pub(crate) async fn remember_approval_rule( command: Vec, state: State<'_, AppState>, ) -> Result { - codex_core::remember_approval_rule_core(&state.workspaces, workspace_id, command).await + opencode_core::remember_approval_rule_core(&state.workspaces, workspace_id, command).await } #[tauri::command] @@ -883,7 +883,7 @@ pub(crate) async fn get_config_model( .await; } - codex_core::get_config_model_core(&state.workspaces, workspace_id).await + opencode_core::get_config_model_core(&state.workspaces, workspace_id).await } /// Generates a commit message in the background without showing in the main chat @@ -914,7 +914,7 @@ pub(crate) async fn generate_commit_message( let settings = state.app_settings.lock().await; settings.commit_message_prompt.clone() }; - crate::shared::codex_aux_core::generate_commit_message_core( + crate::shared::opencode_aux_core::generate_commit_message_core( &state.sessions, &state.workspaces, workspace_id, @@ -927,7 +927,7 @@ pub(crate) async fn generate_commit_message( AppServerEvent { workspace_id: workspace_id.to_string(), message: json!({ - "method": "codex/backgroundThread", + "method": "opencode/backgroundThread", "params": { "threadId": thread_id, "action": "hide" @@ -957,7 +957,7 @@ pub(crate) async fn generate_run_metadata( .await; } - crate::shared::codex_aux_core::generate_run_metadata_core( + crate::shared::opencode_aux_core::generate_run_metadata_core( &state.sessions, &state.workspaces, workspace_id, @@ -968,7 +968,7 @@ pub(crate) async fn generate_run_metadata( AppServerEvent { workspace_id: workspace_id.to_string(), message: json!({ - "method": "codex/backgroundThread", + "method": "opencode/backgroundThread", "params": { "threadId": thread_id, "action": "hide" @@ -987,7 +987,7 @@ pub(crate) async fn generate_agent_description( description: String, state: State<'_, AppState>, app: AppHandle, -) -> Result { +) -> Result { if remote_backend::is_remote_mode(&*state).await { let value = remote_backend::call_remote( &*state, @@ -999,7 +999,7 @@ pub(crate) async fn generate_agent_description( return serde_json::from_value(value).map_err(|err| err.to_string()); } - crate::shared::codex_aux_core::generate_agent_description_core( + crate::shared::opencode_aux_core::generate_agent_description_core( &state.sessions, &state.workspaces, workspace_id, @@ -1010,7 +1010,7 @@ pub(crate) async fn generate_agent_description( AppServerEvent { workspace_id: workspace_id.to_string(), message: json!({ - "method": "codex/backgroundThread", + "method": "opencode/backgroundThread", "params": { "threadId": thread_id, "action": "hide" diff --git a/src-tauri/src/remote_backend/mod.rs b/src-tauri/src/remote_backend/mod.rs index 5cdb56d7c9..45dd24fc15 100644 --- a/src-tauri/src/remote_backend/mod.rs +++ b/src-tauri/src/remote_backend/mod.rs @@ -151,7 +151,7 @@ fn can_retry_after_disconnect(method: &str) -> bool { | "collaboration_mode_list" | "connect_workspace" | "experimental_feature_list" - | "set_workspace_runtime_codex_args" + | "set_workspace_runtime_opencode_args" | "file_read" | "get_agents_settings" | "get_config_model" diff --git a/src-tauri/src/rules.rs b/src-tauri/src/rules.rs index 77ebaa8a7a..fb54825604 100644 --- a/src-tauri/src/rules.rs +++ b/src-tauri/src/rules.rs @@ -7,8 +7,8 @@ use std::time::{Duration, Instant, SystemTime}; const RULES_DIR: &str = "rules"; const DEFAULT_RULES_FILE: &str = "default.rules"; -pub(crate) fn default_rules_path(codex_home: &Path) -> PathBuf { - codex_home.join(RULES_DIR).join(DEFAULT_RULES_FILE) +pub(crate) fn default_rules_path(opencode_home: &Path) -> PathBuf { + opencode_home.join(RULES_DIR).join(DEFAULT_RULES_FILE) } pub(crate) fn append_prefix_rule(path: &Path, pattern: &[String]) -> Result<(), String> { diff --git a/src-tauri/src/settings/mod.rs b/src-tauri/src/settings/mod.rs index 0277feb879..de33ef19f6 100644 --- a/src-tauri/src/settings/mod.rs +++ b/src-tauri/src/settings/mod.rs @@ -1,7 +1,7 @@ use tauri::{State, Window}; use crate::shared::settings_core::{ - get_app_settings_core, get_codex_config_path_core, update_app_settings_core, + get_app_settings_core, get_opencode_config_path_core, update_app_settings_core, }; use crate::state::AppState; use crate::types::{AppSettings, BackendMode}; @@ -35,8 +35,8 @@ pub(crate) async fn update_app_settings( } #[tauri::command] -pub(crate) async fn get_codex_config_path() -> Result { - get_codex_config_path_core() +pub(crate) async fn get_opencode_config_path() -> Result { + get_opencode_config_path_core() } fn should_reset_remote_backend(previous: &AppSettings, updated: &AppSettings) -> bool { diff --git a/src-tauri/src/shared/account.rs b/src-tauri/src/shared/account.rs index 6ad987ef7b..d704a67eec 100644 --- a/src-tauri/src/shared/account.rs +++ b/src-tauri/src/shared/account.rs @@ -60,9 +60,9 @@ pub(crate) fn build_account_response( Value::Object(result) } -pub(crate) fn read_auth_account(codex_home: Option) -> Option { - let codex_home = codex_home?; - let auth_path = codex_home.join("auth.json"); +pub(crate) fn read_auth_account(opencode_home: Option) -> Option { + let opencode_home = opencode_home?; + let auth_path = opencode_home.join("auth.json"); let data = fs::read(auth_path).ok()?; let auth_value: Value = serde_json::from_slice(&data).ok()?; let tokens = auth_value.get("tokens")?; diff --git a/src-tauri/src/shared/agents_config_core.rs b/src-tauri/src/shared/agents_config_core.rs index b8b448a5ab..1338767ca8 100644 --- a/src-tauri/src/shared/agents_config_core.rs +++ b/src-tauri/src/shared/agents_config_core.rs @@ -4,7 +4,7 @@ use std::io::ErrorKind; use std::path::{Component, Path, PathBuf}; use toml_edit::{value, Document, Item, Table}; -use crate::codex::home as codex_home; +use crate::opencode::home as opencode_home; use crate::shared::config_toml_core; pub(crate) const DEFAULT_AGENT_MAX_THREADS: u32 = 6; @@ -15,7 +15,7 @@ const MIN_AGENT_MAX_DEPTH: u32 = 1; const MAX_AGENT_MAX_DEPTH: u32 = 4; const MANAGED_AGENTS_DIR: &str = "agents"; const TEMPLATE_BLANK: &str = "blank"; -const DEFAULT_AGENT_MODEL: &str = "gpt-5-codex"; +const DEFAULT_AGENT_MODEL: &str = "opencode-go/deepseek-v4-flash"; const DEFAULT_REASONING_EFFORT: &str = "medium"; const fn default_agent_max_depth() -> u32 { @@ -82,18 +82,18 @@ pub(crate) struct DeleteAgentInput { } pub(crate) fn get_agents_settings_core() -> Result { - let codex_home = resolve_codex_home()?; - let config_path = codex_home.join("config.toml"); + let opencode_home = resolve_opencode_home()?; + let config_path = opencode_home.join("config.toml"); let config_path_string = config_path .to_str() - .ok_or_else(|| "Unable to resolve CODEX_HOME".to_string())? + .ok_or_else(|| "Unable to resolve OPENCODE_CONFIG_DIR".to_string())? .to_string(); - let (_, document) = config_toml_core::load_global_config_document(&codex_home)?; + let (_, document) = config_toml_core::load_global_config_document(&opencode_home)?; let multi_agent_enabled = read_multi_agent_enabled(&document); let max_threads = read_max_threads(&document); let max_depth = read_max_depth(&document); - let mut agents = collect_agents(&codex_home, &document); + let mut agents = collect_agents(&opencode_home, &document); agents.sort_by(|left, right| left.name.cmp(&right.name)); Ok(AgentsSettingsDto { @@ -111,8 +111,8 @@ pub(crate) fn set_agents_core_settings_core( validate_max_threads(input.max_threads)?; validate_max_depth(input.max_depth)?; - let codex_home = resolve_codex_home()?; - let (_, mut document) = config_toml_core::load_global_config_document(&codex_home)?; + let opencode_home = resolve_opencode_home()?; + let (_, mut document) = config_toml_core::load_global_config_document(&opencode_home)?; let features = config_toml_core::ensure_table(&mut document, "features")?; features["multi_agent"] = value(input.multi_agent_enabled); @@ -121,7 +121,7 @@ pub(crate) fn set_agents_core_settings_core( agents["max_threads"] = value(input.max_threads as i64); agents["max_depth"] = value(input.max_depth as i64); - config_toml_core::persist_global_config_document(&codex_home, &document)?; + config_toml_core::persist_global_config_document(&opencode_home, &document)?; get_agents_settings_core() } @@ -130,8 +130,8 @@ pub(crate) fn create_agent_core(input: CreateAgentInput) -> Result Result Result Result = None; let mut maybe_config_content_backup: Option<(PathBuf, Option>)> = None; @@ -208,11 +208,11 @@ pub(crate) fn update_agent_core(input: UpdateAgentInput) -> Result Result Result { @@ -317,8 +317,8 @@ pub(crate) fn delete_agent_core(input: DeleteAgentInput) -> Result Result Result Result Result { - let (codex_home, relative_path) = resolve_managed_agent_config_relative_path(agent_name)?; - let path = resolve_safe_managed_abs_path_for_read(&codex_home, &relative_path)?; + let (opencode_home, relative_path) = resolve_managed_agent_config_relative_path(agent_name)?; + let path = resolve_safe_managed_abs_path_for_read(&opencode_home, &relative_path)?; if !path.exists() { return Ok(String::new()); } @@ -374,14 +374,14 @@ pub(crate) fn read_agent_config_toml_core(agent_name: &str) -> Result Result<(), String> { - let (codex_home, relative_path) = resolve_managed_agent_config_relative_path(agent_name)?; - let path = resolve_safe_managed_abs_path_for_write(&codex_home, &relative_path)?; + let (opencode_home, relative_path) = resolve_managed_agent_config_relative_path(agent_name)?; + let path = resolve_safe_managed_abs_path_for_write(&opencode_home, &relative_path)?; std::fs::write(path, content).map_err(|err| format!("Failed to write agent config file: {err}")) } -fn resolve_codex_home() -> Result { - codex_home::resolve_default_codex_home() - .ok_or_else(|| "Unable to resolve CODEX_HOME".to_string()) +fn resolve_opencode_home() -> Result { + opencode_home::resolve_default_opencode_home() + .ok_or_else(|| "Unable to resolve OPENCODE_CONFIG_DIR".to_string()) } fn read_multi_agent_enabled(document: &Document) -> bool { @@ -424,7 +424,7 @@ fn read_max_depth(document: &Document) -> u32 { .unwrap_or(DEFAULT_AGENT_MAX_DEPTH) } -fn collect_agents(codex_home: &Path, document: &Document) -> Vec { +fn collect_agents(opencode_home: &Path, document: &Document) -> Vec { let mut result = Vec::new(); let Some(agents_table) = document.get("agents").and_then(Item::as_table_like) else { return result; @@ -437,12 +437,12 @@ fn collect_agents(codex_home: &Path, document: &Document) -> Vec Vec Option { +fn resolve_config_file_path_for_display(opencode_home: &Path, raw_value: &str) -> Option { let trimmed = raw_value.trim(); if trimmed.is_empty() { return None; @@ -470,7 +470,7 @@ fn resolve_config_file_path_for_display(codex_home: &Path, raw_value: &str) -> O return Some(raw_path.to_path_buf()); } let normalized_relative = normalize_relative_path(raw_value)?; - Some(codex_home.join(normalized_relative)) + Some(opencode_home.join(normalized_relative)) } fn normalize_agent_name(raw_name: &str) -> Result { @@ -600,9 +600,9 @@ fn read_role_config_file(item: &Item) -> Option { .and_then(|value| normalize_optional_string(Some(value))) } -fn read_role_developer_instructions(codex_home: &Path, config_file: &str) -> Option { +fn read_role_developer_instructions(opencode_home: &Path, config_file: &str) -> Option { let relative_path = managed_relative_path_from_config(config_file)?; - let path = resolve_safe_managed_abs_path_for_read(codex_home, &relative_path).ok()?; + let path = resolve_safe_managed_abs_path_for_read(opencode_home, &relative_path).ok()?; if !path.is_file() { return None; } @@ -662,8 +662,8 @@ fn resolve_managed_agent_config_relative_path( agent_name: &str, ) -> Result<(PathBuf, PathBuf), String> { let name = normalize_agent_lookup_name(agent_name)?; - let codex_home = resolve_codex_home()?; - let (_, document) = config_toml_core::load_global_config_document(&codex_home)?; + let opencode_home = resolve_opencode_home()?; + let (_, document) = config_toml_core::load_global_config_document(&opencode_home)?; let agents_table = document .get("agents") @@ -680,42 +680,42 @@ fn resolve_managed_agent_config_relative_path( let Some(relative_path) = managed_relative_path_from_config(config_file.as_str()) else { return Err(format!( - "agent '{name}' config_file is not managed by CodexMonitor" + "agent '{name}' config_file is not managed by OpenCodeMonitor" )); }; - Ok((codex_home, relative_path)) + Ok((opencode_home, relative_path)) } fn resolve_safe_managed_abs_path_for_read( - codex_home: &Path, + opencode_home: &Path, relative_path: &Path, ) -> Result { - let path = codex_home.join(relative_path); - assert_managed_path_without_symlinks(codex_home, relative_path, true)?; + let path = opencode_home.join(relative_path); + assert_managed_path_without_symlinks(opencode_home, relative_path, true)?; Ok(path) } fn resolve_safe_managed_abs_path_for_write( - codex_home: &Path, + opencode_home: &Path, relative_path: &Path, ) -> Result { - let path = codex_home.join(relative_path); - assert_managed_path_without_symlinks(codex_home, relative_path, true)?; + let path = opencode_home.join(relative_path); + assert_managed_path_without_symlinks(opencode_home, relative_path, true)?; if let Some(parent) = path.parent() { std::fs::create_dir_all(parent) .map_err(|err| format!("Failed to create agents directory: {err}"))?; } - assert_managed_path_without_symlinks(codex_home, relative_path, true)?; + assert_managed_path_without_symlinks(opencode_home, relative_path, true)?; Ok(path) } fn assert_managed_path_without_symlinks( - codex_home: &Path, + opencode_home: &Path, relative_path: &Path, include_leaf: bool, ) -> Result<(), String> { - let mut current = codex_home.to_path_buf(); + let mut current = opencode_home.to_path_buf(); let mut components = relative_path.components().peekable(); while let Some(component) = components.next() { current.push(component.as_os_str()); @@ -851,7 +851,7 @@ mod tests { .duration_since(UNIX_EPOCH) .expect("clock") .as_nanos(); - let dir = std::env::temp_dir().join(format!("codex-monitor-{prefix}-{nonce}")); + let dir = std::env::temp_dir().join(format!("opencode-monitor-{prefix}-{nonce}")); if dir.exists() { let _ = std::fs::remove_dir_all(&dir); } @@ -927,18 +927,18 @@ mod tests { fn managed_write_rejects_symlinked_agents_dir() { use std::os::unix::fs::symlink; - let codex_home = temp_dir("codex-home"); + let opencode_home = temp_dir("opencode-home"); let outside = temp_dir("outside"); - symlink(&outside, codex_home.join("agents")).expect("symlink agents"); + symlink(&outside, opencode_home.join("agents")).expect("symlink agents"); let err = resolve_safe_managed_abs_path_for_write( - &codex_home, + &opencode_home, std::path::Path::new("agents/researcher.toml"), ) .expect_err("should reject symlink path"); assert!(err.contains("symlinks")); - let _ = std::fs::remove_dir_all(&codex_home); + let _ = std::fs::remove_dir_all(&opencode_home); let _ = std::fs::remove_dir_all(&outside); } @@ -986,7 +986,7 @@ mod tests { #[test] fn collect_agents_ignores_reserved_keys() { - let codex_home = temp_dir("codex-home"); + let opencode_home = temp_dir("opencode-home"); let document: Document = r#" [agents] max_threads = 8 @@ -999,11 +999,11 @@ config_file = "agents/researcher.toml" .parse() .expect("parse"); - let agents = collect_agents(&codex_home, &document); + let agents = collect_agents(&opencode_home, &document); assert_eq!(agents.len(), 1); assert_eq!(agents[0].name, "researcher"); - let _ = std::fs::remove_dir_all(codex_home); + let _ = std::fs::remove_dir_all(opencode_home); } #[test] diff --git a/src-tauri/src/shared/config_toml_core.rs b/src-tauri/src/shared/config_toml_core.rs index cb8d0ffd04..944f26b9ab 100644 --- a/src-tauri/src/shared/config_toml_core.rs +++ b/src-tauri/src/shared/config_toml_core.rs @@ -5,9 +5,9 @@ use toml_edit::{value, Document, Item, Table}; use crate::files::ops::{read_with_policy, write_with_policy}; use crate::files::policy::{policy_for, FileKind, FileScope}; -pub(crate) fn load_global_config_document(codex_home: &Path) -> Result<(bool, Document), String> { +pub(crate) fn load_global_config_document(opencode_home: &Path) -> Result<(bool, Document), String> { let policy = policy_for(FileScope::Global, FileKind::Config)?; - let root = codex_home.to_path_buf(); + let root = opencode_home.to_path_buf(); let response = read_with_policy(&root, policy)?; let document = if response.exists { parse_document(response.content.as_str())? @@ -18,11 +18,11 @@ pub(crate) fn load_global_config_document(codex_home: &Path) -> Result<(bool, Do } pub(crate) fn persist_global_config_document( - codex_home: &Path, + opencode_home: &Path, document: &Document, ) -> Result<(), String> { let policy = policy_for(FileScope::Global, FileKind::Config)?; - let root = codex_home.to_path_buf(); + let root = opencode_home.to_path_buf(); let mut rendered = document.to_string(); if !rendered.ends_with('\n') { rendered.push('\n'); diff --git a/src-tauri/src/shared/files_core.rs b/src-tauri/src/shared/files_core.rs index ef56181222..5316baa989 100644 --- a/src-tauri/src/shared/files_core.rs +++ b/src-tauri/src/shared/files_core.rs @@ -3,15 +3,15 @@ use std::path::PathBuf; use tokio::sync::Mutex; -use crate::codex::home as codex_home; +use crate::opencode::home as opencode_home; use crate::files::io::TextFileResponse; use crate::files::ops::{read_with_policy, write_with_policy}; use crate::files::policy::{policy_for, FileKind, FileScope}; use crate::types::WorkspaceEntry; -fn resolve_default_codex_home() -> Result { - codex_home::resolve_default_codex_home() - .ok_or_else(|| "Unable to resolve CODEX_HOME".to_string()) +fn resolve_default_opencode_home() -> Result { + opencode_home::resolve_default_opencode_home() + .ok_or_else(|| "Unable to resolve OPENCODE_CONFIG_DIR".to_string()) } async fn resolve_workspace_root( @@ -31,7 +31,7 @@ pub(crate) async fn resolve_root_core( workspace_id: Option<&str>, ) -> Result { match scope { - FileScope::Global => resolve_default_codex_home(), + FileScope::Global => resolve_default_opencode_home(), FileScope::Workspace => { let workspace_id = workspace_id.ok_or_else(|| "workspaceId is required".to_string())?; resolve_workspace_root(workspaces, workspace_id).await diff --git a/src-tauri/src/shared/git_ui_core/tests.rs b/src-tauri/src/shared/git_ui_core/tests.rs index 3afcb120b7..cccd4caec6 100644 --- a/src-tauri/src/shared/git_ui_core/tests.rs +++ b/src-tauri/src/shared/git_ui_core/tests.rs @@ -13,7 +13,7 @@ use super::commands; use super::diff; fn create_temp_repo() -> (PathBuf, Repository) { - let root = std::env::temp_dir().join(format!("codex-monitor-test-{}", uuid::Uuid::new_v4())); + let root = std::env::temp_dir().join(format!("opencode-monitor-test-{}", uuid::Uuid::new_v4())); fs::create_dir_all(&root).expect("create temp repo root"); let repo = Repository::init(&root).expect("init repo"); (root, repo) diff --git a/src-tauri/src/shared/local_usage_core.rs b/src-tauri/src/shared/local_usage_core.rs index ca2f40871c..d7c06b4811 100644 --- a/src-tauri/src/shared/local_usage_core.rs +++ b/src-tauri/src/shared/local_usage_core.rs @@ -7,7 +7,7 @@ use std::path::{Path, PathBuf}; use std::time::{SystemTime, UNIX_EPOCH}; use tokio::sync::Mutex; -use crate::codex::home::{resolve_default_codex_home, resolve_workspace_codex_home}; +use crate::opencode::home::{resolve_default_opencode_home, resolve_workspace_opencode_home}; use crate::types::{ LocalUsageDay, LocalUsageModel, LocalUsageSnapshot, LocalUsageTotals, WorkspaceEntry, }; @@ -519,9 +519,9 @@ fn make_day_keys(days: u32) -> Vec { .collect() } -fn resolve_codex_sessions_root(codex_home_override: Option) -> Option { - codex_home_override - .or_else(resolve_default_codex_home) +fn resolve_opencode_sessions_root(opencode_home_override: Option) -> Option { + opencode_home_override + .or_else(resolve_default_opencode_home) .map(|home| home.join("sessions")) } @@ -530,9 +530,9 @@ fn resolve_sessions_roots( workspace_path: Option<&Path>, ) -> Vec { if let Some(workspace_path) = workspace_path { - let codex_home_override = - resolve_workspace_codex_home_for_path(workspaces, Some(workspace_path)); - return resolve_codex_sessions_root(codex_home_override) + let opencode_home_override = + resolve_workspace_opencode_home_for_path(workspaces, Some(workspace_path)); + return resolve_opencode_sessions_root(opencode_home_override) .into_iter() .collect(); } @@ -540,7 +540,7 @@ fn resolve_sessions_roots( let mut roots = Vec::new(); let mut seen = HashSet::new(); - if let Some(root) = resolve_codex_sessions_root(None) { + if let Some(root) = resolve_opencode_sessions_root(None) { if seen.insert(root.clone()) { roots.push(root); } @@ -551,10 +551,10 @@ fn resolve_sessions_roots( .parent_id .as_ref() .and_then(|parent_id| workspaces.get(parent_id)); - let Some(codex_home) = resolve_workspace_codex_home(entry, parent_entry) else { + let Some(opencode_home) = resolve_workspace_opencode_home(entry, parent_entry) else { continue; }; - if let Some(root) = resolve_codex_sessions_root(Some(codex_home)) { + if let Some(root) = resolve_opencode_sessions_root(Some(opencode_home)) { if seen.insert(root.clone()) { roots.push(root); } @@ -564,7 +564,7 @@ fn resolve_sessions_roots( roots } -fn resolve_workspace_codex_home_for_path( +fn resolve_workspace_opencode_home_for_path( workspaces: &HashMap, workspace_path: Option<&Path>, ) -> Option { @@ -582,7 +582,7 @@ fn resolve_workspace_codex_home_for_path( .as_ref() .and_then(|parent_id| workspaces.get(parent_id)); - resolve_workspace_codex_home(entry, parent_entry) + resolve_workspace_opencode_home(entry, parent_entry) } fn day_dir_for_key(root: &Path, day_key: &str) -> PathBuf { @@ -832,7 +832,7 @@ mod tests { workspaces.insert(entry_b.id.clone(), entry_b.clone()); let roots = resolve_sessions_roots(&workspaces, None); - let expected = resolve_codex_sessions_root(None) + let expected = resolve_opencode_sessions_root(None) .map(|root| vec![root]) .unwrap_or_default(); assert_eq!(roots, expected); diff --git a/src-tauri/src/shared/mod.rs b/src-tauri/src/shared/mod.rs index 87e639fbf9..d641f18a33 100644 --- a/src-tauri/src/shared/mod.rs +++ b/src-tauri/src/shared/mod.rs @@ -1,8 +1,8 @@ pub(crate) mod account; pub(crate) mod agents_config_core; -pub(crate) mod codex_aux_core; -pub(crate) mod codex_core; -pub(crate) mod codex_update_core; +pub(crate) mod opencode_aux_core; +pub(crate) mod opencode_core; +pub(crate) mod opencode_update_core; pub(crate) mod config_toml_core; pub(crate) mod files_core; pub(crate) mod git_core; diff --git a/src-tauri/src/shared/codex_aux_core.rs b/src-tauri/src/shared/opencode_aux_core.rs similarity index 97% rename from src-tauri/src/shared/codex_aux_core.rs rename to src-tauri/src/shared/opencode_aux_core.rs index 12f985adec..bc3819d89d 100644 --- a/src-tauri/src/shared/codex_aux_core.rs +++ b/src-tauri/src/shared/opencode_aux_core.rs @@ -8,7 +8,7 @@ use tokio::sync::{mpsc, Mutex}; use tokio::time::timeout; use crate::backend::app_server::{ - build_codex_command_with_bin, build_codex_path_env, check_codex_installation, WorkspaceSession, + build_opencode_command_with_bin, build_opencode_path_env, check_opencode_installation, WorkspaceSession, }; use crate::shared::process_core::tokio_command; use crate::types::{AppSettings, WorkspaceEntry}; @@ -286,26 +286,26 @@ pub(crate) fn sanitize_run_worktree_name(value: &str) -> String { format!("feat/{}", cleaned.trim_start_matches('/')) } -pub(crate) async fn codex_doctor_core( +pub(crate) async fn opencode_doctor_core( app_settings: &Mutex, - codex_bin: Option, - codex_args: Option, + opencode_bin: Option, + opencode_args: Option, ) -> Result { let (default_bin, default_args) = { let settings = app_settings.lock().await; - (settings.codex_bin.clone(), settings.codex_args.clone()) + (settings.opencode_bin.clone(), settings.opencode_args.clone()) }; - let resolved = codex_bin + let resolved = opencode_bin .clone() .filter(|value| !value.trim().is_empty()) .or(default_bin); - let resolved_args = codex_args + let resolved_args = opencode_args .clone() .filter(|value| !value.trim().is_empty()) .or(default_args); - let path_env = build_codex_path_env(resolved.as_deref()); - let version = check_codex_installation(resolved.clone()).await?; - let mut command = build_codex_command_with_bin( + let path_env = build_opencode_path_env(resolved.as_deref()); + let version = check_opencode_installation(resolved.clone()).await?; + let mut command = build_opencode_command_with_bin( resolved.clone(), resolved_args.as_deref(), vec!["app-server".to_string(), "--help".to_string()], @@ -377,11 +377,11 @@ pub(crate) async fn codex_doctor_core( let details = if app_server_ok { None } else { - Some("Failed to run `codex app-server --help`.".to_string()) + Some("Failed to run `opencode serve --help`.".to_string()) }; Ok(json!({ "ok": version.is_some() && app_server_ok, - "codexBin": resolved, + "opencodeBin": resolved, "version": version, "appServerOk": app_server_ok, "details": details, diff --git a/src-tauri/src/shared/codex_core.rs b/src-tauri/src/shared/opencode_core.rs similarity index 91% rename from src-tauri/src/shared/codex_core.rs rename to src-tauri/src/shared/opencode_core.rs index a0f2a4ea6a..d7d73fd5a5 100644 --- a/src-tauri/src/shared/codex_core.rs +++ b/src-tauri/src/shared/opencode_core.rs @@ -12,8 +12,8 @@ use tokio::time::timeout; use tokio::time::Instant; use crate::backend::app_server::WorkspaceSession; -use crate::codex::config as codex_config; -use crate::codex::home::{resolve_default_codex_home, resolve_workspace_codex_home}; +use crate::opencode::config; +use crate::opencode::home::{resolve_default_opencode_home, resolve_workspace_opencode_home}; use crate::rules; use crate::shared::account::{build_account_response, read_auth_account}; use crate::types::WorkspaceEntry; @@ -54,7 +54,7 @@ fn image_mime_type_for_path(path: &str) -> Option<&'static str> { } #[allow(dead_code)] -fn should_inline_image_path_for_codex(path: &str) -> bool { +fn should_inline_image_path_for_opencode(path: &str) -> bool { matches!( image_extension_for_path(path).as_deref(), Some("heic") | Some("heif") @@ -75,7 +75,7 @@ fn temp_converted_image_path(path: &str, extension: &str) -> PathBuf { .duration_since(UNIX_EPOCH) .map(|value| value.as_millis()) .unwrap_or_default(); - std::env::temp_dir().join(format!("codex-monitor-image-{safe_stem}-{ts}.{extension}")) + std::env::temp_dir().join(format!("opencode-monitor-image-{safe_stem}-{ts}.{extension}")) } #[cfg(target_os = "macos")] @@ -91,7 +91,7 @@ fn convert_heif_image_to_jpeg_bytes(path: &str) -> Result, String> { if !status.success() { let _ = std::fs::remove_file(&output_path); return Err(format!( - "Failed to convert HEIC/HEIF image into a Codex-compatible JPEG: {path}" + "Failed to convert HEIC/HEIF image into an OpenCode-compatible JPEG: {path}" )); } let bytes = std::fs::read(&output_path).map_err(|err| { @@ -156,7 +156,7 @@ pub(crate) fn read_image_as_data_url_core(path: &str) -> Result if trimmed_path.is_empty() { return Err("Image path is required".to_string()); } - if should_inline_image_path_for_codex(&trimmed_path) { + if should_inline_image_path_for_opencode(&trimmed_path) { #[cfg(target_os = "macos")] { let encoded = STANDARD.encode(convert_heif_image_to_jpeg_bytes(&trimmed_path)?); @@ -194,7 +194,7 @@ pub(crate) fn read_image_as_data_url_core(path: &str) -> Result Ok(format!("data:{mime_type};base64,{encoded}")) } -pub(crate) enum CodexLoginCancelState { +pub(crate) enum OpenCodeLoginCancelState { PendingStart(oneshot::Sender<()>), LoginId(String), } @@ -227,14 +227,14 @@ async fn resolve_workspace_and_parent( Ok((entry, parent_entry)) } -async fn resolve_codex_home_for_workspace_core( +async fn resolve_opencode_home_for_workspace_core( workspaces: &Mutex>, workspace_id: &str, ) -> Result { let (entry, parent_entry) = resolve_workspace_and_parent(workspaces, workspace_id).await?; - resolve_workspace_codex_home(&entry, parent_entry.as_ref()) - .or_else(resolve_default_codex_home) - .ok_or_else(|| "Unable to resolve CODEX_HOME".to_string()) + resolve_workspace_opencode_home(&entry, parent_entry.as_ref()) + .or_else(resolve_default_opencode_home) + .ok_or_else(|| "Unable to resolve OPENCODE_CONFIG_DIR".to_string()) } async fn resolve_workspace_path_core( @@ -418,7 +418,7 @@ fn build_turn_input_items( || trimmed.starts_with("https://") { input.push(json!({ "type": "image", "url": trimmed })); - } else if should_inline_image_path_for_codex(trimmed) { + } else if should_inline_image_path_for_opencode(trimmed) { input.push(json!({ "type": "image", "url": read_image_as_data_url_core(trimmed)?, @@ -643,33 +643,33 @@ pub(crate) async fn account_read_core( }; let (entry, parent_entry) = resolve_workspace_and_parent(workspaces, &workspace_id).await?; - let codex_home = resolve_workspace_codex_home(&entry, parent_entry.as_ref()) - .or_else(resolve_default_codex_home); - let fallback = read_auth_account(codex_home); + let opencode_home = resolve_workspace_opencode_home(&entry, parent_entry.as_ref()) + .or_else(resolve_default_opencode_home); + let fallback = read_auth_account(opencode_home); Ok(build_account_response(response, fallback)) } -pub(crate) async fn codex_login_core( +pub(crate) async fn opencode_login_core( sessions: &Mutex>>, - codex_login_cancels: &Mutex>, + opencode_login_cancels: &Mutex>, workspace_id: String, ) -> Result { let session = get_session_clone(sessions, &workspace_id).await?; let (cancel_tx, cancel_rx) = oneshot::channel::<()>(); { - let mut cancels = codex_login_cancels.lock().await; + let mut cancels = opencode_login_cancels.lock().await; if let Some(existing) = cancels.remove(&workspace_id) { match existing { - CodexLoginCancelState::PendingStart(tx) => { + OpenCodeLoginCancelState::PendingStart(tx) => { let _ = tx.send(()); } - CodexLoginCancelState::LoginId(_) => {} + OpenCodeLoginCancelState::LoginId(_) => {} } } cancels.insert( workspace_id.clone(), - CodexLoginCancelState::PendingStart(cancel_tx), + OpenCodeLoginCancelState::PendingStart(cancel_tx), ); } @@ -685,21 +685,21 @@ pub(crate) async fn codex_login_core( let response = loop { match cancel_rx.try_recv() { Ok(_) => { - let mut cancels = codex_login_cancels.lock().await; + let mut cancels = opencode_login_cancels.lock().await; cancels.remove(&workspace_id); - return Err("Codex login canceled.".to_string()); + return Err("OpenCode login canceled.".to_string()); } Err(TryRecvError::Closed) => { - let mut cancels = codex_login_cancels.lock().await; + let mut cancels = opencode_login_cancels.lock().await; cancels.remove(&workspace_id); - return Err("Codex login canceled.".to_string()); + return Err("OpenCode login canceled.".to_string()); } Err(TryRecvError::Empty) => {} } let elapsed = start.elapsed(); if elapsed >= LOGIN_START_TIMEOUT { - let mut cancels = codex_login_cancels.lock().await; + let mut cancels = opencode_login_cancels.lock().await; cancels.remove(&workspace_id); return Err("Codex login start timed out.".to_string()); } @@ -729,10 +729,10 @@ pub(crate) async fn codex_login_core( .ok_or_else(|| "missing auth url in account/login/start response".to_string())?; { - let mut cancels = codex_login_cancels.lock().await; + let mut cancels = opencode_login_cancels.lock().await; cancels.insert( workspace_id, - CodexLoginCancelState::LoginId(login_id.clone()), + OpenCodeLoginCancelState::LoginId(login_id.clone()), ); } @@ -743,13 +743,13 @@ pub(crate) async fn codex_login_core( })) } -pub(crate) async fn codex_login_cancel_core( +pub(crate) async fn opencode_login_cancel_core( sessions: &Mutex>>, - codex_login_cancels: &Mutex>, + opencode_login_cancels: &Mutex>, workspace_id: String, ) -> Result { let cancel_state = { - let mut cancels = codex_login_cancels.lock().await; + let mut cancels = opencode_login_cancels.lock().await; cancels.remove(&workspace_id) }; @@ -758,14 +758,14 @@ pub(crate) async fn codex_login_cancel_core( }; match cancel_state { - CodexLoginCancelState::PendingStart(cancel_tx) => { + OpenCodeLoginCancelState::PendingStart(cancel_tx) => { let _ = cancel_tx.send(()); return Ok(json!({ "canceled": true, "status": "canceled", })); } - CodexLoginCancelState::LoginId(login_id) => { + OpenCodeLoginCancelState::LoginId(login_id) => { let session = get_session_clone(sessions, &workspace_id).await?; let response = session .send_request_for_workspace( @@ -801,8 +801,8 @@ pub(crate) async fn skills_list_core( let session = get_session_clone(sessions, &workspace_id).await?; let workspace_path = resolve_workspace_path_core(workspaces, &workspace_id).await?; - // Codex can discover project-scoped skills from `/.agents/skills`. - // Some environments don't surface those reliably in CodexMonitor unless we + // OpenCode can discover project-scoped skills from `/.agents/skills`. + // Some environments don't surface those reliably in OpenCodeMonitor unless we // pass the default project skills path explicitly. let mut source_paths: Vec = vec![]; let project_skills_dir = Path::new(&workspace_path).join(".agents").join("skills"); @@ -869,8 +869,8 @@ pub(crate) async fn remember_approval_rule_core( return Err("empty command".to_string()); } - let codex_home = resolve_codex_home_for_workspace_core(workspaces, &workspace_id).await?; - let rules_path = rules::default_rules_path(&codex_home); + let opencode_home = resolve_opencode_home_for_workspace_core(workspaces, &workspace_id).await?; + let rules_path = rules::default_rules_path(&opencode_home); rules::append_prefix_rule(&rules_path, &command)?; Ok(json!({ @@ -883,8 +883,8 @@ pub(crate) async fn get_config_model_core( workspaces: &Mutex>, workspace_id: String, ) -> Result { - let codex_home = resolve_codex_home_for_workspace_core(workspaces, &workspace_id).await?; - let model = codex_config::read_config_model(Some(codex_home))?; + let opencode_home = resolve_opencode_home_for_workspace_core(workspaces, &workspace_id).await?; + let model = config::read_config_model(Some(opencode_home))?; Ok(json!({ "model": model })) } @@ -952,7 +952,7 @@ mod tests { #[test] fn read_image_data_url_core_succeeds_with_file_uri_for_real_file() { - let dir = std::env::temp_dir().join("codex_monitor_test"); + let dir = std::env::temp_dir().join("opencode_monitor_test"); std::fs::create_dir_all(&dir).unwrap(); let img_path = dir.join("test_photo.png"); let png_bytes: &[u8] = &[ @@ -1003,10 +1003,10 @@ mod tests { } #[test] - fn heif_paths_are_inlined_for_codex() { - assert!(should_inline_image_path_for_codex("/tmp/photo.heic")); - assert!(should_inline_image_path_for_codex("/tmp/photo.HEIF")); - assert!(!should_inline_image_path_for_codex("/tmp/photo.png")); + fn heif_paths_are_inlined_for_opencode() { + assert!(should_inline_image_path_for_opencode("/tmp/photo.heic")); + assert!(should_inline_image_path_for_opencode("/tmp/photo.HEIF")); + assert!(!should_inline_image_path_for_opencode("/tmp/photo.png")); } #[test] diff --git a/src-tauri/src/shared/codex_update_core.rs b/src-tauri/src/shared/opencode_update_core.rs similarity index 86% rename from src-tauri/src/shared/codex_update_core.rs rename to src-tauri/src/shared/opencode_update_core.rs index ee5541a25e..848fb01df4 100644 --- a/src-tauri/src/shared/codex_update_core.rs +++ b/src-tauri/src/shared/opencode_update_core.rs @@ -6,13 +6,13 @@ use std::time::Duration; use tokio::sync::Mutex; use tokio::time::timeout; -use crate::backend::app_server::check_codex_installation; +use crate::backend::app_server::check_opencode_installation; use crate::shared::process_core::tokio_command; use crate::types::AppSettings; #[derive(serde::Serialize)] #[serde(rename_all = "camelCase")] -struct CodexUpdateResult { +struct OpenCodeUpdateResult { ok: bool, method: String, package: Option, @@ -143,46 +143,46 @@ async fn run_npm_install_latest(package: &str) -> Result<(bool, String), String> Ok((output.status.success(), combined.trim().to_string())) } -pub(crate) async fn codex_update_core( +pub(crate) async fn opencode_update_core( app_settings: &Mutex, - codex_bin: Option, - codex_args: Option, + opencode_bin: Option, + opencode_args: Option, ) -> Result { let (default_bin, default_args) = { let settings = app_settings.lock().await; - (settings.codex_bin.clone(), settings.codex_args.clone()) + (settings.opencode_bin.clone(), settings.opencode_args.clone()) }; - let resolved = codex_bin + let resolved = opencode_bin .clone() .filter(|value| !value.trim().is_empty()) .or(default_bin); - let resolved_args = codex_args + let resolved_args = opencode_args .clone() .filter(|value| !value.trim().is_empty()) .or(default_args); let _ = resolved_args; - let before_version = check_codex_installation(resolved.clone()) + let before_version = check_opencode_installation(resolved.clone()) .await .ok() .flatten(); - let (method, package, upgrade_ok, output, upgraded) = if detect_brew_cask("codex").await? { - let (ok, output) = run_brew_upgrade(&["--cask", "codex"]).await?; + let (method, package, upgrade_ok, output, upgraded) = if detect_brew_cask("opencode").await? { + let (ok, output) = run_brew_upgrade(&["--cask", "opencode"]).await?; let upgraded = brew_output_indicates_upgrade(&output); ( "brew_cask".to_string(), - Some("codex".to_string()), + Some("opencode".to_string()), ok, output, upgraded, ) - } else if detect_brew_formula("codex").await? { - let (ok, output) = run_brew_upgrade(&["codex"]).await?; + } else if detect_brew_formula("opencode").await? { + let (ok, output) = run_brew_upgrade(&["opencode"]).await?; let upgraded = brew_output_indicates_upgrade(&output); ( "brew_formula".to_string(), - Some("codex".to_string()), + Some("opencode".to_string()), ok, output, upgraded, @@ -203,10 +203,10 @@ pub(crate) async fn codex_update_core( let after_version = if method == "unknown" { None } else { - match check_codex_installation(resolved.clone()).await { + match check_opencode_installation(resolved.clone()).await { Ok(version) => version, Err(err) => { - let result = CodexUpdateResult { + let result = OpenCodeUpdateResult { ok: false, method, package, @@ -222,14 +222,14 @@ pub(crate) async fn codex_update_core( }; let details = if method == "unknown" { - Some("Unable to detect Codex installation method (brew/npm).".to_string()) + Some("Unable to detect OpenCode installation method (brew/npm).".to_string()) } else if upgrade_ok { None } else { - Some("Codex update failed.".to_string()) + Some("OpenCode update failed.".to_string()) }; - let result = CodexUpdateResult { + let result = OpenCodeUpdateResult { ok: upgrade_ok, method, package, diff --git a/src-tauri/src/shared/prompts_core.rs b/src-tauri/src/shared/prompts_core.rs index a03844b6f4..7ded6250fd 100644 --- a/src-tauri/src/shared/prompts_core.rs +++ b/src-tauri/src/shared/prompts_core.rs @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf}; use tokio::sync::Mutex; use tokio::task; -use crate::codex::home::{resolve_default_codex_home, resolve_workspace_codex_home}; +use crate::opencode::home::{resolve_default_opencode_home, resolve_workspace_opencode_home}; use crate::types::WorkspaceEntry; #[derive(Serialize, Clone)] @@ -20,7 +20,7 @@ pub(crate) struct CustomPromptEntry { pub(crate) scope: Option, } -fn resolve_codex_home_for_workspace( +fn resolve_opencode_home_for_workspace( workspaces: &HashMap, entry: &WorkspaceEntry, ) -> Option { @@ -28,14 +28,14 @@ fn resolve_codex_home_for_workspace( .parent_id .as_ref() .and_then(|parent_id| workspaces.get(parent_id)); - resolve_workspace_codex_home(entry, parent_entry).or_else(resolve_default_codex_home) + resolve_workspace_opencode_home(entry, parent_entry).or_else(resolve_default_opencode_home) } fn default_prompts_dir_for_workspace( workspaces: &HashMap, entry: &WorkspaceEntry, ) -> Option { - resolve_codex_home_for_workspace(workspaces, entry).map(|home| home.join("prompts")) + resolve_opencode_home_for_workspace(workspaces, entry).map(|home| home.join("prompts")) } fn require_workspace_entry( @@ -323,7 +323,7 @@ pub(crate) async fn prompts_global_dir_core( let workspaces = workspaces.lock().await; let entry = require_workspace_entry(&workspaces, &workspace_id)?; let dir = default_prompts_dir_for_workspace(&workspaces, &entry) - .ok_or("Unable to resolve CODEX_HOME".to_string())?; + .ok_or("Unable to resolve OPENCODE_CONFIG_DIR".to_string())?; fs::create_dir_all(&dir).map_err(|err| err.to_string())?; Ok(dir.to_string_lossy().to_string()) } @@ -349,7 +349,7 @@ pub(crate) async fn prompts_create_core( } "global" => { let dir = default_prompts_dir_for_workspace(&workspaces, &entry) - .ok_or("Unable to resolve CODEX_HOME".to_string())?; + .ok_or("Unable to resolve OPENCODE_CONFIG_DIR".to_string())?; (dir, "global") } _ => return Err("Invalid scope.".to_string()), @@ -473,7 +473,7 @@ pub(crate) async fn prompts_move_core( match scope.as_str() { "workspace" => workspace_prompts_dir(settings_path, &entry)?, "global" => default_prompts_dir_for_workspace(&workspaces, &entry) - .ok_or("Unable to resolve CODEX_HOME".to_string())?, + .ok_or("Unable to resolve OPENCODE_CONFIG_DIR".to_string())?, _ => return Err("Invalid scope.".to_string()), } }; diff --git a/src-tauri/src/shared/settings_core.rs b/src-tauri/src/shared/settings_core.rs index e4d9490754..4246616e35 100644 --- a/src-tauri/src/shared/settings_core.rs +++ b/src-tauri/src/shared/settings_core.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use tokio::sync::Mutex; -use crate::codex::config as codex_config; +use crate::opencode::config; use crate::storage::write_settings; use crate::types::AppSettings; use crate::utils::normalize_windows_namespace_path; @@ -17,20 +17,20 @@ fn normalize_personality(value: &str) -> Option<&'static str> { pub(crate) async fn get_app_settings_core(app_settings: &Mutex) -> AppSettings { let mut settings = app_settings.lock().await.clone(); - if let Ok(Some(collaboration_modes_enabled)) = codex_config::read_collaboration_modes_enabled() + if let Ok(Some(collaboration_modes_enabled)) = config::read_collaboration_modes_enabled() { settings.collaboration_modes_enabled = collaboration_modes_enabled; } - if let Ok(Some(steer_enabled)) = codex_config::read_steer_enabled() { + if let Ok(Some(steer_enabled)) = config::read_steer_enabled() { settings.steer_enabled = steer_enabled; } - if let Ok(Some(unified_exec_enabled)) = codex_config::read_unified_exec_enabled() { + if let Ok(Some(unified_exec_enabled)) = config::read_unified_exec_enabled() { settings.unified_exec_enabled = unified_exec_enabled; } - if let Ok(Some(apps_enabled)) = codex_config::read_apps_enabled() { + if let Ok(Some(apps_enabled)) = config::read_apps_enabled() { settings.experimental_apps_enabled = apps_enabled; } - if let Ok(personality) = codex_config::read_personality() { + if let Ok(personality) = config::read_personality() { settings.personality = personality .as_deref() .and_then(normalize_personality) @@ -48,23 +48,23 @@ pub(crate) async fn update_app_settings_core( settings.global_worktrees_folder = settings .global_worktrees_folder .map(|path| normalize_windows_namespace_path(&path)); - let _ = codex_config::write_collaboration_modes_enabled(settings.collaboration_modes_enabled); - let _ = codex_config::write_steer_enabled(settings.steer_enabled); - let _ = codex_config::write_unified_exec_enabled(settings.unified_exec_enabled); - let _ = codex_config::write_apps_enabled(settings.experimental_apps_enabled); - let _ = codex_config::write_personality(settings.personality.as_str()); + let _ = config::write_collaboration_modes_enabled(settings.collaboration_modes_enabled); + let _ = config::write_steer_enabled(settings.steer_enabled); + let _ = config::write_unified_exec_enabled(settings.unified_exec_enabled); + let _ = config::write_apps_enabled(settings.experimental_apps_enabled); + let _ = config::write_personality(settings.personality.as_str()); write_settings(settings_path, &settings)?; let mut current = app_settings.lock().await; *current = settings.clone(); Ok(settings) } -pub(crate) fn get_codex_config_path_core() -> Result { - codex_config::config_toml_path() - .ok_or_else(|| "Unable to resolve CODEX_HOME".to_string()) +pub(crate) fn get_opencode_config_path_core() -> Result { + config::config_toml_path() + .ok_or_else(|| "Unable to resolve OPENCODE_CONFIG_DIR".to_string()) .and_then(|path| { path.to_str() .map(|value| value.to_string()) - .ok_or_else(|| "Unable to resolve CODEX_HOME".to_string()) + .ok_or_else(|| "Unable to resolve OPENCODE_CONFIG_DIR".to_string()) }) } diff --git a/src-tauri/src/shared/workspace_rpc.rs b/src-tauri/src/shared/workspace_rpc.rs index 85acbf46e2..a5235e123f 100644 --- a/src-tauri/src/shared/workspace_rpc.rs +++ b/src-tauri/src/shared/workspace_rpc.rs @@ -23,9 +23,9 @@ pub(crate) struct ReadWorkspaceFileRequest { #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub(crate) struct SetWorkspaceRuntimeCodexArgsRequest { +pub(crate) struct SetWorkspaceRuntimeOpenCodeArgsRequest { pub(crate) workspace_id: String, - pub(crate) codex_args: Option, + pub(crate) opencode_args: Option, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src-tauri/src/shared/workspaces_core.rs b/src-tauri/src/shared/workspaces_core.rs index 90eb5f9117..c9462cd462 100644 --- a/src-tauri/src/shared/workspaces_core.rs +++ b/src-tauri/src/shared/workspaces_core.rs @@ -3,7 +3,7 @@ mod crud_persistence; mod git_orchestration; mod helpers; mod io; -mod runtime_codex_args; +mod runtime_opencode_args; mod worktree; pub(crate) use connect::connect_workspace_core; @@ -17,8 +17,8 @@ pub(crate) use io::{ get_open_app_icon_core, list_workspace_files_core, open_workspace_in_core, read_workspace_file_core, }; -pub(crate) use runtime_codex_args::{ - set_workspace_runtime_codex_args_core, WorkspaceRuntimeCodexArgsResult, +pub(crate) use runtime_opencode_args::{ + set_workspace_runtime_opencode_args_core, WorkspaceRuntimeOpenCodeArgsResult, }; pub(crate) use worktree::{ add_worktree_core, remove_worktree_core, rename_worktree_core, rename_worktree_upstream_core, diff --git a/src-tauri/src/shared/workspaces_core/connect.rs b/src-tauri/src/shared/workspaces_core/connect.rs index bf255a1384..776011ff91 100644 --- a/src-tauri/src/shared/workspaces_core/connect.rs +++ b/src-tauri/src/shared/workspaces_core/connect.rs @@ -7,8 +7,8 @@ use std::sync::Arc; use tokio::sync::Mutex; use crate::backend::app_server::WorkspaceSession; -use crate::codex::args::resolve_workspace_codex_args; -use crate::codex::home::resolve_workspace_codex_home; +use crate::opencode::args::resolve_workspace_opencode_args; +use crate::opencode::home::resolve_workspace_opencode_home; use crate::shared::process_core::kill_child_process_tree; use crate::types::{AppSettings, WorkspaceEntry}; @@ -83,15 +83,15 @@ where .insert(entry.id.clone(), existing_session); return Ok(()); } - let (default_bin, codex_args) = { + let (default_bin, opencode_args) = { let settings = app_settings.lock().await; ( - settings.codex_bin.clone(), - resolve_workspace_codex_args(&entry, parent_entry.as_ref(), Some(&settings)), + settings.opencode_bin.clone(), + resolve_workspace_opencode_args(&entry, parent_entry.as_ref(), Some(&settings)), ) }; - let codex_home = resolve_workspace_codex_home(&entry, parent_entry.as_ref()); - let session = spawn_session(entry.clone(), default_bin, codex_args, codex_home).await?; + let opencode_home = resolve_workspace_opencode_home(&entry, parent_entry.as_ref()); + let session = spawn_session(entry.clone(), default_bin, opencode_args, opencode_home).await?; session .register_workspace_with_path(&entry.id, Some(&entry.path)) .await; @@ -168,7 +168,7 @@ mod tests { let stdin = child.stdin.take().expect("dummy child stdin"); Arc::new(WorkspaceSession { - codex_args: None, + opencode_args: None, child: Mutex::new(child), stdin: Mutex::new(stdin), pending: Mutex::new(HashMap::new()), @@ -201,7 +201,7 @@ mod tests { &workspaces, &sessions, &app_settings, - move |_entry, _default_bin, _codex_args, _codex_home| { + move |_entry, _default_bin, _opencode_args, _opencode_home| { let spawn_calls_ref = spawn_calls_ref.clone(); async move { spawn_calls_ref.fetch_add(1, Ordering::SeqCst); @@ -233,7 +233,7 @@ mod tests { &workspaces, &sessions, &app_settings, - move |_entry, _default_bin, _codex_args, _codex_home| { + move |_entry, _default_bin, _opencode_args, _opencode_home| { let spawn_calls_ref = spawn_calls_ref.clone(); let entry_for_spawn = entry_for_spawn.clone(); async move { diff --git a/src-tauri/src/shared/workspaces_core/crud_persistence.rs b/src-tauri/src/shared/workspaces_core/crud_persistence.rs index 633b078f04..098bc08bdc 100644 --- a/src-tauri/src/shared/workspaces_core/crud_persistence.rs +++ b/src-tauri/src/shared/workspaces_core/crud_persistence.rs @@ -7,8 +7,8 @@ use tokio::sync::Mutex; use uuid::Uuid; use crate::backend::app_server::WorkspaceSession; -use crate::codex::args::resolve_workspace_codex_args; -use crate::codex::home::resolve_workspace_codex_home; +use crate::opencode::args::resolve_workspace_opencode_args; +use crate::opencode::home::resolve_workspace_opencode_home; use crate::shared::process_core::kill_child_process_tree; use crate::shared::{git_core, worktree_core}; use crate::storage::write_workspaces; @@ -58,16 +58,16 @@ where let (session, spawned_new_session) = if let Some(existing_session) = existing_session { (existing_session, false) } else { - let (default_bin, codex_args) = { + let (default_bin, opencode_args) = { let settings = app_settings.lock().await; ( - settings.codex_bin.clone(), - resolve_workspace_codex_args(&entry, None, Some(&settings)), + settings.opencode_bin.clone(), + resolve_workspace_opencode_args(&entry, None, Some(&settings)), ) }; - let codex_home = resolve_workspace_codex_home(&entry, None); + let opencode_home = resolve_workspace_opencode_home(&entry, None); ( - spawn_session(entry.clone(), default_bin, codex_args, codex_home).await?, + spawn_session(entry.clone(), default_bin, opencode_args, opencode_home).await?, true, ) }; @@ -209,15 +209,15 @@ where let (session, spawned_new_session) = if let Some(existing_session) = existing_session { (existing_session, false) } else { - let (default_bin, codex_args) = { + let (default_bin, opencode_args) = { let settings = app_settings.lock().await; ( - settings.codex_bin.clone(), - resolve_workspace_codex_args(&entry, None, Some(&settings)), + settings.opencode_bin.clone(), + resolve_workspace_opencode_args(&entry, None, Some(&settings)), ) }; - let codex_home = resolve_workspace_codex_home(&entry, None); - match spawn_session(entry.clone(), default_bin, codex_args, codex_home).await { + let opencode_home = resolve_workspace_opencode_home(&entry, None); + match spawn_session(entry.clone(), default_bin, opencode_args, opencode_home).await { Ok(session) => (session, true), Err(error) => { let _ = tokio::fs::remove_dir_all(&destination_path).await; @@ -374,15 +374,15 @@ where let (session, spawned_new_session) = if let Some(existing_session) = existing_session { (existing_session, false) } else { - let (default_bin, codex_args) = { + let (default_bin, opencode_args) = { let settings = app_settings.lock().await; ( - settings.codex_bin.clone(), - resolve_workspace_codex_args(&entry, None, Some(&settings)), + settings.opencode_bin.clone(), + resolve_workspace_opencode_args(&entry, None, Some(&settings)), ) }; - let codex_home = resolve_workspace_codex_home(&entry, None); - match spawn_session(entry.clone(), default_bin, codex_args, codex_home).await { + let opencode_home = resolve_workspace_opencode_home(&entry, None); + match spawn_session(entry.clone(), default_bin, opencode_args, opencode_home).await { Ok(session) => (session, true), Err(error) => { let _ = tokio::fs::remove_dir_all(&clone_path).await; diff --git a/src-tauri/src/shared/workspaces_core/helpers.rs b/src-tauri/src/shared/workspaces_core/helpers.rs index da4e00de06..2754f062a4 100644 --- a/src-tauri/src/shared/workspaces_core/helpers.rs +++ b/src-tauri/src/shared/workspaces_core/helpers.rs @@ -70,12 +70,12 @@ pub(crate) fn is_workspace_path_dir_core(path: &str) -> bool { pub(crate) fn normalize_workspace_path_input(path: &str) -> PathBuf { let trimmed = path.trim(); if let Some(rest) = trimmed.strip_prefix("~/") { - if let Some(home) = crate::codex::home::resolve_home_dir() { + if let Some(home) = crate::opencode::home::resolve_home_dir() { return home.join(rest); } } if trimmed == "~" { - if let Some(home) = crate::codex::home::resolve_home_dir() { + if let Some(home) = crate::opencode::home::resolve_home_dir() { return home; } } @@ -162,7 +162,7 @@ mod tests { static ENV_LOCK: Mutex<()> = Mutex::new(()); fn make_temp_dir() -> std::path::PathBuf { - let dir = std::env::temp_dir().join(format!("codex-monitor-{}", Uuid::new_v4())); + let dir = std::env::temp_dir().join(format!("opencode-monitor-{}", Uuid::new_v4())); std::fs::create_dir_all(&dir).expect("failed to create temp dir"); dir } @@ -227,8 +227,8 @@ mod tests { #[test] fn workspace_path_to_string_strips_windows_namespace_prefixes() { assert_eq!( - workspace_path_to_string(&PathBuf::from(r"\\?\I:\gpt-projects\CodexMonitor")), - r"I:\gpt-projects\CodexMonitor" + workspace_path_to_string(&PathBuf::from(r"\\?\I:\gpt-projects\OpenCodeMonitor")), + r"I:\gpt-projects\OpenCodeMonitor" ); } } diff --git a/src-tauri/src/shared/workspaces_core/runtime_codex_args.rs b/src-tauri/src/shared/workspaces_core/runtime_opencode_args.rs similarity index 81% rename from src-tauri/src/shared/workspaces_core/runtime_codex_args.rs rename to src-tauri/src/shared/workspaces_core/runtime_opencode_args.rs index 9801e6c5ec..24d5753cab 100644 --- a/src-tauri/src/shared/workspaces_core/runtime_codex_args.rs +++ b/src-tauri/src/shared/workspaces_core/runtime_opencode_args.rs @@ -7,8 +7,8 @@ use serde::{Deserialize, Serialize}; use tokio::sync::Mutex; use crate::backend::app_server::WorkspaceSession; -use crate::codex::args::resolve_workspace_codex_args; -use crate::codex::home::resolve_workspace_codex_home; +use crate::opencode::args::resolve_workspace_opencode_args; +use crate::opencode::home::resolve_workspace_opencode_home; use crate::shared::process_core::kill_child_process_tree; use crate::types::{AppSettings, WorkspaceEntry}; @@ -17,19 +17,19 @@ use super::helpers::resolve_entry_and_parent; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] -pub(crate) struct WorkspaceRuntimeCodexArgsResult { - pub(crate) applied_codex_args: Option, +pub(crate) struct WorkspaceRuntimeOpenCodeArgsResult { + pub(crate) applied_opencode_args: Option, pub(crate) respawned: bool, } -pub(crate) async fn set_workspace_runtime_codex_args_core( +pub(crate) async fn set_workspace_runtime_opencode_args_core( workspace_id: String, - codex_args_override: Option, + opencode_args_override: Option, workspaces: &Mutex>, sessions: &Mutex>>, app_settings: &Mutex, spawn_session: F, -) -> Result +) -> Result where F: Fn(WorkspaceEntry, Option, Option, Option) -> Fut, Fut: Future, String>>, @@ -40,12 +40,12 @@ where let (default_bin, resolved_args) = { let settings = app_settings.lock().await; ( - settings.codex_bin.clone(), - resolve_workspace_codex_args(&entry, parent_entry.as_ref(), Some(&settings)), + settings.opencode_bin.clone(), + resolve_workspace_opencode_args(&entry, parent_entry.as_ref(), Some(&settings)), ) }; - let target_args = codex_args_override + let target_args = opencode_args_override .as_deref() .map(str::trim) .filter(|value| !value.is_empty()) @@ -62,29 +62,29 @@ where ) }; if !workspace_connected { - return Ok(WorkspaceRuntimeCodexArgsResult { - applied_codex_args: target_args, + return Ok(WorkspaceRuntimeOpenCodeArgsResult { + applied_opencode_args: target_args, respawned: false, }); } let Some(current_session) = current_session else { - return Ok(WorkspaceRuntimeCodexArgsResult { - applied_codex_args: target_args, + return Ok(WorkspaceRuntimeOpenCodeArgsResult { + applied_opencode_args: target_args, respawned: false, }); }; - if current_session.codex_args == target_args { - return Ok(WorkspaceRuntimeCodexArgsResult { - applied_codex_args: target_args, + if current_session.opencode_args == target_args { + return Ok(WorkspaceRuntimeOpenCodeArgsResult { + applied_opencode_args: target_args, respawned: false, }); } - let codex_home = resolve_workspace_codex_home(&entry, parent_entry.as_ref()); + let opencode_home = resolve_workspace_opencode_home(&entry, parent_entry.as_ref()); let new_session = - spawn_session(entry.clone(), default_bin, target_args.clone(), codex_home).await?; + spawn_session(entry.clone(), default_bin, target_args.clone(), opencode_home).await?; let workspace_ids = { let mut sessions = sessions.lock().await; let keys: Vec = sessions.keys().cloned().collect(); @@ -119,8 +119,8 @@ where let mut child = current_session.child.lock().await; kill_child_process_tree(&mut child).await; - Ok(WorkspaceRuntimeCodexArgsResult { - applied_codex_args: target_args, + Ok(WorkspaceRuntimeOpenCodeArgsResult { + applied_opencode_args: target_args, respawned: true, }) } @@ -149,7 +149,7 @@ mod tests { } } - fn make_session(_entry: WorkspaceEntry, codex_args: Option) -> WorkspaceSession { + fn make_session(_entry: WorkspaceEntry, opencode_args: Option) -> WorkspaceSession { let mut cmd = if cfg!(windows) { let mut cmd = Command::new("cmd"); cmd.args(["/C", "more"]); @@ -168,7 +168,7 @@ mod tests { let stdin = child.stdin.take().expect("dummy child stdin"); WorkspaceSession { - codex_args, + opencode_args, child: Mutex::new(child), stdin: Mutex::new(stdin), pending: Mutex::new(HashMap::new()), @@ -184,7 +184,7 @@ mod tests { } #[test] - fn set_workspace_runtime_codex_args_is_noop_when_workspace_not_connected() { + fn set_workspace_runtime_opencode_args_is_noop_when_workspace_not_connected() { tokio::runtime::Runtime::new().unwrap().block_on(async { let entry = make_workspace_entry("ws-1"); let workspaces = Mutex::new(HashMap::from([(entry.id.clone(), entry.clone())])); @@ -194,7 +194,7 @@ mod tests { let spawn_calls = Arc::new(AtomicUsize::new(0)); let spawn_calls_ref = spawn_calls.clone(); - let result = set_workspace_runtime_codex_args_core( + let result = set_workspace_runtime_opencode_args_core( entry.id.clone(), Some(" --profile dev ".to_string()), &workspaces, @@ -213,8 +213,8 @@ mod tests { assert_eq!( result, - WorkspaceRuntimeCodexArgsResult { - applied_codex_args: Some("--profile dev".to_string()), + WorkspaceRuntimeOpenCodeArgsResult { + applied_opencode_args: Some("--profile dev".to_string()), respawned: false } ); @@ -223,7 +223,7 @@ mod tests { } #[test] - fn set_workspace_runtime_codex_args_is_noop_when_args_match() { + fn set_workspace_runtime_opencode_args_is_noop_when_args_match() { tokio::runtime::Runtime::new().unwrap().block_on(async { let entry = make_workspace_entry("ws-1"); let workspaces = Mutex::new(HashMap::from([(entry.id.clone(), entry.clone())])); @@ -234,7 +234,7 @@ mod tests { let spawn_calls = Arc::new(AtomicUsize::new(0)); let spawn_calls_ref = spawn_calls.clone(); - let result = set_workspace_runtime_codex_args_core( + let result = set_workspace_runtime_opencode_args_core( entry.id.clone(), Some("--same".to_string()), &workspaces, @@ -253,8 +253,8 @@ mod tests { assert_eq!( result, - WorkspaceRuntimeCodexArgsResult { - applied_codex_args: Some("--same".to_string()), + WorkspaceRuntimeOpenCodeArgsResult { + applied_opencode_args: Some("--same".to_string()), respawned: false } ); @@ -263,7 +263,7 @@ mod tests { } #[test] - fn set_workspace_runtime_codex_args_respawns_when_args_change() { + fn set_workspace_runtime_opencode_args_respawns_when_args_change() { tokio::runtime::Runtime::new().unwrap().block_on(async { let entry = make_workspace_entry("ws-1"); let workspaces = Mutex::new(HashMap::from([(entry.id.clone(), entry.clone())])); @@ -274,7 +274,7 @@ mod tests { let spawn_calls = Arc::new(AtomicUsize::new(0)); let spawn_calls_ref = spawn_calls.clone(); - let result = set_workspace_runtime_codex_args_core( + let result = set_workspace_runtime_opencode_args_core( entry.id.clone(), Some("--new".to_string()), &workspaces, @@ -293,8 +293,8 @@ mod tests { assert_eq!( result, - WorkspaceRuntimeCodexArgsResult { - applied_codex_args: Some("--new".to_string()), + WorkspaceRuntimeOpenCodeArgsResult { + applied_opencode_args: Some("--new".to_string()), respawned: true } ); @@ -305,7 +305,7 @@ mod tests { .await .get(&entry.id) .expect("session updated") - .codex_args + .opencode_args .clone(); assert_eq!(next, Some("--new".to_string())); }); diff --git a/src-tauri/src/shared/workspaces_core/worktree.rs b/src-tauri/src/shared/workspaces_core/worktree.rs index 824e4aecda..f58898b39e 100644 --- a/src-tauri/src/shared/workspaces_core/worktree.rs +++ b/src-tauri/src/shared/workspaces_core/worktree.rs @@ -7,8 +7,8 @@ use tokio::sync::Mutex; use uuid::Uuid; use crate::backend::app_server::WorkspaceSession; -use crate::codex::args::resolve_workspace_codex_args; -use crate::codex::home::resolve_workspace_codex_home; +use crate::opencode::args::resolve_workspace_opencode_args; +use crate::opencode::home::resolve_workspace_opencode_home; use crate::storage::write_workspaces; use crate::types::{ AppSettings, WorkspaceEntry, WorkspaceInfo, WorkspaceKind, WorkspaceSettings, WorktreeInfo, @@ -225,15 +225,15 @@ where let session = if let Some(existing_session) = existing_session { existing_session } else { - let (default_bin, codex_args) = { + let (default_bin, opencode_args) = { let settings = app_settings.lock().await; ( - settings.codex_bin.clone(), - resolve_workspace_codex_args(&entry, Some(&parent_entry), Some(&settings)), + settings.opencode_bin.clone(), + resolve_workspace_opencode_args(&entry, Some(&parent_entry), Some(&settings)), ) }; - let codex_home = resolve_workspace_codex_home(&entry, Some(&parent_entry)); - spawn_session(entry.clone(), default_bin, codex_args, codex_home).await? + let opencode_home = resolve_workspace_opencode_home(&entry, Some(&parent_entry)); + spawn_session(entry.clone(), default_bin, opencode_args, opencode_home).await? }; { diff --git a/src-tauri/src/state.rs b/src-tauri/src/state.rs index e28cf4ed70..5b25627ddd 100644 --- a/src-tauri/src/state.rs +++ b/src-tauri/src/state.rs @@ -6,7 +6,7 @@ use tokio::process::Child; use tokio::sync::Mutex; use crate::dictation::DictationState; -use crate::shared::codex_core::CodexLoginCancelState; +use crate::shared::opencode_core::OpenCodeLoginCancelState; use crate::storage::{read_settings, read_workspaces}; use crate::types::{AppSettings, TcpDaemonState, TcpDaemonStatus, WorkspaceEntry}; @@ -32,14 +32,14 @@ impl Default for TcpDaemonRuntime { pub(crate) struct AppState { pub(crate) workspaces: Mutex>, - pub(crate) sessions: Mutex>>, + pub(crate) sessions: Mutex>>, pub(crate) terminal_sessions: Mutex>>, pub(crate) remote_backend: Mutex>, pub(crate) storage_path: PathBuf, pub(crate) settings_path: PathBuf, pub(crate) app_settings: Mutex, pub(crate) dictation: Mutex, - pub(crate) codex_login_cancels: Mutex>, + pub(crate) opencode_login_cancels: Mutex>, pub(crate) tcp_daemon: Mutex, } @@ -62,7 +62,7 @@ impl AppState { settings_path, app_settings: Mutex::new(app_settings), dictation: Mutex::new(DictationState::default()), - codex_login_cancels: Mutex::new(HashMap::new()), + opencode_login_cancels: Mutex::new(HashMap::new()), tcp_daemon: Mutex::new(TcpDaemonRuntime::default()), } } diff --git a/src-tauri/src/storage.rs b/src-tauri/src/storage.rs index efdb35d4cf..5acb2ec0f9 100644 --- a/src-tauri/src/storage.rs +++ b/src-tauri/src/storage.rs @@ -238,7 +238,7 @@ mod tests { #[test] fn write_read_workspaces_persists_sort_and_group() { - let temp_dir = std::env::temp_dir().join(format!("codex-monitor-test-{}", Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("opencode-monitor-test-{}", Uuid::new_v4())); std::fs::create_dir_all(&temp_dir).expect("create temp dir"); let path = temp_dir.join("workspaces.json"); @@ -269,7 +269,7 @@ mod tests { #[test] fn write_read_workspaces_sanitizes_windows_namespace_paths() { - let temp_dir = std::env::temp_dir().join(format!("codex-monitor-test-{}", Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("opencode-monitor-test-{}", Uuid::new_v4())); std::fs::create_dir_all(&temp_dir).expect("create temp dir"); let path = temp_dir.join("workspaces.json"); @@ -292,7 +292,7 @@ mod tests { #[test] fn read_workspaces_sanitizes_namespace_paths_without_rewriting_file() { - let temp_dir = std::env::temp_dir().join(format!("codex-monitor-test-{}", Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("opencode-monitor-test-{}", Uuid::new_v4())); std::fs::create_dir_all(&temp_dir).expect("create temp dir"); let path = temp_dir.join("workspaces.json"); @@ -325,7 +325,7 @@ mod tests { #[test] fn read_settings_sanitizes_non_tcp_remote_provider() { - let temp_dir = std::env::temp_dir().join(format!("codex-monitor-test-{}", Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("opencode-monitor-test-{}", Uuid::new_v4())); std::fs::create_dir_all(&temp_dir).expect("create temp dir"); let path = temp_dir.join("settings.json"); @@ -365,7 +365,7 @@ mod tests { #[test] fn read_settings_migrates_follow_up_behavior_from_legacy_steer_enabled_true() { - let temp_dir = std::env::temp_dir().join(format!("codex-monitor-test-{}", Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("opencode-monitor-test-{}", Uuid::new_v4())); std::fs::create_dir_all(&temp_dir).expect("create temp dir"); let path = temp_dir.join("settings.json"); @@ -385,7 +385,7 @@ mod tests { #[test] fn read_settings_migrates_follow_up_behavior_from_legacy_steer_enabled_false() { - let temp_dir = std::env::temp_dir().join(format!("codex-monitor-test-{}", Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("opencode-monitor-test-{}", Uuid::new_v4())); std::fs::create_dir_all(&temp_dir).expect("create temp dir"); let path = temp_dir.join("settings.json"); @@ -405,7 +405,7 @@ mod tests { #[test] fn write_read_settings_sanitizes_global_worktrees_folder_namespace_paths() { - let temp_dir = std::env::temp_dir().join(format!("codex-monitor-test-{}", Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("opencode-monitor-test-{}", Uuid::new_v4())); std::fs::create_dir_all(&temp_dir).expect("create temp dir"); let path = temp_dir.join("settings.json"); @@ -422,7 +422,7 @@ mod tests { #[test] fn read_settings_rewrites_global_worktrees_folder_namespace_paths() { - let temp_dir = std::env::temp_dir().join(format!("codex-monitor-test-{}", Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("opencode-monitor-test-{}", Uuid::new_v4())); std::fs::create_dir_all(&temp_dir).expect("create temp dir"); let path = temp_dir.join("settings.json"); @@ -452,7 +452,7 @@ mod tests { #[test] fn read_settings_keeps_existing_follow_up_behavior() { - let temp_dir = std::env::temp_dir().join(format!("codex-monitor-test-{}", Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("opencode-monitor-test-{}", Uuid::new_v4())); std::fs::create_dir_all(&temp_dir).expect("create temp dir"); let path = temp_dir.join("settings.json"); diff --git a/src-tauri/src/tailscale/core.rs b/src-tauri/src/tailscale/core.rs index d63f7809e0..1196fe4d02 100644 --- a/src-tauri/src/tailscale/core.rs +++ b/src-tauri/src/tailscale/core.rs @@ -427,7 +427,7 @@ extra diagnostics line"#; #[test] fn daemon_command_preview_uses_placeholder_token() { let preview = daemon_command_preview( - Path::new("/tmp/codex_monitor_daemon"), + Path::new("/tmp/opencode_monitor_daemon"), Path::new("/tmp/data-dir"), true, ); diff --git a/src-tauri/src/tailscale/daemon_commands.rs b/src-tauri/src/tailscale/daemon_commands.rs index 33f208954d..acb21792e2 100644 --- a/src-tauri/src/tailscale/daemon_commands.rs +++ b/src-tauri/src/tailscale/daemon_commands.rs @@ -3,7 +3,7 @@ use super::rpc_client::{ }; use super::*; -const EXPECTED_DAEMON_NAME: &str = "codex-monitor-daemon"; +const EXPECTED_DAEMON_NAME: &str = "opencode-monitor-daemon"; const EXPECTED_DAEMON_MODE: &str = "tcp"; const CURRENT_APP_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -431,7 +431,7 @@ mod tests { version: version.to_string(), pid: Some(42), mode: EXPECTED_DAEMON_MODE.to_string(), - binary_path: Some("/tmp/codex-monitor-daemon".to_string()), + binary_path: Some("/tmp/opencode-monitor-daemon".to_string()), } } diff --git a/src-tauri/src/tray.rs b/src-tauri/src/tray.rs index 18dbd26dc2..eb4bef5462 100644 --- a/src-tauri/src/tray.rs +++ b/src-tauri/src/tray.rs @@ -15,7 +15,7 @@ use tauri::{Emitter, Manager, Runtime}; const RECENT_THREADS_SECTION_LIMIT: usize = 3; #[cfg(target_os = "macos")] -const TRAY_ID: &str = "codex-monitor-tray"; +const TRAY_ID: &str = "opencode-monitor-tray"; #[cfg(target_os = "macos")] const TRAY_QUIT_ID: &str = "tray_quit"; #[cfg(target_os = "macos")] @@ -119,7 +119,7 @@ pub(crate) fn initialize( let menu = build_tray_menu(app, state)?; let builder = TrayIconBuilder::with_id(TRAY_ID) .menu(&menu) - .tooltip("Codex Monitor") + .tooltip("OpenCode Monitor") .show_menu_on_left_click(true) .icon(load_tray_icon()?) .icon_as_template(true) diff --git a/src-tauri/src/types.rs b/src-tauri/src/types.rs index 6b595106b5..317397b3a5 100644 --- a/src-tauri/src/types.rs +++ b/src-tauri/src/types.rs @@ -377,10 +377,10 @@ pub(crate) struct RemoteBackendTarget { #[derive(Debug, Serialize, Deserialize, Clone)] pub(crate) struct AppSettings { - #[serde(default, rename = "codexBin")] - pub(crate) codex_bin: Option, - #[serde(default, rename = "codexArgs")] - pub(crate) codex_args: Option, + #[serde(default, rename = "opencodeBin")] + pub(crate) opencode_bin: Option, + #[serde(default, rename = "opencodeArgs")] + pub(crate) opencode_args: Option, #[serde(default, rename = "backendMode")] pub(crate) backend_mode: BackendMode, #[serde(default, rename = "remoteBackendProvider")] @@ -1123,8 +1123,8 @@ fn default_selected_open_app_id() -> String { impl Default for AppSettings { fn default() -> Self { Self { - codex_bin: None, - codex_args: None, + opencode_bin: None, + opencode_args: None, backend_mode: default_backend_mode(), remote_backend_provider: RemoteBackendProvider::Tcp, remote_backend_host: default_remote_backend_host(), @@ -1213,7 +1213,7 @@ mod tests { #[test] fn app_settings_defaults_from_empty_json() { let settings: AppSettings = serde_json::from_str("{}").expect("settings deserialize"); - assert!(settings.codex_bin.is_none()); + assert!(settings.opencode_bin.is_none()); let expected_backend_mode = if cfg!(target_os = "ios") { BackendMode::Remote } else { diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index d257604803..94a3ec297f 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -182,8 +182,8 @@ mod tests { r"\\?\Volume{01234567-89ab-cdef-0123-456789abcdef}\repo" ); assert_eq!( - normalize_windows_namespace_path(r"\\.\pipe\codex-monitor"), - r"\\.\pipe\codex-monitor" + normalize_windows_namespace_path(r"\\.\pipe\opencode-monitor"), + r"\\.\pipe\opencode-monitor" ); } } diff --git a/src-tauri/src/workspaces/commands.rs b/src-tauri/src/workspaces/commands.rs index 4f8166e75f..bcb7d56b49 100644 --- a/src-tauri/src/workspaces/commands.rs +++ b/src-tauri/src/workspaces/commands.rs @@ -17,7 +17,7 @@ use super::worktree::{ }; use crate::backend::app_server::WorkspaceSession; -use crate::codex::spawn_workspace_session; +use crate::opencode::spawn_workspace_session; use crate::git_utils::resolve_git_root; use crate::remote_backend; use crate::shared::{workspace_rpc, workspaces_core}; @@ -28,10 +28,10 @@ fn spawn_with_app( app: &AppHandle, entry: WorkspaceEntry, default_bin: Option, - codex_args: Option, - codex_home: Option, + opencode_args: Option, + opencode_home: Option, ) -> impl std::future::Future, String>> { - spawn_workspace_session(entry, default_bin, codex_args, app.clone(), codex_home) + spawn_workspace_session(entry, default_bin, opencode_args, app.clone(), opencode_home) } fn workspace_remote_params(request: &T) -> Result { @@ -90,30 +90,30 @@ pub(crate) async fn list_workspaces( } #[tauri::command] -pub(crate) async fn set_workspace_runtime_codex_args( +pub(crate) async fn set_workspace_runtime_opencode_args( workspace_id: String, - codex_args: Option, + opencode_args: Option, state: State<'_, AppState>, app: AppHandle, -) -> Result { +) -> Result { if remote_backend::is_remote_mode(&*state).await { - let request = workspace_rpc::SetWorkspaceRuntimeCodexArgsRequest { + let request = workspace_rpc::SetWorkspaceRuntimeOpenCodeArgsRequest { workspace_id, - codex_args, + opencode_args, }; let response = remote_backend::call_remote( &*state, app, - "set_workspace_runtime_codex_args", + "set_workspace_runtime_opencode_args", workspace_remote_params(&request)?, ) .await?; return serde_json::from_value(response).map_err(|err| err.to_string()); } - workspaces_core::set_workspace_runtime_codex_args_core( + workspaces_core::set_workspace_runtime_opencode_args_core( workspace_id, - codex_args, + opencode_args, &state.workspaces, &state.sessions, &state.app_settings, @@ -167,8 +167,8 @@ pub(crate) async fn add_workspace( &state.sessions, &state.app_settings, &state.storage_path, - |entry, default_bin, codex_args, codex_home| { - spawn_with_app(&app, entry, default_bin, codex_args, codex_home) + |entry, default_bin, opencode_args, opencode_home| { + spawn_with_app(&app, entry, default_bin, opencode_args, opencode_home) }, ) .await @@ -207,8 +207,8 @@ pub(crate) async fn add_workspace_from_git_url( &state.sessions, &state.app_settings, &state.storage_path, - |entry, default_bin, codex_args, codex_home| { - spawn_with_app(&app, entry, default_bin, codex_args, codex_home) + |entry, default_bin, opencode_args, opencode_home| { + spawn_with_app(&app, entry, default_bin, opencode_args, opencode_home) }, ) .await @@ -230,8 +230,8 @@ pub(crate) async fn add_clone( &state.sessions, &state.app_settings, &state.storage_path, - |entry, default_bin, codex_args, codex_home| { - spawn_with_app(&app, entry, default_bin, codex_args, codex_home) + |entry, default_bin, opencode_args, opencode_home| { + spawn_with_app(&app, entry, default_bin, opencode_args, opencode_home) }, ) .await @@ -292,8 +292,8 @@ pub(crate) async fn add_worktree( run_git_command_owned(repo, args_owned) }) }, - |entry, default_bin, codex_args, codex_home| { - spawn_with_app(&app, entry, default_bin, codex_args, codex_home) + |entry, default_bin, opencode_args, opencode_home| { + spawn_with_app(&app, entry, default_bin, opencode_args, opencode_home) }, ) .await @@ -474,8 +474,8 @@ pub(crate) async fn rename_worktree( run_git_command_owned(repo, args_owned) }) }, - |entry, default_bin, codex_args, codex_home| { - spawn_with_app(&app, entry, default_bin, codex_args, codex_home) + |entry, default_bin, opencode_args, opencode_home| { + spawn_with_app(&app, entry, default_bin, opencode_args, opencode_home) }, ) .await @@ -578,8 +578,8 @@ pub(crate) async fn update_workspace_settings( |workspaces, workspace_id, next_settings| { apply_workspace_settings_update(workspaces, workspace_id, next_settings) }, - |entry, default_bin, codex_args, codex_home| { - spawn_with_app(&app, entry, default_bin, codex_args, codex_home) + |entry, default_bin, opencode_args, opencode_home| { + spawn_with_app(&app, entry, default_bin, opencode_args, opencode_home) }, ) .await @@ -608,8 +608,8 @@ pub(crate) async fn connect_workspace( &state.workspaces, &state.sessions, &state.app_settings, - |entry, default_bin, codex_args, codex_home| { - spawn_with_app(&app, entry, default_bin, codex_args, codex_home) + |entry, default_bin, opencode_args, opencode_home| { + spawn_with_app(&app, entry, default_bin, opencode_args, opencode_home) }, ) .await diff --git a/src-tauri/src/workspaces/macos.rs b/src-tauri/src/workspaces/macos.rs index b98a1a29bb..41129330f4 100644 --- a/src-tauri/src/workspaces/macos.rs +++ b/src-tauri/src/workspaces/macos.rs @@ -155,7 +155,7 @@ fn temp_png_path(app_name: &str) -> PathBuf { .chars() .filter(|ch| ch.is_ascii_alphanumeric()) .collect::(); - std::env::temp_dir().join(format!("codex-monitor-icon-{safe_name}-{ts}.png")) + std::env::temp_dir().join(format!("opencode-monitor-icon-{safe_name}-{ts}.png")) } #[cfg(target_os = "macos")] diff --git a/src-tauri/src/workspaces/tests.rs b/src-tauri/src/workspaces/tests.rs index 84208dfd10..a267e085ca 100644 --- a/src-tauri/src/workspaces/tests.rs +++ b/src-tauri/src/workspaces/tests.rs @@ -102,7 +102,7 @@ fn sanitize_clone_dir_name_allows_safe_chars() { #[test] fn build_clone_destination_path_sanitizes_and_uniquifies() { - let temp_dir = std::env::temp_dir().join(format!("codex-monitor-test-{}", Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("opencode-monitor-test-{}", Uuid::new_v4())); let copies_folder = temp_dir.join("copies"); std::fs::create_dir_all(&copies_folder).expect("create copies folder"); @@ -241,7 +241,7 @@ fn update_workspace_settings_persists_sort_and_group() { Some(r"\\?\I:\gpt-projects\worktrees"), ); - let temp_dir = std::env::temp_dir().join(format!("codex-monitor-test-{}", Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("opencode-monitor-test-{}", Uuid::new_v4())); std::fs::create_dir_all(&temp_dir).expect("create temp dir"); let path = PathBuf::from(temp_dir.join("workspaces.json")); let list: Vec<_> = workspaces.values().cloned().collect(); @@ -270,7 +270,7 @@ fn update_workspace_settings_persists_sort_and_group() { #[test] fn rename_worktree_preserves_custom_name() { run_async(async { - let temp_dir = std::env::temp_dir().join(format!("codex-monitor-test-{}", Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("opencode-monitor-test-{}", Uuid::new_v4())); let repo_path = temp_dir.join("repo"); std::fs::create_dir_all(&repo_path).expect("create repo path"); let worktree_path = temp_dir.join("worktrees").join("parent").join("old"); @@ -320,7 +320,7 @@ fn rename_worktree_preserves_custom_name() { |value| sanitize_worktree_name(value), |_, _, current| Ok(current.to_path_buf()), |_root, _args| async move { Ok(()) }, - |_entry, _default_bin, _codex_args, _codex_home| async move { + |_entry, _default_bin, _opencode_args, _opencode_home| async move { Err("spawn not expected".to_string()) }, ) @@ -341,7 +341,7 @@ fn rename_worktree_preserves_custom_name() { #[test] fn rename_worktree_updates_name_when_unmodified() { run_async(async { - let temp_dir = std::env::temp_dir().join(format!("codex-monitor-test-{}", Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("opencode-monitor-test-{}", Uuid::new_v4())); let repo_path = temp_dir.join("repo"); std::fs::create_dir_all(&repo_path).expect("create repo path"); let worktree_path = temp_dir.join("worktrees").join("parent").join("old"); @@ -391,7 +391,7 @@ fn rename_worktree_updates_name_when_unmodified() { |value| sanitize_worktree_name(value), |_, _, current| Ok(current.to_path_buf()), |_root, _args| async move { Ok(()) }, - |_entry, _default_bin, _codex_args, _codex_home| async move { + |_entry, _default_bin, _opencode_args, _opencode_home| async move { Err("spawn not expected".to_string()) }, ) @@ -405,7 +405,7 @@ fn rename_worktree_updates_name_when_unmodified() { #[test] fn rename_worktree_validates_worktree_root_before_branch_rename() { run_async(async { - let temp_dir = std::env::temp_dir().join(format!("codex-monitor-test-{}", Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("opencode-monitor-test-{}", Uuid::new_v4())); let repo_path = temp_dir.join("repo"); std::fs::create_dir_all(&repo_path).expect("create repo path"); let worktree_path = temp_dir.join("worktrees").join("parent").join("old"); @@ -468,7 +468,7 @@ fn rename_worktree_validates_worktree_root_before_branch_rename() { Ok(()) } }, - |_entry, _default_bin, _codex_args, _codex_home| async move { + |_entry, _default_bin, _opencode_args, _opencode_home| async move { Err("spawn not expected".to_string()) }, ) @@ -495,7 +495,7 @@ fn rename_worktree_validates_worktree_root_before_branch_rename() { #[cfg(target_os = "windows")] fn update_workspace_settings_core_sanitizes_namespace_worktrees_folder() { run_async(async { - let temp_dir = std::env::temp_dir().join(format!("codex-monitor-test-{}", Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("opencode-monitor-test-{}", Uuid::new_v4())); std::fs::create_dir_all(&temp_dir).expect("create temp dir"); let storage_path = temp_dir.join("workspaces.json"); @@ -524,7 +524,7 @@ fn update_workspace_settings_core_sanitizes_namespace_worktrees_folder() { &app_settings, &storage_path, apply_workspace_settings_update, - |_entry, _default_bin, _codex_args, _codex_home| async move { + |_entry, _default_bin, _opencode_args, _opencode_home| async move { Err("spawn not expected".to_string()) }, ) @@ -542,7 +542,7 @@ fn update_workspace_settings_core_sanitizes_namespace_worktrees_folder() { #[cfg(target_os = "windows")] fn rename_worktree_ignores_namespace_only_difference_in_worktree_root() { run_async(async { - let temp_dir = std::env::temp_dir().join(format!("codex-monitor-test-{}", Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("opencode-monitor-test-{}", Uuid::new_v4())); let repo_path = temp_dir.join("repo"); std::fs::create_dir_all(&repo_path).expect("create repo path"); let worktree_root = temp_dir.join("worktrees").join("parent"); @@ -605,7 +605,7 @@ fn rename_worktree_ignores_namespace_only_difference_in_worktree_root() { Ok(()) } }, - |_entry, _default_bin, _codex_args, _codex_home| async move { + |_entry, _default_bin, _opencode_args, _opencode_home| async move { Err("spawn not expected".to_string()) }, ) @@ -626,7 +626,7 @@ fn rename_worktree_ignores_namespace_only_difference_in_worktree_root() { #[test] fn remove_workspace_succeeds_when_parent_repo_folder_is_missing() { run_async(async { - let temp_dir = std::env::temp_dir().join(format!("codex-monitor-test-{}", Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("opencode-monitor-test-{}", Uuid::new_v4())); let parent_repo_path = temp_dir.join("deleted-parent-repo"); let child_path = temp_dir.join("worktrees").join("parent").join("feature-a"); std::fs::create_dir_all(&child_path).expect("create child path"); @@ -683,7 +683,7 @@ fn remove_workspace_succeeds_when_parent_repo_folder_is_missing() { #[test] fn remove_worktree_succeeds_when_parent_repo_folder_is_missing() { run_async(async { - let temp_dir = std::env::temp_dir().join(format!("codex-monitor-test-{}", Uuid::new_v4())); + let temp_dir = std::env::temp_dir().join(format!("opencode-monitor-test-{}", Uuid::new_v4())); let parent_repo_path = temp_dir.join("deleted-parent-repo"); let child_path = temp_dir.join("worktrees").join("parent").join("feature-b"); std::fs::create_dir_all(&child_path).expect("create child path"); diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index dd910c2a94..117371e893 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,8 +1,8 @@ { "$schema": "https://schema.tauri.app/config/2", - "productName": "Codex Monitor", + "productName": "OpenCode Monitor", "version": "0.7.68", - "identifier": "com.dimillian.codexmonitor", + "identifier": "com.dimillian.opencodemonitor", "build": { "beforeDevCommand": "npm run dev", "devUrl": "http://localhost:1420", @@ -13,7 +13,7 @@ "macOSPrivateApi": true, "windows": [ { - "title": "Codex Monitor", + "title": "OpenCode Monitor", "width": 1200, "height": 700, "minWidth": 360, @@ -65,7 +65,7 @@ "updater": { "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEY0QTgzQUU0QTc2MEVBNDMKUldSRDZtQ241RHFvOURJbm1KeC81aEZaOXlhZHlHd2NEZVpPVWs5NjdjOFNhUFEyZGJpTkV0S2YK", "endpoints": [ - "https://github.com/Dimillian/CodexMonitor/releases/latest/download/latest.json" + "https://github.com/Dimillian/OpenCodeMonitor/releases/latest/download/latest.json" ] } } diff --git a/src/features/about/components/AboutView.tsx b/src/features/about/components/AboutView.tsx index 12ab9696ef..f935a90f10 100644 --- a/src/features/about/components/AboutView.tsx +++ b/src/features/about/components/AboutView.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from "react"; import { getVersion } from "@tauri-apps/api/app"; import { openUrl } from "@tauri-apps/plugin-opener"; -const GITHUB_URL = "https://github.com/Dimillian/CodexMonitor"; +const GITHUB_URL = "https://github.com/Dimillian/OpenCodeMonitor"; const TWITTER_URL = "https://x.com/dimillian"; export function AboutView() { @@ -44,15 +44,15 @@ export function AboutView() { Codex Monitor icon -
Codex Monitor
+
OpenCode Monitor
{version ? `Version ${version}` : "Version —"}
- Monitor the situation of your Codex agents + Monitor the situation of your OpenCode agents
@@ -72,7 +72,7 @@ export function AboutView() { Twitter
-
Made with ♥ by Codex & Dimillian
+
Made with ♥ by OpenCode & Dimillian
); diff --git a/src/features/app/components/AppLayout.tsx b/src/features/app/components/AppLayout.tsx index 8846f9cc00..b91edebfaf 100644 --- a/src/features/app/components/AppLayout.tsx +++ b/src/features/app/components/AppLayout.tsx @@ -8,8 +8,8 @@ type AppLayoutProps = { isTablet: boolean; showHome: boolean; showGitDetail: boolean; - activeTab: "home" | "projects" | "codex" | "git" | "log"; - tabletTab: "codex" | "git" | "log"; + activeTab: "home" | "projects" | "opencode" | "git" | "log"; + tabletTab: "opencode" | "git" | "log"; centerMode: "chat" | "diff"; preloadGitDiffs: boolean; splitChatDiffView: boolean; @@ -33,7 +33,7 @@ type AppLayoutProps = { debugPanelNode: ReactNode; debugPanelFullNode: ReactNode; terminalDockNode: ReactNode; - compactEmptyCodexNode: ReactNode; + compactEmptyOpenCodeNode: ReactNode; compactEmptyGitNode: ReactNode; compactGitBackNode: ReactNode; onSidebarResizeStart: (event: MouseEvent) => void; @@ -72,7 +72,7 @@ export const AppLayout = memo(function AppLayout({ debugPanelNode, debugPanelFullNode, terminalDockNode, - compactEmptyCodexNode, + compactEmptyOpenCodeNode, compactEmptyGitNode, compactGitBackNode, onSidebarResizeStart, @@ -92,7 +92,7 @@ export const AppLayout = memo(function AppLayout({ activeTab={activeTab} activeWorkspace={activeWorkspace} showGitDetail={showGitDetail} - compactEmptyCodexNode={compactEmptyCodexNode} + compactEmptyOpenCodeNode={compactEmptyOpenCodeNode} compactEmptyGitNode={compactEmptyGitNode} compactGitBackNode={compactGitBackNode} topbarLeftNode={mainHeaderNode} diff --git a/src/features/app/components/ApprovalToasts.test.tsx b/src/features/app/components/ApprovalToasts.test.tsx index aaaa41ee6f..28ecdd666f 100644 --- a/src/features/app/components/ApprovalToasts.test.tsx +++ b/src/features/app/components/ApprovalToasts.test.tsx @@ -18,13 +18,13 @@ const approvals: ApprovalRequest[] = [ { workspace_id: "workspace-1", request_id: 1, - method: "codex/requestApproval/shell", + method: "opencode/requestApproval/shell", params: { command: "echo one" }, }, { workspace_id: "workspace-1", request_id: 2, - method: "codex/requestApproval/shell", + method: "opencode/requestApproval/shell", params: { command: "echo two" }, }, ]; diff --git a/src/features/app/components/ApprovalToasts.tsx b/src/features/app/components/ApprovalToasts.tsx index 67a7023990..1059b4aedf 100644 --- a/src/features/app/components/ApprovalToasts.tsx +++ b/src/features/app/components/ApprovalToasts.tsx @@ -69,7 +69,7 @@ export function ApprovalToasts({ .trim(); const methodLabel = (method: string) => { - const trimmed = method.replace(/^codex\/requestApproval\/?/, ""); + const trimmed = method.replace(/^opencode\/requestApproval\/?/, ""); return trimmed || method; }; diff --git a/src/features/app/components/MainApp.tsx b/src/features/app/components/MainApp.tsx index 1ce7cc5874..9cb7d1cd5e 100644 --- a/src/features/app/components/MainApp.tsx +++ b/src/features/app/components/MainApp.tsx @@ -45,7 +45,7 @@ import { useMainAppPromptActions } from "@app/hooks/useMainAppPromptActions"; import { useMainAppShellProps } from "@app/hooks/useMainAppShellProps"; import { useMainAppSidebarMenuOrchestration } from "@app/hooks/useMainAppSidebarMenuOrchestration"; import { useMainAppSettingsActions } from "@app/hooks/useMainAppSettingsActions"; -import { useMainAppThreadCodexState } from "@app/hooks/useMainAppThreadCodexState"; +import { useMainAppThreadOpenCodeState } from "@app/hooks/useMainAppThreadOpenCodeState"; import { useMainAppWorktreeState } from "@app/hooks/useMainAppWorktreeState"; import { useMainAppWorkspaceActions } from "@app/hooks/useMainAppWorkspaceActions"; import { useMainAppWorkspaceLifecycle } from "@app/hooks/useMainAppWorkspaceLifecycle"; @@ -68,8 +68,8 @@ import { useTraySessionUsage } from "@app/hooks/useTraySessionUsage"; import { useTauriEvent } from "@app/hooks/useTauriEvent"; import { useAppBootstrapOrchestration } from "@app/bootstrap/useAppBootstrapOrchestration"; import { - useThreadCodexBootstrapOrchestration, - useThreadCodexSyncOrchestration, + useThreadOpenCodeBootstrapOrchestration, + useThreadOpenCodeSyncOrchestration, useThreadSelectionHandlersOrchestration, useThreadUiOrchestration, } from "@app/orchestration/useThreadOrchestration"; @@ -78,7 +78,7 @@ import { useWorkspaceOrderingOrchestration, } from "@app/orchestration/useWorkspaceOrchestration"; import { useAppShellOrchestration } from "@app/orchestration/useLayoutOrchestration"; -import { normalizeCodexArgsInput } from "@/utils/codexArgsInput"; +import { normalizeOpenCodeArgsInput } from "@/utils/opencodeArgsInput"; import { subscribeTrayOpenThread } from "@services/events"; const SettingsView = lazy(() => @@ -92,7 +92,7 @@ export default function MainApp() { appSettings, setAppSettings, doctor, - codexUpdate, + opencodeUpdate, appSettingsLoading, reduceTransparency, setReduceTransparency, @@ -127,10 +127,10 @@ export default function MainApp() { setThreadListOrganizeMode, } = useThreadListSortKey(); const [activeTab, setActiveTab] = useState< - "home" | "projects" | "codex" | "git" | "log" - >("codex"); + "home" | "projects" | "opencode" | "git" | "log" + >("opencode"); const tabletTab = - activeTab === "projects" || activeTab === "home" ? "codex" : activeTab; + activeTab === "projects" || activeTab === "home" ? "opencode" : activeTab; const { workspaces, workspaceGroups, @@ -189,9 +189,9 @@ export default function MainApp() { [workspaces], ); const { - threadCodexParamsVersion, - getThreadCodexParams, - patchThreadCodexParams, + threadOpenCodeParamsVersion, + getThreadOpenCodeParams, + patchThreadOpenCodeParams, accessMode, setAccessMode, preferredModelId, @@ -202,14 +202,14 @@ export default function MainApp() { setPreferredServiceTier, preferredCollabModeId, setPreferredCollabModeId, - preferredCodexArgsOverride, - setPreferredCodexArgsOverride, - threadCodexSelectionKey, - setThreadCodexSelectionKey, + preferredOpenCodeArgsOverride, + setPreferredOpenCodeArgsOverride, + threadOpenCodeSelectionKey, + setThreadOpenCodeSelectionKey, activeThreadIdRef, pendingNewThreadSeedRef, - persistThreadCodexParams, - } = useThreadCodexBootstrapOrchestration({ + persistThreadOpenCodeParams, + } = useThreadOpenCodeBootstrapOrchestration({ activeWorkspaceId, }); const { @@ -291,7 +291,7 @@ export default function MainApp() { onDebug: addDebugEntry, preferredModelId, preferredEffort, - selectionKey: threadCodexSelectionKey, + selectionKey: threadOpenCodeSelectionKey, }); const { @@ -303,22 +303,22 @@ export default function MainApp() { activeWorkspace, enabled: appSettings.collaborationModesEnabled, preferredModeId: preferredCollabModeId, - selectionKey: threadCodexSelectionKey, + selectionKey: threadOpenCodeSelectionKey, onDebug: addDebugEntry, }); - const [selectedCodexArgsOverride, setSelectedCodexArgsOverride] = useState( + const [selectedOpenCodeArgsOverride, setSelectedOpenCodeArgsOverride] = useState( null, ); const [selectedServiceTier, setSelectedServiceTier] = useState< ServiceTier | null | undefined >(undefined); useEffect(() => { - setSelectedCodexArgsOverride(normalizeCodexArgsInput(preferredCodexArgsOverride)); - }, [preferredCodexArgsOverride, threadCodexSelectionKey]); + setSelectedOpenCodeArgsOverride(normalizeOpenCodeArgsInput(preferredOpenCodeArgsOverride)); + }, [preferredOpenCodeArgsOverride, threadOpenCodeSelectionKey]); useEffect(() => { setSelectedServiceTier(preferredServiceTier); - }, [preferredServiceTier, threadCodexSelectionKey]); + }, [preferredServiceTier, threadOpenCodeSelectionKey]); const { handleSelectModel, @@ -326,7 +326,7 @@ export default function MainApp() { handleSelectServiceTier, handleSelectCollaborationMode, handleSelectAccessMode, - handleSelectCodexArgsOverride, + handleSelectOpenCodeArgsOverride, } = useThreadSelectionHandlersOrchestration({ appSettingsLoading, setAppSettings, @@ -337,8 +337,8 @@ export default function MainApp() { setSelectedServiceTier, setSelectedCollaborationModeId, setAccessMode, - setSelectedCodexArgsOverride, - persistThreadCodexParams, + setSelectedOpenCodeArgsOverride, + persistThreadOpenCodeParams, }); const commitMessageModelId = useMemo( () => effectiveCommitMessageModelId(models, appSettings.commitMessageModelId), @@ -406,15 +406,15 @@ export default function MainApp() { const resolvedEffort = reasoningSupported ? selectedEffort : null; const { - handleThreadCodexMetadataDetected, - codexArgsOptions, - ensureWorkspaceRuntimeCodexArgs, + handleThreadOpenCodeMetadataDetected, + opencodeArgsOptions, + ensureWorkspaceRuntimeOpenCodeArgs, getThreadArgsBadge, - } = useMainAppThreadCodexState({ - appCodexArgs: appSettings.codexArgs, - selectedCodexArgsOverride, - getThreadCodexParams, - patchThreadCodexParams, + } = useMainAppThreadOpenCodeState({ + appOpenCodeArgs: appSettings.opencodeArgs, + selectedOpenCodeArgsOverride, + getThreadOpenCodeParams, + patchThreadOpenCodeParams, }); const { collaborationModePayload } = useCollaborationModeSelection({ @@ -504,7 +504,7 @@ export default function MainApp() { collaborationMode: collaborationModePayload, onSelectServiceTier: handleSelectServiceTier, accessMode, - ensureWorkspaceRuntimeCodexArgs, + ensureWorkspaceRuntimeOpenCodeArgs, reviewDeliveryMode: appSettings.reviewDeliveryMode, steerEnabled: appSettings.steerEnabled, threadTitleAutogenerationEnabled: appSettings.threadTitleAutogenerationEnabled, @@ -514,7 +514,7 @@ export default function MainApp() { customPrompts: prompts, onMessageActivity: handleThreadMessageActivity, threadSortKey: threadListSortKey, - onThreadCodexMetadataDetected: handleThreadCodexMetadataDetected, + onThreadOpenCodeMetadataDetected: handleThreadOpenCodeMetadataDetected, }); const { connectionState: remoteThreadConnectionState, reconnectLive } = useRemoteThreadLiveConnection({ @@ -663,7 +663,7 @@ export default function MainApp() { onDebug: addDebugEntry, }); - useThreadCodexSyncOrchestration({ + useThreadOpenCodeSyncOrchestration({ activeWorkspaceId, activeThreadId, appSettings: { @@ -671,16 +671,16 @@ export default function MainApp() { lastComposerModelId: appSettings.lastComposerModelId, lastComposerReasoningEffort: appSettings.lastComposerReasoningEffort, }, - threadCodexParamsVersion, - getThreadCodexParams, - patchThreadCodexParams, - setThreadCodexSelectionKey, + threadOpenCodeParamsVersion, + getThreadOpenCodeParams, + patchThreadOpenCodeParams, + setThreadOpenCodeSelectionKey, setAccessMode, setPreferredModelId, setPreferredEffort, setPreferredServiceTier, setPreferredCollabModeId, - setPreferredCodexArgsOverride, + setPreferredOpenCodeArgsOverride, activeThreadIdRef, pendingNewThreadSeedRef, selectedModelId, @@ -688,7 +688,7 @@ export default function MainApp() { selectedServiceTier, accessMode, selectedCollaborationModeId, - selectedCodexArgsOverride, + selectedOpenCodeArgsOverride, }); const { handleSetThreadListSortKey, handleRefreshAllWorkspaceThreads } = @@ -969,7 +969,7 @@ export default function MainApp() { handleWorktreeCreated, resolveCloneProjectContext, persistProjectCopiesFolder, - onCompactActivate: isCompact ? () => setActiveTab("codex") : undefined, + onCompactActivate: isCompact ? () => setActiveTab("opencode") : undefined, onWorkspacePromptError: (message, kind) => { addDebugEntry({ id: `${Date.now()}-client-add-${kind}-error`, @@ -1014,7 +1014,7 @@ export default function MainApp() { queueSaveSettings, handleToggleAutomaticAppUpdateChecks, doctor, - codexUpdate, + opencodeUpdate, updateWorkspaceSettings, scaleShortcutTitle, scaleShortcutText, @@ -1140,7 +1140,7 @@ export default function MainApp() { startThreadForWorkspace, sendUserMessage, sendUserMessageToThread, - seedThreadCodexParams: patchThreadCodexParams, + seedThreadOpenCodeParams: patchThreadOpenCodeParams, startFork, startReview, startResume, @@ -1329,7 +1329,7 @@ export default function MainApp() { accessMode, selectedServiceTier, selectedCollaborationModeId, - selectedCodexArgsOverride, + selectedOpenCodeArgsOverride, pendingNewThreadSeedRef, runWithDraftStart, handleComposerSend, @@ -1347,7 +1347,7 @@ export default function MainApp() { const handleOpenThreadLinkFromExternal = useCallback( (workspaceId: string, threadId: string) => { - setActiveTab("codex"); + setActiveTab("opencode"); handleOpenThreadLink(threadId, workspaceId); }, [handleOpenThreadLink, setActiveTab], @@ -1385,7 +1385,7 @@ export default function MainApp() { connectWorkspace, sendUserMessageToThread, setSelectedCollaborationModeId, - persistThreadCodexParams, + persistThreadOpenCodeParams, }); const { @@ -1480,12 +1480,12 @@ export default function MainApp() { shortcut: appSettings.archiveThreadShortcut, onTrigger: handleArchiveActiveThread, }); - const showCompactCodexThreadActions = + const showCompactOpenCodeThreadActions = Boolean(activeWorkspace) && isCompact && - ((isPhone && activeTab === "codex") || (isTablet && tabletTab === "codex")); + ((isPhone && activeTab === "opencode") || (isTablet && tabletTab === "opencode")); const showMobilePollingFetchStatus = - showCompactCodexThreadActions && + showCompactOpenCodeThreadActions && Boolean(activeWorkspace?.connected) && appSettings.backendMode === "remote" && remoteThreadConnectionState === "polling"; @@ -1495,7 +1495,7 @@ export default function MainApp() { const showGitInitBanner = Boolean(activeWorkspace) && !hasGitRootOverride && isMissingRepo(gitStatus.error); const displayNodes = useMainAppDisplayNodes({ - showCompactCodexThreadActions, + showCompactOpenCodeThreadActions, handleMobileThreadRefresh, mobileThreadRefreshLoading, centerMode, @@ -1707,9 +1707,9 @@ export default function MainApp() { selectedEffort, onSelectEffort: handleSelectEffort, reasoningSupported, - codexArgsOptions, - selectedCodexArgsOverride, - onSelectCodexArgsOverride: handleSelectCodexArgsOverride, + opencodeArgsOptions, + selectedOpenCodeArgsOverride, + onSelectOpenCodeArgsOverride: handleSelectOpenCodeArgsOverride, accessMode, onSelectAccessMode: handleSelectAccessMode, skills, @@ -1799,7 +1799,7 @@ export default function MainApp() { debugPanelNode, debugPanelFullNode, terminalDockNode, - compactEmptyCodexNode, + compactEmptyOpenCodeNode, compactEmptyGitNode, compactGitBackNode, } = useMainAppLayoutNodes(layoutSurfaces); @@ -1860,7 +1860,7 @@ export default function MainApp() { debugPanelNode, debugPanelFullNode, terminalDockNode, - compactEmptyCodexNode, + compactEmptyOpenCodeNode, compactEmptyGitNode, compactGitBackNode, onSidebarResizeStart, diff --git a/src/features/app/components/Sidebar.tsx b/src/features/app/components/Sidebar.tsx index 395d620101..8504f4a1f7 100644 --- a/src/features/app/components/Sidebar.tsx +++ b/src/features/app/components/Sidebar.tsx @@ -40,7 +40,7 @@ import { getUsageLabels } from "../utils/usageLabels"; import { formatRelativeTimeShort } from "../../../utils/time"; import type { ThreadStatusById } from "../../../utils/threadStatus"; -const COLLAPSED_GROUPS_STORAGE_KEY = "codexmonitor.collapsedGroups"; +const COLLAPSED_GROUPS_STORAGE_KEY = "opencodemonitor.collapsedGroups"; const UNGROUPED_COLLAPSE_ID = "__ungrouped__"; const ADD_MENU_WIDTH = 200; const ALL_THREADS_ADD_MENU_WIDTH = 220; @@ -359,7 +359,7 @@ export const Sidebar = memo(function Sidebar({ ? accountEmail : accountInfo?.type === "apikey" ? "API key" - : "Sign in to Codex"; + : "Sign in to OpenCode"; const accountActionLabel = accountEmail ? "Switch account" : "Sign in"; const showAccountSwitcher = Boolean(activeWorkspaceId); const accountSwitchDisabled = accountSwitching || !activeWorkspaceId; diff --git a/src/features/app/components/TabBar.tsx b/src/features/app/components/TabBar.tsx index 66c1997369..820ba34467 100644 --- a/src/features/app/components/TabBar.tsx +++ b/src/features/app/components/TabBar.tsx @@ -5,7 +5,7 @@ import House from "lucide-react/dist/esm/icons/house"; import MessagesSquare from "lucide-react/dist/esm/icons/messages-square"; import TerminalSquare from "lucide-react/dist/esm/icons/terminal-square"; -type TabKey = "home" | "projects" | "codex" | "git" | "log"; +type TabKey = "home" | "projects" | "opencode" | "git" | "log"; type TabBarProps = { activeTab: TabKey; @@ -15,7 +15,7 @@ type TabBarProps = { const tabs: { id: TabKey; label: string; icon: ReactNode }[] = [ { id: "home", label: "Home", icon: }, { id: "projects", label: "Projects", icon: }, - { id: "codex", label: "Codex", icon: }, + { id: "opencode", label: "OpenCode", icon: }, { id: "git", label: "Git", icon: }, { id: "log", label: "Log", icon: }, ]; diff --git a/src/features/app/components/TabletNav.tsx b/src/features/app/components/TabletNav.tsx index 625d51b37f..ec3c1313e5 100644 --- a/src/features/app/components/TabletNav.tsx +++ b/src/features/app/components/TabletNav.tsx @@ -3,7 +3,7 @@ import GitBranch from "lucide-react/dist/esm/icons/git-branch"; import MessagesSquare from "lucide-react/dist/esm/icons/messages-square"; import TerminalSquare from "lucide-react/dist/esm/icons/terminal-square"; -type TabletNavTab = "codex" | "git" | "log"; +type TabletNavTab = "opencode" | "git" | "log"; type TabletNavProps = { activeTab: TabletNavTab; @@ -11,7 +11,7 @@ type TabletNavProps = { }; const tabs: { id: TabletNavTab; label: string; icon: ReactNode }[] = [ - { id: "codex", label: "Codex", icon: }, + { id: "opencode", label: "OpenCode", icon: }, { id: "git", label: "Git", icon: }, { id: "log", label: "Log", icon: }, ]; diff --git a/src/features/app/components/WorkspaceCard.tsx b/src/features/app/components/WorkspaceCard.tsx index dae94c00b5..6a57946250 100644 --- a/src/features/app/components/WorkspaceCard.tsx +++ b/src/features/app/components/WorkspaceCard.tsx @@ -106,7 +106,7 @@ export function WorkspaceCard({ {!workspace.connected && ( { event.stopPropagation(); onConnectWorkspace(workspace); diff --git a/src/features/app/components/WorktreeCard.tsx b/src/features/app/components/WorktreeCard.tsx index b38e3da36b..dc7486f896 100644 --- a/src/features/app/components/WorktreeCard.tsx +++ b/src/features/app/components/WorktreeCard.tsx @@ -84,7 +84,7 @@ export function WorktreeCard({ {!worktree.connected && ( { event.stopPropagation(); onConnectWorkspace(worktree); diff --git a/src/features/app/hooks/useAccountSwitching.test.tsx b/src/features/app/hooks/useAccountSwitching.test.tsx index 4b124e4524..b9fa06f152 100644 --- a/src/features/app/hooks/useAccountSwitching.test.tsx +++ b/src/features/app/hooks/useAccountSwitching.test.tsx @@ -3,14 +3,14 @@ import { act } from "react"; import { createRoot } from "react-dom/client"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { AppServerEvent, AccountSnapshot } from "../../../types"; -import { cancelCodexLogin, runCodexLogin } from "../../../services/tauri"; +import { cancelOpenCodeLogin, runOpenCodeLogin } from "../../../services/tauri"; import { subscribeAppServerEvents } from "../../../services/events"; import { openUrl } from "@tauri-apps/plugin-opener"; import { useAccountSwitching } from "./useAccountSwitching"; vi.mock("../../../services/tauri", () => ({ - runCodexLogin: vi.fn(), - cancelCodexLogin: vi.fn(), + runOpenCodeLogin: vi.fn(), + cancelOpenCodeLogin: vi.fn(), })); vi.mock("../../../services/events", () => ({ @@ -71,7 +71,7 @@ function makeAccount(): AccountSnapshot { describe("useAccountSwitching", () => { it("opens the auth URL and refreshes after account/login/completed", async () => { - vi.mocked(runCodexLogin).mockResolvedValue({ + vi.mocked(runOpenCodeLogin).mockResolvedValue({ loginId: "login-1", authUrl: "https://example.com/auth", }); @@ -94,7 +94,7 @@ describe("useAccountSwitching", () => { await latest?.handleSwitchAccount(); }); - expect(runCodexLogin).toHaveBeenCalledWith("ws-1"); + expect(runOpenCodeLogin).toHaveBeenCalledWith("ws-1"); expect(openUrl).toHaveBeenCalledWith("https://example.com/auth"); expect(refreshAccountInfo).not.toHaveBeenCalled(); expect(refreshAccountRateLimits).not.toHaveBeenCalled(); @@ -122,11 +122,11 @@ describe("useAccountSwitching", () => { }); it("cancels and ignores a failed completion event", async () => { - vi.mocked(runCodexLogin).mockResolvedValue({ + vi.mocked(runOpenCodeLogin).mockResolvedValue({ loginId: "login-2", authUrl: "https://example.com/auth-2", }); - vi.mocked(cancelCodexLogin).mockResolvedValue({ canceled: true, status: "canceled" }); + vi.mocked(cancelOpenCodeLogin).mockResolvedValue({ canceled: true, status: "canceled" }); const refreshAccountInfo = vi.fn(); const refreshAccountRateLimits = vi.fn(); @@ -148,7 +148,7 @@ describe("useAccountSwitching", () => { await act(async () => { await latest?.handleCancelSwitchAccount(); }); - expect(cancelCodexLogin).toHaveBeenCalledWith("ws-1"); + expect(cancelOpenCodeLogin).toHaveBeenCalledWith("ws-1"); expect(latest?.accountSwitching).toBe(false); act(() => { @@ -172,13 +172,13 @@ describe("useAccountSwitching", () => { it("does not open the auth URL when canceled while login is pending", async () => { let resolveLogin: ((value: { loginId: string; authUrl: string }) => void) | null = null; - vi.mocked(runCodexLogin).mockImplementation( + vi.mocked(runOpenCodeLogin).mockImplementation( () => new Promise((resolve) => { resolveLogin = resolve; }), ); - vi.mocked(cancelCodexLogin).mockResolvedValue({ canceled: true, status: "canceled" }); + vi.mocked(cancelOpenCodeLogin).mockResolvedValue({ canceled: true, status: "canceled" }); const refreshAccountInfo = vi.fn(); const refreshAccountRateLimits = vi.fn(); @@ -208,7 +208,7 @@ describe("useAccountSwitching", () => { }); expect(openUrl).not.toHaveBeenCalled(); - expect(cancelCodexLogin).toHaveBeenCalledWith("ws-1"); + expect(cancelOpenCodeLogin).toHaveBeenCalledWith("ws-1"); expect(refreshAccountInfo).not.toHaveBeenCalled(); expect(refreshAccountRateLimits).not.toHaveBeenCalled(); expect(alertError).not.toHaveBeenCalled(); @@ -219,7 +219,7 @@ describe("useAccountSwitching", () => { }); it("resets switching state when login fails with a cancellation-shaped error", async () => { - vi.mocked(runCodexLogin).mockRejectedValue(new Error("request canceled")); + vi.mocked(runOpenCodeLogin).mockRejectedValue(new Error("request canceled")); const refreshAccountInfo = vi.fn(); const refreshAccountRateLimits = vi.fn(); @@ -240,7 +240,7 @@ describe("useAccountSwitching", () => { expect(latest?.accountSwitching).toBe(false); expect(alertError).not.toHaveBeenCalled(); expect(openUrl).not.toHaveBeenCalled(); - expect(cancelCodexLogin).not.toHaveBeenCalled(); + expect(cancelOpenCodeLogin).not.toHaveBeenCalled(); await act(async () => { root.unmount(); @@ -248,7 +248,7 @@ describe("useAccountSwitching", () => { }); it("clears switching state on workspace change and still completes the original login", async () => { - vi.mocked(runCodexLogin).mockResolvedValue({ + vi.mocked(runOpenCodeLogin).mockResolvedValue({ loginId: "login-ws-1", authUrl: "https://example.com/ws-1", }); diff --git a/src/features/app/hooks/useAccountSwitching.ts b/src/features/app/hooks/useAccountSwitching.ts index 8e42d2e851..04af20cbae 100644 --- a/src/features/app/hooks/useAccountSwitching.ts +++ b/src/features/app/hooks/useAccountSwitching.ts @@ -1,5 +1,5 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; -import { cancelCodexLogin, runCodexLogin } from "../../../services/tauri"; +import { cancelOpenCodeLogin, runOpenCodeLogin } from "../../../services/tauri"; import { subscribeAppServerEvents } from "../../../services/events"; import type { AccountSnapshot } from "../../../types"; import { getAppServerParams, getAppServerRawMethod } from "../../../utils/appServerEvents"; @@ -44,13 +44,13 @@ export function useAccountSwitching({ return accountByWorkspace[activeWorkspaceId] ?? null; }, [activeWorkspaceId, accountByWorkspace]); - const isCodexLoginCanceled = useCallback((error: unknown) => { + const isOpenCodeLoginCanceled = useCallback((error: unknown) => { const message = typeof error === "string" ? error : error instanceof Error ? error.message : ""; const normalized = message.toLowerCase(); return ( - normalized.includes("codex login canceled") || - normalized.includes("codex login cancelled") || + normalized.includes("opencode login canceled") || + normalized.includes("opencode login cancelled") || normalized.includes("request canceled") ); }, []); @@ -152,12 +152,12 @@ export function useAccountSwitching({ loginIdRef.current = null; loginWorkspaceIdRef.current = workspaceId; try { - const { loginId, authUrl } = await runCodexLogin(workspaceId); + const { loginId, authUrl } = await runOpenCodeLogin(workspaceId); if (accountSwitchCanceledRef.current) { loginIdRef.current = loginId; try { - await cancelCodexLogin(workspaceId); + await cancelOpenCodeLogin(workspaceId); } catch { // Best effort: the user already canceled. } @@ -171,7 +171,7 @@ export function useAccountSwitching({ loginIdRef.current = loginId; await openUrl(authUrl); } catch (error) { - if (accountSwitchCanceledRef.current || isCodexLoginCanceled(error)) { + if (accountSwitchCanceledRef.current || isOpenCodeLoginCanceled(error)) { setAccountSwitching(false); accountSwitchCanceledRef.current = false; loginIdRef.current = null; @@ -181,7 +181,7 @@ export function useAccountSwitching({ alertError(error); if (loginIdRef.current) { try { - await cancelCodexLogin(workspaceId); + await cancelOpenCodeLogin(workspaceId); } catch { // Ignore cancel errors here; we already surfaced the primary failure. } @@ -197,7 +197,7 @@ export function useAccountSwitching({ activeWorkspaceId, accountSwitching, alertError, - isCodexLoginCanceled, + isOpenCodeLoginCanceled, ]); const handleCancelSwitchAccount = useCallback(async () => { @@ -207,7 +207,7 @@ export function useAccountSwitching({ } accountSwitchCanceledRef.current = true; try { - await cancelCodexLogin(targetWorkspaceId); + await cancelOpenCodeLogin(targetWorkspaceId); } catch (error) { alertError(error); } finally { diff --git a/src/features/app/hooks/useAppServerEvents.test.tsx b/src/features/app/hooks/useAppServerEvents.test.tsx index 92bfb98e3b..1e5abf1f7d 100644 --- a/src/features/app/hooks/useAppServerEvents.test.tsx +++ b/src/features/app/hooks/useAppServerEvents.test.tsx @@ -72,7 +72,7 @@ describe("useAppServerEvents", () => { expect(listener).toBeTypeOf("function"); act(() => { - listener?.({ workspace_id: "ws-1", message: { method: "codex/connected" } }); + listener?.({ workspace_id: "ws-1", message: { method: "opencode/connected" } }); }); expect(handlers.onWorkspaceConnected).toHaveBeenCalledWith("ws-1"); @@ -242,7 +242,7 @@ describe("useAppServerEvents", () => { listener?.({ workspace_id: "ws-1", message: { - method: "codex/backgroundThread", + method: "opencode/backgroundThread", params: { threadId: "thread-2", action: "hide" }, }, }); diff --git a/src/features/app/hooks/useAppServerEvents.ts b/src/features/app/hooks/useAppServerEvents.ts index 6f21dafb47..48cf44c6e7 100644 --- a/src/features/app/hooks/useAppServerEvents.ts +++ b/src/features/app/hooks/useAppServerEvents.ts @@ -111,8 +111,8 @@ export const METHODS_ROUTED_IN_USE_APP_SERVER_EVENTS = [ "account/login/completed", "account/rateLimits/updated", "account/updated", - "codex/backgroundThread", - "codex/connected", + "opencode/backgroundThread", + "opencode/connected", "error", "hook/completed", "hook/started", @@ -186,7 +186,7 @@ export function useAppServerEvents(handlers: AppServerEventHandlers) { } const params = getAppServerParams(payload); - if (method === "codex/connected") { + if (method === "opencode/connected") { currentHandlers.onWorkspaceConnected?.(workspace_id); return; } @@ -358,7 +358,7 @@ export function useAppServerEvents(handlers: AppServerEventHandlers) { return; } - if (method === "codex/backgroundThread") { + if (method === "opencode/backgroundThread") { const threadId = String(params.threadId ?? params.thread_id ?? ""); const action = String(params.action ?? "hide"); if (threadId) { diff --git a/src/features/app/hooks/useAppSettingsController.ts b/src/features/app/hooks/useAppSettingsController.ts index e9e37cf7a2..e5974c775c 100644 --- a/src/features/app/hooks/useAppSettingsController.ts +++ b/src/features/app/hooks/useAppSettingsController.ts @@ -2,7 +2,7 @@ import { useThemePreference } from "../../layout/hooks/useThemePreference"; import { useTransparencyPreference } from "../../layout/hooks/useTransparencyPreference"; import { useUiScaleShortcuts } from "../../layout/hooks/useUiScaleShortcuts"; import { useAppSettings } from "../../settings/hooks/useAppSettings"; -import { runCodexUpdate } from "../../../services/tauri"; +import { runOpenCodeUpdate } from "../../../services/tauri"; export function useAppSettingsController() { const { @@ -34,8 +34,8 @@ export function useAppSettingsController() { saveSettings, queueSaveSettings, doctor, - codexUpdate: (codexBin: string | null, codexArgs: string | null) => - runCodexUpdate(codexBin, codexArgs), + opencodeUpdate: (opencodeBin: string | null, opencodeArgs: string | null) => + runOpenCodeUpdate(opencodeBin, opencodeArgs), appSettingsLoading, reduceTransparency, setReduceTransparency, diff --git a/src/features/app/hooks/useGitPanelController.test.tsx b/src/features/app/hooks/useGitPanelController.test.tsx index 7021cfd81e..c88f3aa8bc 100644 --- a/src/features/app/hooks/useGitPanelController.test.tsx +++ b/src/features/app/hooks/useGitPanelController.test.tsx @@ -27,7 +27,7 @@ vi.mock("../../git/hooks/useGitCommitDiffs", () => ({ const workspace: WorkspaceInfo = { id: "workspace-1", - name: "CodexMonitor", + name: "OpenCodeMonitor", path: "/tmp/codex-monitor", connected: true, settings: { sidebarCollapsed: false }, @@ -42,8 +42,8 @@ function makeProps(overrides?: Partial[ splitChatDiffView: false, isCompact: false, isTablet: false, - activeTab: "codex" as const, - tabletTab: "codex" as const, + activeTab: "opencode" as const, + tabletTab: "opencode" as const, setActiveTab: vi.fn(), prDiffs: [], prDiffsLoading: false, diff --git a/src/features/app/hooks/useGitPanelController.ts b/src/features/app/hooks/useGitPanelController.ts index fb23ab5eca..ed7729f924 100644 --- a/src/features/app/hooks/useGitPanelController.ts +++ b/src/features/app/hooks/useGitPanelController.ts @@ -34,9 +34,9 @@ export function useGitPanelController({ splitChatDiffView: boolean; isCompact: boolean; isTablet: boolean; - activeTab: "home" | "projects" | "codex" | "git" | "log"; - tabletTab: "codex" | "git" | "log"; - setActiveTab: (tab: "home" | "projects" | "codex" | "git" | "log") => void; + activeTab: "home" | "projects" | "opencode" | "git" | "log"; + tabletTab: "opencode" | "git" | "log"; + setActiveTab: (tab: "home" | "projects" | "opencode" | "git" | "log") => void; prDiffs: GitHubPullRequestDiff[]; prDiffsLoading: boolean; prDiffsError: string | null; diff --git a/src/features/app/hooks/useLayoutController.ts b/src/features/app/hooks/useLayoutController.ts index 41faf0ccb7..37ba1cb8c8 100644 --- a/src/features/app/hooks/useLayoutController.ts +++ b/src/features/app/hooks/useLayoutController.ts @@ -12,7 +12,7 @@ export function useLayoutController({ toggleTerminalShortcut, }: { activeWorkspaceId: string | null; - setActiveTab: (tab: "home" | "projects" | "codex" | "git" | "log") => void; + setActiveTab: (tab: "home" | "projects" | "opencode" | "git" | "log") => void; setDebugOpen: (value: boolean | ((prev: boolean) => boolean)) => void; toggleDebugPanelShortcut: string | null; toggleTerminalShortcut: string | null; diff --git a/src/features/app/hooks/useMainAppComposerWorkspaceState.ts b/src/features/app/hooks/useMainAppComposerWorkspaceState.ts index 247e8a75b9..45210f61d2 100644 --- a/src/features/app/hooks/useMainAppComposerWorkspaceState.ts +++ b/src/features/app/hooks/useMainAppComposerWorkspaceState.ts @@ -23,8 +23,8 @@ type UseMainAppComposerWorkspaceStateArgs = { centerMode: "chat" | "diff"; isCompact: boolean; isTablet: boolean; - activeTab: "home" | "projects" | "codex" | "git" | "log"; - tabletTab: "codex" | "git" | "log"; + activeTab: "home" | "projects" | "opencode" | "git" | "log"; + tabletTab: "opencode" | "git" | "log"; filePanelMode: "git" | "files" | "prompts"; rightPanelCollapsed: boolean; }; @@ -75,8 +75,8 @@ type UseMainAppComposerWorkspaceStateArgs = { sendUserMessage: Parameters[0]["sendUserMessage"]; sendUserMessageToThread: Parameters[0]["sendUserMessageToThread"] & Parameters[0]["sendUserMessageToThread"]; - seedThreadCodexParams: NonNullable< - Parameters[0]["seedThreadCodexParams"] + seedThreadOpenCodeParams: NonNullable< + Parameters[0]["seedThreadOpenCodeParams"] >; startFork: Parameters[0]["startFork"]; startReview: Parameters[0]["startReview"]; @@ -137,7 +137,7 @@ export function useMainAppComposerWorkspaceState({ startThreadForWorkspace, sendUserMessage, sendUserMessageToThread, - seedThreadCodexParams, + seedThreadOpenCodeParams, startFork, startReview, startResume, @@ -155,7 +155,7 @@ export function useMainAppComposerWorkspaceState({ const showComposer = (!isCompact ? centerMode === "chat" || centerMode === "diff" - : (isTablet ? tabletTab : activeTab) === "codex") && !showWorkspaceHome; + : (isTablet ? tabletTab : activeTab) === "opencode") && !showWorkspaceHome; const { files, isLoading: isFilesLoading, setFileAutocompleteActive } = useWorkspaceFileListing({ @@ -254,7 +254,7 @@ export function useMainAppComposerWorkspaceState({ effort: resolvedEffort, serviceTier: selectedServiceTier, collaborationMode: collaborationModePayload, - seedThreadCodexParams, + seedThreadOpenCodeParams, addWorktreeAgent, connectWorkspace, startThreadForWorkspace, diff --git a/src/features/app/hooks/useMainAppDisplayNodes.tsx b/src/features/app/hooks/useMainAppDisplayNodes.tsx index 69b03d8b91..d897816932 100644 --- a/src/features/app/hooks/useMainAppDisplayNodes.tsx +++ b/src/features/app/hooks/useMainAppDisplayNodes.tsx @@ -4,7 +4,7 @@ import { MainHeaderActions } from "@app/components/MainHeaderActions"; import { WorkspaceHome } from "@/features/workspaces/components/WorkspaceHome"; type UseMainAppDisplayNodesArgs = { - showCompactCodexThreadActions: boolean; + showCompactOpenCodeThreadActions: boolean; handleMobileThreadRefresh: () => void; mobileThreadRefreshLoading: boolean; centerMode: "chat" | "diff"; @@ -17,7 +17,7 @@ type UseMainAppDisplayNodesArgs = { }; export function useMainAppDisplayNodes({ - showCompactCodexThreadActions, + showCompactOpenCodeThreadActions, handleMobileThreadRefresh, mobileThreadRefreshLoading, centerMode, @@ -30,7 +30,7 @@ export function useMainAppDisplayNodes({ }: UseMainAppDisplayNodesArgs) { const mainHeaderActionsNode = ( <> - {showCompactCodexThreadActions ? ( + {showCompactOpenCodeThreadActions ? (
Leave empty to use the system PATH resolution.
-