Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/main/broker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1280,7 +1280,7 @@
}

const label = spawnCliLabel(input.cli)
if (!['claude', 'codex', 'opencode'].includes(label)) return input
if (!['claude', 'codex', 'opencode', 'grok'].includes(label)) return input
const resolved = resolveCommandWithAugmentedPath(input.cli)
if (!resolved) {
throw new Error(
Expand Down Expand Up @@ -3075,7 +3075,7 @@
): Promise<void> {
let output = ''
let timer: ReturnType<typeof setTimeout> | undefined
let livenessTimer: ReturnType<typeof setInterval> | undefined

Check warning on line 3078 in src/main/broker.ts

View workflow job for this annotation

GitHub Actions / checks

'livenessTimer' is never reassigned. Use 'const' instead
let settled = false
let resolveReady: (() => void) | undefined
let rejectReady: ((error: Error) => void) | undefined
Expand Down
2 changes: 1 addition & 1 deletion src/main/proactive-agent.bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export type ProactiveAgentDraft = {
name: string
description?: string
cloudAgentId: string
harness: 'claude' | 'codex' | 'opencode'
harness: 'claude' | 'codex' | 'opencode' | 'grok'
model: string
systemPrompt: string
integrations: Record<string, Record<string, unknown>>
Expand Down
4 changes: 2 additions & 2 deletions src/main/proactive-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type PersonaKitModule = {

const PERSONA_ID_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/
const WATCH_EVENTS = new Set<ProactiveAgentWatchEventKind>(['created', 'updated', 'deleted'])
const HARNESSES = new Set(['claude', 'codex', 'opencode'])
const HARNESSES = new Set(['claude', 'codex', 'opencode', 'grok'])
const RUN_MODES = new Set(['cloud', 'local'])
const MEMORY_SCOPES = new Set(['workspace', 'project', 'persona'])
const REASONING_LEVELS = new Set(['low', 'medium', 'high'])
Expand Down Expand Up @@ -390,7 +390,7 @@ export class ProactiveAgentManager {
throw new Error('Agent id must be kebab-case')
}
if (!HARNESSES.has(draft.harness)) {
throw new Error('Harness must be one of claude, codex, or opencode')
throw new Error('Harness must be one of claude, codex, opencode, or grok')
}
if (!RUN_MODES.has(draft.runMode || 'cloud')) {
throw new Error('Run mode must be cloud or local')
Expand Down
2 changes: 1 addition & 1 deletion src/main/proactive-agent.types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export type ProactiveAgentHarness = 'claude' | 'codex' | 'opencode'
export type ProactiveAgentHarness = 'claude' | 'codex' | 'opencode' | 'grok'
export type ProactiveAgentStatus = 'draft' | 'warming' | 'active' | 'paused' | 'error'
export type ProactiveAgentRunStatus = 'running' | 'succeeded' | 'failed'
export type ProactiveAgentRunMode = 'cloud' | 'local'
Expand Down
6 changes: 4 additions & 2 deletions src/renderer/src/components/agents/CloudAgentPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ export type CloudAgentPickerProps = {
const HARNESS_OPTIONS = [
{ value: 'claude', label: 'Claude', defaultModel: 'claude-opus-4-7' },
{ value: 'codex', label: 'Codex', defaultModel: 'gpt-5.2' },
{ value: 'opencode', label: 'OpenCode', defaultModel: 'claude-sonnet-4-6' }
{ value: 'opencode', label: 'OpenCode', defaultModel: 'claude-sonnet-4-6' },
{ value: 'grok', label: 'Grok', defaultModel: 'grok-build-0.1' }
]

function getErrorMessage(error: unknown): string {
Expand Down Expand Up @@ -140,9 +141,10 @@ function cloudWorkerName(agent: CloudAgentRecord): string {

function cloudWorkerCli(agent: CloudAgentRecord): string {
const harness = agent.harness.trim().toLowerCase()
if (harness === 'claude' || harness === 'codex' || harness === 'opencode') return harness
if (harness === 'claude' || harness === 'codex' || harness === 'opencode' || harness === 'grok') return harness
if (harness === 'anthropic') return 'claude'
if (harness === 'openai' || harness === 'gpt' || harness === 'chatgpt') return 'codex'
if (harness === 'xai' || harness === 'x.ai') return 'grok'
return 'claude'
}

Expand Down
14 changes: 13 additions & 1 deletion src/renderer/src/components/common/AgentIcons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,24 @@ export function GeminiIcon({ className }: AgentIconProps): React.ReactNode {
)
}

export function GrokIcon({ className }: AgentIconProps): React.ReactNode {
return (
<svg viewBox="0 0 24 24" fill="none" className={className} aria-hidden="true">
<path
d="M13.545 11.998 20.5 4H18.64L12.72 10.89 7.955 4H2l7.29 10.608L2 22.5h1.86l6.38-7.408 5.1 7.408H21.5l-7.955-11.502Zm-2.26 2.621-.74-1.059L4.52 5.26h2.535l4.753 6.799.74 1.059 6.177 8.836H16.19l-4.905-7.335Z"
fill="currentColor"
/>
</svg>
)
}

const AGENT_ICON_COMPONENTS = {
claude: ClaudeIcon,
codex: CodexIcon,
copilot: CopilotIcon,
opencode: OpenCodeIcon,
gemini: GeminiIcon
gemini: GeminiIcon,
grok: GrokIcon
} satisfies Record<string, React.ComponentType<AgentIconProps>>

export function getAgentIcon(cli?: string): React.ComponentType<AgentIconProps> | null {
Expand Down
5 changes: 3 additions & 2 deletions src/renderer/src/components/common/AgentToolbar.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import type React from 'react'
import { Settings } from 'lucide-react'
import { ClaudeIcon, CodexIcon, CopilotIcon, GeminiIcon, OpenCodeIcon } from '@/components/common/AgentIcons'
import { ClaudeIcon, CodexIcon, CopilotIcon, GeminiIcon, GrokIcon, OpenCodeIcon } from '@/components/common/AgentIcons'
import { useUIStore } from '@/stores/ui-store'

const AGENTS = [
{ cli: 'claude', label: 'claude', Icon: ClaudeIcon },
{ cli: 'codex', label: 'codex', Icon: CodexIcon },
{ cli: 'copilot', label: 'copilot', Icon: CopilotIcon },
{ cli: 'opencode', label: 'opencode', Icon: OpenCodeIcon },
{ cli: 'gemini', label: 'gemini', Icon: GeminiIcon }
{ cli: 'gemini', label: 'gemini', Icon: GeminiIcon },
{ cli: 'grok', label: 'grok', Icon: GrokIcon }
]

export function AgentToolbar(): React.ReactNode {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export type ProactiveAgentDraft = {
name: string
description?: string
cloudAgentId: string
harness: 'claude' | 'codex' | 'opencode'
harness: 'claude' | 'codex' | 'opencode' | 'grok'
model: string
systemPrompt: string
integrations: Record<string, Record<string, unknown>>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ type KeyValueRow = {
const MODEL_OPTIONS: Record<Harness, string[]> = {
claude: ['claude-opus-4-7', 'claude-sonnet-4-6', 'claude-haiku-4-5'],
codex: ['gpt-5.2', 'gpt-5.1-codex', 'gpt-5.1-codex-mini'],
opencode: ['claude-sonnet-4-6', 'gpt-5.2', 'qwen3-coder']
opencode: ['claude-sonnet-4-6', 'gpt-5.2', 'qwen3-coder'],
grok: ['grok-build-0.1', 'grok-code-fast-1', 'grok-code-fast']
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

const DEPLOY_PHASES: DeployPhase[] = [
Expand Down Expand Up @@ -926,6 +927,7 @@ export function ProactiveAgentEditor({
<option value="claude">Claude</option>
<option value="codex">Codex</option>
<option value="opencode">OpenCode</option>
<option value="grok">Grok</option>
</select>
<FieldError message={errors.harness} />
</label>
Expand Down
7 changes: 4 additions & 3 deletions src/renderer/src/components/sidebar/SpawnAgentDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import type React from 'react'
import { useCallback, useEffect, useRef, useState } from 'react'
import { Loader2, X } from 'lucide-react'
import { ClaudeIcon, CodexIcon } from '@/components/common/AgentIcons'
import { ClaudeIcon, CodexIcon, GrokIcon } from '@/components/common/AgentIcons'
import { listProjectPersonas, spawnProjectAgent, spawnProjectPersona, type SpawnAgentCli } from '@/lib/spawn-agent'
import type { WorkforcePersona } from '@/lib/ipc'
import { useProjectStore, type ProjectRoot } from '@/stores/project-store'
import { useUIStore } from '@/stores/ui-store'

const AGENT_OPTIONS: Array<{ cli: SpawnAgentCli; label: string; Icon: typeof ClaudeIcon }> = [
{ cli: 'claude', label: 'Claude', Icon: ClaudeIcon },
{ cli: 'codex', label: 'Codex', Icon: CodexIcon }
{ cli: 'codex', label: 'Codex', Icon: CodexIcon },
{ cli: 'grok', label: 'Grok', Icon: GrokIcon }
]

export function SpawnAgentDialog(): React.ReactNode {
Expand Down Expand Up @@ -207,7 +208,7 @@ export function SpawnAgentDialog(): React.ReactNode {
className="h-9 w-full rounded-md border border-[var(--pear-border-subtle)] bg-[var(--pear-bg)] px-3 text-sm text-[var(--pear-text)] outline-none placeholder:text-[var(--pear-text-faint)] focus:border-[var(--pear-accent-dim)] disabled:opacity-50"
/>
</div>
<div className="grid grid-cols-2 gap-3">
<div className="grid grid-cols-3 gap-3">
{AGENT_OPTIONS.map(({ cli, label, Icon }) => (
<button
key={cli}
Expand Down
16 changes: 13 additions & 3 deletions src/renderer/src/components/terminal/TerminalPane.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type React from 'react'
import { useEffect, useMemo, useRef, useState } from 'react'
import { AlertTriangle, ChevronLeft, ChevronRight, Columns2, CornerUpLeft, Loader2, PanelTop, X } from 'lucide-react'
import { AgentHarnessIcon, ClaudeIcon, CodexIcon } from '@/components/common/AgentIcons'
import { AlertTriangle, ChevronLeft, ChevronRight, Columns2, CornerUpLeft, Loader2, Network, PanelTop, X } from 'lucide-react'
import { AgentHarnessIcon, ClaudeIcon, CodexIcon, GrokIcon } from '@/components/common/AgentIcons'
import { ChatComposerInput } from '@/components/chat/ChatComposerInput'
import { spawnProjectAgent, type SpawnAgentCli } from '@/lib/spawn-agent'
import { formatTokenCount } from '@/lib/format'
Expand Down Expand Up @@ -777,7 +777,7 @@ export function TerminalPane(): React.ReactNode {
{activeProject ? 'No agents running' : 'No project selected'}
</p>
{activeProject ? (
<div className="mt-4 grid w-full max-w-[340px] grid-cols-2 gap-3">
<div className="mt-4 grid w-full max-w-[420px] grid-cols-3 gap-3">
<button
type="button"
onClick={() => handleSpawn('claude')}
Expand All @@ -798,6 +798,16 @@ export function TerminalPane(): React.ReactNode {
<CodexIcon className="h-4 w-4" />
<span>{spawningCli === 'codex' ? 'Starting' : 'Codex'}</span>
</button>
<button
type="button"
onClick={() => handleSpawn('grok')}
disabled={!activeRoot?.pathExists || spawningCli !== null}
className="flex items-center justify-center gap-2 rounded-lg border border-[var(--pear-border)] px-4 py-3 text-sm text-[var(--pear-text-dim)] hover:border-[var(--pear-accent-dim)] hover:text-[var(--pear-text)] disabled:cursor-not-allowed disabled:opacity-40"
title={activeRoot?.pathExists ? 'Spawn Grok' : `Path not found: ${activeRoot?.path || activeProject.rootPath}`}
>
<GrokIcon className="h-4 w-4" />
<span>{spawningCli === 'grok' ? 'Starting' : 'Grok'}</span>
</button>
</div>
) : (
<button
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/src/lib/spawn-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { getAgentKey, useAgentStore } from '@/stores/agent-store'
import { useProjectStore, type Project, type ProjectRoot } from '@/stores/project-store'
import { useUIStore } from '@/stores/ui-store'

export type SpawnAgentCli = 'claude' | 'codex'
export type SpawnAgentCli = 'claude' | 'codex' | 'grok'

function nextAgentName(cli: SpawnAgentCli, projectId: string, liveNames: string[]): string {
const existingNames = new Set([
Expand Down
2 changes: 1 addition & 1 deletion src/shared/types/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ export type CloudAgentEvent =
| { type: 'sync-mode-changed'; projectId: string; syncMode: CloudAgentSyncMode }
| { type: 'error'; projectId: string; message: string }

export type ProactiveAgentHarness = 'claude' | 'codex' | 'opencode'
export type ProactiveAgentHarness = 'claude' | 'codex' | 'opencode' | 'grok'
export type ProactiveAgentStatus = 'draft' | 'warming' | 'active' | 'paused' | 'error'
export type ProactiveAgentRunStatus = 'running' | 'succeeded' | 'failed'
export type ProactiveAgentRunMode = 'cloud' | 'local'
Expand Down
Loading