Files
orca/src/shared/agent-process-recognition.test.ts
T
NeilandWooseong Kim af13da5db7 Recognize Build terminals and preserve Windows confirmation key routing
Recognize dsb terminal identity and preserve foreground Windows confirmation key routing.

Co-authored-by: Wooseong Kim <innocarpe@gmail.com>
2026-10-03 20:23:33 -07:00

606 lines
25 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { withFreshOmpLaunch } from './omp-fresh-launch'
import { buildAgentDraftLaunchPlan } from './tui-agent-startup'
import { detectExplicitPiAgentKindFromCommand } from './pi-agent-kind'
import {
isAgentForegroundWrapperProcess,
isExpectedAgentProcess,
isRecognizedAgentType,
recognizeAgentProcess,
recognizeAgentProcessFromCommandLine
} from './agent-process-recognition'
describe('agent process recognition', () => {
it.each([
'/usr/local/bin/dsb',
'/usr/bin/deepseek-build',
'C:\\Users\\dev\\bin\\dsb.cmd',
'C:\\Users\\dev\\bin\\deepseek-build-agent.exe'
])('recognizes manually started DeepSeek Build at %s', (processName) => {
expect(recognizeAgentProcess(processName)?.agent).toBe('dsb')
})
it('recognizes DeepSeek Build by binary name and its npm shim', () => {
expect(recognizeAgentProcess('dsb')).toEqual({ agent: 'dsb', processName: 'dsb' })
expect(recognizeAgentProcess('deepseek-build')).toEqual({
agent: 'dsb',
processName: 'deepseek-build'
})
expect(recognizeAgentProcess('deepseek-build-agent')).toEqual({
agent: 'dsb',
processName: 'deepseek-build-agent'
})
expect(
recognizeAgentProcessFromCommandLine(
'node /usr/lib/node_modules/@innocarpe/deepseek-build/npm/bin/dsb.js'
)
).toEqual({ agent: 'dsb', processName: 'dsb' })
expect(
recognizeAgentProcessFromCommandLine(
'node /usr/lib/node_modules/@innocarpe/deepseek-build/npm/bin/dsb.js run "explain this"'
)
).toBeNull()
expect(recognizeAgentProcessFromCommandLine('dsb run "explain this"')).toBeNull()
})
it.each([
'-r ./preload.js',
'--require "./preload path.js"',
'--import ./preload.mjs',
'--loader ./loader.mjs',
'--experimental-loader ./loader.mjs',
'--require=./preload.js',
'--import=./preload.mjs'
])('excludes a one-shot DSB npm shim after Node options %s', (options) => {
const shim = `node ${options} /usr/lib/node_modules/@innocarpe/deepseek-build/npm/bin/dsb.js`
expect(recognizeAgentProcessFromCommandLine(`${shim} run "task"`)).toBeNull()
expect(
recognizeAgentProcessFromCommandLine(`${shim} run "task"`, { includeHeadlessOneShot: true })
?.agent
).toBe('dsb')
expect(recognizeAgentProcessFromCommandLine(`${shim} agent`)?.agent).toBe('dsb')
})
it('recognizes packaged Codex foreground process names', () => {
expect(recognizeAgentProcess('codex-aarch64-ap')).toEqual({
agent: 'codex',
processName: 'codex-aarch64-ap'
})
expect(isRecognizedAgentType('codex-aarch64-ap')).toBe(true)
})
it.each(['posix', 'powershell', 'cmd'] as const)(
'recognizes fresh OMP commands and drafts in %s',
(shell) => {
for (const command of ['omp', 'omp launch', 'omp --model example']) {
const generated = withFreshOmpLaunch(command, shell)
expect(recognizeAgentProcessFromCommandLine(generated)).toEqual({
agent: 'omp',
processName: 'omp'
})
expect(detectExplicitPiAgentKindFromCommand(generated)).toBe('omp')
}
const draft = buildAgentDraftLaunchPlan({
agent: 'omp',
draft: 'task',
cmdOverrides: {},
platform: 'linux',
shell
})
expect(recognizeAgentProcessFromCommandLine(draft?.launchCommand)).toEqual({
agent: 'omp',
processName: 'omp'
})
expect(detectExplicitPiAgentKindFromCommand(draft?.launchCommand)).toBe('omp')
}
)
it('does not classify embedded fresh-launch text as an agent command', () => {
for (const command of [
`echo 'omp --config "$ORCA_OMP_FRESH_CONFIG"'`,
`echo '${withFreshOmpLaunch('omp', 'posix')}'`
]) {
expect(recognizeAgentProcessFromCommandLine(command)).toBeNull()
expect(detectExplicitPiAgentKindFromCommand(command)).toBeNull()
}
})
it('recognizes both published DeepSeek Build npm entrypoints and excludes run with cwd', () => {
const shim = '/usr/lib/node_modules/@innocarpe/deepseek-build/npm/bin/deepseek-build.js'
expect(recognizeAgentProcessFromCommandLine(`node ${shim}`)?.agent).toBe('dsb')
expect(recognizeAgentProcessFromCommandLine(`node ${shim} --cwd folder run task`)).toBeNull()
expect(recognizeAgentProcessFromCommandLine('dsb --cwd folder run task')).toBeNull()
})
it('recognizes the OpenClaude foreground process', () => {
expect(recognizeAgentProcess('/usr/local/bin/openclaude')).toEqual({
agent: 'openclaude',
processName: 'openclaude'
})
expect(isRecognizedAgentType('openclaude')).toBe(true)
expect(isExpectedAgentProcess('/usr/local/bin/openclaude', 'claude')).toBe(false)
})
it('recognizes the Droid foreground process on Windows', () => {
expect(recognizeAgentProcess(String.raw`C:\Users\dev\AppData\Roaming\npm\droid.cmd`)).toEqual({
agent: 'droid',
processName: 'droid'
})
})
it('matches expected agents from platform-specific foreground process paths', () => {
expect(recognizeAgentProcess('claude')).toEqual({
agent: 'claude',
processName: 'claude'
})
expect(
isExpectedAgentProcess(String.raw`C:\Users\dev\AppData\Roaming\npm\claude.exe`, 'claude')
).toBe(true)
expect(isExpectedAgentProcess('/usr/local/bin/claude', 'claude')).toBe(true)
expect(isExpectedAgentProcess('powershell.exe', 'claude')).toBe(false)
})
it('does not recognize Claude print-mode hook subprocesses as interactive agents', () => {
expect(
recognizeAgentProcessFromCommandLine(
'claude --print --model haiku "Analyze this conversation and determine: Does the assistant have more autonomous work to do RIGHT NOW?"'
)
).toBeNull()
expect(
recognizeAgentProcessFromCommandLine(
String.raw`/home/dev/.local/bin/claude -p "Context: This summary will be shown in a list"`
)
).toBeNull()
expect(
recognizeAgentProcessFromCommandLine(
String.raw`C:\Users\dev\AppData\Roaming\npm\claude.exe --output-format=json "hook prompt"`
)
).toBeNull()
expect(recognizeAgentProcessFromCommandLine('claude --resume abc123')).toEqual({
agent: 'claude',
processName: 'claude'
})
})
it('recognizes Command Code without classifying Windows cmd.exe as an agent', () => {
expect(recognizeAgentProcess('command-code')).toEqual({
agent: 'command-code',
processName: 'command-code'
})
expect(
recognizeAgentProcess(String.raw`C:\Users\dev\AppData\Roaming\npm\command-code.cmd`)
).toEqual({
agent: 'command-code',
processName: 'command-code'
})
expect(isRecognizedAgentType('command-code')).toBe(true)
expect(isRecognizedAgentType('cmd.exe')).toBe(false)
expect(recognizeAgentProcess('cmd.exe')).toBeNull()
})
it('recognizes Ante without classifying ante-prefixed path fragments as the agent', () => {
expect(recognizeAgentProcess('ante')).toEqual({
agent: 'ante',
processName: 'ante'
})
expect(recognizeAgentProcess('/Users/dev/.ante/bin/ante')).toEqual({
agent: 'ante',
processName: 'ante'
})
expect(isExpectedAgentProcess('/Users/dev/.ante/bin/ante', 'ante')).toBe(true)
expect(isRecognizedAgentType('ante')).toBe(true)
// Why: 'ante' is a common token in directory and binary names; only the
// exact normalized basename may classify as the agent.
expect(recognizeAgentProcess('ante-obsidian')).toBeNull()
expect(recognizeAgentProcess('antechamber')).toBeNull()
expect(isExpectedAgentProcess('ante-obsidian', 'ante')).toBe(false)
})
it('does not recognize Ante headless one-shot commands as interactive agents', () => {
expect(recognizeAgentProcessFromCommandLine('ante -p "summarize this diff"')).toBeNull()
expect(recognizeAgentProcessFromCommandLine('ante -psummarize')).toBeNull()
expect(
recognizeAgentProcessFromCommandLine('ante --prompt "review this for security issues"')
).toBeNull()
expect(
recognizeAgentProcessFromCommandLine('ante --prompt=review --output-format minimal')
).toBeNull()
expect(recognizeAgentProcessFromCommandLine('ante --resume ses_123')).toEqual({
agent: 'ante',
processName: 'ante'
})
})
it('does not recognize wrapped Ante headless one-shot commands as interactive agents', () => {
expect(
recognizeAgentProcessFromCommandLine('node /Users/dev/.ante/bin/ante --prompt "review"')
).toBeNull()
expect(
recognizeAgentProcessFromCommandLine(
String.raw`node C:\Users\dev\.ante\bin\ante.cmd -p review`
)
).toBeNull()
expect(recognizeAgentProcessFromCommandLine('node /Users/dev/.ante/bin/ante')).toEqual({
agent: 'ante',
processName: 'ante'
})
})
it('recognizes Trae by its traecli binary, not the ambiguous trae-cli name', () => {
expect(recognizeAgentProcess('traecli')).toEqual({
agent: 'trae',
processName: 'traecli'
})
expect(recognizeAgentProcess('/Users/dev/.local/bin/traecli')).toEqual({
agent: 'trae',
processName: 'traecli'
})
expect(isExpectedAgentProcess('/Users/dev/.local/bin/traecli', 'traecli')).toBe(true)
expect(isRecognizedAgentType('traecli')).toBe(true)
// Why: `trae-cli` and `trae-agent` both name the unrelated open-source bytedance/trae-agent.
expect(recognizeAgentProcess('trae-cli')).toBeNull()
expect(recognizeAgentProcess('trae-agent')).toBeNull()
})
it('does not recognize Trae headless one-shot commands as interactive agents', () => {
expect(recognizeAgentProcessFromCommandLine('traecli -p "summarize this diff"')).toBeNull()
expect(recognizeAgentProcessFromCommandLine('traecli --print "review this"')).toBeNull()
expect(
recognizeAgentProcessFromCommandLine('traecli --output-format json "review this"')
).toBeNull()
expect(
recognizeAgentProcessFromCommandLine('traecli --output-format=stream-json review')
).toBeNull()
expect(recognizeAgentProcessFromCommandLine('traecli --resume AUTO')).toEqual({
agent: 'trae',
processName: 'traecli'
})
// Why: past `--` nothing is a flag, so this is the interactive pane Orca itself launches.
expect(recognizeAgentProcessFromCommandLine('traecli -- "--print the release notes"')).toEqual({
agent: 'trae',
processName: 'traecli'
})
})
it('recognizes Muse by its muse binary', () => {
expect(recognizeAgentProcess('muse')).toEqual({
agent: 'muse',
processName: 'muse'
})
expect(recognizeAgentProcess('/Users/dev/.local/bin/muse')).toEqual({
agent: 'muse',
processName: 'muse'
})
expect(isExpectedAgentProcess('/Users/dev/.local/bin/muse', 'muse')).toBe(true)
expect(isRecognizedAgentType('muse')).toBe(true)
})
it('recognizes Muse by its versioned muse-bin sibling binary', () => {
// Why: the `muse` launcher execs `muse-bin-<version>` (a 242MB sibling),
// so the live foreground process carries the versioned name — truncated
// to `muse-bin-1.0.3-R` in macOS comm output (verified on-device).
expect(recognizeAgentProcess('muse-bin-1.0.3-R2198.1')).toEqual({
agent: 'muse',
processName: 'muse-bin-1.0.3-r2198.1'
})
expect(recognizeAgentProcess('muse-bin-1.0.3-R')).toEqual({
agent: 'muse',
processName: 'muse-bin-1.0.3-r'
})
expect(recognizeAgentProcess('/Users/dev/.local/bin/muse-bin-1.0.3-R2198.1')).toEqual({
agent: 'muse',
processName: 'muse-bin-1.0.3-r2198.1'
})
})
it('does not recognize Muse headless exec commands as interactive agents', () => {
expect(recognizeAgentProcessFromCommandLine('muse exec "summarize this diff"')).toBeNull()
expect(
recognizeAgentProcessFromCommandLine('muse exec --json "review this" > result.jsonl')
).toBeNull()
// Why: a bare `exec` token dispatches as the subcommand even past `--`
// (verified: `muse -- resume` still resumes), so this errors instead of
// hosting a pane — never an interactive agent.
expect(recognizeAgentProcessFromCommandLine('muse -- exec "summarize this diff"')).toBeNull()
// Why: a whole-prompt `muse 'exec'` takes the exec missing-prompt error
// path, not a TUI, so filtering it is correct.
expect(recognizeAgentProcessFromCommandLine("muse 'exec'")).toBeNull()
// Why: `muse resume` reopens the interactive TUI, so it still hosts a live session.
expect(recognizeAgentProcessFromCommandLine('muse resume')).toEqual({
agent: 'muse',
processName: 'muse'
})
// Why: `muse -- resume` still dispatches to the resume subcommand (verified
// against muse 1.0.3), which reopens the interactive TUI.
expect(recognizeAgentProcessFromCommandLine('muse -- resume')).toEqual({
agent: 'muse',
processName: 'muse'
})
// Why: the prompt is one quoted argv, so it never equals the bare `exec`
// token — this is the interactive pane Orca itself launches.
expect(recognizeAgentProcessFromCommandLine('muse -- "exec the release notes"')).toEqual({
agent: 'muse',
processName: 'muse'
})
})
it('recognizes Mistral Vibe by its installed executable and legacy alias', () => {
expect(recognizeAgentProcess('/home/dev/.local/bin/vibe')).toEqual({
agent: 'mistral-vibe',
processName: 'vibe'
})
expect(recognizeAgentProcess('mistral-vibe')).toEqual({
agent: 'mistral-vibe',
processName: 'mistral-vibe'
})
expect(isRecognizedAgentType('vibe')).toBe(true)
})
it('recognizes Kimi Code by the kimi-code process its launcher becomes', () => {
expect(recognizeAgentProcess('/home/dev/.kimi-code/bin/kimi')).toEqual({
agent: 'kimi',
processName: 'kimi'
})
expect(recognizeAgentProcess('kimi-code')).toEqual({
agent: 'kimi',
processName: 'kimi-code'
})
expect(isExpectedAgentProcess('/home/dev/.kimi-code/bin/kimi', 'kimi')).toBe(true)
expect(isRecognizedAgentType('kimi-code')).toBe(true)
})
it('recognizes Qwen Code by its installed qwen executable', () => {
expect(recognizeAgentProcess('/home/dev/.local/bin/qwen')).toEqual({
agent: 'qwen-code',
processName: 'qwen'
})
expect(recognizeAgentProcess(String.raw`C:\Users\dev\AppData\Roaming\npm\qwen.cmd`)).toEqual({
agent: 'qwen-code',
processName: 'qwen'
})
expect(isExpectedAgentProcess('/usr/local/bin/qwen', 'qwen')).toBe(true)
expect(isRecognizedAgentType('qwen')).toBe(true)
})
it('recognizes agent CLIs launched through interpreter wrappers', () => {
expect(
recognizeAgentProcessFromCommandLine('node /Users/dev/.nvm/versions/node/bin/codex')
).toEqual({ agent: 'codex', processName: 'codex' })
expect(
recognizeAgentProcessFromCommandLine('node /Users/dev/.nvm/versions/node/bin/gemini')
).toEqual({ agent: 'gemini', processName: 'gemini' })
expect(recognizeAgentProcessFromCommandLine('python3 /opt/homebrew/bin/hermes --tui')).toEqual({
agent: 'hermes',
processName: 'hermes'
})
expect(
recognizeAgentProcessFromCommandLine('python3.12 /opt/homebrew/bin/hermes --tui')
).toEqual({
agent: 'hermes',
processName: 'hermes'
})
expect(recognizeAgentProcessFromCommandLine('python -m aider')).toEqual({
agent: 'aider',
processName: 'aider'
})
expect(
recognizeAgentProcessFromCommandLine(
String.raw`python C:\Users\dev\AppData\Roaming\Python\Python312\Scripts\aider.py`
)
).toEqual({ agent: 'aider', processName: 'aider' })
expect(
recognizeAgentProcessFromCommandLine(
String.raw`node C:\Users\dev\AppData\Roaming\npm\codex.cmd`
)
).toEqual({ agent: 'codex', processName: 'codex' })
expect(
recognizeAgentProcessFromCommandLine(
String.raw`node C:\Users\dev\AppData\Roaming\npm\node_modules\@openai\codex\bin\codex.js`
)
).toEqual({ agent: 'codex', processName: 'codex' })
expect(
recognizeAgentProcessFromCommandLine(
String.raw`node C:\Users\dev\AppData\Roaming\npm\node_modules\@google\gemini-cli\bundle\gemini.mjs`
)
).toEqual({ agent: 'gemini', processName: 'gemini' })
})
it.each(['earendil-works', 'mariozechner'])('recognizes the @%s Pi npm entrypoint', (scope) => {
expect(
recognizeAgentProcessFromCommandLine(
String.raw`node.exe C:\Users\dev\AppData\Roaming\npm\node_modules\@${scope}\pi-coding-agent\dist\cli.js`
)
).toEqual({ agent: 'pi', processName: 'pi' })
})
it('recognizes Prime Agent by its binary and npm entrypoint', () => {
expect(recognizeAgentProcess('prime-agent')).toEqual({
agent: 'prime-agent',
processName: 'prime-agent'
})
expect(recognizeAgentProcess('/opt/homebrew/bin/prime-agent')).toEqual({
agent: 'prime-agent',
processName: 'prime-agent'
})
expect(
recognizeAgentProcessFromCommandLine(
'node /opt/homebrew/lib/node_modules/prime-agent/dist/bundle/cli.js'
)
).toEqual({ agent: 'prime-agent', processName: 'prime-agent' })
expect(
recognizeAgentProcessFromCommandLine(
String.raw`node.exe C:\Users\dev\AppData\Roaming\npm\node_modules\prime-agent\dist\bundle\cli.js`
)
).toEqual({ agent: 'prime-agent', processName: 'prime-agent' })
})
it('does not recognize Prime Agent headless one-shot commands as interactive agents', () => {
expect(recognizeAgentProcessFromCommandLine('prime-agent -p "summarize this diff"')).toBeNull()
expect(recognizeAgentProcessFromCommandLine('prime-agent --print "review this"')).toBeNull()
expect(recognizeAgentProcessFromCommandLine('prime-agent --resume abc123')).toEqual({
agent: 'prime-agent',
processName: 'prime-agent'
})
// Why: past `--` nothing is a flag, so this is the interactive pane Orca itself launches.
expect(
recognizeAgentProcessFromCommandLine('prime-agent -- "--print the release notes"')
).toEqual({ agent: 'prime-agent', processName: 'prime-agent' })
})
it('does not recognize Prime Agent non-interactive --mode runs as interactive agents', () => {
for (const mode of ['json', 'rpc', 'acp', 'daemon']) {
expect(recognizeAgentProcessFromCommandLine(`prime-agent --mode ${mode}`)).toBeNull()
}
// Why: `text` is the interactive TUI mode Orca hosts.
expect(recognizeAgentProcessFromCommandLine('prime-agent --mode text')).toEqual({
agent: 'prime-agent',
processName: 'prime-agent'
})
// Why: the CLI only parses `--mode <value>` as separate tokens, so `--mode=json`
// is ignored by it and still starts the interactive mode.
expect(recognizeAgentProcessFromCommandLine('prime-agent --mode=json')).toEqual({
agent: 'prime-agent',
processName: 'prime-agent'
})
expect(recognizeAgentProcessFromCommandLine('prime-agent -- --mode rpc')).toEqual({
agent: 'prime-agent',
processName: 'prime-agent'
})
})
it('recognizes only the agent subcommand of the generic Orca CLI', () => {
expect(recognizeAgentProcessFromCommandLine('orca claude-teams')).toEqual({
agent: 'claude-agent-teams',
processName: 'orca'
})
expect(recognizeAgentProcessFromCommandLine('orca status')).toBeNull()
expect(recognizeAgentProcessFromCommandLine('orca-dev terminal list')).toBeNull()
expect(recognizeAgentProcessFromCommandLine('node /usr/local/bin/orca claude-teams')).toEqual({
agent: 'claude-agent-teams',
processName: 'orca'
})
expect(recognizeAgentProcessFromCommandLine('node /usr/local/bin/orca status')).toBeNull()
})
it('recognizes the versioned Cursor Node wrapper without accepting generic agent processes', () => {
const cursorEntrypoint = String.raw`C:\Users\dev\AppData\Local\cursor-agent\versions\2026.07.09-a3815c0\index.js`
expect(recognizeAgentProcessFromCommandLine(`node.exe ${cursorEntrypoint}`)).toEqual({
agent: 'cursor',
processName: 'cursor-agent'
})
expect(
recognizeAgentProcessFromCommandLine(`node.exe ${cursorEntrypoint} worker-server`)
).toEqual({ agent: 'cursor', processName: 'cursor-agent' })
expect(
recognizeAgentProcessFromCommandLine(String.raw`node.exe C:\repo\cursor-agent\index.js`)
).toBeNull()
expect(
recognizeAgentProcessFromCommandLine(String.raw`C:\Users\dev\.grok\bin\agent.exe`)
).toBeNull()
})
it('does not classify prompt text as a wrapped agent command', () => {
expect(
recognizeAgentProcessFromCommandLine(
'node /tmp/not-an-agent.js "compare opencode vs orca in Gemini CLI"'
)
).toBeNull()
expect(recognizeAgentProcessFromCommandLine(String.raw`node C:\tmp\not-an-agent.js`)).toBeNull()
expect(
recognizeAgentProcessFromCommandLine(
String.raw`node C:\repo\server.js --plugin C:\tmp\codex.js`
)
).toBeNull()
expect(recognizeAgentProcessFromCommandLine(String.raw`node C:\repo\codex.js`)).toBeNull()
expect(recognizeAgentProcessFromCommandLine(String.raw`node C:\repo\gemini.mjs`)).toBeNull()
expect(
recognizeAgentProcessFromCommandLine(
String.raw`node C:\repo\node_modules\@example\pi-coding-agent\dist\cli.js`
)
).toBeNull()
expect(recognizeAgentProcessFromCommandLine(String.raw`python C:\repo\aider.py`)).toBeNull()
expect(recognizeAgentProcessFromCommandLine('python -m not_aider')).toBeNull()
})
it('identifies only foreground processes that can wrap agent entrypoints', () => {
expect(isAgentForegroundWrapperProcess('node.exe')).toBe(true)
expect(isAgentForegroundWrapperProcess('/usr/bin/python3')).toBe(true)
expect(isAgentForegroundWrapperProcess('python3.12.exe')).toBe(true)
expect(isAgentForegroundWrapperProcess('bash')).toBe(false)
expect(isAgentForegroundWrapperProcess('vim.exe')).toBe(false)
})
it('recognizes the Antigravity CLI from bare, POSIX and Windows command lines', () => {
const agy = { agent: 'antigravity', processName: 'agy' }
expect(recognizeAgentProcess('agy')).toEqual(agy)
expect(recognizeAgentProcess('/Users/dev/.local/bin/agy')).toEqual(agy)
expect(recognizeAgentProcess(String.raw`C:\Users\dev\AppData\Local\agy\bin\agy.exe`)).toEqual(
agy
)
expect(
recognizeAgentProcessFromCommandLine(
String.raw`"C:\Users\dev\AppData\Local\agy\bin\agy.exe" --dangerously-skip-permissions`
)
).toEqual(agy)
expect(recognizeAgentProcessFromCommandLine('agy --dangerously-skip-permissions')).toEqual(agy)
})
it('recognizes versioned Grok process names observed from the installed CLI', () => {
expect(recognizeAgentProcess('grok-0.2.51')).toEqual({
agent: 'grok',
processName: 'grok-0.2.51'
})
})
it('recognizes the versioned Muse binary execed by the launcher', () => {
expect(recognizeAgentProcess('muse-bin-1.3.0-r3401.1')).toEqual({
agent: 'muse',
processName: 'muse-bin-1.3.0-r3401.1'
})
expect(
recognizeAgentProcessFromCommandLine('/Users/dev/.local/bin/muse-bin-1.3.0-R3401.1')
).toEqual({
agent: 'muse',
processName: 'muse-bin-1.3.0-r3401.1'
})
// Why: Linux truncates comm to 15 chars, so `muse-bin-1.0.3-R…` rows still match.
expect(recognizeAgentProcess('muse-bin-1.0.3-R')).toEqual({
agent: 'muse',
processName: 'muse-bin-1.0.3-r'
})
expect(recognizeAgentProcess('muse-workbench')).toBeNull()
expect(isRecognizedAgentType('muse-bin-1.3.0-R3401.1')).toBe(true)
expect(isExpectedAgentProcess('muse', 'muse')).toBe(true)
expect(isExpectedAgentProcess('muse-bin-1.3.0-R3401.1', 'muse')).toBe(true)
expect(isExpectedAgentProcess('/Users/dev/.local/bin/muse-bin-1.3.0-R3401.1', 'muse')).toBe(
true
)
expect(isExpectedAgentProcess('not-muse', 'muse')).toBe(false)
expect(isExpectedAgentProcess('muse-workbench', 'muse')).toBe(false)
})
it('does not recognize Muse headless exec runs as interactive agents', () => {
expect(recognizeAgentProcessFromCommandLine('muse exec "summarize this diff"')).toBeNull()
expect(
recognizeAgentProcessFromCommandLine(
'/Users/dev/.local/bin/muse-bin-1.3.0-R3401.1 exec --session-id abc "hi"'
)
).toBeNull()
// Why: `exec` past any position is never the TUI — `muse exec` dispatches headless
// while `muse <flags> exec` fails fast with an arg error (verified on Muse 1.3.0).
expect(recognizeAgentProcessFromCommandLine('muse -- exec "summarize this diff"')).toBeNull()
expect(recognizeAgentProcessFromCommandLine('muse --yolo exec "hi"')).toBeNull()
expect(recognizeAgentProcessFromCommandLine('muse -- yolo')).toEqual({
agent: 'muse',
processName: 'muse'
})
// Why: subcommand dispatch is case-sensitive, so an uppercase prompt is the TUI.
expect(recognizeAgentProcessFromCommandLine("muse 'EXEC'")).toEqual({
agent: 'muse',
processName: 'muse'
})
})
})