diff --git a/ROADMAP.md b/ROADMAP.md index 68b10195..90a2c261 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -228,12 +228,13 @@ annotations and exact projected curves remain deferred. See [view DXF](docs/view `diagnostics.crash_reports`, the MCP `crash_reports` tool or the CLI. Nothing is sent anywhere. See [crash reports](docs/crash-reports.md). - Agent chat (off by default, desktop): a side panel that drives a coding agent the user - already has (Claude Code through its ACP adapter, Codex, Gemini CLI, OpenCode, …) over the + already has (Claude Code through its ACP adapter, Codex, Gemini CLI, OpenCode, Grok Build, …) over the Agent Client Protocol, under the user's own login; SolidCraft stores no keys. The agent works through SolidCraft's MCP tools on a gated endpoint of its own: file actions wait for Allow or Deny, crash reports are off limits, 24 changes per message, one undo step per message, and the agent's whole process group ends with the panel or the app. Docks left or right, - minimises to a strip. See [agent chat](docs/agent-chat.md). + minimises to a strip. Grok Build discovery includes `~/.grok/bin` and reuses the user's + Grok login. See [agent chat](docs/agent-chat.md). - Command scripts from designs (#886): `timeline.export_script` (CLI `solidcraft-cli script`) writes a design's history as a script that `eval` and `run` replay into the same design — user parameters, units, sheet metal and plastic rules and materials as their own commands, diff --git a/crates/ui-egui/src/agent_chat/discover.rs b/crates/ui-egui/src/agent_chat/discover.rs index bdbf2809..c7f24c69 100644 --- a/crates/ui-egui/src/agent_chat/discover.rs +++ b/crates/ui-egui/src/agent_chat/discover.rs @@ -68,6 +68,16 @@ pub const KNOWN: &[Known] = &[ config_dir_var: None, key_vars: &[], }, + Known { + id: "grok", + name: "XAI Grok", + programs: &["grok"], + args: &["agent", "stdio"], + install: "see https://docs.x.ai/build/overview (Grok Build installer); then run grok login", + credentials: Some(".grok/auth.json"), + config_dir_var: None, + key_vars: &["XAI_API_KEY"], + }, Known { id: "copilot", name: "GitHub Copilot CLI", @@ -153,14 +163,14 @@ fn home() -> Option { std::env::var_os(if cfg!(windows) { "USERPROFILE" } else { "HOME" }).map(PathBuf::from).filter(|p| p.is_absolute()) } -/// PATH, then the usual places npm, Homebrew, nvm, Volta, bun and pipx put commands. +/// PATH, then the usual places npm, Homebrew, nvm, Volta, bun, pipx and Grok put commands. pub fn search_dirs() -> Vec { let mut dirs: Vec = std::env::var_os("PATH").map(|p| std::env::split_paths(&p).collect()).unwrap_or_default(); if let Some(prefix) = std::env::var_os("NPM_CONFIG_PREFIX").map(PathBuf::from) { dirs.push(if cfg!(windows) { prefix.clone() } else { prefix.join("bin") }); } if let Some(h) = home() { - for d in [".local/bin", ".npm-global/bin", ".npm-packages/bin", ".volta/bin", ".bun/bin", ".cargo/bin", "bin"] { + for d in [".local/bin", ".npm-global/bin", ".npm-packages/bin", ".volta/bin", ".bun/bin", ".cargo/bin", ".grok/bin", "bin"] { dirs.push(h.join(d)); } // nvm: every installed Node version's bin. @@ -326,6 +336,7 @@ mod tests { assert_eq!(version_of("@agentclientprotocol/codex-acp 2.2.2"), "2.2.2"); assert_eq!(version_of("2.1.295 (Claude Code)"), "2.1.295"); assert_eq!(version_of("goose v1.9.0"), "v1.9.0"); + assert_eq!(version_of("grok 1.0.58 (26283d10dd58) [alpha]"), "1.0.58"); assert_eq!(version_of("dev build"), "dev build"); } @@ -336,6 +347,7 @@ mod tests { let gemini = KNOWN.iter().find(|k| k.id == "gemini").unwrap(); let qwen = KNOWN.iter().find(|k| k.id == "qwen").unwrap(); let goose = KNOWN.iter().find(|k| k.id == "goose").unwrap(); + let grok = KNOWN.iter().find(|k| k.id == "grok").unwrap(); if std::env::var_os("GEMINI_API_KEY").is_none() && std::env::var_os("GOOGLE_API_KEY").is_none() { assert_eq!(login_of(gemini, Some(&home)), Login::NotLoggedIn); } @@ -345,6 +357,13 @@ mod tests { assert_eq!(login_of(qwen, Some(&home)), Login::NotLoggedIn); } assert_eq!(login_of(goose, Some(&home)), Login::Unknown, "keeps no file we know"); + if std::env::var_os("XAI_API_KEY").is_none() { + assert_eq!(login_of(grok, Some(&home)), Login::NotLoggedIn); + } + std::fs::create_dir_all(home.join(".grok")).unwrap(); + // Discovery checks only for the file; it never needs to parse the user's tokens. + std::fs::write(home.join(".grok/auth.json"), "not credential data").unwrap(); + assert_eq!(login_of(grok, Some(&home)), Login::LooksLoggedIn); let _ = std::fs::remove_dir_all(home); } diff --git a/docs/agent-chat.md b/docs/agent-chat.md index 756060c1..f3981244 100644 --- a/docs/agent-chat.md +++ b/docs/agent-chat.md @@ -1,7 +1,7 @@ # Agent chat Agent chat is a side panel where you talk to a coding agent you already use (Claude Code, -Codex, Gemini CLI, OpenCode and others), or to a model behind an OpenAI-compatible endpoint you +Codex, Gemini CLI, OpenCode, Grok Build and others), or to a model behind an OpenAI-compatible endpoint you choose (Ollama or LM Studio on your computer, OpenAI, any other URL), and have it work on the design that's open. A coding agent runs on your computer under **your own account** with that agent: SolidCraft doesn't sell or proxy a model and needs no key for it. An endpoint's key, if @@ -53,7 +53,7 @@ conversation starts with), its own permission setting, and **Remove** for the on SolidCraft looks for agents that speak the [Agent Client Protocol](https://agentclientprotocol.com) on your `PATH` and in the usual install folders a desktop app's `PATH` often misses (npm's -global folder, nvm, Volta, bun, `~/.local/bin`, Homebrew, `%APPDATA%\npm`). For each one it +global folder, nvm, Volta, bun, `~/.local/bin`, `~/.grok/bin`, Homebrew, `%APPDATA%\npm`). For each one it shows its **version** (from `--version`, given three seconds) and whether it looks **signed in**. SolidCraft only checks whether the agent's own login file (`~/.claude/.credentials.json`, `~/.codex/auth.json`, `~/.gemini/oauth_creds.json`, …) or one of its key variables exists. It never @@ -66,12 +66,26 @@ the keychain, so SolidCraft doesn't guess there. | Codex | `npm install -g @agentclientprotocol/codex-acp` | | Gemini CLI | `npm install -g @google/gemini-cli` (it speaks ACP itself: `gemini --acp`) | | OpenCode | `npm install -g opencode-ai` (`opencode acp`) | +| XAI Grok | [Grok Build installer](https://docs.x.ai/build/overview), then `grok login` (`grok agent stdio` speaks ACP) | | GitHub Copilot CLI, Qwen Code, goose | listed with their install command when missing | The panel lists agents that aren't installed with their install command and a **Copy** button. **Refresh** looks again after you install one. **Test** starts an agent briefly, asks it for a session and ends it again. +### XAI Grok + +Install **Grok Build** and run `grok login` in a terminal to sign in with your Grok account. +In SolidCraft, open **AI → Refresh**, select +**XAI Grok**, then **Connect**. You can make it the default under +**Preferences → AI → Agents**. + +SolidCraft reuses Grok Build's sign-in in `~/.grok/auth.json`; it checks only whether that file +exists and does not read or copy its tokens. If sign-in is needed, the panel offers Grok's own +sign-in methods. You can also run `grok login` again and reconnect. Grok controls model access +and usage limits for your account. This connection does not require an API key in SolidCraft. +Grok Build also supports `XAI_API_KEY` for users who choose API authentication. + ### Add agent… - **Installed agent:** your own entry for an installed agent, for example with other arguments. diff --git a/docs/design/in-app-agent-chat.md b/docs/design/in-app-agent-chat.md index 56f65a27..8db181ba 100644 --- a/docs/design/in-app-agent-chat.md +++ b/docs/design/in-app-agent-chat.md @@ -50,6 +50,7 @@ with SolidCraft, the user installs the agent. | Codex | `codex-acp` adapter (`@zed-industries/codex-acp` 0.16 moved to `@agentclientprotocol/codex-acp`) | `@agentclientprotocol/codex-acp` 2.2.2, Apache-2.0 | `--version` (0.16 rejected the flag; 2.x prints it) | Agent method `chat-gpt` (the adapter opens the browser for the ChatGPT login when the client calls `authenticate`), and `api-key` for a key the user configures in Codex. 0.16 also listed `env_var` methods for `CODEX_API_KEY` / `OPENAI_API_KEY`. The login is Codex's own: `~/.codex/auth.json`. | | Gemini CLI | built in: `gemini --acp` (the ACP registry's current flag; older releases used `--experimental-acp`) | `@google/gemini-cli` 0.64, Apache-2.0 | `--version` | Its own Google login (`~/.gemini/oauth_creds.json`) or a key in the environment. | | OpenCode | built in: `opencode acp` | `opencode-ai` 1.19, MIT | `--version` | Its own providers' logins (`~/.local/share/opencode/auth.json`) or keys in the environment. | +| XAI Grok | built in: `grok agent stdio` | [Grok Build](https://github.com/xai-org/grok-build), Apache-2.0; installed separately | `grok --version` prints `grok 1.0.58 (…) [alpha]` (checked 2026-10-15; in-app connection also checked with 1.0.60) | Its own `~/.grok/auth.json` or `XAI_API_KEY`. `grok login` signs in in the browser; ACP advertises `cached_token` and `grok.com` authentication methods. | | Others in the ACP registry | `copilot --acp`, `qwen --acp`, `opencode acp`, `goose acp`, `cline --acp`, `kimi acp`, … | mixed; several are proprietary, one is GPL and one AGPL (we only start them as programs, never link them) | `--version` | each its own | The registry (`https://cdn.agentclientprotocol.com/registry/v1/latest/registry.json`) lists