Skip to content

Commit d442b7f

Browse files
h4x0rclaude
andcommitted
feat: add Mistral Vibe agent support and comprehensive test coverage
Add first-class Mistral Vibe agent integration (adapter TOML, Rust scanner, ecosystem plugin card). Fix unimplemented!() panics in logogen mocks, replace hardcoded fetch calls in FocusView with typed API helpers, and add error states to EcosystemManager, ReplayViewer, and TriggerToast. Expand test suite from 226 to 1,211 tests covering all core UI components, lifecycle tools, cloud settings, hooks, and shared components. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b63d5f2 commit d442b7f

File tree

31 files changed

+3111
-43
lines changed

31 files changed

+3111
-43
lines changed

README.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<p align="center">
88
<strong>One screen. Every agent. Full control.</strong><br/>
9-
The missing command center for developers running Claude Code, Codex, AdaL, OpenCode, Gemini CLI, Aider, Goose, and more — simultaneously.
9+
The missing command center for developers running Claude Code, Codex, AdaL, OpenCode, Gemini CLI, Aider, Mistral Vibe, Goose, and more — simultaneously.
1010
</p>
1111

1212
<p align="center">
@@ -68,7 +68,7 @@ That's it. The GUI opens. What happens next depends on how you work:
6868

6969
Shepherd finds them automatically. No config, no restart, no flags.
7070

71-
Every iTerm2 pane running a known agent (Claude Code, Codex, AdaL, Aider, Gemini CLI, OpenCode, Goose, Plandex, gptme) appears on the Kanban board within seconds. Click any card to see the terminal, approve permissions, or review diffs.
71+
Every iTerm2 pane running a known agent (Claude Code, Codex, AdaL, Aider, Gemini CLI, OpenCode, Mistral Vibe, Goose, Plandex, gptme) appears on the Kanban board within seconds. Click any card to see the terminal, approve permissions, or review diffs.
7272

7373
Shepherd connects to iTerm2's native WebSocket API to discover sessions — no bridge scripts or manual setup required. It reads your iTerm2 auth cookie automatically.
7474

@@ -150,7 +150,7 @@ No single tool combines Kanban + rules engine + quality gates + multi-agent + on
150150

151151
### Agent-agnostic from day one
152152

153-
Nine agents supported out of the box, plus iTerm2 session adoption for agents already running in your terminal. Drop a TOML file to add any other terminal-based agent.
153+
Ten agents supported out of the box, plus iTerm2 session adoption for agents already running in your terminal. Drop a TOML file to add any other terminal-based agent.
154154

155155
| Agent | Hook Protocol | iTerm2 Adoption |
156156
|-------|---------------|-----------------|
@@ -160,6 +160,7 @@ Nine agents supported out of the box, plus iTerm2 session adoption for agents al
160160
| OpenCode | Output parsing ||
161161
| Gemini CLI | Output parsing ||
162162
| Aider | Output parsing ||
163+
| Mistral Vibe | Output parsing ||
163164
| Goose | Output parsing ||
164165
| Plandex | Output parsing ||
165166
| gptme | Output parsing ||
@@ -322,7 +323,7 @@ BACKEND (Rust · localhost)
322323
├── LLM Client — OpenAI, Anthropic, Ollama (provider-agnostic)
323324
├── Lifecycle Tools — name gen, logo gen, North Star PMF, wizard
324325
├── Ecosystem — Superpowers + context-mode + Alaya MCP auto-install
325-
├── iTerm2 Manager — session adoption, jobName detection, 9 agents
326+
├── iTerm2 Manager — session adoption, jobName detection, 10 agents
326327
├── Triggers — contextual suggestions (name, logo, strategy)
327328
├── PR Pipeline — stage, commit, rebase, gates, push, gh pr create
328329
└── State (SQLite) — tasks, sessions, permissions, diffs, gate results
@@ -331,8 +332,8 @@ BACKEND (Rust · localhost)
331332
AGENTS (your existing tools, unchanged)
332333
├── Claude Code ├── Codex CLI ├── AdaL
333334
├── OpenCode ├── Gemini CLI ├── Aider
334-
├── Goose ├── Plandex ├── gptme
335-
└── community adapters (TOML)
335+
├── Mistral Vibe ├── Goose ├── Plandex
336+
├── gptme └── community adapters (TOML)
336337
```
337338
338339
**Why Tauri over Electron**: ~600KB vs ~150MB. Native performance. Rust backend. No bundled Chromium.
@@ -420,7 +421,7 @@ Restart Shepherd. Your agent shows up in the New Task dropdown.
420421

421422
| | Shepherd | Vibe Kanban | Clorch | Claude Squad | Emdash | JetBrains Air |
422423
|---|:---:|:---:|:---:|:---:|:---:|:---:|
423-
| Multi-agent (6+ providers) | ✓ (9 adapters) || Claude only | 5 agents | 20+ agents | 4 agents |
424+
| Multi-agent (6+ providers) | ✓ (10 adapters) || Claude only | 5 agents | 20+ agents | 4 agents |
424425
| Kanban board |||||||
425426
| YOLO rules engine || YOLO only |||| 4-level |
426427
| Quality gates || Plugin |||||
@@ -436,7 +437,7 @@ Restart Shepherd. Your agent shows up in the New Task dropdown.
436437

437438
## Roadmap
438439

439-
**v0.1.0-alpha** (current): Core engine with embedded Axum server, task dispatch loop (polls every 2s), PTY agent execution via portable-pty, session monitoring with regex pattern detection, YOLO rules engine (YAML deny/allow), Kanban board (React + Zustand + xterm.js), WebSocket real-time events (14 event types), REST + WebSocket approve/deny, CLI with auto-server-spawn and shell completions, 9 agent adapters (TOML-defined), iTerm2 session adoption via WebSocket API, quality gates (auto-detect + custom scripts), PR pipeline (diff/commit/push/gh-pr-create), name/logo generators, North Star PMF wizard, nono.sh sandbox integration. 1,500+ tests. CI with fmt, clippy, cargo-deny, typos, Codecov, Vitest, and Playwright.
440+
**v0.1.0-alpha** (current): Core engine with embedded Axum server, task dispatch loop (polls every 2s), PTY agent execution via portable-pty, session monitoring with regex pattern detection, YOLO rules engine (YAML deny/allow), Kanban board (React + Zustand + xterm.js), WebSocket real-time events (14 event types), REST + WebSocket approve/deny, CLI with auto-server-spawn and shell completions, 10 agent adapters (TOML-defined, incl. Mistral Vibe), iTerm2 session adoption via WebSocket API, quality gates (auto-detect + custom scripts), PR pipeline (diff/commit/push/gh-pr-create), name/logo generators, North Star PMF wizard, nono.sh sandbox integration. 1,500+ tests. CI with fmt, clippy, cargo-deny, typos, Codecov, Vitest, and Playwright.
440441

441442
**v0.2**: Docker isolation mode. Homebrew tap + winget package. shepherd-bridge auto-registration script. Inline diff viewer with comments.
442443

@@ -461,7 +462,7 @@ cargo test --workspace # 1,500+ Rust tests
461462
# Frontend
462463
npm install
463464
npx tsc --noEmit # type check
464-
npx vitest run # 187 unit tests
465+
npx vitest run # 226 unit tests
465466
npx playwright test # 8 e2e browser tests
466467

467468
# Run the desktop app in dev mode

adapters/mistral-vibe.toml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[agent]
2+
name = "Mistral Vibe"
3+
command = "mistral-vibe"
4+
args = ["--auto-approve"]
5+
args_interactive = []
6+
version_check = "mistral-vibe --version"
7+
icon = "mistral-vibe"
8+
9+
[status]
10+
working_patterns = ["Thinking", "Running", "Writing", "Editing"]
11+
idle_patterns = ["> ", "vibe> "]
12+
input_patterns = ["[y/n", "approve?", "Allow?"]
13+
error_patterns = ["Error:", "error:", "FAILED", "Traceback"]
14+
15+
[permissions]
16+
approve = "y\n"
17+
approve_all = "y\n"
18+
deny = "n\n"
19+
20+
[capabilities]
21+
supports_hooks = false
22+
supports_prompt_arg = true
23+
supports_resume = false
24+
supports_mcp = false
25+
supports_worktree = true

crates/shepherd-core/src/iterm2/scanner.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const KNOWN_AGENTS: &[(&str, &str)] = &[
88
("codex", "codex"),
99
("adal", "adal"),
1010
("aider", "aider"),
11+
("mistral-vibe", "mistral-vibe"),
1112
("gemini", "gemini-cli"),
1213
("opencode", "opencode"),
1314
("goose", "goose"),
@@ -426,6 +427,11 @@ mod tests {
426427
assert_eq!(detect_agent("aider"), Some("aider"));
427428
}
428429

430+
#[test]
431+
fn test_detect_agent_mistral_vibe() {
432+
assert_eq!(detect_agent("mistral-vibe"), Some("mistral-vibe"));
433+
}
434+
429435
#[test]
430436
fn test_detect_agent_gemini() {
431437
assert_eq!(detect_agent("gemini"), Some("gemini-cli"));
@@ -687,6 +693,24 @@ mod tests {
687693
assert!(ids.is_empty());
688694
}
689695

696+
#[tokio::test]
697+
async fn test_scan_finds_mistral_vibe_session() {
698+
make_agent_mock!(
699+
MockMistralVibe,
700+
"sess-mistral-vibe",
701+
"mistral-vibe",
702+
"/src/ml-project"
703+
);
704+
let mut scanner = Scanner::new(std::collections::HashSet::new());
705+
let candidates = scanner
706+
.scan(&mut MockMistralVibe { calls: 0 })
707+
.await
708+
.unwrap();
709+
assert_eq!(candidates.len(), 1);
710+
assert_eq!(candidates[0].agent_name, "mistral-vibe");
711+
assert_eq!(candidates[0].cwd, "/src/ml-project");
712+
}
713+
690714
#[tokio::test]
691715
async fn test_scan_finds_opencode_session() {
692716
make_agent_mock!(MockOpencode, "sess-opencode", "opencode", "/src/app");

crates/shepherd-core/src/logogen/generate.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ mod tests {
178178
#[async_trait::async_trait]
179179
impl LlmProvider for MockImageProvider {
180180
async fn chat(&self, _request: &LlmRequest) -> anyhow::Result<LlmResponse> {
181-
unimplemented!()
181+
anyhow::bail!("chat not supported by image-only mock")
182182
}
183183
async fn generate_image(
184184
&self,
@@ -225,7 +225,7 @@ mod tests {
225225
#[async_trait::async_trait]
226226
impl LlmProvider for FailImageProvider {
227227
async fn chat(&self, _request: &LlmRequest) -> anyhow::Result<LlmResponse> {
228-
unimplemented!()
228+
anyhow::bail!("chat not supported by image-only mock")
229229
}
230230
async fn generate_image(
231231
&self,

src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { NewTaskDialog } from "./features/tasks/NewTaskDialog";
1212
import { useWebSocket } from "./hooks/useWebSocket";
1313
import { useKeyboardShortcuts } from "./hooks/useKeyboardShortcuts";
1414
import { useNotifications, notifyFromServer } from "./hooks/useNotifications";
15+
import { useAuthCallback } from "./hooks/useAuthCallback";
1516
import { useStore } from "./store";
1617
import type { ServerEvent } from "./types";
1718
import type { ConnectionStatus } from "./lib/ws";
@@ -69,6 +70,7 @@ const App: React.FC = () => {
6970
const wsRef = useWebSocket(handleServerEvent, handleStatusChange);
7071
useKeyboardShortcuts(wsRef);
7172
useNotifications();
73+
useAuthCallback();
7274

7375
// Sync the wsClient ref into the store whenever connection status changes.
7476
// The wsRef.current is set before onStatusChange fires, so it's safe to read here.

0 commit comments

Comments
 (0)