From 29cad7333ea905cdb48dfe367542da54413c3b08 Mon Sep 17 00:00:00 2001 From: Yeachan-Heo Date: Mon, 17 Aug 2026 14:49:23 +0900 Subject: [PATCH] feat(agents): add Gajae Code to the built-in agent registry Gajae Code (gjc) is a terminal coding agent that runs on an existing Claude/Codex subscription. It launches as a plain interactive TUI in the worktree cwd, so it only needed registry wiring: detection, display name, telemetry kind, icon, and auto-pick order. The launch table moved to src/shared/tui-agent-config-table.ts because one more agent pushed tui-agent-config.ts past the 300-line ceiling; per AGENTS.md the file is split instead of baselined, and the table is re-exported from the old path so no importer changes. --- README.md | 1 + config/scripts/locale-translation-policy.mjs | 1 + .../components/mobile-agent-icon-assets.ts | 3 +- src/renderer/src/i18n/locales/en.json | 1 + src/renderer/src/i18n/locales/es.json | 1 + src/renderer/src/i18n/locales/ja.json | 1 + src/renderer/src/i18n/locales/ko.json | 1 + src/renderer/src/i18n/locales/zh.json | 1 + src/renderer/src/lib/agent-catalog.tsx | 7 + src/renderer/src/lib/agent-favicon-assets.ts | 4 +- src/renderer/src/lib/agent-status.ts | 1 + src/shared/agent-icons/gjc.png | Bin 0 -> 8925 bytes src/shared/agent-kind.ts | 1 + src/shared/gjc-agent-registration.test.ts | 39 +++ src/shared/skills-cli-agent-keys.ts | 2 + src/shared/telemetry-events.ts | 1 + src/shared/tui-agent-config-table.ts | 300 ++++++++++++++++++ src/shared/tui-agent-config.ts | 291 +---------------- src/shared/tui-agent-display-names.ts | 1 + src/shared/tui-agent-selection.ts | 1 + src/shared/tui-agent.ts | 1 + 21 files changed, 371 insertions(+), 288 deletions(-) create mode 100644 src/shared/agent-icons/gjc.png create mode 100644 src/shared/gjc-agent-registration.test.ts create mode 100644 src/shared/tui-agent-config-table.ts diff --git a/README.md b/README.md index 5d75bcc89d32..d5320e51a889 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,7 @@ Works with **any CLI agent** — if it runs in a terminal, it runs in Orca. OpenClaude logo OpenClaude   Antigravity logo Antigravity   Pi logo Pi   + Gajae Code logo Gajae Code   oh-my-pi logo oh-my-pi   Hermes Agent logo Hermes Agent   Devin logo Devin   diff --git a/config/scripts/locale-translation-policy.mjs b/config/scripts/locale-translation-policy.mjs index eb1a7ea0b925..ec34a1c61bee 100644 --- a/config/scripts/locale-translation-policy.mjs +++ b/config/scripts/locale-translation-policy.mjs @@ -43,6 +43,7 @@ export const NEVER_TRANSLATE_VALUES = new Set([ 'Cursor', 'Droid', 'Devin', + 'Gajae Code', 'Gemini', 'Git', 'Git Bash', diff --git a/mobile/src/components/mobile-agent-icon-assets.ts b/mobile/src/components/mobile-agent-icon-assets.ts index 38a48373734b..12311c2edcd8 100644 --- a/mobile/src/components/mobile-agent-icon-assets.ts +++ b/mobile/src/components/mobile-agent-icon-assets.ts @@ -39,5 +39,6 @@ export const MOBILE_AGENT_ICON_ASSETS: Partial faviconDomain: 'primeintellect.ai', homepageUrl: 'https://github.com/PrimeIntellect-ai/prime-agent' }, + { + id: 'gjc', + label: translate('auto.lib.agent.catalog.c851f042e2', 'Gajae Code'), + cmd: 'gjc', + faviconDomain: 'gajae-code.com', + homepageUrl: 'https://gajae-code.com' + }, { id: 'gemini', label: translate('auto.lib.agent.catalog.12e6baa4f7', 'Gemini'), diff --git a/src/renderer/src/lib/agent-favicon-assets.ts b/src/renderer/src/lib/agent-favicon-assets.ts index 565437f75bef..04327137341d 100644 --- a/src/renderer/src/lib/agent-favicon-assets.ts +++ b/src/renderer/src/lib/agent-favicon-assets.ts @@ -24,6 +24,7 @@ import rovoUrl from '../../../shared/agent-icons/rovo.png?url' import hermesUrl from '../../../shared/agent-icons/hermes.png?url' import devinUrl from '../../../shared/agent-icons/devin.png?url' import openclawUrl from '../../../shared/agent-icons/openclaw.png?url' +import gjcUrl from '../../../shared/agent-icons/gjc.png?url' // Why: these agents have no hand-authored SVG glyph, so previously their icons // loaded live from Google's favicon service. That service is unreachable in some @@ -57,5 +58,6 @@ export const AGENT_FAVICON_ASSETS: Partial> = { rovo: rovoUrl, hermes: hermesUrl, devin: devinUrl, - openclaw: openclawUrl + openclaw: openclawUrl, + gjc: gjcUrl } diff --git a/src/renderer/src/lib/agent-status.ts b/src/renderer/src/lib/agent-status.ts index 94933a05bffa..5d6d75613c7c 100644 --- a/src/renderer/src/lib/agent-status.ts +++ b/src/renderer/src/lib/agent-status.ts @@ -108,6 +108,7 @@ const ICONABLE_AGENT_TYPES: Record = { pi: true, omp: true, 'prime-agent': true, + gjc: true, gemini: true, antigravity: true, aider: true, diff --git a/src/shared/agent-icons/gjc.png b/src/shared/agent-icons/gjc.png new file mode 100644 index 0000000000000000000000000000000000000000..e96bf350668803fc578d6d3a33ff539c81585751 GIT binary patch literal 8925 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 literal 0 HcmV?d00001 diff --git a/src/shared/agent-kind.ts b/src/shared/agent-kind.ts index 324a73f2cd89..a549efb047fe 100644 --- a/src/shared/agent-kind.ts +++ b/src/shared/agent-kind.ts @@ -24,6 +24,7 @@ const TUI_AGENT_KIND_BY_AGENT = { pi: 'pi', omp: 'omp', 'prime-agent': 'prime-agent', + gjc: 'gjc', gemini: 'gemini', antigravity: 'antigravity', aider: 'aider', diff --git a/src/shared/gjc-agent-registration.test.ts b/src/shared/gjc-agent-registration.test.ts new file mode 100644 index 000000000000..0862c5b28654 --- /dev/null +++ b/src/shared/gjc-agent-registration.test.ts @@ -0,0 +1,39 @@ +import { describe, expect, it } from 'vitest' +import { tuiAgentToAgentKind } from './agent-kind' +import { SKILLS_CLI_AGENT_KEY_BY_TUI_AGENT } from './skills-cli-agent-keys' +import { TUI_AGENT_DISPLAY_NAMES } from './tui-agent-display-names' +import { getTuiAgentLaunchCommand, isTuiAgent, TUI_AGENT_CONFIG } from './tui-agent-config' +import { TUI_AGENT_AUTO_PICK_ORDER } from './tui-agent-selection' + +// Why: Gajae Code launches as a plain interactive TUI on `gjc`, so the only thing +// that can silently break it is a half-finished registration (union member with no +// config, or a config the auto-pick order never reaches). +describe('Gajae Code agent registration', () => { + it('detects and launches the published `gjc` binary', () => { + expect(isTuiAgent('gjc')).toBe(true) + const config = TUI_AGENT_CONFIG.gjc + expect(config.detectCmd).toBe('gjc') + expect(getTuiAgentLaunchCommand(config, 'darwin')).toBe('gjc') + expect(config.expectedProcess).toBe('gjc') + }) + + it('injects the launch prompt after startup instead of as argv', () => { + // Why: `gjc -p ` is its non-interactive print mode, and it exposes no + // prefill flag or env var, so argv/flag injection would exit the hosted session. + expect(TUI_AGENT_CONFIG.gjc.promptInjectionMode).toBe('stdin-after-start') + expect(TUI_AGENT_CONFIG.gjc.draftPromptFlag).toBeUndefined() + expect(TUI_AGENT_CONFIG.gjc.draftPromptEnvVar).toBeUndefined() + }) + + it('is selectable, labelled, and telemetry-mapped', () => { + expect(TUI_AGENT_DISPLAY_NAMES.gjc).toBe('Gajae Code') + expect(TUI_AGENT_AUTO_PICK_ORDER).toContain('gjc') + expect(tuiAgentToAgentKind('gjc')).toBe('gjc') + }) + + it('claims no skills CLI agent key', () => { + // Why: the community skills CLI exits 1 on an unknown --agent value, and it has + // no gjc key; Gajae Code reads its own .gjc roots plus shared .agents/skills. + expect(SKILLS_CLI_AGENT_KEY_BY_TUI_AGENT.gjc).toBeNull() + }) +}) diff --git a/src/shared/skills-cli-agent-keys.ts b/src/shared/skills-cli-agent-keys.ts index 3126c0a81e5f..5e0406ee16f5 100644 --- a/src/shared/skills-cli-agent-keys.ts +++ b/src/shared/skills-cli-agent-keys.ts @@ -23,6 +23,8 @@ export const SKILLS_CLI_AGENT_KEY_BY_TUI_AGENT = { pi: 'pi', omp: null, 'prime-agent': null, + // Why: the skills CLI has no gjc key; Gajae Code reads its own .gjc roots plus shared .agents/skills. + gjc: null, gemini: 'gemini-cli', antigravity: 'antigravity', aider: null, diff --git a/src/shared/telemetry-events.ts b/src/shared/telemetry-events.ts index f6bbea3c755f..bf87ccdd555a 100644 --- a/src/shared/telemetry-events.ts +++ b/src/shared/telemetry-events.ts @@ -100,6 +100,7 @@ export const AGENT_KIND_VALUES = [ 'devin', 'ante', 'trae', + 'gjc', 'other' ] as const export const agentKindSchema = z.enum(AGENT_KIND_VALUES) diff --git a/src/shared/tui-agent-config-table.ts b/src/shared/tui-agent-config-table.ts new file mode 100644 index 000000000000..b96d8db9a722 --- /dev/null +++ b/src/shared/tui-agent-config-table.ts @@ -0,0 +1,300 @@ +// Why: split out of tui-agent-config.ts so the launch table can keep growing with +// new agents without pushing that module past the 300-line lint ceiling; the types +// and helpers live beside it in ./tui-agent-config. +import { getOrcaCliCommandNameForPlatform } from './orca-cli-command-name' +import type { TuiAgent } from './tui-agent' +import type { TuiAgentConfig } from './tui-agent-config' + +export const TUI_AGENT_CONFIG: Record = { + claude: { + detectCmd: 'claude', + launchCmd: 'claude', + expectedProcess: 'claude', + promptInjectionMode: 'argv', + // Why: `claude --prefill ` seeds the input without submitting, avoiding the paste-after-ready race (PR https://github.com/stablyai/orca/pull/926). + draftPromptFlag: '--prefill' + }, + 'claude-agent-teams': { + // Why: an Orca-provided launch mode, not a separate binary; detection follows the Orca CLI. + detectCmd: 'orca', + detectCmdAliases: ['orca-dev', 'orca-ide'], + // Why: require Claude too so fresh installs (Orca shim always present) don't report Agent Teams without an agent CLI. + detectRequiredCommands: ['claude'], + // Why: Windows/WSL use Claude's in-process Agent Teams fallback, not this Orca native-pane/tmux-shim wrapper. + detectUnsupportedRuntimes: ['win32', 'wsl'], + launchCmd: 'orca claude-teams', + launchCmdByPlatform: { + linux: `${getOrcaCliCommandNameForPlatform('linux')} claude-teams`, + win32: `${getOrcaCliCommandNameForPlatform('win32')} claude-teams` + }, + expectedProcess: 'claude', + promptInjectionMode: 'stdin-after-start' + }, + openclaude: { + detectCmd: 'openclaude', + launchCmd: 'openclaude', + expectedProcess: 'openclaude', + promptInjectionMode: 'argv', + draftPromptFlag: '--prefill' + }, + codex: { + detectCmd: 'codex', + launchCmd: 'codex', + expectedProcess: 'codex', + promptInjectionMode: 'argv', + windowsInputRecordPasteNewline: 'alt-enter', + preflightTrust: 'codex', + draftPasteReadySignal: 'codex-composer-prompt', + draftPasteReadyTimeoutMs: 20_000 + }, + autohand: { + detectCmd: 'autohand', + launchCmd: 'autohand', + expectedProcess: 'autohand', + promptInjectionMode: 'stdin-after-start' + }, + ante: { + detectCmd: 'ante', + launchCmd: 'ante', + expectedProcess: 'ante', + // Why: `ante --prompt` is headless (runs once and exits), so launch the bare TUI and inject after startup. + promptInjectionMode: 'stdin-after-start' + }, + trae: { + // Why: the unrelated open-source bytedance/trae-agent also installs a `trae-cli` + // binary, so detect TRAE CN's CLI on `traecli`, an alias only TRAE CN ships. + detectCmd: 'traecli', + launchCmd: 'traecli', + expectedProcess: 'traecli', + // Why: `traecli [prompt]` takes the task as a positional argv, same as Claude/Codex. + promptInjectionMode: 'argv', + // Why: separator so prompts starting with `help`/`config`/`-…` aren't parsed as a + // Trae subcommand or flag — `--` stops both in its Cobra parser. + argvPromptSeparator: '--' + }, + opencode: { + detectCmd: 'opencode', + launchCmd: 'opencode', + expectedProcess: 'opencode', + promptInjectionMode: 'flag-prompt', + // Why: opencode enables bracketed paste before its composer mounts; wait for the post-\x1b[?2004h show-cursor so paste lands. + draftPasteReadySignal: 'render-cursor-after-bracketed-paste' + }, + 'mimo-code': { + detectCmd: 'mimo', + launchCmd: 'mimo', + expectedProcess: 'mimo', + promptInjectionMode: 'flag-prompt', + // Why: mirrors opencode's cursor-gated signal by parity; mimo's startup stream isn't separately validated. + draftPasteReadySignal: 'render-cursor-after-bracketed-paste' + }, + pi: { + detectCmd: 'pi', + launchCmd: 'pi', + expectedProcess: 'pi', + promptInjectionMode: 'argv', + // Why: pi has no `--prefill` and paste-after-ready races its long startup; the orca-prefill extension seeds this env var instead. + draftPromptEnvVar: 'ORCA_PI_PREFILL', + // Why: Pi decodes CSI-u; Esc+CR submits after tool subprocesses reset live KKP state (#9703). + windowsShiftEnterEncoding: 'csi-u' + }, + omp: { + detectCmd: 'omp', + launchCmd: 'omp', + expectedProcess: 'omp', + promptInjectionMode: 'argv', + draftPromptEnvVar: 'ORCA_OMP_PREFILL' + }, + 'prime-agent': { + detectCmd: 'prime-agent', + launchCmd: 'prime-agent', + expectedProcess: 'prime-agent', + // Why: `prime-agent [options] [@files...] [message...]` takes the task as positional argv. + promptInjectionMode: 'argv', + // Why: separator so prompts starting with `help`/`agents`/`-…` aren't parsed as a + // subcommand or flag — its help documents `--` as "treat all following arguments as messages". + argvPromptSeparator: '--', + // Why: Prime Agent embeds Pi's TUI and decodes CSI-u the same way (see pi above). + windowsShiftEnterEncoding: 'csi-u' + }, + gjc: { + detectCmd: 'gjc', + launchCmd: 'gjc', + expectedProcess: 'gjc', + // Why: `gjc -p ` is its non-interactive print mode (processes and exits), so + // launch the bare TUI and inject after startup instead of passing the task as argv. + promptInjectionMode: 'stdin-after-start' + }, + gemini: { + detectCmd: 'gemini', + launchCmd: 'gemini', + expectedProcess: 'gemini', + promptInjectionMode: 'flag-prompt-interactive' + }, + antigravity: { + detectCmd: 'agy', + launchCmd: 'agy', + expectedProcess: 'agy', + promptInjectionMode: 'flag-prompt-interactive' + }, + aider: { + detectCmd: 'aider', + launchCmd: 'aider', + expectedProcess: 'aider', + promptInjectionMode: 'stdin-after-start' + }, + goose: { + detectCmd: 'goose', + launchCmd: 'goose', + expectedProcess: 'goose', + promptInjectionMode: 'stdin-after-start' + }, + amp: { + detectCmd: 'amp', + launchCmd: 'amp', + expectedProcess: 'amp', + promptInjectionMode: 'stdin-after-start' + }, + kilo: { + detectCmd: 'kilo', + launchCmd: 'kilo', + expectedProcess: 'kilo', + promptInjectionMode: 'stdin-after-start' + }, + kiro: { + // Why: the Kiro installer (https://cli.kiro.dev/install) ships `kiro-cli`, not `kiro`; keep id 'kiro' for stored prefs. + detectCmd: 'kiro-cli', + // Why: trust flags like --trust-all-tools attach to Kiro's `chat` subcommand, not top-level kiro-cli. + launchCmd: 'kiro-cli chat --tui', + expectedProcess: 'kiro-cli', + promptInjectionMode: 'stdin-after-start' + }, + crush: { + detectCmd: 'crush', + launchCmd: 'crush', + expectedProcess: 'crush', + promptInjectionMode: 'stdin-after-start' + }, + aug: { + // Why: @augmentcode/auggie installs a binary named `auggie`, not `aug`; keep id 'aug' for stored prefs. + detectCmd: 'auggie', + launchCmd: 'auggie', + expectedProcess: 'auggie', + promptInjectionMode: 'stdin-after-start' + }, + cline: { + detectCmd: 'cline', + launchCmd: 'cline', + expectedProcess: 'cline', + promptInjectionMode: 'stdin-after-start' + }, + codebuff: { + detectCmd: 'codebuff', + launchCmd: 'codebuff', + expectedProcess: 'codebuff', + promptInjectionMode: 'stdin-after-start' + }, + 'command-code': { + // Why: use the full name (not its `cmd` alias) so detection doesn't collide with Windows' built-in cmd.exe. + detectCmd: 'command-code', + // Why: `--trust` skips the first-run trust prompt so it doesn't consume the task text. + launchCmd: 'command-code --trust', + expectedProcess: 'command-code', + promptInjectionMode: 'argv' + }, + continue: { + // Why: Continue's CLI binary is `cn`; `continue` is a bash/zsh builtin and would resolve to the shell keyword. + detectCmd: 'cn', + launchCmd: 'cn', + expectedProcess: 'cn', + promptInjectionMode: 'stdin-after-start' + }, + cursor: { + detectCmd: 'cursor-agent', + launchCmd: 'cursor-agent', + expectedProcess: 'cursor-agent', + promptInjectionMode: 'argv', + // Why: first-launch trust menu swallows the bracketed paste; pre-write the .workspace-trusted marker so it skips (agent-trust-presets.ts). + preflightTrust: 'cursor' + }, + droid: { + detectCmd: 'droid', + launchCmd: 'droid', + expectedProcess: 'droid', + promptInjectionMode: 'argv', + // Why: Droid decodes CSI-u on Windows; the legacy Esc+CR fallback reads as Enter and submits instead of newline. + windowsShiftEnterEncoding: 'csi-u', + ctrlEnterEncoding: 'csi-u' + }, + kimi: { + detectCmd: 'kimi', + launchCmd: 'kimi', + expectedProcess: 'kimi', + promptInjectionMode: 'stdin-after-start' + }, + 'mistral-vibe': { + // Why: installer exposes binary `vibe` though the package is mistral-vibe; keep old name as alias for wrapped installs. + detectCmd: 'vibe', + detectCmdAliases: ['mistral-vibe'], + launchCmd: 'vibe', + expectedProcess: 'vibe', + promptInjectionMode: 'stdin-after-start' + }, + 'qwen-code': { + // Why: package is qwen-code but its installed CLI binary on PATH is `qwen`. + detectCmd: 'qwen', + launchCmd: 'qwen', + expectedProcess: 'qwen', + promptInjectionMode: 'stdin-after-start' + }, + rovo: { + detectCmd: 'rovo', + launchCmd: 'rovo', + expectedProcess: 'rovo', + promptInjectionMode: 'stdin-after-start' + }, + hermes: { + detectCmd: 'hermes', + // Why: bare `hermes` opens the classic REPL; `--tui` starts the full-screen agent UI Orca hosts. + launchCmd: 'hermes --tui', + expectedProcess: 'hermes', + // Why: Hermes delivers the prompt via its startup-query contract, submitting only after the composer is ready. + promptInjectionMode: 'hermes-query' + }, + openclaw: { + detectCmd: 'openclaw', + launchCmd: 'openclaw', + expectedProcess: 'openclaw', + promptInjectionMode: 'stdin-after-start' + }, + copilot: { + detectCmd: 'copilot', + launchCmd: 'copilot', + expectedProcess: 'copilot', + // Why: `--prompt` exits on completion (kills the hosted session); `-i/--interactive` keeps it interactive. + promptInjectionMode: 'flag-interactive', + // Why: first-launch trust menu swallows the bracketed paste; pre-write trust so it skips (see agent-trust-presets.ts). + preflightTrust: 'copilot' + }, + grok: { + detectCmd: 'grok', + launchCmd: 'grok', + expectedProcess: 'grok', + // Why: argv (grok takes a positional prompt) so multi-line/special-char text isn't mangled as raw PTY keystrokes. + promptInjectionMode: 'argv', + // Why: separator so prompts like `help`/`--version` aren't parsed as Grok CLI syntax. + argvPromptSeparator: '--', + // Why: grok shimmers its startup logo until the session opens, so the quiet + // window never settles and launch drafts waited out the full 8s hard + // timeout; its composer glyph lands ~0.6s in. + draftPasteReadySignal: 'grok-composer-prompt', + ctrlEnterEncoding: 'csi-u' + }, + devin: { + detectCmd: 'devin', + launchCmd: 'devin', + expectedProcess: 'devin', + // Why: `devin -- ` auto-submits immediately (docs.devin.ai/cli), so start the REPL with no argv prompt. + promptInjectionMode: 'stdin-after-start' + } +} diff --git a/src/shared/tui-agent-config.ts b/src/shared/tui-agent-config.ts index 78772924c4ce..10cd18728e5c 100644 --- a/src/shared/tui-agent-config.ts +++ b/src/shared/tui-agent-config.ts @@ -1,5 +1,4 @@ import type { TuiAgent } from './tui-agent' -import { getOrcaCliCommandNameForPlatform } from './orca-cli-command-name' export type AgentPromptInjectionMode = | 'argv' @@ -50,291 +49,11 @@ export type TuiAgentConfig = { ctrlEnterEncoding?: 'csi-u' } -export const TUI_AGENT_CONFIG: Record = { - claude: { - detectCmd: 'claude', - launchCmd: 'claude', - expectedProcess: 'claude', - promptInjectionMode: 'argv', - // Why: `claude --prefill ` seeds the input without submitting, avoiding the paste-after-ready race (PR https://github.com/stablyai/orca/pull/926). - draftPromptFlag: '--prefill' - }, - 'claude-agent-teams': { - // Why: an Orca-provided launch mode, not a separate binary; detection follows the Orca CLI. - detectCmd: 'orca', - detectCmdAliases: ['orca-dev', 'orca-ide'], - // Why: require Claude too so fresh installs (Orca shim always present) don't report Agent Teams without an agent CLI. - detectRequiredCommands: ['claude'], - // Why: Windows/WSL use Claude's in-process Agent Teams fallback, not this Orca native-pane/tmux-shim wrapper. - detectUnsupportedRuntimes: ['win32', 'wsl'], - launchCmd: 'orca claude-teams', - launchCmdByPlatform: { - linux: `${getOrcaCliCommandNameForPlatform('linux')} claude-teams`, - win32: `${getOrcaCliCommandNameForPlatform('win32')} claude-teams` - }, - expectedProcess: 'claude', - promptInjectionMode: 'stdin-after-start' - }, - openclaude: { - detectCmd: 'openclaude', - launchCmd: 'openclaude', - expectedProcess: 'openclaude', - promptInjectionMode: 'argv', - draftPromptFlag: '--prefill' - }, - codex: { - detectCmd: 'codex', - launchCmd: 'codex', - expectedProcess: 'codex', - promptInjectionMode: 'argv', - windowsInputRecordPasteNewline: 'alt-enter', - preflightTrust: 'codex', - draftPasteReadySignal: 'codex-composer-prompt', - draftPasteReadyTimeoutMs: 20_000 - }, - autohand: { - detectCmd: 'autohand', - launchCmd: 'autohand', - expectedProcess: 'autohand', - promptInjectionMode: 'stdin-after-start' - }, - ante: { - detectCmd: 'ante', - launchCmd: 'ante', - expectedProcess: 'ante', - // Why: `ante --prompt` is headless (runs once and exits), so launch the bare TUI and inject after startup. - promptInjectionMode: 'stdin-after-start' - }, - trae: { - // Why: the unrelated open-source bytedance/trae-agent also installs a `trae-cli` - // binary, so detect TRAE CN's CLI on `traecli`, an alias only TRAE CN ships. - detectCmd: 'traecli', - launchCmd: 'traecli', - expectedProcess: 'traecli', - // Why: `traecli [prompt]` takes the task as a positional argv, same as Claude/Codex. - promptInjectionMode: 'argv', - // Why: separator so prompts starting with `help`/`config`/`-…` aren't parsed as a - // Trae subcommand or flag — `--` stops both in its Cobra parser. - argvPromptSeparator: '--' - }, - opencode: { - detectCmd: 'opencode', - launchCmd: 'opencode', - expectedProcess: 'opencode', - promptInjectionMode: 'flag-prompt', - // Why: opencode enables bracketed paste before its composer mounts; wait for the post-\x1b[?2004h show-cursor so paste lands. - draftPasteReadySignal: 'render-cursor-after-bracketed-paste' - }, - 'mimo-code': { - detectCmd: 'mimo', - launchCmd: 'mimo', - expectedProcess: 'mimo', - promptInjectionMode: 'flag-prompt', - // Why: mirrors opencode's cursor-gated signal by parity; mimo's startup stream isn't separately validated. - draftPasteReadySignal: 'render-cursor-after-bracketed-paste' - }, - pi: { - detectCmd: 'pi', - launchCmd: 'pi', - expectedProcess: 'pi', - promptInjectionMode: 'argv', - // Why: pi has no `--prefill` and paste-after-ready races its long startup; the orca-prefill extension seeds this env var instead. - draftPromptEnvVar: 'ORCA_PI_PREFILL', - // Why: Pi decodes CSI-u; Esc+CR submits after tool subprocesses reset live KKP state (#9703). - windowsShiftEnterEncoding: 'csi-u' - }, - omp: { - detectCmd: 'omp', - launchCmd: 'omp', - expectedProcess: 'omp', - promptInjectionMode: 'argv', - draftPromptEnvVar: 'ORCA_OMP_PREFILL' - }, - 'prime-agent': { - detectCmd: 'prime-agent', - launchCmd: 'prime-agent', - expectedProcess: 'prime-agent', - // Why: `prime-agent [options] [@files...] [message...]` takes the task as positional argv. - promptInjectionMode: 'argv', - // Why: separator so prompts starting with `help`/`agents`/`-…` aren't parsed as a - // subcommand or flag — its help documents `--` as "treat all following arguments as messages". - argvPromptSeparator: '--', - // Why: Prime Agent embeds Pi's TUI and decodes CSI-u the same way (see pi above). - windowsShiftEnterEncoding: 'csi-u' - }, - gemini: { - detectCmd: 'gemini', - launchCmd: 'gemini', - expectedProcess: 'gemini', - promptInjectionMode: 'flag-prompt-interactive' - }, - antigravity: { - detectCmd: 'agy', - launchCmd: 'agy', - expectedProcess: 'agy', - promptInjectionMode: 'flag-prompt-interactive' - }, - aider: { - detectCmd: 'aider', - launchCmd: 'aider', - expectedProcess: 'aider', - promptInjectionMode: 'stdin-after-start' - }, - goose: { - detectCmd: 'goose', - launchCmd: 'goose', - expectedProcess: 'goose', - promptInjectionMode: 'stdin-after-start' - }, - amp: { - detectCmd: 'amp', - launchCmd: 'amp', - expectedProcess: 'amp', - promptInjectionMode: 'stdin-after-start' - }, - kilo: { - detectCmd: 'kilo', - launchCmd: 'kilo', - expectedProcess: 'kilo', - promptInjectionMode: 'stdin-after-start' - }, - kiro: { - // Why: the Kiro installer (https://cli.kiro.dev/install) ships `kiro-cli`, not `kiro`; keep id 'kiro' for stored prefs. - detectCmd: 'kiro-cli', - // Why: trust flags like --trust-all-tools attach to Kiro's `chat` subcommand, not top-level kiro-cli. - launchCmd: 'kiro-cli chat --tui', - expectedProcess: 'kiro-cli', - promptInjectionMode: 'stdin-after-start' - }, - crush: { - detectCmd: 'crush', - launchCmd: 'crush', - expectedProcess: 'crush', - promptInjectionMode: 'stdin-after-start' - }, - aug: { - // Why: @augmentcode/auggie installs a binary named `auggie`, not `aug`; keep id 'aug' for stored prefs. - detectCmd: 'auggie', - launchCmd: 'auggie', - expectedProcess: 'auggie', - promptInjectionMode: 'stdin-after-start' - }, - cline: { - detectCmd: 'cline', - launchCmd: 'cline', - expectedProcess: 'cline', - promptInjectionMode: 'stdin-after-start' - }, - codebuff: { - detectCmd: 'codebuff', - launchCmd: 'codebuff', - expectedProcess: 'codebuff', - promptInjectionMode: 'stdin-after-start' - }, - 'command-code': { - // Why: use the full name (not its `cmd` alias) so detection doesn't collide with Windows' built-in cmd.exe. - detectCmd: 'command-code', - // Why: `--trust` skips the first-run trust prompt so it doesn't consume the task text. - launchCmd: 'command-code --trust', - expectedProcess: 'command-code', - promptInjectionMode: 'argv' - }, - continue: { - // Why: Continue's CLI binary is `cn`; `continue` is a bash/zsh builtin and would resolve to the shell keyword. - detectCmd: 'cn', - launchCmd: 'cn', - expectedProcess: 'cn', - promptInjectionMode: 'stdin-after-start' - }, - cursor: { - detectCmd: 'cursor-agent', - launchCmd: 'cursor-agent', - expectedProcess: 'cursor-agent', - promptInjectionMode: 'argv', - // Why: first-launch trust menu swallows the bracketed paste; pre-write the .workspace-trusted marker so it skips (agent-trust-presets.ts). - preflightTrust: 'cursor' - }, - droid: { - detectCmd: 'droid', - launchCmd: 'droid', - expectedProcess: 'droid', - promptInjectionMode: 'argv', - // Why: Droid decodes CSI-u on Windows; the legacy Esc+CR fallback reads as Enter and submits instead of newline. - windowsShiftEnterEncoding: 'csi-u', - ctrlEnterEncoding: 'csi-u' - }, - kimi: { - detectCmd: 'kimi', - launchCmd: 'kimi', - expectedProcess: 'kimi', - promptInjectionMode: 'stdin-after-start' - }, - 'mistral-vibe': { - // Why: installer exposes binary `vibe` though the package is mistral-vibe; keep old name as alias for wrapped installs. - detectCmd: 'vibe', - detectCmdAliases: ['mistral-vibe'], - launchCmd: 'vibe', - expectedProcess: 'vibe', - promptInjectionMode: 'stdin-after-start' - }, - 'qwen-code': { - // Why: package is qwen-code but its installed CLI binary on PATH is `qwen`. - detectCmd: 'qwen', - launchCmd: 'qwen', - expectedProcess: 'qwen', - promptInjectionMode: 'stdin-after-start' - }, - rovo: { - detectCmd: 'rovo', - launchCmd: 'rovo', - expectedProcess: 'rovo', - promptInjectionMode: 'stdin-after-start' - }, - hermes: { - detectCmd: 'hermes', - // Why: bare `hermes` opens the classic REPL; `--tui` starts the full-screen agent UI Orca hosts. - launchCmd: 'hermes --tui', - expectedProcess: 'hermes', - // Why: Hermes delivers the prompt via its startup-query contract, submitting only after the composer is ready. - promptInjectionMode: 'hermes-query' - }, - openclaw: { - detectCmd: 'openclaw', - launchCmd: 'openclaw', - expectedProcess: 'openclaw', - promptInjectionMode: 'stdin-after-start' - }, - copilot: { - detectCmd: 'copilot', - launchCmd: 'copilot', - expectedProcess: 'copilot', - // Why: `--prompt` exits on completion (kills the hosted session); `-i/--interactive` keeps it interactive. - promptInjectionMode: 'flag-interactive', - // Why: first-launch trust menu swallows the bracketed paste; pre-write trust so it skips (see agent-trust-presets.ts). - preflightTrust: 'copilot' - }, - grok: { - detectCmd: 'grok', - launchCmd: 'grok', - expectedProcess: 'grok', - // Why: argv (grok takes a positional prompt) so multi-line/special-char text isn't mangled as raw PTY keystrokes. - promptInjectionMode: 'argv', - // Why: separator so prompts like `help`/`--version` aren't parsed as Grok CLI syntax. - argvPromptSeparator: '--', - // Why: grok shimmers its startup logo until the session opens, so the quiet - // window never settles and launch drafts waited out the full 8s hard - // timeout; its composer glyph lands ~0.6s in. - draftPasteReadySignal: 'grok-composer-prompt', - ctrlEnterEncoding: 'csi-u' - }, - devin: { - detectCmd: 'devin', - launchCmd: 'devin', - expectedProcess: 'devin', - // Why: `devin -- ` auto-submits immediately (docs.devin.ai/cli), so start the REPL with no argv prompt. - promptInjectionMode: 'stdin-after-start' - } -} +import { TUI_AGENT_CONFIG } from './tui-agent-config-table' + +// Re-export: the launch table moved to its own module; every existing importer of +// `TUI_AGENT_CONFIG` from this path keeps working unchanged. +export { TUI_AGENT_CONFIG } export function isTuiAgent(value: unknown): value is TuiAgent { return typeof value === 'string' && Object.hasOwn(TUI_AGENT_CONFIG, value) diff --git a/src/shared/tui-agent-display-names.ts b/src/shared/tui-agent-display-names.ts index 0b2078f0479c..3dfe9193496c 100644 --- a/src/shared/tui-agent-display-names.ts +++ b/src/shared/tui-agent-display-names.ts @@ -19,6 +19,7 @@ export const TUI_AGENT_DISPLAY_NAMES: Record = { pi: 'Pi', omp: 'OMP', 'prime-agent': 'Prime Agent', + gjc: 'Gajae Code', gemini: 'Gemini', antigravity: 'Antigravity', aider: 'Aider', diff --git a/src/shared/tui-agent-selection.ts b/src/shared/tui-agent-selection.ts index 86216e589b82..42d809b98a3d 100644 --- a/src/shared/tui-agent-selection.ts +++ b/src/shared/tui-agent-selection.ts @@ -17,6 +17,7 @@ export const TUI_AGENT_AUTO_PICK_ORDER = [ 'pi', 'omp', 'prime-agent', + 'gjc', 'gemini', 'antigravity', 'aider', diff --git a/src/shared/tui-agent.ts b/src/shared/tui-agent.ts index a885e3dd24cb..f3ca2f38ed6b 100644 --- a/src/shared/tui-agent.ts +++ b/src/shared/tui-agent.ts @@ -37,3 +37,4 @@ export type TuiAgent = | 'ante' // Ante (Antigma Labs) | 'trae' // Trae CLI | 'prime-agent' // Prime Agent (Prime Intellect) + | 'gjc' // Gajae Code (gajae-code.com)