From e0767135a5fbe9de4d3419ddf52545771f733b1f Mon Sep 17 00:00:00 2001 From: DEV MASTER <53788141+STIFLEUR390@users.noreply.github.com> Date: Sat, 16 May 2026 22:24:46 +0100 Subject: [PATCH 1/5] docs: add migration-plan and reference files for Codex-to-OpenCode migration Create 11-file migration plan in migration-plan/ covering architecture comparison, rename patterns, Rust backend, frontend, config adaptation, daemon RPC, docs/scripts/CI, optimizations, testing strategy, and execution order. Add opencode_ai_llms.txt and developers_openai_codex_llms.txt as reference context files. --- developers_openai_codex_llms.txt | 1063 +++++++++++++++++ migration-plan/00-summary.md | 55 + migration-plan/01-architecture.md | 131 +++ migration-plan/02-categories-changes.md | 101 ++ migration-plan/03-rename-patterns.md | 155 +++ migration-plan/04-rust-backend-plan.md | 225 ++++ migration-plan/05-frontend-plan.md | 286 +++++ migration-plan/06-config-adaptation.md | 167 +++ migration-plan/07-daemon-rpc-plan.md | 193 ++++ migration-plan/08-docs-scripts-ci.md | 234 ++++ migration-plan/09-optimizations.md | 127 ++ migration-plan/10-testing-strategy.md | 197 ++++ migration-plan/11-execution-order.md | 231 ++++ opencode_ai_llms.txt | 1401 +++++++++++++++++++++++ 14 files changed, 4566 insertions(+) create mode 100644 developers_openai_codex_llms.txt create mode 100644 migration-plan/00-summary.md create mode 100644 migration-plan/01-architecture.md create mode 100644 migration-plan/02-categories-changes.md create mode 100644 migration-plan/03-rename-patterns.md create mode 100644 migration-plan/04-rust-backend-plan.md create mode 100644 migration-plan/05-frontend-plan.md create mode 100644 migration-plan/06-config-adaptation.md create mode 100644 migration-plan/07-daemon-rpc-plan.md create mode 100644 migration-plan/08-docs-scripts-ci.md create mode 100644 migration-plan/09-optimizations.md create mode 100644 migration-plan/10-testing-strategy.md create mode 100644 migration-plan/11-execution-order.md create mode 100644 opencode_ai_llms.txt diff --git a/developers_openai_codex_llms.txt b/developers_openai_codex_llms.txt new file mode 100644 index 0000000000..eb6365af54 --- /dev/null +++ b/developers_openai_codex_llms.txt @@ -0,0 +1,1063 @@ +### Windows Sandbox Setup Start + +Source: https://developers.openai.com/codex/app-server + +Initiates the Windows sandbox setup process asynchronously. + +```APIDOC +## windowsSandbox/setupStart + +### Description +Custom Windows clients can trigger sandbox setup asynchronously instead of blocking on startup checks. This method starts the setup process in the background. + +### Method +POST + +### Endpoint +/windowsSandbox/setupStart + +### Parameters +#### Request Body +- **mode** (string) - Required - The sandbox setup mode. Can be `elevated` or `unelevated`. + +### Request Example +```json +{ + "method": "windowsSandbox/setupStart", + "id": 53, + "params": { "mode": "elevated" } +} +``` + +### Response +#### Success Response (200) +- **started** (boolean) - Indicates whether the setup process was successfully started. + +#### Response Example +```json +{ + "id": 53, + "result": { "started": true } +} +``` +``` + +-------------------------------- + +### Install Tools and Dependencies with Setup Scripts + +Source: https://developers.openai.com/codex/cloud/environments + +Use setup scripts to install custom tools like type checkers and manage project dependencies with package managers like Poetry and pnpm. Commands like `export` in setup scripts do not persist to the agent phase. + +```bash +# Install type checker +pip install pyright + +# Install dependencies +poetry install --with test +pnpm install +``` + +-------------------------------- + +### Install Curated Skill using Skill Installer + +Source: https://developers.openai.com/codex/skills/create-skill + +Install a curated skill for local use with the `$skill-installer` command. This is useful for local setup and experimentation. For example, to install the `$linear` skill. + +```bash +$skill-installer linear + +``` + +-------------------------------- + +### Start Windows Sandbox Setup + +Source: https://developers.openai.com/codex/app-server + +Initiates the Windows sandbox setup process in either `elevated` or `unelevated` mode. This operation returns quickly and later emits a completion event. + +```APIDOC +## windowsSandbox/setupStart + +### Description +Starts Windows sandbox setup for `elevated` or `unelevated` mode; returns quickly and later emits `windowsSandbox/setupCompleted`. + +### Method +POST + +### Endpoint +/windowsSandbox/setupStart + +### Request Body +- **mode** (string) - Required - The setup mode. Allowed values: `"elevated"`, `"unelevated"`. +``` + +-------------------------------- + +### Install Default Linux Distribution and Start WSL Shell + +Source: https://developers.openai.com/codex/windows + +Install the default Linux distribution (e.g., Ubuntu) and then start a shell within the Windows Subsystem for Linux. These commands are run from an elevated PowerShell or Windows Terminal. + +```powershell +# Install default Linux distribution (like Ubuntu) +wsl --install + +# Start a shell inside Windows Subsystem for Linux +wsl +``` + +-------------------------------- + +### Start Windows Sandbox Setup + +Source: https://developers.openai.com/codex/app-server + +Initiates the Windows sandbox setup process asynchronously. Supports 'elevated' or 'unelevated' modes. A 'windowsSandbox/setupCompleted' notification is emitted upon completion. + +```json +{ "method": "windowsSandbox/setupStart", "id": 53, "params": { "mode": "elevated" } } +``` + +```json +{ "id": 53, "result": { "started": true } } +``` + +```json +{ "method": "windowsSandbox/setupCompleted", "params": { "mode": "elevated", "success": true, "error": null } } +``` + +-------------------------------- + +### Install Dependencies and Build TypeScript Project + +Source: https://developers.openai.com/codex/app/local-environments + +Use this setup script for TypeScript projects to install dependencies and perform an initial build. It ensures the project is ready when a new worktree is created. + +```bash +npm install +npm run build +``` + +-------------------------------- + +### Complete Plugin Manifest Example + +Source: https://developers.openai.com/codex/plugins/build + +This is a comprehensive example of a `plugin.json` manifest file. It includes fields for package metadata, pointers to bundled components like skills, apps, and MCP servers, and detailed interface configurations for install surfaces. + +```json +{ + "name": "my-plugin", + "version": "0.1.0", + "description": "Bundle reusable skills and app integrations.", + "author": { + "name": "Your team", + "email": "team@example.com", + "url": "https://example.com" + }, + "homepage": "https://example.com/plugins/my-plugin", + "repository": "https://github.com/example/my-plugin", + "license": "MIT", + "keywords": ["research", "crm"], + "skills": "./skills/", + "mcpServers": "./.mcp.json", + "apps": "./.app.json", + "interface": { + "displayName": "My Plugin", + "shortDescription": "Reusable skills and apps", + "longDescription": "Distribute skills and app integrations together.", + "developerName": "Your team", + "category": "Productivity", + "capabilities": ["Read", "Write"], + "websiteURL": "https://example.com", + "privacyPolicyURL": "https://example.com/privacy", + "termsOfServiceURL": "https://example.com/terms", + "defaultPrompt": [ + "Use My Plugin to summarize new CRM notes.", + "Use My Plugin to triage new customer follow-ups." + ], + "brandColor": "#10A37F", + "composerIcon": "./assets/icon.png", + "logo": "./assets/logo.png", + "screenshots": ["./assets/screenshot-1.png"] + } +} +``` + +-------------------------------- + +### TypeScript SDK - Start Thread and Run Prompt + +Source: https://developers.openai.com/codex/sdk + +Demonstrates how to initialize the Codex SDK, start a new thread, and run an initial prompt to get a result. + +```APIDOC +## TypeScript SDK Usage + +### Description +Start a thread with Codex and run it with your prompt. + +### Method +```ts +const codex = new Codex(); +const thread = codex.startThread(); +const result = await thread.run( + "Make a plan to diagnose and fix the CI failures" +); + +console.log(result); +``` +``` + +-------------------------------- + +### Add Context7 MCP Server via CLI + +Source: https://developers.openai.com/codex/mcp + +Example of adding the Context7 MCP server using the CLI. This command installs and runs the server using npx. + +```bash +codex mcp add context7 -- npx -y @upstash/context7-mcp +``` + +-------------------------------- + +### Example Codex Configuration (config.toml) + +Source: https://developers.openai.com/codex/config-sample + +This TOML file lists the main keys Codex reads from `config.toml`. Adjust values for your specific setup. Root keys must appear before tables. + +```toml +# Codex example configuration (config.toml) +# +# This file lists the main keys Codex reads from config.toml, along with default +# behaviors, recommended examples, and concise explanations. Adjust as needed. +# +# Notes +# - Root keys must appear before tables in TOML. +# - Optional keys that default to "unset" are shown commented out with notes. +# - MCP servers, profiles, and model providers are examples; remove or edit. + +################################################################################ +# Core Model Selection +################################################################################ + +# Primary model used by Codex. Recommended example for most users: "gpt-5.5". +model = "gpt-5.5" + +# Communication style for supported models. Allowed values: none | friendly | pragmatic +# personality = "pragmatic" + +# Optional model override for /review. Default: unset (uses current session model). +# review_model = "gpt-5.5" + +# Provider id selected from [model_providers]. Default: "openai". +model_provider = "openai" + +# Default OSS provider for --oss sessions. When unset, Codex prompts. Default: unset. +# oss_provider = "ollama" + +# Preferred service tier. `fast` is honored only when enabled in [features]. +# service_tier = "flex" # fast | flex + +# Optional manual model metadata. When unset, Codex uses model or preset defaults. +# model_context_window = 128000 # tokens; default: auto for model +# model_auto_compact_token_limit = 64000 # tokens; unset uses model defaults +# tool_output_token_limit = 12000 # tokens stored per tool output +# model_catalog_json = "/absolute/path/to/models.json" # optional startup-only model catalog override +# background_terminal_max_timeout = 300000 # ms; max empty write_stdin poll window (default 5m) +# log_dir = "/absolute/path/to/codex-logs" # directory for Codex logs; default: "$CODEX_HOME/log" +# sqlite_home = "/absolute/path/to/codex-state" # optional SQLite-backed runtime state directory + +################################################################################ +# Reasoning & Verbosity (Responses API capable models) +################################################################################ + +# Reasoning effort: minimal | low | medium | high | xhigh +# model_reasoning_effort = "medium" + +# Optional override used when Codex runs in plan mode: none | minimal | low | medium | high | xhigh +# plan_mode_reasoning_effort = "high" + +# Reasoning summary: auto | concise | detailed | none +# model_reasoning_summary = "auto" + +# Text verbosity for GPT-5 family (Responses API): low | medium | high +# model_verbosity = "medium" + +# Force enable or disable reasoning summaries for current model. +# model_supports_reasoning_summaries = true + +################################################################################ +# Instruction Overrides +################################################################################ + +# Additional user instructions are injected before AGENTS.md. Default: unset. +# developer_instructions = "" + +# Inline override for the history compaction prompt. Default: unset. +# compact_prompt = "" + +# Override the default commit co-author trailer. Set to "" to disable it. +# commit_attribution = "Jane Doe " + +# Override built-in base instructions with a file path. Default: unset. +# model_instructions_file = "/absolute/or/relative/path/to/instructions.txt" + +# Load the compact prompt override from a file. Default: unset. +# experimental_compact_prompt_file = "/absolute/or/relative/path/to/compact_prompt.txt" + +################################################################################ +# Notifications +################################################################################ + +# External notifier program (argv array). When unset: disabled. +# notify = ["notify-send", "Codex"] + +################################################################################ +# Approval & Sandbox +################################################################################ + +# When to ask for command approval: +# - untrusted: only known-safe read-only commands auto-run; others prompt + +``` + +-------------------------------- + +### Example JSON-RPC Request + +Source: https://developers.openai.com/codex/app-server + +This is an example of a JSON-RPC 2.0 request message for starting a thread. + +```json +{ "method": "thread/start", "id": 10, "params": { "model": "gpt-5.4" } } +``` + +-------------------------------- + +### Configure Remote Codex Server with Capability Token + +Source: https://developers.openai.com/codex/cli/features + +Start the Codex app server with a capability token for authentication. This example assumes the token file is located at `$HOME/.codex/codex-app-server-token` and the server is accessible via TLS. + +```bash +# Remote host +TOKEN_FILE="$HOME/.codex/codex-app-server-token" +codex app-server \ + --listen ws://0.0.0.0:4500 \ + --ws-auth capability-token \ + --ws-token-file "$TOKEN_FILE" +``` + +-------------------------------- + +### Install a Skill with Skill Installer + +Source: https://developers.openai.com/codex/skills + +Use the `$skill-installer` command to add curated skills for local use. Restart Codex if a newly installed skill doesn't appear. + +```bash +$skill-installer linear +``` + +-------------------------------- + +### Set up Project Directory and API Key + +Source: https://developers.openai.com/codex/guides/agents-sdk + +Create a working directory for the project and store your OpenAI API key in a .env file. + +```bash +mkdir codex-workflows +cd codex-workflows +printf "OPENAI_API_KEY=sk-... +" > .env +``` + +-------------------------------- + +### Invoke App (turn/start) + +Source: https://developers.openai.com/codex/app-server + +Invoke an app by mentioning it in the text input and providing its path in a `mention` input item. This is the recommended way to interact with apps. + +```json +{ + "method": "turn/start", + "id": 51, + "params": { + "threadId": "thread-1", + "input": [ + { + "type": "text", + "text": "$demo-app Pull the latest updates from the team." + }, + { + "type": "mention", + "name": "Demo App", + "path": "app://demo-app" + } + ] + } +} +``` + +-------------------------------- + +### Integrate Codex with SDK in TypeScript + +Source: https://developers.openai.com/codex/changelog + +Use the Codex SDK in TypeScript to integrate the agent into your tools and workflows. This example demonstrates starting a thread and running commands. + +```typescript +import { Codex } from "@openai/codex-sdk"; + +const agent = new Codex(); +const thread = await agent.startThread(); + +const result = await thread.run("Explore this repo"); +console.log(result); + +const result2 = await thread.run("Propose changes"); +console.log(result2); + +``` + +-------------------------------- + +### Start Dev Container from CLI + +Source: https://developers.openai.com/codex/agent-approvals-security + +Use this command to start a Dev Container with a specific configuration from the command line. Ensure the workspace folder and config path are correct. + +```bash +devcontainer up --workspace-folder . --config .devcontainer/devcontainer.secure.json +``` + +-------------------------------- + +### Get Codex CLI Version + +Source: https://developers.openai.com/codex/app/troubleshooting + +Use this command to check the version of the Codex CLI installed on your system. This is useful for diagnosing issues where features work in the CLI but not the app. + +```bash +codex --version +``` + +-------------------------------- + +### Launch Codex MCP Server with Inspector + +Source: https://developers.openai.com/codex/guides/agents-sdk + +An alternative method to start a Codex MCP server using the Model Context Protocol Inspector. Ensure you have Node.js and npm installed. + +```bash +npx @modelcontextprotocol/inspector codex mcp-server +``` + +-------------------------------- + +### Initialize with Experimental API Enabled + +Source: https://developers.openai.com/codex/app-server + +Include `"experimentalApi": true` in the `capabilities` object to enable experimental features. Omitting `capabilities` or setting `experimentalApi` to `false` will keep you on the stable API surface. + +```json +{ + "method": "initialize", + "id": 1, + "params": { + "clientInfo": { + "name": "my_client", + "title": "My Client", + "version": "0.1.0" + }, + "capabilities": { + "experimentalApi": true + } + } +} +``` + +-------------------------------- + +### Plugin Structure Example + +Source: https://developers.openai.com/codex/changelog + +Illustrates the directory structure for a Codex plugin, including the required manifest and optional supporting files. + +```bash +my-plugin/ + .codex-plugin/ + plugin.json # Required: plugin manifest + skills/ # Optional: packaged skills + .app.json # Optional: app or connector mappings + .mcp.json # Optional: MCP server configuration + assets/ # Optional: icons, logos, screenshots + +``` + +-------------------------------- + +### Example Prompt: Fix Bugs + +Source: https://developers.openai.com/codex/quickstart + +This prompt guides Codex to find and fix bugs in a codebase with minimal, high-confidence changes. It outlines a disciplined method including reproduction, localization, fixing, and proving the fix. + +```text +Find and fix bugs in my codebase with minimal, high-confidence changes. + +Method (grounded + disciplined): +1) Reproduce: run tests/lint/build (or follow the existing repo scripts). If I provided an error, reproduce that exact failure. +2) Localize: identify the smallest set of files/lines involved (stack traces, failing tests, logs). +3) Fix: implement the minimal change that resolves the issue without refactors or unrelated cleanup. +4) Prove: add/update a focused test (or a tight repro) that fails before and passes after. + +Constraints: + +``` + +-------------------------------- + +### Start a turn (invoke a skill) + +Source: https://developers.openai.com/codex/app-server + +Explicitly invokes a skill by including `$` in the text input and adding a `skill` input item. The `skill-creator` example shows how to add a new skill for triaging flaky CI. + +```json +{ "method": "turn/start", "id": 33, "params": { + "threadId": "thr_123", + "input": [ + { "type": "text", "text": "$skill-creator Add a new skill for triaging flaky CI and include step-by-step usage." }, + { "type": "skill", "name": "skill-creator", "path": "/Users/me/.codex/skills/skill-creator/SKILL.md" } + ] +} } +``` + +```json +{ "id": 33, "result": { "turn": { "id": "turn_457", "status": "inProgress", "items": [], "error": null } } } +``` + +-------------------------------- + +### Start and Run Thread (Async Python) + +Source: https://developers.openai.com/codex/sdk + +Start a thread and run a prompt using the asynchronous Python SDK. Suitable for applications that are already using asyncio. + +```python +import asyncio + +from codex_app_server import AsyncCodex + + +async def main() -> None: + async with AsyncCodex() as codex: + thread = await codex.thread_start(model="gpt-5.4") + result = await thread.run("Implement the plan") + print(result.final_response) + + +asyncio.run(main()) +``` + +-------------------------------- + +### Example Prompt for Multi-Agent Review + +Source: https://developers.openai.com/codex/subagents + +An example prompt demonstrating how to orchestrate multiple agents for a comprehensive code review, including mapping code paths, identifying risks, and verifying framework APIs. + +```text +Review this branch against main. Have pr_explorer map the affected code paths, reviewer find real risks, and docs_researcher verify the framework APIs that the patch relies on. + +``` + +-------------------------------- + +### Node.js Client for Codex App Server + +Source: https://developers.openai.com/codex/app-server + +Example of a Node.js client connecting to the Codex app server via stdio. It demonstrates sending 'initialize', 'initialized', and 'thread/start' requests, and handling server responses to start a turn. + +```typescript +const proc = spawn("codex", ["app-server"], { + stdio: ["pipe", "pipe", "inherit"], +}); +const rl = readline.createInterface({ input: proc.stdout }); + +const send = (message: unknown) => { + proc.stdin.write(`${JSON.stringify(message)}\n`); +}; + +let threadId: string | null = null; + +rl.on("line", (line) => { + const msg = JSON.parse(line) as any; + console.log("server:", msg); + + if (msg.id === 1 && msg.result?.thread?.id && !threadId) { + threadId = msg.result.thread.id; + send({ + method: "turn/start", + id: 2, + params: { + threadId, + input: [{ type: "text", text: "Summarize this repo." }], + }, + }); + } +}); + +send({ + method: "initialize", + id: 0, + params: { + clientInfo: { + name: "my_product", + title: "My Product", + version: "0.1.0", + }, + }, +}); +send({ method: "initialized", params: {} }); +send({ method: "thread/start", id: 1, params: { model: "gpt-5.4" } }); +``` + +-------------------------------- + +### Autofix CI Failures with GitHub Actions + +Source: https://developers.openai.com/codex/noninteractive + +Automate the process of fixing CI workflow failures by triggering a follow-up workflow that uses Codex to propose and apply fixes. This example demonstrates the core steps for checkout, dependency installation, Codex execution, and pull request creation. + +```yaml +name: Codex auto-fix on CI failure + +on: + workflow_run: + workflows: ["CI"] + types: [completed] + +permissions: + contents: write + pull-requests: write + +jobs: + auto-fix: + if: ${{ github.event.workflow_run.conclusion == 'failure' }} + runs-on: ubuntu-latest + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} + FAILED_HEAD_SHA: ${{ github.event.workflow_run.head_sha }} + FAILED_HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }} + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ env.FAILED_HEAD_SHA }} + fetch-depth: 0 + + - uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Install dependencies + run: | + if [ -f package-lock.json ]; then npm ci; else npm i; fi + + - name: Install Codex + run: npm i -g @openai/codex + + - name: Authenticate Codex + run: codex login --api-key "$OPENAI_API_KEY" + + - name: Run Codex + run: | + codex exec --full-auto --sandbox workspace-write \ + "Read the repository, run the test suite, identify the minimal change needed to make all tests pass, implement only that change, and stop. Do not refactor unrelated files." + + - name: Verify tests + run: npm test --silent + + - name: Create pull request + if: success() + uses: peter-evans/create-pull-request@v6 + with: + branch: codex/auto-fix-${{ github.event.workflow_run.run_id }} + base: ${{ env.FAILED_HEAD_BRANCH }} + title: "Auto-fix failing CI via Codex" +``` + +-------------------------------- + +### Example Prompt: Build Snake Game + +Source: https://developers.openai.com/codex/quickstart + +Use this prompt to instruct Codex to build a classic Snake game within the current project. It includes specific scope, constraints, an implementation plan, and deliverables. + +```text +Build a classic Snake game in this repo. + +Scope & constraints: +- Implement ONLY the classic Snake loop: grid movement, growing snake, food spawn, score, game-over, restart. +- Reuse existing project tooling/frameworks; do NOT add new dependencies unless truly required. +- Keep UI minimal and consistent with the repo’s existing styles (no new design systems, no extra animations). + +Implementation plan: +1) Inspect the repo to find the right place to add a small interactive game (existing pages/routes/components). +2) Implement game state (snake positions, direction, food, score, tick timer) with deterministic, testable logic. +3) Render: simple grid + snake + food; support keyboard controls (arrow keys/WASD) and on-screen controls if mobile is present in the repo. +4) Add basic tests for the core game logic (movement, collisions, growth, food placement) if the repo has a test runner. + +Deliverables: +- A small set of files/changes with clear names. +- Short run instructions (how to start dev server + where to navigate). +- A brief checklist of what to manually verify (controls, pause/restart, boundaries). + +``` + +-------------------------------- + +### Install Node.js and Codex in WSL + +Source: https://developers.openai.com/codex/windows + +Install Node.js using nvm and then install and run Codex globally within your WSL shell. Ensure Node.js is installed in a new shell session after running the nvm install script. + +```bash +# https://learn.microsoft.com/en-us/windows/dev-environment/javascript/nodejs-on-wsl +# Install Node.js in WSL (via nvm) +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash + +# In a new tab or after exiting and running `wsl` again to install Node.js +nvm install 22 + +# Install and run Codex in WSL +npm i -g @openai/codex +codex +``` + +-------------------------------- + +### Install Codex CLI + +Source: https://developers.openai.com/codex/changelog + +Installs a specific version of the Codex CLI globally using npm. Ensure Node.js and npm are installed. + +```bash +$ npm install -g @openai/codex@0.123.0 + +``` + +-------------------------------- + +### Explain Service Protocol with CLI + +Source: https://developers.openai.com/codex/workflows + +Use this prompt in the CLI to understand a service's protocol, focusing on schema, request/response flow, required/optional fields, and backward compatibility. + +```text +I need to understand the protocol used by this service. Read @foo.ts @schema.ts and explain the schema and request/response flow. Focus on required vs optional fields and backward compatibility rules. +``` + +-------------------------------- + +### Install Codex CLI 0.122.0 + +Source: https://developers.openai.com/codex/changelog + +Installs the specified version of the Codex CLI globally using npm. Ensure Node.js and npm are installed. + +```bash +$ npm install -g @openai/codex@0.122.0 + +``` + +-------------------------------- + +### CLI Workflow: Iterate on UI with Live Updates + +Source: https://developers.openai.com/codex/workflows + +This workflow is for a rapid design-tweak-refresh loop. Start the dev server and use focused prompts to iterate on UI elements. + +```bash +codex +``` + +```bash +npm run dev +``` + +```text +Propose 2-3 styling improvements for the landing page. +``` + +```text +Go with option 2. + +Change only the header: +- make the typography more editorial +- increase whitespace +- ensure it still looks good on mobile +``` + +```text +Next iteration: reduce visual noise. +Keep the layout, but simplify colors and remove any redundant borders. +``` + +-------------------------------- + +### Install Codex CLI Version 0.124.0 + +Source: https://developers.openai.com/codex/changelog + +Install a specific version of the Codex CLI using npm. Ensure you have Node.js and npm installed. + +```bash +$ npm install -g @openai/codex@0.124.0 +``` + +-------------------------------- + +### Start Node.js Development Server + +Source: https://developers.openai.com/codex/app/local-environments + +Define this action for Node.js projects to quickly start the development server. It can be accessed from the Codex app top bar. + +```bash +npm start +``` + +-------------------------------- + +### Account Login Start + +Source: https://developers.openai.com/codex/app-server + +Initiates a login process using various authentication modes. + +```APIDOC +## account/login/start + +### Description +Begins the login process for different authentication modes. + +### Method +POST (assumed, based on JSON-RPC structure) + +### Endpoint +/rpc + +### Parameters +#### Request Body +- **method** (string) - Required - The method name, should be "account/login/start". +- **id** (number) - Required - A unique identifier for the request. +- **params** (object) - Required - Parameters for starting the login. + - **type** (string) - Required - The authentication mode to use (`apiKey`, `chatgpt`, `chatgptDeviceCode`, or `chatgptAuthTokens`). + - **apiKey** (string, optional) - The API key to use if `type` is "apiKey". + - **chatgpt** (object, optional) - Parameters for ChatGPT browser flow if `type` is "chatgpt". + - **chatgptDeviceCode** (object, optional) - Parameters for ChatGPT device-code flow if `type` is "chatgptDeviceCode". + - **chatgptAuthTokens** (object, optional) - Parameters for experimental external tokens if `type` is "chatgptAuthTokens". + - **accessToken** (string) - Required - The access token. + - **chatgptAccountId** (string) - Required - The ChatGPT account ID. + - **chatgptPlanType** (string, optional) - The ChatGPT plan type. + +### Request Example +```json +{ + "method": "account/login/start", + "id": 2, + "params": { + "type": "apiKey", + "apiKey": "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + } +} +``` + +### Response +#### Success Response (200) +- **id** (number) - The identifier for the request. +- **result** (object) - Details about the login process (e.g., `loginId` for cancellation, or device code information). +``` + +-------------------------------- + +### Install Codex CLI 0.119.0 + +Source: https://developers.openai.com/codex/changelog + +Installs version 0.119.0 of the OpenAI Codex CLI globally using npm. Ensure Node.js and npm are installed. + +```bash +$ npm install -g @openai/codex@0.119.0 + +``` + +-------------------------------- + +### CLI Workflow: Generate UI from Image + +Source: https://developers.openai.com/codex/workflows + +Use this workflow to generate UI components based on a screenshot. Provide the image and detailed constraints for implementation. + +```bash +codex +``` + +```text +Create a new dashboard based on this image. + +Constraints: +- Use react, vite, and tailwind. Write the code in typescript. +- Match spacing, typography, and layout as closely as possible. + +Deliverables: +- A new route/page that renders the UI +- Any small components needed +- README.md with instructions to run it locally +``` + +```text +Start the dev server and tell me the local URL/route to view the prototype. +``` + +-------------------------------- + +### Install Codex CLI 0.120.0 + +Source: https://developers.openai.com/codex/changelog + +Installs version 0.120.0 of the OpenAI Codex CLI globally using npm. Ensure Node.js and npm are installed. + +```bash +$ npm install -g @openai/codex@0.120.0 + +``` + +-------------------------------- + +### Install Git using winget + +Source: https://developers.openai.com/codex/app/windows + +Install Git on Windows using the winget package manager from PowerShell or cmd.exe. This is required for certain app features. + +```powershell +winget install Git.Git +``` + +-------------------------------- + +### Install Codex CLI 0.118.0 + +Source: https://developers.openai.com/codex/changelog + +Installs version 0.118.0 of the Codex CLI using npm. This command is used to update or install a specific version of the Codex command-line interface. + +```bash +$ npm install -g @openai/codex@0.118.0 + +``` + +-------------------------------- + +### Install Shell Completions + +Source: https://developers.openai.com/codex/cli/features + +Speed up everyday usage by installing generated completion scripts for your shell. Add the script to your shell configuration file for new sessions. + +```bash +codex completion bash +``` + +```bash +codex completion zsh +``` + +```bash +codex completion fish +``` + +-------------------------------- + +### Start Codex MCP Server + +Source: https://developers.openai.com/codex/guides/agents-sdk + +Command to start the Codex MCP server. + +```APIDOC +## Start Codex MCP Server + +### Description +Starts the Codex MCP server. + +### Command +```bash +codex mcp-server +``` +``` + +-------------------------------- + +### Initialize Request with Notification Opt-out (JSON) + +Source: https://developers.openai.com/codex/app-server + +Example of an initialize request that also specifies capabilities, including opting out of certain notifications. + +```json +{ + "method": "initialize", + "id": 1, + "params": { + "clientInfo": { + "name": "my_client", + "title": "My Client", + "version": "0.1.0" + }, + "capabilities": { + "experimentalApi": true, + "optOutNotificationMethods": ["thread/started", "item/agentMessage/delta"] + } + } +} +``` \ No newline at end of file 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 From 2739ed7923d36b639b2d147c7dcc7f429201fa2d Mon Sep 17 00:00:00 2001 From: DEV MASTER <53788141+STIFLEUR390@users.noreply.github.com> Date: Sat, 16 May 2026 23:39:18 +0100 Subject: [PATCH 2/5] refactor(project): rename codex to opencode across the entire codebase Rename all files, modules, types, functions, JSON-RPC methods, environment variables, and package identifiers from 'codex' to 'opencode' to reflect the rebranding from Codex to OpenCode. --- package.json | 2 +- src-tauri/Cargo.toml | 8 +- src-tauri/src/backend/app_server.rs | 56 +++--- ...r_daemon.rs => opencode_monitor_daemon.rs} | 180 +++++++++--------- .../rpc.rs | 2 +- .../rpc/codex.rs | 24 +-- .../rpc/daemon.rs | 0 .../rpc/dispatcher.rs | 0 .../rpc/git.rs | 0 .../rpc/prompts.rs | 0 .../rpc/workspace.rs | 8 +- .../transport.rs | 0 ...onctl.rs => opencode_monitor_daemonctl.rs} | 4 +- src-tauri/src/daemon_binary.rs | 8 +- src-tauri/src/files/io.rs | 12 +- src-tauri/src/files/mod.rs | 6 +- src-tauri/src/files/policy.rs | 8 +- src-tauri/src/lib.rs | 16 +- src-tauri/src/main.rs | 2 +- src-tauri/src/{codex => opencode}/args.rs | 28 +-- src-tauri/src/{codex => opencode}/config.rs | 20 +- src-tauri/src/{codex => opencode}/home.rs | 38 ++-- src-tauri/src/{codex => opencode}/mod.rs | 110 +++++------ src-tauri/src/remote_backend/mod.rs | 2 +- src-tauri/src/rules.rs | 4 +- src-tauri/src/settings/mod.rs | 6 +- src-tauri/src/shared/account.rs | 6 +- src-tauri/src/shared/agents_config_core.rs | 118 ++++++------ src-tauri/src/shared/config_toml_core.rs | 8 +- src-tauri/src/shared/files_core.rs | 10 +- src-tauri/src/shared/local_usage_core.rs | 22 +-- src-tauri/src/shared/mod.rs | 6 +- ...codex_aux_core.rs => opencode_aux_core.rs} | 14 +- .../{codex_core.rs => opencode_core.rs} | 62 +++--- ...update_core.rs => opencode_update_core.rs} | 24 +-- src-tauri/src/shared/prompts_core.rs | 14 +- src-tauri/src/shared/settings_core.rs | 8 +- src-tauri/src/shared/workspace_rpc.rs | 4 +- src-tauri/src/shared/workspaces_core.rs | 6 +- .../src/shared/workspaces_core/connect.rs | 20 +- .../workspaces_core/crud_persistence.rs | 34 ++-- .../src/shared/workspaces_core/helpers.rs | 8 +- ...codex_args.rs => runtime_opencode_args.rs} | 72 +++---- .../src/shared/workspaces_core/worktree.rs | 14 +- src-tauri/src/state.rs | 8 +- src-tauri/src/tailscale/core.rs | 2 +- src-tauri/src/tailscale/daemon_commands.rs | 2 +- src-tauri/src/types.rs | 14 +- src-tauri/src/workspaces/commands.rs | 52 ++--- src-tauri/src/workspaces/tests.rs | 10 +- src-tauri/tauri.conf.json | 6 +- src/features/about/components/AboutView.tsx | 2 +- src/features/app/components/AppLayout.tsx | 10 +- src/features/app/components/MainApp.tsx | 80 ++++---- src/features/app/components/Sidebar.tsx | 2 +- src/features/app/components/TabBar.tsx | 4 +- src/features/app/components/TabletNav.tsx | 4 +- .../app/hooks/useAccountSwitching.test.tsx | 28 +-- src/features/app/hooks/useAccountSwitching.ts | 10 +- .../app/hooks/useAppServerEvents.test.tsx | 4 +- src/features/app/hooks/useAppServerEvents.ts | 8 +- .../app/hooks/useAppSettingsController.ts | 6 +- .../app/hooks/useGitPanelController.test.tsx | 6 +- .../app/hooks/useGitPanelController.ts | 6 +- src/features/app/hooks/useLayoutController.ts | 2 +- .../hooks/useMainAppComposerWorkspaceState.ts | 14 +- .../app/hooks/useMainAppDisplayNodes.tsx | 6 +- src/features/app/hooks/useMainAppGitState.ts | 6 +- .../app/hooks/useMainAppLayoutSurfaces.ts | 34 ++-- src/features/app/hooks/useMainAppModals.ts | 16 +- .../app/hooks/useMainAppThreadCodexState.ts | 118 ------------ .../hooks/useMainAppThreadOpenCodeState.ts | 118 ++++++++++++ .../app/hooks/useMainAppWorkspaceLifecycle.ts | 4 +- .../app/hooks/usePlanReadyActions.test.tsx | 30 +-- src/features/app/hooks/usePlanReadyActions.ts | 12 +- .../hooks/useRemoteThreadLiveConnection.ts | 2 +- .../app/hooks/useSettingsModalState.ts | 2 +- .../hooks/useSidebarLayoutActions.test.tsx | 2 +- .../app/hooks/useSidebarLayoutActions.ts | 4 +- .../app/hooks/useTabActivationGuard.test.tsx | 2 +- .../app/hooks/useTabActivationGuard.ts | 4 +- .../app/hooks/useThreadListSortKey.ts | 4 +- .../app/hooks/useUpdaterController.ts | 2 +- src/features/app/hooks/useWorkspaceActions.ts | 6 +- .../app/hooks/useWorkspaceController.test.tsx | 2 +- src/features/app/hooks/useWorkspaceDialogs.ts | 4 +- .../app/hooks/useWorkspaceFileListing.ts | 4 +- ...=> useThreadOpenCodeOrchestration.test.ts} | 22 +-- ...n.ts => useThreadOpenCodeOrchestration.ts} | 50 ++--- .../useThreadOrchestration.test.ts | 80 ++++---- .../orchestration/useThreadOrchestration.ts | 110 +++++------ src/features/apps/hooks/useApps.test.ts | 2 +- src/features/composer/components/Composer.tsx | 20 +- .../composer/components/ComposerMetaBar.tsx | 22 +-- .../composer/hooks/usePromptHistory.test.tsx | 2 +- .../composer/hooks/usePromptHistory.ts | 2 +- .../git/hooks/useAutoExitEmptyDiff.ts | 4 +- .../git/hooks/useGitHubIssues.test.tsx | 2 +- src/features/git/hooks/useGitStatus.test.tsx | 4 +- .../git/hooks/usePullRequestComposer.test.tsx | 2 +- .../git/hooks/usePullRequestComposer.ts | 2 +- .../usePullRequestReviewActions.test.tsx | 2 +- src/features/home/components/Home.test.tsx | 6 +- .../layout/components/PhoneLayout.tsx | 10 +- .../layout/components/TabletLayout.tsx | 4 +- .../hooks/layoutNodes/buildSecondaryNodes.tsx | 6 +- .../layout/hooks/layoutNodes/types.ts | 2 +- .../layout/hooks/usePanelVisibility.ts | 2 +- .../layout/hooks/useResizablePanels.test.ts | 8 +- .../layout/hooks/useResizablePanels.ts | 12 +- .../layout/hooks/useSidebarToggles.tsx | 4 +- .../messages/components/Markdown.test.tsx | 42 ++-- .../messages/components/Messages.test.tsx | 22 +-- .../messages/hooks/useFileLinkOpener.test.tsx | 28 +-- .../components/MobileServerSetupWizard.tsx | 2 +- src/features/models/hooks/useModels.test.tsx | 2 +- .../useAgentResponseRequiredNotifications.ts | 2 +- .../settings/components/SettingsNav.tsx | 10 +- .../settings/components/SettingsView.test.tsx | 14 +- .../settings/components/SettingsView.tsx | 20 +- .../sections/SettingsAboutSection.tsx | 2 +- .../sections/SettingsFeaturesSection.tsx | 12 +- ...ection.tsx => SettingsOpenCodeSection.tsx} | 26 +-- .../sections/SettingsSectionContainers.tsx | 10 +- .../sections/SettingsServerSection.tsx | 10 +- .../settings/components/settingsTypes.ts | 4 +- .../components/settingsViewConstants.ts | 6 +- .../settings/hooks/useAppSettings.test.ts | 22 +-- src/features/settings/hooks/useAppSettings.ts | 14 +- ...Toml.ts => useGlobalOpenCodeConfigJson.ts} | 8 +- .../hooks/useSettingsFeaturesSection.ts | 34 ++-- ...ction.ts => useSettingsOpenCodeSection.ts} | 66 +++---- .../hooks/useSettingsViewNavigation.ts | 8 +- .../hooks/useSettingsViewOrchestration.ts | 24 +-- src/features/skills/hooks/useSkills.test.tsx | 4 +- .../threads/hooks/useQueuedSend.test.tsx | 2 +- .../threads/hooks/useThreadActions.test.tsx | 14 +- .../threads/hooks/useThreadActions.ts | 12 +- .../threads/hooks/useThreadEventHandlers.ts | 2 +- .../threads/hooks/useThreadMessaging.test.tsx | 14 +- .../threads/hooks/useThreadMessaging.ts | 18 +- ...t.tsx => useThreadOpenCodeParams.test.tsx} | 60 +++--- ...exParams.ts => useThreadOpenCodeParams.ts} | 82 ++++---- .../hooks/useThreads.integration.test.tsx | 62 +++--- src/features/threads/hooks/useThreads.ts | 40 ++-- ...s.test.ts => opencodeArgsProfiles.test.ts} | 18 +- ...rgsProfiles.ts => opencodeArgsProfiles.ts} | 56 +++--- ...test.ts => threadOpenCodeMetadata.test.ts} | 12 +- ...xMetadata.ts => threadOpenCodeMetadata.ts} | 2 +- ...st.ts => threadOpenCodeParamsSeed.test.ts} | 154 +++++++-------- ...amsSeed.ts => threadOpenCodeParamsSeed.ts} | 76 ++++---- src/features/threads/utils/threadStorage.ts | 24 +-- src/features/threads/utils/threadSummary.ts | 4 +- .../update/components/UpdateToast.test.tsx | 6 +- src/features/update/hooks/useUpdater.test.ts | 8 +- .../update/utils/postUpdateRelease.ts | 6 +- .../hooks/useWorkspaceHome.test.tsx | 12 +- .../workspaces/hooks/useWorkspaceHome.ts | 10 +- .../workspaces/hooks/useWorkspaceSelection.ts | 4 +- .../workspaces/hooks/useWorkspaces.test.tsx | 16 +- src/services/tauri.test.ts | 12 +- src/services/tauri.ts | 52 ++--- src/types.ts | 20 +- src/utils/appServerEvents.test.ts | 2 +- src/utils/appServerEvents.ts | 10 +- ...nput.test.ts => opencodeArgsInput.test.ts} | 12 +- ...codexArgsInput.ts => opencodeArgsInput.ts} | 2 +- 167 files changed, 1626 insertions(+), 1626 deletions(-) rename src-tauri/src/bin/{codex_monitor_daemon.rs => opencode_monitor_daemon.rs} (91%) rename src-tauri/src/bin/{codex_monitor_daemon => opencode_monitor_daemon}/rpc.rs (99%) rename src-tauri/src/bin/{codex_monitor_daemon => opencode_monitor_daemon}/rpc/codex.rs (96%) rename src-tauri/src/bin/{codex_monitor_daemon => opencode_monitor_daemon}/rpc/daemon.rs (100%) rename src-tauri/src/bin/{codex_monitor_daemon => opencode_monitor_daemon}/rpc/dispatcher.rs (100%) rename src-tauri/src/bin/{codex_monitor_daemon => opencode_monitor_daemon}/rpc/git.rs (100%) rename src-tauri/src/bin/{codex_monitor_daemon => opencode_monitor_daemon}/rpc/prompts.rs (100%) rename src-tauri/src/bin/{codex_monitor_daemon => opencode_monitor_daemon}/rpc/workspace.rs (97%) rename src-tauri/src/bin/{codex_monitor_daemon => opencode_monitor_daemon}/transport.rs (100%) rename src-tauri/src/bin/{codex_monitor_daemonctl.rs => opencode_monitor_daemonctl.rs} (99%) rename src-tauri/src/{codex => opencode}/args.rs (69%) rename src-tauri/src/{codex => opencode}/config.rs (87%) rename src-tauri/src/{codex => opencode}/home.rs (84%) rename src-tauri/src/{codex => opencode}/mod.rs (87%) rename src-tauri/src/shared/{codex_aux_core.rs => opencode_aux_core.rs} (98%) rename src-tauri/src/shared/{codex_core.rs => opencode_core.rs} (94%) rename src-tauri/src/shared/{codex_update_core.rs => opencode_update_core.rs} (92%) rename src-tauri/src/shared/workspaces_core/{runtime_codex_args.rs => runtime_opencode_args.rs} (81%) delete mode 100644 src/features/app/hooks/useMainAppThreadCodexState.ts create mode 100644 src/features/app/hooks/useMainAppThreadOpenCodeState.ts rename src/features/app/orchestration/{useThreadCodexOrchestration.test.ts => useThreadOpenCodeOrchestration.test.ts} (58%) rename src/features/app/orchestration/{useThreadCodexOrchestration.ts => useThreadOpenCodeOrchestration.ts} (74%) rename src/features/settings/components/sections/{SettingsCodexSection.tsx => SettingsOpenCodeSection.tsx} (97%) rename src/features/settings/hooks/{useGlobalCodexConfigToml.ts => useGlobalOpenCodeConfigJson.ts} (52%) rename src/features/settings/hooks/{useSettingsCodexSection.ts => useSettingsOpenCodeSection.ts} (84%) rename src/features/threads/hooks/{useThreadCodexParams.test.tsx => useThreadOpenCodeParams.test.tsx} (61%) rename src/features/threads/hooks/{useThreadCodexParams.ts => useThreadOpenCodeParams.ts} (57%) rename src/features/threads/utils/{codexArgsProfiles.test.ts => opencodeArgsProfiles.test.ts} (89%) rename src/features/threads/utils/{codexArgsProfiles.ts => opencodeArgsProfiles.ts} (88%) rename src/features/threads/utils/{threadCodexMetadata.test.ts => threadOpenCodeMetadata.test.ts} (78%) rename src/features/threads/utils/{threadCodexMetadata.ts => threadOpenCodeMetadata.ts} (97%) rename src/features/threads/utils/{threadCodexParamsSeed.test.ts => threadOpenCodeParamsSeed.test.ts} (76%) rename src/features/threads/utils/{threadCodexParamsSeed.ts => threadOpenCodeParamsSeed.ts} (68%) rename src/utils/{codexArgsInput.test.ts => opencodeArgsInput.test.ts} (53%) rename src/utils/{codexArgsInput.ts => opencodeArgsInput.ts} (93%) 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/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/src/backend/app_server.rs b/src-tauri/src/backend/app_server.rs index 9dce23cc2f..76a32df42b 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") ) } @@ -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_codex_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()); } @@ -644,17 +644,17 @@ pub(crate) fn build_codex_path_env(codex_bin: Option<&str>) -> Option { } pub(crate) fn build_codex_command_with_bin( - codex_bin: Option, - codex_args: Option<&str>, + 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_codex_path_env(opencode_bin.as_deref()); + let mut command_args = parse_opencode_args(opencode_args)?; command_args.extend(args); #[cfg(target_os = "windows")] @@ -698,9 +698,9 @@ pub(crate) fn build_codex_command_with_bin( } pub(crate) async fn check_codex_installation( - codex_bin: Option, + opencode_bin: Option, ) -> Result, String> { - let mut command = build_codex_command_with_bin(codex_bin, None, vec!["--version".to_string()])?; + let mut command = build_codex_command_with_bin(opencode_bin, None, vec!["--version".to_string()])?; command.stdout(std::process::Stdio::piped()); command.stderr(std::process::Stdio::piped()); @@ -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_codex_installation(opencode_bin.clone()).await?; let mut command = build_codex_command_with_bin( - codex_bin, - codex_args.as_deref(), + 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()), @@ -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 }, }), }; @@ -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() } }), }; @@ -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 91% rename from src-tauri/src/bin/codex_monitor_daemon.rs rename to src-tauri/src/bin/opencode_monitor_daemon.rs index 59bfc00bc8..09160567f6 100644 --- a/src-tauri/src/bin/codex_monitor_daemon.rs +++ b/src-tauri/src/bin/opencode_monitor_daemon.rs @@ -2,11 +2,11 @@ #[path = "../backend/mod.rs"] mod backend; #[path = "../codex/args.rs"] -mod codex_args; +mod opencode_args; #[path = "../codex/config.rs"] -mod codex_config; +mod opencode_config; #[path = "../codex/home.rs"] -mod codex_home; +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) 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,7 +588,7 @@ impl DaemonState { .await } - async fn set_codex_feature_flag( + async fn set_opencode_feature_flag( &self, feature_key: String, enabled: bool, @@ -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,14 +1486,14 @@ 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 { @@ -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(), ); } @@ -1613,7 +1613,7 @@ 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()), + opencode_login_cancels: Mutex::new(HashMap::new()), daemon_binary_path: Some("/tmp/codex-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()), 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..f5b73bd627 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; +mod opencode; #[path = "rpc/daemon.rs"] mod daemon; #[path = "rpc/dispatcher.rs"] diff --git a/src-tauri/src/bin/codex_monitor_daemon/rpc/codex.rs b/src-tauri/src/bin/opencode_monitor_daemon/rpc/codex.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/codex.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/codex.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/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 100% rename from src-tauri/src/bin/codex_monitor_daemon/rpc/dispatcher.rs rename to src-tauri/src/bin/opencode_monitor_daemon/rpc/dispatcher.rs 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/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 99% rename from src-tauri/src/bin/codex_monitor_daemonctl.rs rename to src-tauri/src/bin/opencode_monitor_daemonctl.rs index f31c6aef95..e2c51e30f1 100644 --- a/src-tauri/src/bin/codex_monitor_daemonctl.rs +++ b/src-tauri/src/bin/opencode_monitor_daemonctl.rs @@ -22,7 +22,7 @@ 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"; @@ -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())) }) diff --git a/src-tauri/src/daemon_binary.rs b/src-tauri/src/daemon_binary.rs index 09f20e2219..e51a12838b 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", "codex-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..e8525dbb95 100644 --- a/src-tauri/src/files/io.rs +++ b/src-tauri/src/files/io.rs @@ -150,7 +150,7 @@ mod tests { 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/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/lib.rs b/src-tauri/src/lib.rs index 83e9dacae7..c1e8b98e5f 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,7 +182,7 @@ 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, @@ -191,8 +191,8 @@ pub fn run() { menu::menu_set_accelerators, tray::set_tray_recent_threads, tray::set_tray_session_usage, - codex::codex_doctor, - codex::codex_update, + codex::opencode_doctor, + codex::opencode_update, workspaces::list_workspaces, workspaces::is_workspace_path_dir, workspaces::add_workspace, @@ -207,7 +207,7 @@ pub fn run() { workspaces::rename_worktree_upstream, workspaces::apply_worktree_changes, workspaces::update_workspace_settings, - workspaces::set_workspace_runtime_codex_args, + workspaces::set_workspace_runtime_opencode_args, codex::start_thread, codex::send_user_message, codex::turn_steer, @@ -262,7 +262,7 @@ pub fn run() { git::create_git_branch, codex::model_list, codex::experimental_feature_list, - codex::set_codex_feature_flag, + codex::set_opencode_feature_flag, codex::get_agents_settings, codex::set_agents_core_settings, codex::create_agent, @@ -272,8 +272,8 @@ pub fn run() { codex::write_agent_config_toml, codex::account_rate_limits, codex::account_read, - codex::codex_login, - codex::codex_login_cancel, + codex::opencode_login, + codex::opencode_login_cancel, codex::skills_list, codex::apps_list, prompts::prompts_list, 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/codex/args.rs b/src-tauri/src/opencode/args.rs similarity index 69% rename from src-tauri/src/codex/args.rs rename to src-tauri/src/opencode/args.rs index 6560c64d93..033f8fb46b 100644 --- a/src-tauri/src/codex/args.rs +++ b/src-tauri/src/opencode/args.rs @@ -1,6 +1,6 @@ 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()), @@ -10,20 +10,20 @@ pub(crate) fn parse_codex_args(value: Option<&str>) -> Result, Strin .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 84% rename from src-tauri/src/codex/home.rs rename to src-tauri/src/opencode/home.rs index cd3e29e251..10d6518043 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")) } -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,24 +197,24 @@ 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/codex-global"); - let resolved = resolve_workspace_codex_home(&entry, None); + let resolved = resolve_workspace_opencode_home(&entry, None); assert_eq!(resolved, Some(PathBuf::from("/tmp/codex-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_str = home_dir.to_string_lossy().to_string(); @@ -225,19 +225,19 @@ 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"); + let tilde = normalize_opencode_home("~/.config/opencode-api"); assert_eq!(tilde, Some(home_dir.join(".codex-api"))); - let dollar = normalize_codex_home("$HOME/.codex-api"); + let dollar = normalize_opencode_home("$HOME/.codex-api"); assert_eq!(dollar, Some(home_dir.join(".codex-api"))); - let braces = normalize_codex_home("${HOME}/.codex-api"); + let braces = normalize_opencode_home("${HOME}/.codex-api"); assert_eq!(braces, Some(home_dir.join(".codex-api"))); - let appdata = normalize_codex_home("%APPDATA%/Codex"); + let appdata = normalize_opencode_home("%APPDATA%/Codex"); assert_eq!(appdata, Some(PathBuf::from("/tmp/appdata-root/Codex"))); - let appdata_lower = normalize_codex_home("$appdata/Codex"); + let appdata_lower = normalize_opencode_home("$appdata/Codex"); assert_eq!( appdata_lower, Some(PathBuf::from("/tmp/appdata-root/Codex")) 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..e30aa63265 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; @@ -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()); @@ -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("codex-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("codex-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/local_usage_core.rs b/src-tauri/src/shared/local_usage_core.rs index ca2f40871c..6f970db060 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_codex_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_codex_sessions_root(opencode_home_override) .into_iter() .collect(); } @@ -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_codex_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 { 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 98% rename from src-tauri/src/shared/codex_aux_core.rs rename to src-tauri/src/shared/opencode_aux_core.rs index 12f985adec..4cdf714aa3 100644 --- a/src-tauri/src/shared/codex_aux_core.rs +++ b/src-tauri/src/shared/opencode_aux_core.rs @@ -286,20 +286,20 @@ 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); @@ -381,7 +381,7 @@ pub(crate) async fn codex_doctor_core( }; 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 94% rename from src-tauri/src/shared/codex_core.rs rename to src-tauri/src/shared/opencode_core.rs index a0f2a4ea6a..82fb87431d 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 as codex_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; @@ -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( @@ -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,12 +685,12 @@ 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()); } 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()); } @@ -699,7 +699,7 @@ pub(crate) async fn codex_login_core( 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( @@ -802,7 +802,7 @@ pub(crate) async fn skills_list_core( 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 + // 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 = codex_config::read_config_model(Some(opencode_home))?; Ok(json!({ "model": model })) } diff --git a/src-tauri/src/shared/codex_update_core.rs b/src-tauri/src/shared/opencode_update_core.rs similarity index 92% rename from src-tauri/src/shared/codex_update_core.rs rename to src-tauri/src/shared/opencode_update_core.rs index ee5541a25e..9048e22df2 100644 --- a/src-tauri/src/shared/codex_update_core.rs +++ b/src-tauri/src/shared/opencode_update_core.rs @@ -143,20 +143,20 @@ 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); @@ -167,22 +167,22 @@ pub(crate) async fn codex_update_core( .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, 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..6f6e1393b1 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 as codex_config; use crate::storage::write_settings; use crate::types::AppSettings; use crate::utils::normalize_windows_namespace_path; @@ -59,12 +59,12 @@ pub(crate) async fn update_app_settings_core( Ok(settings) } -pub(crate) fn get_codex_config_path_core() -> Result { +pub(crate) fn get_opencode_config_path_core() -> Result { codex_config::config_toml_path() - .ok_or_else(|| "Unable to resolve CODEX_HOME".to_string()) + .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..6746535ee1 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; } } @@ -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/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..e30c8d9008 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"); 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/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/tests.rs b/src-tauri/src/workspaces/tests.rs index 84208dfd10..8755cbf3b2 100644 --- a/src-tauri/src/workspaces/tests.rs +++ b/src-tauri/src/workspaces/tests.rs @@ -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()) }, ) @@ -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()) }, ) @@ -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()) }, ) @@ -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()) }, ) @@ -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()) }, ) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index dd910c2a94..3ba931dd9c 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, diff --git a/src/features/about/components/AboutView.tsx b/src/features/about/components/AboutView.tsx index 12ab9696ef..70b397db3c 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() { 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/MainApp.tsx b/src/features/app/components/MainApp.tsx index 1ce7cc5874..d1e1bd4926 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"; @@ -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(() => @@ -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, @@ -190,8 +190,8 @@ export default function MainApp() { ); const { threadCodexParamsVersion, - getThreadCodexParams, - patchThreadCodexParams, + getThreadOpenCodeParams, + patchThreadOpenCodeParams, accessMode, setAccessMode, preferredModelId, @@ -202,13 +202,13 @@ export default function MainApp() { setPreferredServiceTier, preferredCollabModeId, setPreferredCollabModeId, - preferredCodexArgsOverride, + preferredOpenCodeArgsOverride, setPreferredCodexArgsOverride, threadCodexSelectionKey, setThreadCodexSelectionKey, activeThreadIdRef, pendingNewThreadSeedRef, - persistThreadCodexParams, + persistThreadOpenCodeParams, } = useThreadCodexBootstrapOrchestration({ activeWorkspaceId, }); @@ -307,15 +307,15 @@ export default function MainApp() { onDebug: addDebugEntry, }); - const [selectedCodexArgsOverride, setSelectedCodexArgsOverride] = useState( + const [selectedOpenCodeArgsOverride, setSelectedCodexArgsOverride] = useState( null, ); const [selectedServiceTier, setSelectedServiceTier] = useState< ServiceTier | null | undefined >(undefined); useEffect(() => { - setSelectedCodexArgsOverride(normalizeCodexArgsInput(preferredCodexArgsOverride)); - }, [preferredCodexArgsOverride, threadCodexSelectionKey]); + setSelectedCodexArgsOverride(normalizeOpenCodeArgsInput(preferredOpenCodeArgsOverride)); + }, [preferredOpenCodeArgsOverride, threadCodexSelectionKey]); useEffect(() => { setSelectedServiceTier(preferredServiceTier); }, [preferredServiceTier, threadCodexSelectionKey]); @@ -338,7 +338,7 @@ export default function MainApp() { setSelectedCollaborationModeId, setAccessMode, setSelectedCodexArgsOverride, - persistThreadCodexParams, + 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({ + appCodexArgs: 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({ @@ -672,8 +672,8 @@ export default function MainApp() { lastComposerReasoningEffort: appSettings.lastComposerReasoningEffort, }, threadCodexParamsVersion, - getThreadCodexParams, - patchThreadCodexParams, + getThreadOpenCodeParams, + patchThreadOpenCodeParams, setThreadCodexSelectionKey, setAccessMode, setPreferredModelId, @@ -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`, @@ -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: handleSelectCodexArgsOverride, 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..50f9c924f4 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; 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/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..69ba289d8f 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"; @@ -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. } @@ -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. } @@ -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..853453c8cf 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), + codexUpdate: (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..162ca4a895 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 ? ( -
Made with ♥ by Codex & Dimillian
+
Made with ♥ by OpenCode & Dimillian
); 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 d1e1bd4926..9cb7d1cd5e 100644 --- a/src/features/app/components/MainApp.tsx +++ b/src/features/app/components/MainApp.tsx @@ -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"; @@ -92,7 +92,7 @@ export default function MainApp() { appSettings, setAppSettings, doctor, - codexUpdate, + opencodeUpdate, appSettingsLoading, reduceTransparency, setReduceTransparency, @@ -189,7 +189,7 @@ export default function MainApp() { [workspaces], ); const { - threadCodexParamsVersion, + threadOpenCodeParamsVersion, getThreadOpenCodeParams, patchThreadOpenCodeParams, accessMode, @@ -203,13 +203,13 @@ export default function MainApp() { preferredCollabModeId, setPreferredCollabModeId, preferredOpenCodeArgsOverride, - setPreferredCodexArgsOverride, - threadCodexSelectionKey, - setThreadCodexSelectionKey, + setPreferredOpenCodeArgsOverride, + threadOpenCodeSelectionKey, + setThreadOpenCodeSelectionKey, activeThreadIdRef, pendingNewThreadSeedRef, persistThreadOpenCodeParams, - } = useThreadCodexBootstrapOrchestration({ + } = 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 [selectedOpenCodeArgsOverride, setSelectedCodexArgsOverride] = useState( + const [selectedOpenCodeArgsOverride, setSelectedOpenCodeArgsOverride] = useState( null, ); const [selectedServiceTier, setSelectedServiceTier] = useState< ServiceTier | null | undefined >(undefined); useEffect(() => { - setSelectedCodexArgsOverride(normalizeOpenCodeArgsInput(preferredOpenCodeArgsOverride)); - }, [preferredOpenCodeArgsOverride, 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,7 +337,7 @@ export default function MainApp() { setSelectedServiceTier, setSelectedCollaborationModeId, setAccessMode, - setSelectedCodexArgsOverride, + setSelectedOpenCodeArgsOverride, persistThreadOpenCodeParams, }); const commitMessageModelId = useMemo( @@ -411,7 +411,7 @@ export default function MainApp() { ensureWorkspaceRuntimeOpenCodeArgs, getThreadArgsBadge, } = useMainAppThreadOpenCodeState({ - appCodexArgs: appSettings.opencodeArgs, + appOpenCodeArgs: appSettings.opencodeArgs, selectedOpenCodeArgsOverride, getThreadOpenCodeParams, patchThreadOpenCodeParams, @@ -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, + threadOpenCodeParamsVersion, getThreadOpenCodeParams, patchThreadOpenCodeParams, - setThreadCodexSelectionKey, + setThreadOpenCodeSelectionKey, setAccessMode, setPreferredModelId, setPreferredEffort, setPreferredServiceTier, setPreferredCollabModeId, - setPreferredCodexArgsOverride, + setPreferredOpenCodeArgsOverride, activeThreadIdRef, pendingNewThreadSeedRef, selectedModelId, @@ -1014,7 +1014,7 @@ export default function MainApp() { queueSaveSettings, handleToggleAutomaticAppUpdateChecks, doctor, - codexUpdate, + opencodeUpdate, updateWorkspaceSettings, scaleShortcutTitle, scaleShortcutText, @@ -1709,7 +1709,7 @@ export default function MainApp() { reasoningSupported, opencodeArgsOptions, selectedOpenCodeArgsOverride, - onSelectOpenCodeArgsOverride: handleSelectCodexArgsOverride, + onSelectOpenCodeArgsOverride: handleSelectOpenCodeArgsOverride, accessMode, onSelectAccessMode: handleSelectAccessMode, skills, diff --git a/src/features/app/components/Sidebar.tsx b/src/features/app/components/Sidebar.tsx index 50f9c924f4..8504f4a1f7 100644 --- a/src/features/app/components/Sidebar.tsx +++ b/src/features/app/components/Sidebar.tsx @@ -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/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.ts b/src/features/app/hooks/useAccountSwitching.ts index 69ba289d8f..04af20cbae 100644 --- a/src/features/app/hooks/useAccountSwitching.ts +++ b/src/features/app/hooks/useAccountSwitching.ts @@ -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") ); }, []); @@ -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; @@ -197,7 +197,7 @@ export function useAccountSwitching({ activeWorkspaceId, accountSwitching, alertError, - isCodexLoginCanceled, + isOpenCodeLoginCanceled, ]); const handleCancelSwitchAccount = useCallback(async () => { diff --git a/src/features/app/hooks/useAppSettingsController.ts b/src/features/app/hooks/useAppSettingsController.ts index 853453c8cf..e5974c775c 100644 --- a/src/features/app/hooks/useAppSettingsController.ts +++ b/src/features/app/hooks/useAppSettingsController.ts @@ -34,7 +34,7 @@ export function useAppSettingsController() { saveSettings, queueSaveSettings, doctor, - codexUpdate: (opencodeBin: string | null, opencodeArgs: string | null) => + opencodeUpdate: (opencodeBin: string | null, opencodeArgs: string | null) => runOpenCodeUpdate(opencodeBin, opencodeArgs), appSettingsLoading, reduceTransparency, diff --git a/src/features/app/hooks/useMainAppDisplayNodes.tsx b/src/features/app/hooks/useMainAppDisplayNodes.tsx index 162ca4a895..d897816932 100644 --- a/src/features/app/hooks/useMainAppDisplayNodes.tsx +++ b/src/features/app/hooks/useMainAppDisplayNodes.tsx @@ -43,7 +43,7 @@ export function useMainAppDisplayNodes({ disabled={mobileThreadRefreshLoading} > diff --git a/src/features/app/hooks/useMainAppModals.ts b/src/features/app/hooks/useMainAppModals.ts index a7fee1e6a4..3ac7871a5d 100644 --- a/src/features/app/hooks/useMainAppModals.ts +++ b/src/features/app/hooks/useMainAppModals.ts @@ -112,7 +112,7 @@ type UseMainAppModalsArgs = { opencodeBin: string | null, opencodeArgs: string | null, ) => Promise; - codexUpdate?: ( + opencodeUpdate?: ( opencodeBin: string | null, opencodeArgs: string | null, ) => Promise; @@ -185,7 +185,7 @@ function buildSettingsViewProps({ onToggleAutomaticAppUpdateChecks: settings.handleToggleAutomaticAppUpdateChecks, onRunDoctor: settings.doctor, - onRunCodexUpdate: settings.codexUpdate, + onRunOpenCodeUpdate: settings.opencodeUpdate, onUpdateWorkspaceSettings: async (id, nextSettings) => { await settings.updateWorkspaceSettings(id, nextSettings); }, diff --git a/src/features/app/hooks/useMainAppThreadOpenCodeState.ts b/src/features/app/hooks/useMainAppThreadOpenCodeState.ts index e7c49bc378..fcc81c284b 100644 --- a/src/features/app/hooks/useMainAppThreadOpenCodeState.ts +++ b/src/features/app/hooks/useMainAppThreadOpenCodeState.ts @@ -2,7 +2,7 @@ import { useCallback, useMemo } from "react"; import { setWorkspaceRuntimeOpenCodeArgs } from "@services/tauri"; import { buildOpenCodeArgsOptions } from "@threads/utils/opencodeArgsProfiles"; import { - resolveWorkspaceRuntimeCodexArgsBadgeLabel, + resolveWorkspaceRuntimeOpenCodeArgsBadgeLabel, resolveWorkspaceRuntimeOpenCodeArgsOverride, } from "@threads/utils/threadOpenCodeParamsSeed"; import type { ThreadOpenCodeParams } from "@threads/utils/threadStorage"; @@ -24,8 +24,8 @@ type ThreadOpenCodeMetadata = { effort: string | null; }; -type UseMainAppThreadCodexStateArgs = { - appCodexArgs: string | null | undefined; +type UseMainAppThreadOpenCodeStateArgs = { + appOpenCodeArgs: string | null | undefined; selectedOpenCodeArgsOverride: string | null; getThreadOpenCodeParams: ( workspaceId: string, @@ -39,11 +39,11 @@ type UseMainAppThreadCodexStateArgs = { }; export function useMainAppThreadOpenCodeState({ - appCodexArgs, + appOpenCodeArgs, selectedOpenCodeArgsOverride, getThreadOpenCodeParams, patchThreadOpenCodeParams, -}: UseMainAppThreadCodexStateArgs) { +}: UseMainAppThreadOpenCodeStateArgs) { const handleThreadOpenCodeMetadataDetected = useCallback( (workspaceId: string, threadId: string, metadata: ThreadOpenCodeMetadata) => { if (!workspaceId || !threadId) { @@ -81,27 +81,27 @@ export function useMainAppThreadOpenCodeState({ const opencodeArgsOptions = useMemo( () => buildOpenCodeArgsOptions({ - appCodexArgs: appCodexArgs ?? null, - additionalCodexArgs: [selectedOpenCodeArgsOverride], + appOpenCodeArgs: appOpenCodeArgs ?? null, + additionalOpenCodeArgs: [selectedOpenCodeArgsOverride], }), - [appCodexArgs, selectedOpenCodeArgsOverride], + [appOpenCodeArgs, selectedOpenCodeArgsOverride], ); const ensureWorkspaceRuntimeOpenCodeArgs = useCallback( async (workspaceId: string, threadId: string | null) => { - const sanitizedCodexArgsOverride = resolveWorkspaceRuntimeOpenCodeArgsOverride({ + const sanitizedOpenCodeArgsOverride = resolveWorkspaceRuntimeOpenCodeArgsOverride({ workspaceId, threadId, getThreadOpenCodeParams, }); - await setWorkspaceRuntimeOpenCodeArgs(workspaceId, sanitizedCodexArgsOverride); + await setWorkspaceRuntimeOpenCodeArgs(workspaceId, sanitizedOpenCodeArgsOverride); }, [getThreadOpenCodeParams], ); const getThreadArgsBadge = useCallback( (workspaceId: string, threadId: string) => - resolveWorkspaceRuntimeCodexArgsBadgeLabel({ + resolveWorkspaceRuntimeOpenCodeArgsBadgeLabel({ workspaceId, threadId, getThreadOpenCodeParams, diff --git a/src/features/app/orchestration/useThreadOpenCodeOrchestration.ts b/src/features/app/orchestration/useThreadOpenCodeOrchestration.ts index 0a7cfafae5..dfc02c9276 100644 --- a/src/features/app/orchestration/useThreadOpenCodeOrchestration.ts +++ b/src/features/app/orchestration/useThreadOpenCodeOrchestration.ts @@ -7,7 +7,7 @@ import { NO_THREAD_SCOPE_SUFFIX, } from "@threads/utils/threadOpenCodeParamsSeed"; -type ThreadCodexOrchestration = { +type ThreadOpenCodeOrchestration = { accessMode: AccessMode; setAccessMode: Dispatch>; preferredModelId: string | null; @@ -19,10 +19,10 @@ type ThreadCodexOrchestration = { preferredCollabModeId: string | null; setPreferredCollabModeId: Dispatch>; preferredOpenCodeArgsOverride: string | null; - setPreferredCodexArgsOverride: Dispatch>; - threadCodexSelectionKey: string | null; - setThreadCodexSelectionKey: Dispatch>; - threadCodexParamsVersion: number; + setPreferredOpenCodeArgsOverride: Dispatch>; + threadOpenCodeSelectionKey: string | null; + setThreadOpenCodeSelectionKey: Dispatch>; + threadOpenCodeParamsVersion: number; getThreadOpenCodeParams: ReturnType["getThreadOpenCodeParams"]; patchThreadOpenCodeParams: ReturnType["patchThreadOpenCodeParams"]; persistThreadOpenCodeParams: (patch: { @@ -37,15 +37,15 @@ type ThreadCodexOrchestration = { pendingNewThreadSeedRef: MutableRefObject; }; -type UseThreadCodexOrchestrationParams = { +type UseThreadOpenCodeOrchestrationParams = { activeWorkspaceIdForParamsRef: MutableRefObject; }; export function useThreadOpenCodeOrchestration({ activeWorkspaceIdForParamsRef, -}: UseThreadCodexOrchestrationParams): ThreadCodexOrchestration { +}: UseThreadOpenCodeOrchestrationParams): ThreadOpenCodeOrchestration { const { - version: threadCodexParamsVersion, + version: threadOpenCodeParamsVersion, getThreadOpenCodeParams, patchThreadOpenCodeParams, } = useThreadOpenCodeParams(); @@ -58,10 +58,10 @@ export function useThreadOpenCodeOrchestration({ const [preferredCollabModeId, setPreferredCollabModeId] = useState( null, ); - const [preferredOpenCodeArgsOverride, setPreferredCodexArgsOverride] = useState( + const [preferredOpenCodeArgsOverride, setPreferredOpenCodeArgsOverride] = useState( null, ); - const [threadCodexSelectionKey, setThreadCodexSelectionKey] = useState( + const [threadOpenCodeSelectionKey, setThreadOpenCodeSelectionKey] = useState( null, ); const activeThreadIdRef = useRef(null); @@ -107,10 +107,10 @@ export function useThreadOpenCodeOrchestration({ preferredCollabModeId, setPreferredCollabModeId, preferredOpenCodeArgsOverride, - setPreferredCodexArgsOverride, - threadCodexSelectionKey, - setThreadCodexSelectionKey, - threadCodexParamsVersion, + setPreferredOpenCodeArgsOverride, + threadOpenCodeSelectionKey, + setThreadOpenCodeSelectionKey, + threadOpenCodeParamsVersion, getThreadOpenCodeParams, patchThreadOpenCodeParams, persistThreadOpenCodeParams, @@ -124,9 +124,9 @@ export function useThreadOpenCodeOrchestration({ preferredEffort, preferredModelId, preferredServiceTier, - threadCodexSelectionKey, - threadCodexParamsVersion, - setPreferredCodexArgsOverride, + threadOpenCodeSelectionKey, + threadOpenCodeParamsVersion, + setPreferredOpenCodeArgsOverride, getThreadOpenCodeParams, patchThreadOpenCodeParams, persistThreadOpenCodeParams, diff --git a/src/features/app/orchestration/useThreadOrchestration.test.ts b/src/features/app/orchestration/useThreadOrchestration.test.ts index a0b4f368bf..11b92e2860 100644 --- a/src/features/app/orchestration/useThreadOrchestration.test.ts +++ b/src/features/app/orchestration/useThreadOrchestration.test.ts @@ -6,7 +6,7 @@ import { pushErrorToast } from "@/services/toasts"; import type { AccessMode, AppSettings } from "@/types"; import type { PendingNewThreadSeed } from "@threads/utils/threadOpenCodeParamsSeed"; import { - useThreadCodexSyncOrchestration, + useThreadOpenCodeSyncOrchestration, useThreadSelectionHandlersOrchestration, useThreadUiOrchestration, } from "./useThreadOrchestration"; @@ -16,17 +16,17 @@ vi.mock("@/services/toasts", () => ({ })); type SelectionParams = Parameters[0]; -type SyncParams = Parameters[0]; +type SyncParams = Parameters[0]; function makeSelectionParams(): SelectionParams & { persistThreadOpenCodeParams: ReturnType; - setSelectedCodexArgsOverride: ReturnType; + setSelectedOpenCodeArgsOverride: ReturnType; } { const setAppSettings = vi.fn() as unknown as Dispatch>; const setAccessMode = vi.fn() as unknown as Dispatch>; const activeThreadIdRef = { current: null } as MutableRefObject; const persistThreadOpenCodeParams = vi.fn(); - const setSelectedCodexArgsOverride = vi.fn(); + const setSelectedOpenCodeArgsOverride = vi.fn(); return { appSettingsLoading: false, @@ -38,7 +38,7 @@ function makeSelectionParams(): SelectionParams & { setSelectedServiceTier: vi.fn(), setSelectedCollaborationModeId: vi.fn(), setAccessMode, - setSelectedCodexArgsOverride, + setSelectedOpenCodeArgsOverride, persistThreadOpenCodeParams, }; } @@ -60,10 +60,10 @@ function makeSyncParams( lastComposerModelId: "gpt-5", lastComposerReasoningEffort: "medium", }, - threadCodexParamsVersion: 0, + threadOpenCodeParamsVersion: 0, getThreadOpenCodeParams, patchThreadOpenCodeParams, - setThreadCodexSelectionKey: vi.fn() as unknown as Dispatch< + setThreadOpenCodeSelectionKey: vi.fn() as unknown as Dispatch< SetStateAction >, setAccessMode: vi.fn() as unknown as Dispatch>, @@ -75,7 +75,7 @@ function makeSyncParams( setPreferredCollabModeId: vi.fn() as unknown as Dispatch< SetStateAction >, - setPreferredCodexArgsOverride: vi.fn() as unknown as Dispatch< + setPreferredOpenCodeArgsOverride: vi.fn() as unknown as Dispatch< SetStateAction >, activeThreadIdRef: { current: null } as MutableRefObject, @@ -101,7 +101,7 @@ describe("useThreadSelectionHandlersOrchestration codex args selection", () => { const { result } = renderHook(() => useThreadSelectionHandlersOrchestration(params)); act(() => { - result.current.handleSelectCodexArgsOverride( + result.current.handleSelectOpenCodeArgsOverride( "--profile dev --model gpt-5 --sandbox workspace-write", ); }); @@ -109,7 +109,7 @@ describe("useThreadSelectionHandlersOrchestration codex args selection", () => { expect(params.persistThreadOpenCodeParams).toHaveBeenCalledWith({ opencodeArgsOverride: "--profile dev --model gpt-5 --sandbox workspace-write", }); - expect(params.setSelectedCodexArgsOverride).toHaveBeenCalledWith( + expect(params.setSelectedOpenCodeArgsOverride).toHaveBeenCalledWith( "--profile dev --model gpt-5 --sandbox workspace-write", ); expect(pushErrorToast).toHaveBeenCalledTimes(1); @@ -126,7 +126,7 @@ describe("useThreadSelectionHandlersOrchestration codex args selection", () => { const { result } = renderHook(() => useThreadSelectionHandlersOrchestration(params)); act(() => { - result.current.handleSelectCodexArgsOverride("--profile dev --config codex.toml"); + result.current.handleSelectOpenCodeArgsOverride("--profile dev --config codex.toml"); }); expect(params.persistThreadOpenCodeParams).toHaveBeenCalledWith({ @@ -153,19 +153,19 @@ describe("useThreadSelectionHandlersOrchestration codex args selection", () => { const { result } = renderHook(() => useThreadSelectionHandlersOrchestration(params)); act(() => { - result.current.handleSelectCodexArgsOverride("“—search —enable memory_tool”"); + result.current.handleSelectOpenCodeArgsOverride("“—search —enable memory_tool”"); }); expect(params.persistThreadOpenCodeParams).toHaveBeenCalledWith({ opencodeArgsOverride: "--search --enable memory_tool", }); - expect(params.setSelectedCodexArgsOverride).toHaveBeenCalledWith( + expect(params.setSelectedOpenCodeArgsOverride).toHaveBeenCalledWith( "--search --enable memory_tool", ); }); }); -describe("useThreadCodexSyncOrchestration seed behavior", () => { +describe("useThreadOpenCodeSyncOrchestration seed behavior", () => { beforeEach(() => { vi.clearAllMocks(); }); @@ -173,7 +173,7 @@ describe("useThreadCodexSyncOrchestration seed behavior", () => { it("preserves inherit semantics when seeding unseeded thread scope", async () => { const params = makeSyncParams(); - renderHook(() => useThreadCodexSyncOrchestration(params)); + renderHook(() => useThreadOpenCodeSyncOrchestration(params)); await waitFor(() => { expect(params.patchThreadOpenCodeParams).toHaveBeenCalledTimes(1); @@ -202,7 +202,7 @@ describe("useThreadCodexSyncOrchestration seed behavior", () => { } as MutableRefObject, }); - renderHook(() => useThreadCodexSyncOrchestration(params)); + renderHook(() => useThreadOpenCodeSyncOrchestration(params)); await waitFor(() => { expect(params.patchThreadOpenCodeParams).toHaveBeenCalledTimes(1); @@ -223,7 +223,7 @@ describe("useThreadCodexSyncOrchestration seed behavior", () => { selectedOpenCodeArgsOverride: "--profile selected", }); - renderHook(() => useThreadCodexSyncOrchestration(params)); + renderHook(() => useThreadOpenCodeSyncOrchestration(params)); await waitFor(() => { expect(params.patchThreadOpenCodeParams).toHaveBeenCalledTimes(1); @@ -241,7 +241,7 @@ describe("useThreadCodexSyncOrchestration seed behavior", () => { selectedOpenCodeArgsOverride: null, }); - renderHook(() => useThreadCodexSyncOrchestration(params)); + renderHook(() => useThreadOpenCodeSyncOrchestration(params)); await waitFor(() => { expect(params.patchThreadOpenCodeParams).toHaveBeenCalledTimes(1); @@ -282,10 +282,10 @@ describe("useThreadCodexSyncOrchestration seed behavior", () => { }, ); - renderHook(() => useThreadCodexSyncOrchestration(params)); + renderHook(() => useThreadOpenCodeSyncOrchestration(params)); await waitFor(() => { - expect(params.setPreferredCodexArgsOverride).toHaveBeenCalledWith( + expect(params.setPreferredOpenCodeArgsOverride).toHaveBeenCalledWith( "--profile inherited", ); }); @@ -298,7 +298,7 @@ describe("useThreadCodexSyncOrchestration seed behavior", () => { selectedServiceTier: "fast", }); - renderHook(() => useThreadCodexSyncOrchestration(params)); + renderHook(() => useThreadOpenCodeSyncOrchestration(params)); await waitFor(() => { expect(params.patchThreadOpenCodeParams).toHaveBeenCalledWith( diff --git a/src/features/app/orchestration/useThreadOrchestration.ts b/src/features/app/orchestration/useThreadOrchestration.ts index dceb788f83..8f3da83510 100644 --- a/src/features/app/orchestration/useThreadOrchestration.ts +++ b/src/features/app/orchestration/useThreadOrchestration.ts @@ -10,12 +10,12 @@ import type { } from "@/types"; import { normalizeOpenCodeArgsInput } from "@/utils/opencodeArgsInput"; import { useThreadOpenCodeParams } from "@threads/hooks/useThreadOpenCodeParams"; -import { getIgnoredCodexArgsFlagsMetadata } from "@threads/utils/opencodeArgsProfiles"; +import { getIgnoredOpenCodeArgsFlagsMetadata } from "@threads/utils/opencodeArgsProfiles"; import { buildThreadOpenCodeSeedPatch, createPendingThreadSeed, NO_THREAD_SCOPE_SUFFIX, - resolveThreadCodexState, + resolveThreadOpenCodeState, type PendingNewThreadSeed, } from "@threads/utils/threadOpenCodeParamsSeed"; import { makeThreadOpenCodeParamsKey } from "@threads/utils/threadStorage"; @@ -44,31 +44,31 @@ type UseThreadSelectionHandlersOrchestrationParams = { setSelectedServiceTier: (tier: ServiceTier | null | undefined) => void; setSelectedCollaborationModeId: (id: string | null) => void; setAccessMode: SetState; - setSelectedCodexArgsOverride?: (value: string | null) => void; + setSelectedOpenCodeArgsOverride?: (value: string | null) => void; persistThreadOpenCodeParams: PersistThreadOpenCodeParams; }; -type UseThreadCodexBootstrapOrchestrationParams = { +type UseThreadOpenCodeBootstrapOrchestrationParams = { activeWorkspaceId: string | null | undefined; }; -type UseThreadCodexSyncOrchestrationParams = { +type UseThreadOpenCodeSyncOrchestrationParams = { activeWorkspaceId: string | null | undefined; activeThreadId: string | null; appSettings: Pick< AppSettings, "defaultAccessMode" | "lastComposerModelId" | "lastComposerReasoningEffort" >; - threadCodexParamsVersion: number; + threadOpenCodeParamsVersion: number; getThreadOpenCodeParams: ReturnType["getThreadOpenCodeParams"]; patchThreadOpenCodeParams: ReturnType["patchThreadOpenCodeParams"]; - setThreadCodexSelectionKey: SetState; + setThreadOpenCodeSelectionKey: SetState; setAccessMode: SetState; setPreferredModelId: SetState; setPreferredEffort: SetState; setPreferredServiceTier: SetState; setPreferredCollabModeId: SetState; - setPreferredCodexArgsOverride?: SetState; + setPreferredOpenCodeArgsOverride?: SetState; activeThreadIdRef: MutableRefObject; pendingNewThreadSeedRef: MutableRefObject; selectedModelId: string | null; @@ -110,9 +110,9 @@ type UseThreadUiOrchestrationParams = { removeImagesForThread: (threadId: string) => void; }; -export function useThreadCodexBootstrapOrchestration({ +export function useThreadOpenCodeBootstrapOrchestration({ activeWorkspaceId, -}: UseThreadCodexBootstrapOrchestrationParams) { +}: UseThreadOpenCodeBootstrapOrchestrationParams) { const activeWorkspaceIdForParamsRef = useRef(activeWorkspaceId ?? null); useEffect(() => { @@ -122,20 +122,20 @@ export function useThreadCodexBootstrapOrchestration({ return useThreadOpenCodeOrchestration({ activeWorkspaceIdForParamsRef }); } -export function useThreadCodexSyncOrchestration({ +export function useThreadOpenCodeSyncOrchestration({ activeWorkspaceId, activeThreadId, appSettings, - threadCodexParamsVersion, + threadOpenCodeParamsVersion, getThreadOpenCodeParams, patchThreadOpenCodeParams, - setThreadCodexSelectionKey, + setThreadOpenCodeSelectionKey, setAccessMode, setPreferredModelId, setPreferredEffort, setPreferredServiceTier, setPreferredCollabModeId, - setPreferredCodexArgsOverride, + setPreferredOpenCodeArgsOverride, activeThreadIdRef, pendingNewThreadSeedRef, selectedModelId, @@ -144,7 +144,7 @@ export function useThreadCodexSyncOrchestration({ accessMode, selectedCollaborationModeId, selectedOpenCodeArgsOverride, -}: UseThreadCodexSyncOrchestrationParams) { +}: UseThreadOpenCodeSyncOrchestrationParams) { useLayoutEffect(() => { const workspaceId = activeWorkspaceId ?? null; const threadId = activeThreadId ?? null; @@ -159,7 +159,7 @@ export function useThreadCodexSyncOrchestration({ threadId ?? NO_THREAD_SCOPE_SUFFIX, ); const noThreadStored = getThreadOpenCodeParams(workspaceId, NO_THREAD_SCOPE_SUFFIX); - const resolved = resolveThreadCodexState({ + const resolved = resolveThreadOpenCodeState({ workspaceId, threadId, defaultAccessMode: appSettings.defaultAccessMode, @@ -170,13 +170,13 @@ export function useThreadCodexSyncOrchestration({ pendingSeed: pendingNewThreadSeedRef.current, }); - setThreadCodexSelectionKey(resolved.scopeKey); + setThreadOpenCodeSelectionKey(resolved.scopeKey); setAccessMode(resolved.accessMode); setPreferredModelId(resolved.preferredModelId); setPreferredEffort(resolved.preferredEffort); setPreferredServiceTier(resolved.preferredServiceTier); setPreferredCollabModeId(resolved.preferredCollabModeId); - setPreferredCodexArgsOverride?.(resolved.preferredOpenCodeArgsOverride); + setPreferredOpenCodeArgsOverride?.(resolved.preferredOpenCodeArgsOverride); }, [ activeThreadId, activeWorkspaceId, @@ -185,12 +185,12 @@ export function useThreadCodexSyncOrchestration({ appSettings.lastComposerReasoningEffort, getThreadOpenCodeParams, setPreferredCollabModeId, - setPreferredCodexArgsOverride, + setPreferredOpenCodeArgsOverride, setPreferredEffort, setPreferredModelId, setPreferredServiceTier, - setThreadCodexSelectionKey, - threadCodexParamsVersion, + setThreadOpenCodeSelectionKey, + threadOpenCodeParamsVersion, setAccessMode, activeThreadIdRef, pendingNewThreadSeedRef, @@ -283,7 +283,7 @@ export function useThreadSelectionHandlersOrchestration({ setSelectedServiceTier, setSelectedCollaborationModeId, setAccessMode, - setSelectedCodexArgsOverride, + setSelectedOpenCodeArgsOverride, persistThreadOpenCodeParams, }: UseThreadSelectionHandlersOrchestrationParams) { const handleSelectModel = useCallback( @@ -363,19 +363,19 @@ export function useThreadSelectionHandlersOrchestration({ [persistThreadOpenCodeParams, setAccessMode], ); - const handleSelectCodexArgsOverride = useCallback( + const handleSelectOpenCodeArgsOverride = useCallback( (value: string | null) => { const next = normalizeOpenCodeArgsInput(value); - if (next && getIgnoredCodexArgsFlagsMetadata(next).hasIgnoredFlags) { + if (next && getIgnoredOpenCodeArgsFlagsMetadata(next).hasIgnoredFlags) { pushErrorToast({ - title: "Some codex args are ignored", + title: "Some opencode args are ignored", message: "Selected flags are ignored for per-thread overrides.", }); } - setSelectedCodexArgsOverride?.(next); + setSelectedOpenCodeArgsOverride?.(next); persistThreadOpenCodeParams({ opencodeArgsOverride: next }); }, - [persistThreadOpenCodeParams, setSelectedCodexArgsOverride], + [persistThreadOpenCodeParams, setSelectedOpenCodeArgsOverride], ); return { @@ -384,7 +384,7 @@ export function useThreadSelectionHandlersOrchestration({ handleSelectServiceTier, handleSelectCollaborationMode, handleSelectAccessMode, - handleSelectCodexArgsOverride, + handleSelectOpenCodeArgsOverride, }; } diff --git a/src/features/composer/components/ComposerInput.tsx b/src/features/composer/components/ComposerInput.tsx index e6a3595e5f..f3ec4f711b 100644 --- a/src/features/composer/components/ComposerInput.tsx +++ b/src/features/composer/components/ComposerInput.tsx @@ -276,7 +276,7 @@ export function ComposerInput({ placeholder={ disabled ? "Review in progress. Chat will re-enable when it completes." - : "Ask Codex to do something..." + : "Ask OpenCode to do something..." } value={text} onChange={handleTextareaChange} diff --git a/src/features/composer/components/ComposerMetaBar.tsx b/src/features/composer/components/ComposerMetaBar.tsx index 71ed830992..8eccf78f2b 100644 --- a/src/features/composer/components/ComposerMetaBar.tsx +++ b/src/features/composer/components/ComposerMetaBar.tsx @@ -224,7 +224,7 @@ export function ComposerMetaBar({ {steerUnavailable && (
- Steer is unavailable in the current Codex config. Follow-ups will queue. + Steer is unavailable in the current OpenCode config. Follow-ups will queue.
)} diff --git a/src/features/settings/components/sections/SettingsDisplaySection.tsx b/src/features/settings/components/sections/SettingsDisplaySection.tsx index 0dc2b9583c..1ea2f2e1df 100644 --- a/src/features/settings/components/sections/SettingsDisplaySection.tsx +++ b/src/features/settings/components/sections/SettingsDisplaySection.tsx @@ -189,7 +189,7 @@ export function SettingsDisplaySection({ = { remote_models: "Refresh remote models before AppReady.", powershell_utf8: "Enforce UTF-8 output in PowerShell.", enable_request_compression: - "Compress streaming request bodies sent to codex-backend.", + "Compress streaming request bodies sent to opencode-backend.", apps: "Enable ChatGPT Apps integration.", apps_mcp_gateway: "Route Apps MCP calls through the configured gateway.", skill_mcp_dependency_install: "Allow prompting and installing missing MCP dependencies.", skill_env_var_dependency_prompt: "Prompt for missing skill environment variable dependencies.", - steer: "Enable turn steering capability when supported by Codex.", + steer: "Enable turn steering capability when supported by OpenCode.", collaboration_modes: "Enable collaboration mode presets.", personality: "Enable personality selection.", responses_websockets: @@ -96,11 +96,11 @@ export function SettingsFeaturesSection({ return (
Leave empty to use the system PATH resolution.
-