test: remove 113 low-value tests (#34541)

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
OrcaWin
2026-10-27 14:45:01 -07:00
committed by GitHub
co-authored by OrcaWin
parent 8fe31c930e
commit 649dc1a6fb
21 changed files with 2 additions and 1196 deletions
-2
View File
@@ -2921,7 +2921,6 @@
"src/main/ipc/github-repo-routing-twin-host.test.ts": 91,
"src/main/ipc/github-ssh-connection-routing.test.ts": 508,
"src/main/ipc/github-star-telemetry.test.ts": 520,
"src/main/ipc/github-work-item-args.test.ts": 33,
"src/main/ipc/github-wsl-runtime-routing.test.ts": 726,
"src/main/ipc/gitlab-repo-access.test.ts": 111,
"src/main/ipc/gitlab.test.ts": 181,
@@ -10601,7 +10600,6 @@
"src/renderer/src/lib/ime-composition-keyboard-event.test.ts": 199,
"src/renderer/src/lib/ime-overlay-escape.test.tsx": 615,
"src/renderer/src/lib/ime-text-field.test.tsx": 463,
"src/renderer/src/lib/ios-web-platform.test.ts": 48,
"src/renderer/src/lib/ipc-error.test.ts": 69,
"src/renderer/src/lib/jira-board-drag-payload.test.ts": 59,
"src/renderer/src/lib/jira-issue-workspace-attachment.test.ts": 95,
@@ -1,26 +0,0 @@
import { describe, expect, it } from 'vitest'
import { agentBrowserSetMediaArguments } from './agent-browser-set-media-arguments'
describe('agentBrowserSetMediaArguments', () => {
it.each([
[undefined, 'reduce', ['set', 'media', 'reduced-motion']],
[undefined, 'no-preference', ['set', 'media']],
['dark', undefined, ['set', 'media', 'dark']],
['light', 'reduce', ['set', 'media', 'light', 'reduced-motion']]
])('maps color scheme %s and reduced motion %s', (colorScheme, reducedMotion, expected) => {
expect(agentBrowserSetMediaArguments(colorScheme, reducedMotion)).toEqual(expected)
})
it.each([
['sepia', undefined, 'Unsupported --color-scheme: sepia (expected dark or light)'],
[
undefined,
'reduced-motion',
'Unsupported --reduced-motion: reduced-motion (expected reduce or no-preference)'
]
])('rejects color scheme %s and reduced motion %s', (colorScheme, reducedMotion, message) => {
expect(() => agentBrowserSetMediaArguments(colorScheme, reducedMotion)).toThrow(
expect.objectContaining({ code: 'invalid_argument', message })
)
})
})
@@ -1,21 +0,0 @@
import { describe, expect, it } from 'vitest'
import { agentBrowserWaitArguments } from './agent-browser-wait-arguments'
describe('agentBrowserWaitArguments', () => {
it.each([
[
{ fn: 'window.ready', timeout: 60_000 },
['wait', '--fn', 'window.ready', '--timeout', '60000'],
60_000,
65_000
],
[{ selector: '#done' }, ['wait', '#done', '--timeout', '25000'], 25_000, 30_000],
[{ timeout: 40_000 }, ['wait', '40000'], undefined, undefined]
])('builds %j', (options, args, conditionTimeoutMs, processTimeoutMs) => {
expect(agentBrowserWaitArguments(options)).toEqual({
args,
conditionTimeoutMs,
processTimeoutMs
})
})
})
@@ -72,8 +72,4 @@ describe('a Claude informational frame', () => {
expect(items).toEqual([{ kind: 'status', tone: 'warning', text: content }])
})
it('writes no row for a warning with nothing to say', async () => {
expect(await itemsFor([informational('warning', ' ')])).toEqual([])
})
})
@@ -1,87 +0,0 @@
import { describe, expect, it, vi } from 'vitest'
import { dispatchWorkItem } from './github-work-item-args'
describe('dispatchWorkItem', () => {
const repo = { path: '/r', connectionId: null }
it('rejects non-integer numbers', () => {
const fn = vi.fn()
expect(dispatchWorkItem({ repoPath: '/r', number: 1.5 }, repo, fn)).toBeNull()
expect(fn).not.toHaveBeenCalled()
})
it('rejects numbers < 1', () => {
const fn = vi.fn()
expect(dispatchWorkItem({ repoPath: '/r', number: 0 }, repo, fn)).toBeNull()
expect(dispatchWorkItem({ repoPath: '/r', number: -5 }, repo, fn)).toBeNull()
expect(fn).not.toHaveBeenCalled()
})
it('rejects non-number values coming across IPC', () => {
const fn = vi.fn()
// Model malformed renderer input despite the static type.
const bogus = { repoPath: '/r', number: 'abc' as unknown as number }
expect(dispatchWorkItem(bogus, repo, fn)).toBeNull()
expect(fn).not.toHaveBeenCalled()
})
it('coerces unknown type values to undefined', async () => {
const fn = vi.fn().mockResolvedValue(null)
const bogus = {
repoPath: '/r',
number: 42,
type: 'bogus' as unknown as 'issue' | 'pr'
}
await dispatchWorkItem(bogus, repo, fn)
expect(fn).toHaveBeenCalledWith('/r', 42, undefined, null, undefined, undefined)
})
it('passes valid issue type through', async () => {
const fn = vi.fn().mockResolvedValue(null)
await dispatchWorkItem({ repoPath: '/r', number: 42, type: 'issue' }, repo, fn)
expect(fn).toHaveBeenCalledWith('/r', 42, 'issue', null, undefined, undefined)
})
it('passes valid pr type through', async () => {
const fn = vi.fn().mockResolvedValue(null)
await dispatchWorkItem({ repoPath: '/r', number: 42, type: 'pr' }, repo, fn)
expect(fn).toHaveBeenCalledWith('/r', 42, 'pr', null, undefined, undefined)
})
it('passes SSH connection context through', async () => {
const fn = vi.fn().mockResolvedValue(null)
await dispatchWorkItem(
{ repoPath: '/remote/repo', number: 42, type: 'issue' },
{ path: '/remote/repo', connectionId: 'ssh-1' },
fn
)
expect(fn).toHaveBeenCalledWith('/remote/repo', 42, 'issue', 'ssh-1', undefined, undefined)
})
it('pins the repo issue source preference for open-by-number', async () => {
const fn = vi.fn().mockResolvedValue(null)
await dispatchWorkItem(
{ repoPath: '/r', number: 42, type: 'pr' },
{ path: '/r', connectionId: null, issueSourcePreference: 'origin' },
fn,
{ wslDistro: 'Ubuntu' }
)
expect(fn).toHaveBeenCalledWith('/r', 42, 'pr', null, { wslDistro: 'Ubuntu' }, 'origin')
})
it('leaves upstream and auto preferences on the multi-candidate probe', async () => {
const fn = vi.fn().mockResolvedValue(null)
await dispatchWorkItem(
{ repoPath: '/r', number: 7, type: 'pr' },
{ path: '/r', connectionId: null, issueSourcePreference: 'upstream' },
fn
)
await dispatchWorkItem(
{ repoPath: '/r', number: 7, type: 'pr' },
{ path: '/r', connectionId: null, issueSourcePreference: 'auto' },
fn
)
expect(fn).toHaveBeenNthCalledWith(1, '/r', 7, 'pr', null, undefined, 'upstream')
expect(fn).toHaveBeenNthCalledWith(2, '/r', 7, 'pr', null, undefined, 'auto')
})
})
@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest'
import { formatMessageBanner, formatMessagePointer, formatMessagesForInjection } from './formatter'
import { formatMessageBanner } from './formatter'
import type { MessageRow } from './types'
function makeMessage(overrides: Partial<MessageRow> = {}): MessageRow {
@@ -32,43 +32,6 @@ describe('formatMessageBanner', () => {
expect(banner).not.toContain('[HIGH]')
})
it('includes [HIGH] tag for high priority', () => {
const banner = formatMessageBanner(makeMessage({ priority: 'high' }))
expect(banner).toContain('[HIGH]')
})
it('includes [URGENT] tag for urgent priority', () => {
const banner = formatMessageBanner(makeMessage({ priority: 'urgent' }))
expect(banner).toContain('[URGENT]')
})
it('includes body after subject', () => {
const banner = formatMessageBanner(makeMessage({ body: 'Some details here' }))
const lines = banner.split('\n')
const subjectIdx = lines.findIndex((l) => l.startsWith('Subject:'))
const bodyIdx = lines.indexOf('Some details here')
expect(subjectIdx).toBeGreaterThanOrEqual(0)
expect(bodyIdx).toBeGreaterThan(subjectIdx)
})
it('omits body line when body is empty', () => {
const banner = formatMessageBanner(makeMessage({ body: '' }))
const lines = banner.split('\n')
const subjectIdx = lines.findIndex((l) => l.startsWith('Subject:'))
expect(lines[subjectIdx + 1]).toMatch(/^\[Reply:/)
})
it('includes payload when present', () => {
const payload = '{"taskId":"task_1","exitCode":0}'
const banner = formatMessageBanner(makeMessage({ payload }))
expect(banner).toContain(`[Payload: ${payload}]`)
})
it('omits payload line when payload is null', () => {
const banner = formatMessageBanner(makeMessage({ payload: null }))
expect(banner).not.toContain('[Payload:')
})
it('includes reply hint with message ID', () => {
const banner = formatMessageBanner(makeMessage({ id: 'msg_xyz789' }))
expect(banner).toContain(
@@ -143,46 +106,4 @@ describe('formatMessageBanner', () => {
expect(banner).not.toContain('[Reply:')
}
})
it('ends with a separator line', () => {
const banner = formatMessageBanner(makeMessage())
const lines = banner.split('\n')
expect(lines.at(-1)).toMatch(/^─+$/)
})
})
describe('formatMessagesForInjection', () => {
it('returns empty string for empty array', () => {
expect(formatMessagesForInjection([])).toBe('')
})
it('wraps multiple banners with orchestration messages header', () => {
const messages = [makeMessage({ id: 'msg_1' }), makeMessage({ id: 'msg_2' })]
const result = formatMessagesForInjection(messages)
expect(result).toContain('--- Orchestration Messages (2) ---')
expect(result).toContain('msg_1')
expect(result).toContain('msg_2')
expect(result).toMatch(/\n---\n$/)
})
})
describe('formatMessagePointer', () => {
it('formats a singular pointer without message content', () => {
expect(formatMessagePointer(1, 'run:run_1')).toBe(
'\nYou have 1 orchestration message. Run `orca orchestration check --run run_1`.\n'
)
})
it('pluralizes a batched pointer', () => {
expect(formatMessagePointer(3)).toContain('3 orchestration messages')
})
it('uses the terminal-resolved CLI command', () => {
expect(formatMessagePointer(1, 'run:run_wsl', 'orca-ide')).toContain(
'`orca-ide orchestration check --run run_wsl`'
)
expect(formatMessagePointer(1, 'run:run_dev', 'orca-dev')).toContain(
'`orca-dev orchestration check --run run_dev`'
)
})
})
+1 -24
View File
@@ -1,30 +1,7 @@
import { describe, expect, it } from 'vitest'
import {
assertSafeRemotePathSegment,
getRemoteHostPlatform,
joinRemotePath
} from './ssh-remote-platform'
describe('joinRemotePath', () => {
it('joins POSIX remote paths', () => {
expect(joinRemotePath(getRemoteHostPlatform('linux-x64'), '/home/me', '.orca-remote')).toBe(
'/home/me/.orca-remote'
)
})
it('normalizes and joins Windows remote paths with forward slashes for SFTP and Node', () => {
expect(
joinRemotePath(getRemoteHostPlatform('win32-x64'), 'C:\\Users\\me', '.orca-remote', 'relay')
).toBe('C:/Users/me/.orca-remote/relay')
})
})
import { assertSafeRemotePathSegment } from './ssh-remote-platform'
describe('assertSafeRemotePathSegment', () => {
it('accepts ordinary names under both path flavors', () => {
expect(() => assertSafeRemotePathSegment('report copy.txt', 'posix')).not.toThrow()
expect(() => assertSafeRemotePathSegment('report copy.txt', 'windows')).not.toThrow()
})
it.each(['.', '..', '../secret', 'child/name', 'nul\0byte'])(
'rejects invalid segment %j under both path flavors',
(segment) => {
@@ -78,21 +78,4 @@ describe('generateConversationName', () => {
cancelLocalGeneration('conversation-name', '/repo')
expect(await pending).toMatchObject({ success: false, canceled: true })
})
it('returns a sanitized name from the local generation lane', async () => {
const child = createMockDiscoveryChild()
const spawnAgent = vi.fn(() => {
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: The test child implements every process member the generation lane reads.
return child as unknown as SpawnedSourceControlAgentProcess
})
const pending = generateConversationName({
context: { firstPrompt: 'Fix login' },
params: { agentId: 'custom', model: '', customAgentCommand: 'agent' },
target: { kind: 'local', cwd: '/repo' },
spawnAgent
})
child.stdout.emit('data', Buffer.from('Title: "Fix login flow"\n'))
child.emit('close', 0)
expect(await pending).toEqual({ success: true, name: 'Fix login flow', agentLabel: 'agent' })
})
})
@@ -1,49 +0,0 @@
import { describe, expect, it } from 'vitest'
import { isIosWebPlatform } from './ios-web-platform'
const IPAD_DESKTOP_MODE_UA =
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15'
const IPAD_MOBILE_MODE_UA =
'Mozilla/5.0 (iPad; CPU OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/120.0.0.0 Mobile/15E148 Safari/604.1'
const IPHONE_UA =
'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1'
const IPOD_UA =
'Mozilla/5.0 (iPod touch; CPU iPhone OS 14_8 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.2 Mobile/15E148 Safari/604.1'
const MAC_DESKTOP_UA =
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'
const MAC_ELECTRON_UA =
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) orca/1.0.0 Chrome/126.0.0.0 Electron/31.0.0 Safari/537.36'
const WINDOWS_UA =
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'
const ANDROID_UA =
'Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Mobile Safari/537.36'
describe('isIosWebPlatform', () => {
it('detects iPadOS desktop mode, which reports Macintosh and omits iPad', () => {
expect(isIosWebPlatform(IPAD_DESKTOP_MODE_UA, 5)).toBe(true)
})
it('detects iPad, iPhone and iPod mobile-mode user agents', () => {
expect(isIosWebPlatform(IPAD_MOBILE_MODE_UA, 5)).toBe(true)
expect(isIosWebPlatform(IPHONE_UA, 5)).toBe(true)
expect(isIosWebPlatform(IPOD_UA, 5)).toBe(true)
})
it('detects a mobile-mode iPad even when the touch count is unavailable', () => {
expect(isIosWebPlatform(IPAD_MOBILE_MODE_UA, 0)).toBe(true)
})
it('does not claim a Mac browser or the Electron app', () => {
expect(isIosWebPlatform(MAC_DESKTOP_UA, 0)).toBe(false)
expect(isIosWebPlatform(MAC_ELECTRON_UA, 0)).toBe(false)
})
it('does not claim a Mac whose touch peripheral reports a single point', () => {
expect(isIosWebPlatform(MAC_DESKTOP_UA, 1)).toBe(false)
})
it('does not claim Windows, Linux or Android', () => {
expect(isIosWebPlatform(WINDOWS_UA, 0)).toBe(false)
expect(isIosWebPlatform(ANDROID_UA, 5)).toBe(false)
})
})
@@ -36,39 +36,6 @@ describe('orderEmptyQueryWorktrees', () => {
expect(result.switchableWorktreesForRows.map((w) => w.id)).toEqual(['ssh', 'local'])
})
it('sorts visited worktrees by lastVisitedAt descending', () => {
const a = wt({ id: 'a', displayName: 'a' })
const b = wt({ id: 'b', displayName: 'b' })
const result = orderEmptyQueryWorktrees({
visibleWorktrees: [a, b],
activeWorktreeId: null,
lastVisitedAtByWorktreeId: { a: 100, b: 200 }
})
expect(result.switchableWorktreesForRows.map((w) => w.id)).toEqual(['b', 'a'])
})
it('falls back to lastActivityAt for never-visited worktrees', () => {
const a = wt({ id: 'a', displayName: 'a', lastActivityAt: 100 })
const b = wt({ id: 'b', displayName: 'b', lastActivityAt: 200 })
const result = orderEmptyQueryWorktrees({
visibleWorktrees: [a, b],
activeWorktreeId: null,
lastVisitedAtByWorktreeId: {}
})
expect(result.switchableWorktreesForRows.map((w) => w.id)).toEqual(['b', 'a'])
})
it('uses displayName as final tie-breaker', () => {
const a = wt({ id: 'a', displayName: 'apple', lastActivityAt: 100 })
const b = wt({ id: 'b', displayName: 'banana', lastActivityAt: 100 })
const result = orderEmptyQueryWorktrees({
visibleWorktrees: [b, a],
activeWorktreeId: null,
lastVisitedAtByWorktreeId: {}
})
expect(result.switchableWorktreesForRows.map((w) => w.id)).toEqual(['a', 'b'])
})
it('does not crash the switcher when a visible worktree has no displayName (crash 99657ab1)', () => {
// Persisted/discovered displayName can be undefined despite its type; raw localeCompare once crashed Cmd+J.
const named = wt({ id: 'a', displayName: 'apple', lastActivityAt: 100 })
@@ -86,18 +53,6 @@ describe('orderEmptyQueryWorktrees', () => {
).not.toThrow()
})
it('excludes current worktree from rows but includes it in state list', () => {
const cur = wt({ id: 'cur', displayName: 'cur' })
const other = wt({ id: 'other', displayName: 'other' })
const result = orderEmptyQueryWorktrees({
visibleWorktrees: [cur, other],
activeWorktreeId: 'cur',
lastVisitedAtByWorktreeId: {}
})
expect(result.switchableWorktreesForRows.map((w) => w.id)).toEqual(['other'])
expect(result.visibleWorktreesForState.map((w) => w.id)).toEqual(['cur', 'other'])
})
// Filter current workspace by host too or its same-ID SSH twin becomes unreachable.
it('keeps the same-id worktree on the other host switchable', () => {
const local = wt({ id: 'shared', displayName: 'local', hostId: 'local' })
@@ -110,15 +65,4 @@ describe('orderEmptyQueryWorktrees', () => {
})
expect(result.switchableWorktreesForRows.map((w) => w.displayName)).toEqual(['ssh'])
})
it('returns empty rows but non-empty state when only the current worktree is visible', () => {
const cur = wt({ id: 'cur', displayName: 'cur' })
const result = orderEmptyQueryWorktrees({
visibleWorktrees: [cur],
activeWorktreeId: 'cur',
lastVisitedAtByWorktreeId: {}
})
expect(result.switchableWorktreesForRows).toEqual([])
expect(result.visibleWorktreesForState).toHaveLength(1)
})
})
@@ -57,35 +57,12 @@ function count(overrides: Partial<UnreadBadgeCountSources>): number {
}
describe('getUnreadBadgeCount', () => {
it('counts unread worktrees', () => {
expect(
count({
worktreesByRepo: { repo1: [worktree('wt-1'), worktree('wt-2', { isUnread: false })] }
})
).toBe(1)
})
it('skips archived worktrees, which the sidebar never shows', () => {
expect(count({ worktreesByRepo: { repo1: [worktree('wt-1', { isArchived: true })] } })).toBe(0)
})
it('preserves id-only deduplication across execution hosts', () => {
const rows = [worktree('wt-1', { hostId: 'local' }), worktree('wt-1', { hostId: 'ssh:remote' })]
expect(count({ worktreesByRepo: { repo1: rows } })).toBe(1)
expect(count({ worktreesByRepo: { repo1: rows }, visibleHostIds: new Set(['local']) })).toBe(1)
})
it('counts a row repeated across repo buckets once', () => {
expect(
count({
worktreesByRepo: {
'repo-a': [worktree('wt-1', { hostId: 'local' })],
'repo-b': [worktree('wt-1', { hostId: 'local' })]
}
})
).toBe(1)
})
it('counts unread folder workspaces alongside worktrees', () => {
expect(
count({
-65
View File
@@ -29,15 +29,6 @@ function makeWorktree(overrides: Partial<Worktree> = {}): Worktree {
}
describe('deriveAiVaultWorkspaceScopePaths', () => {
it('returns the active workspace path', () => {
const active = makeWorktree()
expect(deriveAiVaultWorkspaceScopePaths(active, [active])).toEqual(['/repo/orca'])
})
it('returns nothing without an active workspace', () => {
expect(deriveAiVaultWorkspaceScopePaths(null, [makeWorktree()])).toEqual([])
})
it('includes prior paths so renamed workspaces keep their transcripts', () => {
const active = makeWorktree({
id: 'repo-1::/repo/orca-renamed',
@@ -51,25 +42,6 @@ describe('deriveAiVaultWorkspaceScopePaths', () => {
])
})
it('drops a prior path another live workspace now owns', () => {
// Sessions use cwd identity; claiming an occupied prior path would expose another workspace's transcripts.
const claimant = makeWorktree({ id: 'repo-1::/repo/orca', path: '/repo/orca' })
const active = makeWorktree({
id: 'repo-1::/repo/orca-renamed',
path: '/repo/orca-renamed',
priorWorktreeIds: ['repo-1::/repo/orca']
})
expect(deriveAiVaultWorkspaceScopePaths(active, [claimant, active])).toEqual([
'/repo/orca-renamed'
])
})
it('keeps a prior path the active workspace itself still owns', () => {
const active = makeWorktree({ priorWorktreeIds: ['repo-1::/repo/orca'] })
expect(deriveAiVaultWorkspaceScopePaths(active, [active])).toEqual(['/repo/orca'])
})
it('drops a claimed prior path regardless of where the claimant sits in the list', () => {
// Exclude the active workspace before indexing owners so duplicates cannot hide later claimants.
const active = makeWorktree({
@@ -93,27 +65,6 @@ describe('deriveAiVaultWorkspaceScopePaths', () => {
}
})
it('derives workspace scope paths at scale', () => {
// The session-scope guard cannot catch quadratic deduplication confined to the workspace pass.
const prefix = '/Users/dev/orca/workspaces/orca-monorepo/feature-'
const worktrees = Array.from({ length: 1200 }, (_, i) =>
makeWorktree({ id: `repo-1::${prefix}${i}`, path: `${prefix}${i}` })
)
const active = makeWorktree({
id: `repo-1::${prefix}0`,
path: `${prefix}0`,
// Priors drive the claim check, which is the other per-call scan here.
priorWorktreeIds: Array.from({ length: 25 }, (_, i) => `repo-1::${prefix}prior-${i}`)
})
const startedAt = performance.now()
const paths = deriveAiVaultWorkspaceScopePaths(active, worktrees)
const elapsedMs = performance.now() - startedAt
expect(paths).toHaveLength(1 + 25)
expect(elapsedMs).toBeLessThan(100)
})
it('ignores prior ids belonging to another repo', () => {
const active = makeWorktree({ priorWorktreeIds: ['repo-2::/repo/other'] })
expect(deriveAiVaultWorkspaceScopePaths(active, [active])).toEqual(['/repo/orca'])
@@ -161,20 +112,4 @@ describe('deriveAiVaultScopeSessionPaths', () => {
expect(deriveAiVaultScopeSessionPaths(active, [active, nfd])).toEqual([nfc])
})
it('derives scope paths at scale without re-normalizing the accumulator', () => {
// Match profile count/path lengths to catch quadratic normalization on workspace switches (~190ms before).
const prefix = '/Users/dev/orca/workspaces/orca-monorepo/feature-'
const worktrees = Array.from({ length: 1200 }, (_, i) =>
makeWorktree({ id: `repo-1::${prefix}${i}`, path: `${prefix}${i}` })
)
const startedAt = performance.now()
const paths = deriveAiVaultScopeSessionPaths(worktrees[0], worktrees)
const elapsedMs = performance.now() - startedAt
expect(paths).toHaveLength(worktrees.length)
// Allow slow CI hosts while catching the previous ~190ms cost (now ~1ms).
expect(elapsedMs).toBeLessThan(100)
})
})
@@ -1,7 +1,6 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import {
configureHardeningRetryBudget,
hardeningRetryDelayMs,
mayAttemptHardening,
recordHardeningOutcome
} from './secure-path-hardening-retry-budget'
@@ -55,28 +54,6 @@ describe('secure path hardening retry budget', () => {
return attemptedAt
}
it('doubles the delay after each consecutive failure, up to the ceiling', () => {
expect(hardeningRetryDelayMs(1)).toBe(1 * MINUTE)
expect(hardeningRetryDelayMs(2)).toBe(2 * MINUTE)
expect(hardeningRetryDelayMs(3)).toBe(4 * MINUTE)
expect(hardeningRetryDelayMs(4)).toBe(8 * MINUTE)
expect(hardeningRetryDelayMs(5)).toBe(16 * MINUTE)
expect(hardeningRetryDelayMs(6)).toBe(30 * MINUTE)
expect(hardeningRetryDelayMs(50)).toBe(30 * MINUTE)
expect(hardeningRetryDelayMs(5000)).toBe(30 * MINUTE)
})
it('allows the first attempt for a path it has never seen', () => {
expect(mayAttemptHardening(PATH)).toBe(true)
})
// The #4901 condition: the env store re-hardens on the read path about twice a second.
it('collapses a read-path poll to a single attempt in the first minute', () => {
const attemptedAt = pollUntil(55_000, 500)
expect(attemptedAt).toEqual([0])
})
it('re-probes on the documented curve rather than on every read', () => {
// Six hours of polling every 30s: 720 reads, and only the backoff decides how many run.
const attemptedAt = pollUntil(6 * 60 * MINUTE, 30_000)
@@ -88,14 +65,6 @@ describe('secure path hardening retry budget', () => {
expect(trailingGaps.slice(0, -1)).toEqual([30, 30, 30])
})
// The failure this replaced: three transient failures used to disable a path until restart.
it('never abandons a path, however long it has been failing', () => {
pollUntil(30 * 24 * 60 * MINUTE, 15 * MINUTE)
clock += 31 * MINUTE
expect(mayAttemptHardening(PATH)).toBe(true)
})
/** Backwards wall-clock steps previously held paths below retry delay until time caught up; monotonic elapsed time must keep probing. */
it('re-probes after a backwards clock step rather than waiting for the wall clock', () => {
pollUntil(6 * 60 * MINUTE, 30_000)
@@ -4,7 +4,6 @@ import {
getStageAllPaths,
getUnstageAllPaths,
isStageableStatusEntry,
isSubmoduleWorktreeOnlyChange,
runDiscardAllForArea
} from './source-control-discard-all-sequence'
import type { GitStatusEntry } from './git-status-types'
@@ -18,17 +17,6 @@ function entry(partial: Partial<GitStatusEntry> & { path: string }): GitStatusEn
}
describe('getDiscardAllPaths', () => {
it('returns only paths in the requested area', () => {
const entries: GitStatusEntry[] = [
entry({ path: 'a.ts', area: 'staged' }),
entry({ path: 'b.ts', area: 'unstaged' }),
entry({ path: 'c.ts', area: 'untracked', status: 'untracked' })
]
expect(getDiscardAllPaths(entries, 'staged')).toEqual(['a.ts'])
expect(getDiscardAllPaths(entries, 'unstaged')).toEqual(['b.ts', 'c.ts'])
expect(getDiscardAllPaths(entries, 'untracked')).toEqual(['c.ts'])
})
it('skips entries with an unresolved conflict', () => {
const entries: GitStatusEntry[] = [
entry({ path: 'clean.ts', area: 'unstaged' }),
@@ -56,24 +44,9 @@ describe('getDiscardAllPaths', () => {
// Bulk discard must preserve local resolutions or users would have to resolve them again.
expect(getDiscardAllPaths(entries, 'unstaged')).toEqual(['clean.ts'])
})
it('returns an empty array when nothing matches', () => {
expect(getDiscardAllPaths([], 'staged')).toEqual([])
expect(getDiscardAllPaths([entry({ path: 'a.ts', area: 'staged' })], 'unstaged')).toEqual([])
})
})
describe('getStageAllPaths', () => {
it('returns only paths in the requested area', () => {
const entries: GitStatusEntry[] = [
entry({ path: 'a.ts', area: 'staged' }),
entry({ path: 'b.ts', area: 'unstaged' }),
entry({ path: 'c.ts', area: 'untracked', status: 'untracked' })
]
expect(getStageAllPaths(entries, 'unstaged')).toEqual(['b.ts'])
expect(getStageAllPaths(entries, 'untracked')).toEqual(['c.ts'])
})
it('skips entries with an unresolved conflict', () => {
const entries: GitStatusEntry[] = [
entry({ path: 'clean.ts', area: 'unstaged' }),
@@ -117,36 +90,9 @@ describe('getStageAllPaths', () => {
]
expect(getStageAllPaths(entries, 'unstaged')).toEqual(['changed-gitlink'])
})
it('returns an empty array when nothing matches', () => {
expect(getStageAllPaths([], 'unstaged')).toEqual([])
expect(getStageAllPaths([entry({ path: 'a.ts', area: 'staged' })], 'unstaged')).toEqual([])
})
})
describe('status entry stageability', () => {
it('marks nested-only submodule changes as not stageable from the parent repo', () => {
const nestedOnly = entry({
path: 'nested-repo',
area: 'unstaged',
submodule: { commitChanged: false, trackedChanges: true, untrackedChanges: false }
})
expect(isSubmoduleWorktreeOnlyChange(nestedOnly)).toBe(true)
expect(isStageableStatusEntry(nestedOnly)).toBe(false)
})
it('keeps changed submodule gitlinks stageable from the parent repo', () => {
const changedGitlink = entry({
path: 'nested-repo',
area: 'unstaged',
submodule: { commitChanged: true, trackedChanges: true, untrackedChanges: true }
})
expect(isSubmoduleWorktreeOnlyChange(changedGitlink)).toBe(false)
expect(isStageableStatusEntry(changedGitlink)).toBe(true)
})
it('marks lazily-expanded submodule-internal entries as not stageable', () => {
const innerEntry = entry({
path: 'flutter_mine/lib/main.dart',
@@ -161,15 +107,6 @@ describe('status entry stageability', () => {
})
describe('getUnstageAllPaths', () => {
it('returns only staged-area paths', () => {
const entries: GitStatusEntry[] = [
entry({ path: 'a.ts', area: 'staged' }),
entry({ path: 'b.ts', area: 'unstaged' }),
entry({ path: 'c.ts', area: 'untracked', status: 'untracked' })
]
expect(getUnstageAllPaths(entries)).toEqual(['a.ts'])
})
it('includes staged conflict rows', () => {
const entries: GitStatusEntry[] = [
entry({ path: 'clean.ts', area: 'staged' }),
@@ -189,11 +126,6 @@ describe('getUnstageAllPaths', () => {
// Unstaging conflicts safely mirrors the per-row action; no conflict filtering is needed.
expect(getUnstageAllPaths(entries)).toEqual(['clean.ts', 'conflict.ts', 'resolved.ts'])
})
it('returns an empty array when nothing is staged', () => {
expect(getUnstageAllPaths([])).toEqual([])
expect(getUnstageAllPaths([entry({ path: 'a.ts', area: 'unstaged' })])).toEqual([])
})
})
describe('runDiscardAllForArea', () => {
@@ -248,30 +180,6 @@ describe('runDiscardAllForArea', () => {
}
}
it('no-ops when the path list is empty', async () => {
const ctx = makeDeps()
const result = await runDiscardAllForArea('staged', [], ctx.deps)
expect(result).toEqual({ discarded: [], failed: [], aborted: false })
expect(ctx.bulkUnstage).not.toHaveBeenCalled()
expect(ctx.discardOne).not.toHaveBeenCalled()
})
it('discards unstaged paths one-by-one without bulk-unstaging', async () => {
const ctx = makeDeps()
const result = await runDiscardAllForArea('unstaged', ['a.ts', 'b.ts'], ctx.deps)
expect(result).toEqual({ discarded: ['a.ts', 'b.ts'], failed: [], aborted: false })
expect(ctx.bulkUnstage).not.toHaveBeenCalled()
expect(ctx.discardOneCalls).toEqual(['a.ts', 'b.ts'])
})
it('discards untracked paths one-by-one without bulk-unstaging', async () => {
const ctx = makeDeps()
const result = await runDiscardAllForArea('untracked', ['new.ts'], ctx.deps)
expect(result).toEqual({ discarded: ['new.ts'], failed: [], aborted: false })
expect(ctx.bulkUnstage).not.toHaveBeenCalled()
expect(ctx.discardOneCalls).toEqual(['new.ts'])
})
it('bulk-unstages staged paths before the per-file discard loop', async () => {
const ctx = makeDeps()
const result = await runDiscardAllForArea('staged', ['a.ts', 'b.ts'], ctx.deps)
@@ -284,14 +192,6 @@ describe('runDiscardAllForArea', () => {
)
})
it('uses bulk discard when the dependency is available', async () => {
const ctx = makeDeps()
const result = await runDiscardAllForArea('unstaged', ['a.ts', 'b.ts'], ctx.depsWithBulkDiscard)
expect(result).toEqual({ discarded: ['a.ts', 'b.ts'], failed: [], aborted: false })
expect(ctx.discardManyCalls).toEqual([['a.ts', 'b.ts']])
expect(ctx.discardOne).not.toHaveBeenCalled()
})
it('bulk-unstages staged paths before bulk discard', async () => {
const ctx = makeDeps()
const result = await runDiscardAllForArea('staged', ['a.ts', 'b.ts'], ctx.depsWithBulkDiscard)
@@ -339,10 +239,4 @@ describe('runDiscardAllForArea', () => {
// Reserve aborted for failed bulk unstage so callers can distinguish no work from partial success.
expect(ctx.errors).toEqual([error])
})
it('does not invoke the error callback on a happy-path staged run', async () => {
const ctx = makeDeps()
await runDiscardAllForArea('staged', ['a.ts'], ctx.deps)
expect(ctx.onError).not.toHaveBeenCalled()
})
})
@@ -2,7 +2,6 @@ import { describe, expect, it } from 'vitest'
import type { GitStatusEntry } from './git-status-types'
import {
buildSourceControlDisplaySections,
getConflictReviewEntries,
getSourceControlSectionViewAction,
resolveSourceControlGroupOrder,
splitPinnedSourceControlConflicts,
@@ -26,35 +25,7 @@ function groups(partial: Partial<SourceControlEntryGroups>): SourceControlEntryG
}
}
describe('resolveSourceControlGroupOrder', () => {
it('keeps Changes first by default', () => {
expect(resolveSourceControlGroupOrder(undefined)).toEqual(['unstaged', 'staged'])
})
it('supports staged-first and untracked-first presets', () => {
expect(resolveSourceControlGroupOrder('staged-first')).toEqual(['staged', 'unstaged'])
expect(resolveSourceControlGroupOrder('untracked-first')).toEqual(['unstaged', 'staged'])
})
})
describe('buildSourceControlDisplaySections', () => {
it('uses the configured order for normal sections', () => {
const sections = buildSourceControlDisplaySections(
groups({
staged: [entry({ area: 'staged', path: 'staged.ts' })],
unstaged: [entry({ area: 'unstaged', path: 'changed.ts' })],
untracked: [entry({ area: 'untracked', path: 'new.ts', status: 'untracked' })]
}),
resolveSourceControlGroupOrder('staged-first')
)
expect(sections.map((section) => section.id)).toEqual(['staged', 'unstaged'])
expect(sections[1]?.items.map(({ path, area }) => ({ path, area }))).toEqual([
{ path: 'changed.ts', area: 'unstaged' },
{ path: 'new.ts', area: 'untracked' }
])
})
it('combines working files in path order before staged changes by default', () => {
const sections = buildSourceControlDisplaySections(
groups({
@@ -69,27 +40,6 @@ describe('buildSourceControlDisplaySections', () => {
expect(sections[0]?.items.map((item) => item.path)).toEqual(['new.ts', 'working.ts'])
})
it('keeps conflicts pinned before the configured normal order', () => {
const sections = buildSourceControlDisplaySections(
groups({
staged: [entry({ area: 'staged', path: 'staged.ts' })],
unstaged: [
entry({
area: 'unstaged',
path: 'conflict.ts',
conflictKind: 'both_modified',
conflictStatus: 'unresolved'
}),
entry({ area: 'unstaged', path: 'changed.ts' })
],
untracked: [entry({ area: 'untracked', path: 'new.ts', status: 'untracked' })]
}),
resolveSourceControlGroupOrder('staged-first')
)
expect(sections.map((section) => section.id)).toEqual(['conflicts', 'staged', 'unstaged'])
})
it('pins conflict rows and removes them from the normal Changes section', () => {
const unresolved = entry({
area: 'unstaged',
@@ -140,25 +90,6 @@ describe('buildSourceControlDisplaySections', () => {
expect(sections[1]?.items).toEqual([staged])
})
it('builds review entries only for unresolved conflicts', () => {
expect(
getConflictReviewEntries([
entry({
area: 'unstaged',
path: 'conflict.ts',
conflictKind: 'both_modified',
conflictStatus: 'unresolved'
}),
entry({
area: 'unstaged',
path: 'resolved.ts',
conflictKind: 'both_modified',
conflictStatus: 'resolved_locally'
})
])
).toEqual([{ path: 'conflict.ts', conflictKind: 'both_modified' }])
})
it('routes the pinned Conflicts section to conflict review', () => {
const sections = buildSourceControlDisplaySections(
groups({
@@ -186,26 +117,6 @@ describe('buildSourceControlDisplaySections', () => {
})
})
it('scopes normal combined-diff actions to the conflict-split section items', () => {
const pinned = entry({
area: 'unstaged',
path: 'resolved.ts',
conflictKind: 'both_modified',
conflictStatus: 'resolved_locally'
})
const normal = entry({ area: 'unstaged', path: 'normal.ts' })
const sections = buildSourceControlDisplaySections(
groups({ unstaged: [pinned, normal] }),
resolveSourceControlGroupOrder('changes-first')
)
expect(getSourceControlSectionViewAction(sections[1]!)).toEqual({
kind: 'combined-diff',
area: 'unstaged',
entries: [normal]
})
})
it('routes locally resolved-only conflict sections to combined diff', () => {
const resolved = entry({
area: 'unstaged',
@@ -2,80 +2,10 @@ import { describe, expect, it, vi } from 'vitest'
import {
dispatchStructuredAgentSessionComposerCommand,
isStructuredAgentSessionComposerCommand,
structuredAgentSessionGoalObjective,
structuredSessionSlashCommands,
structuredSlashCommands
} from './structured-agent-session-composer'
describe('structuredSlashCommands', () => {
const hostController = {
snapshot: [],
invokeAction: async () => true,
setOption: async () => true,
conversationCommands: ['clear', 'compact'] as const,
runConversationCommand: async () => ({ accepted: true, error: null })
}
const REFUSAL = /is not available in chat sessions/
// Menu and dispatcher must share policy or Codex-only tokens can reach Claude as literal prose instead of being handled.
it.each(['codex', 'claude'] as const)(
'offers %s only commands the host answers or the agent runs',
async (agent) => {
const offered = structuredSlashCommands(['clear', 'compact'], agent)
expect(offered.length).toBeGreaterThan(0)
for (const command of offered) {
const outcome = await dispatchStructuredAgentSessionComposerCommand(`/${command.name}`, {
...hostController,
agent
})
expect(outcome.error ?? '').not.toMatch(REFUSAL)
}
}
)
// Codex reports no catalog; fallback rows make its working text-driven commands discoverable.
it('offers Codex the /goal the model acts on, described from the catalog', () => {
const offered = structuredSlashCommands(['clear', 'compact'], 'codex')
expect(offered.map((command) => command.name)).toEqual([
'model',
'effort',
'clear',
'compact',
'goal'
])
expect(offered.find((command) => command.name === 'goal')?.description).toBe(
'Set or view the goal'
)
expect(isStructuredAgentSessionComposerCommand('/goal', 'codex')).toBe(false)
})
it('adds nothing for an agent whose own harness expands its commands', () => {
expect(structuredSlashCommands(['clear', 'compact'], 'claude').map((c) => c.name)).toEqual([
'model',
'effort',
'clear',
'compact'
])
})
it('offers only the commands a chat session can carry out', () => {
expect(structuredSlashCommands().map((command) => command.name)).toEqual(['model', 'effort'])
})
it('adds only implemented host-supported conversation commands', () => {
expect(structuredSlashCommands(['clear', 'compact']).map((command) => command.name)).toEqual([
'model',
'effort',
'clear',
'compact'
])
expect(structuredSlashCommands(['compact']).map((command) => command.name)).toEqual([
'model',
'effort',
'compact'
])
})
})
describe('structuredSessionSlashCommands', () => {
const names = (commands: readonly { name: string }[]) => commands.map(({ name }) => name)
@@ -111,22 +41,6 @@ describe('structuredSessionSlashCommands', () => {
})
})
describe('isStructuredAgentSessionComposerCommand', () => {
// Claim typed TUI-only commands even when hidden from the menu, so they do not reach the model as prose.
it.each([
['codex', 'vim'],
['codex', 'clear'],
['claude', 'compact'],
['claude', 'clear']
] as const)('claims the unoffered %s command /%s', (agent, name) => {
expect(isStructuredAgentSessionComposerCommand(`/${name}`, agent)).toBe(true)
})
it('leaves an unknown token to the chat path', () => {
expect(isStructuredAgentSessionComposerCommand('/my-skill', 'claude')).toBe(false)
})
})
describe('dispatchStructuredAgentSessionComposerCommand', () => {
const controller = {
agent: 'codex' as const,
@@ -134,14 +48,6 @@ describe('dispatchStructuredAgentSessionComposerCommand', () => {
invokeAction: async () => true,
setOption: async () => true
}
it('names what does work when a TUI-only command is typed', async () => {
const outcome = await dispatchStructuredAgentSessionComposerCommand('/vim', controller)
expect(outcome.handled).toBe(true)
expect(outcome.error).toBe(
'/vim is not available in chat sessions. Use the slash menu to see available commands.'
)
})
it.each(['claude', 'codex'] as const)(
'handles %s conversation commands without message fallthrough',
async (agent) => {
@@ -196,21 +102,6 @@ describe('agent-implemented commands pass through to the agent', () => {
}
)
it.each(['clear', 'compact', 'model', 'effort'] as const)(
'still claims the host-owned /%s on Claude',
async (name) => {
expect(isStructuredAgentSessionComposerCommand(`/${name}`, 'claude')).toBe(true)
expect(
(
await dispatchStructuredAgentSessionComposerCommand(`/${name}`, {
...controller,
agent: 'claude'
})
).handled
).toBe(true)
}
)
// Codex app-server lacks a slash parser, but its model handles /goal through goal tools.
it('passes /goal through on Codex, arguments and all', async () => {
expect(isStructuredAgentSessionComposerCommand('/goal', 'codex')).toBe(false)
@@ -244,14 +135,6 @@ describe('agent-implemented commands pass through to the agent', () => {
).toEqual({ handled: true, accepted: false, error: null })
})
it('reads the objective a goal-mode draft names, with or without a typed /goal', () => {
expect(structuredAgentSessionGoalObjective(' Ship the parser ')).toBe('Ship the parser')
expect(structuredAgentSessionGoalObjective('/goal Ship the parser ')).toBe('Ship the parser')
expect(structuredAgentSessionGoalObjective('/GOAL')).toBe('')
// Goal mode treats non-goal commands as objective text.
expect(structuredAgentSessionGoalObjective('/model gpt-5')).toBe('/model gpt-5')
})
it('asks for an objective when a goal-capable host gets a bare /goal', async () => {
const setThreadGoalObjective = vi.fn(async () => true)
expect(
@@ -26,10 +26,6 @@ describe('isStructuredAgentSessionThinking', () => {
blocks: [{ type: 'text', text: 'Weighing two approaches' }]
})
it('is true while reasoning is the newest thing the turn produced', () => {
expect(isStructuredAgentSessionThinking({ items: [turnStart, reasoning(2)] })).toBe(true)
})
it("reads a reasoning row's own state when its host keeps one", () => {
const withState = (state: 'running' | 'completed'): AgentJournalRenderItem =>
item('reasoning-state', 2, {
@@ -64,21 +60,6 @@ describe('isStructuredAgentSessionThinking', () => {
).toBe(false)
})
it('is false when a turn produced no reasoning at all', () => {
expect(isStructuredAgentSessionThinking({ items: [turnStart] })).toBe(false)
expect(isStructuredAgentSessionThinking({ items: [] })).toBe(false)
})
it('does not read an earlier turn as this one reasoning', () => {
// A new turn with no content must not inherit the previous turn’s reasoning.
const newTurn = item('turn-2-start', 2, {
kind: 'status',
text: 'Working',
turnLifecycle: { turnId: 'turn-2', state: 'running' }
})
expect(isStructuredAgentSessionThinking({ items: [reasoning(1), newTurn] })).toBe(false)
})
it('does not read a completed turn as reasoning during the next pending dispatch', () => {
const completedTurn = item('turn-1', 1, {
kind: 'turn',
@@ -191,17 +172,6 @@ describe("the live-turn readers answer for the session's own agent", () => {
).toBe(false)
})
it('still reports the parent as thinking when the parent itself is reasoning', () => {
const ownReasoning = item('own-reasoning', 3, {
kind: 'message',
role: 'reasoning',
blocks: [{ type: 'text', text: 'Weighing two approaches' }]
})
expect(isStructuredAgentSessionThinking({ items: [turnStart, spawnCall, ownReasoning] })).toBe(
true
)
})
it("reports the parent's own running call while a subagent runs its own", () => {
const childCall = child('child-grep', 3, {
kind: 'tool-call',
@@ -236,16 +206,4 @@ describe("the live-turn readers answer for the session's own agent", () => {
'Task'
)
})
it("reads a row written before linkage existed as the parent's own", () => {
const legacyChildCall = item('legacy-call', 3, {
kind: 'tool-call',
name: 'Grep',
input: { pattern: 'x' },
state: 'running'
})
expect(
statusStructuredAgentSessionToolCall([turnStart, spawnCall, legacyChildCall])?.name
).toBe('Grep')
})
})
@@ -7,7 +7,6 @@ import {
applyStructuredAgentSessionModelCatalog,
applyStructuredAgentSessionOptions,
createStructuredAgentSessionOptionState,
settleStructuredAgentSessionBuiltinCatalog,
structuredAgentSessionOptionSnapshot,
canSetStructuredAgentSessionOption,
commitStructuredAgentSessionOption
@@ -36,29 +35,6 @@ const HOST_CATALOG: AgentSessionModelCatalogResult = {
const LAUNCH = { newLaunch: true }
describe('structured option state from the host model catalog', () => {
it('renders the quiet placeholder before the host answers, never a built-in label', () => {
const state = createStructuredAgentSessionOptionState('codex', SEED)
expect(structuredAgentSessionOptionSnapshot(state)).toEqual([
expect.objectContaining({
id: 'model',
valueSource: 'unknown',
settable: false,
kind: { type: 'select', choices: [] }
})
])
})
it('makes the built-in list pickable, naming nothing, once the host says it has none', () => {
const state = settleStructuredAgentSessionBuiltinCatalog(
createStructuredAgentSessionOptionState('codex', SEED)
)
expect(state.catalogSource).toBe('builtin')
const model = structuredAgentSessionOptionSnapshot(state).find((d) => d.id === 'model')!
expect(model.kind.type === 'select' && model.kind.choices.length).toBeGreaterThan(0)
expect(model.settable).toBe(true)
expect(model.kind.type === 'select' ? model.kind.currentValue : null).toBeUndefined()
})
it('upgrades the seed with host models as a provisional, uncommitted default', () => {
const state = applyStructuredAgentSessionModelCatalog(
createStructuredAgentSessionOptionState('codex', SEED),
@@ -154,58 +130,6 @@ describe('structured option state from the host model catalog', () => {
).toBe(hosted)
})
it('refreshes inventory after a live answer while retaining the chat’s own selection', () => {
const live = applyStructuredAgentSessionOptions(
createStructuredAgentSessionOptionState('codex', SEED),
SEED,
{
models: [{ id: 'gpt-live', label: 'GPT Live', isDefault: true, efforts: [] }],
current: { model: 'gpt-live', confirmed: ['model'] }
}
)
expect(live.catalogSource).toBe('live')
const refreshed = applyStructuredAgentSessionModelCatalog(live, SEED, HOST_CATALOG, {
...LAUNCH,
coherentCatalog: true
})
for (const agent of ['grok', 'pi']) {
const sourced = { ...live, record: { ...live.record, agent } }
expect(applyStructuredAgentSessionModelCatalog(sourced, SEED, HOST_CATALOG, LAUNCH)).toBe(
sourced
)
}
expect(refreshed.catalog?.models.map((row) => row.id)).toEqual(['gpt-hosted'])
expect(refreshed.record).toBe(live.record)
const snapshot = structuredAgentSessionOptionSnapshot(live)
const model = snapshot.find((descriptor) => descriptor.id === 'model')!
expect(model.kind.type === 'select' ? model.kind.currentValue : null).toBe('gpt-live')
})
it('shows Pi live choices immediately and keeps them after a late, narrower host list', () => {
const seed = structuredAgentSessionSeedCatalog('pi')!
const models = [
{ id: 'A', label: 'A', isDefault: true, efforts: [] },
{ id: 'B', label: 'B', isDefault: false, efforts: [] }
]
const launch = { ...LAUNCH, coherentCatalog: true }
const live = applyStructuredAgentSessionOptions(
createStructuredAgentSessionOptionState('pi', seed),
seed,
{ models, current: { model: 'A', defaulted: [] } },
launch
)
const choices = (state: typeof live) => structuredAgentSessionOptionSnapshot(state)[0]?.kind
expect(choices(live)).toMatchObject({ choices: [{ value: 'A' }, { value: 'B' }] })
const settled = applyStructuredAgentSessionModelCatalog(
live,
seed,
{ origin: 'probe', models: [models[0]!], fetchedAt: 1 },
launch
)
expect(choices(settled)).toEqual(choices(live))
expect(canSetStructuredAgentSessionOption(settled, 'model', 'B')).toBe(true)
})
it.each([
['codex', false],
['pi', true]
@@ -4,7 +4,6 @@ import type { AgentSessionQueuedMessage } from './agent-session-wire'
import {
newestSteerableQueuedMessageCard,
projectQueuedMessageCards,
queuedMessageCardSteers,
queuedMessagesQueuePause
} from './structured-agent-session-queued-cards'
@@ -51,16 +50,6 @@ function handOff(
const IDLE = {}
describe('queued message cards', () => {
it('orders by host position whatever order the list arrives in', () => {
const cards = projectQueuedMessageCards([draft('b', 2), draft('a', 1), draft('c', 3)], [], IDLE)
expect(cards.map((card) => card.messageId)).toEqual(['a', 'b', 'c'])
expect(cards[0]?.text).toBe('text of a')
})
it('holds: a waiting card waits its turn', () => {
expect(projectQueuedMessageCards([draft('a', 1)], [], IDLE)[0]?.hold).toBe('turn')
})
it('a returned card carries its stored reason and blocks the label of drafts behind it', () => {
const cards = projectQueuedMessageCards(
[
@@ -83,15 +72,6 @@ describe('queued message cards', () => {
expect(cards[1]?.hold).toBe('behind-returned')
})
it('a paused draft says so, carrying the host marker for the caption to localize', () => {
const cards = projectQueuedMessageCards(
[draft('a', 1, { paused: true, pausedReason: 'send_failed' })],
[],
IDLE
)
expect(cards[0]).toMatchObject({ hold: 'paused', pausedReason: 'send_failed' })
})
it('shows a draft a Stop put back: its rejected hand-off is what sent it back', () => {
// The Stop pause belongs to the queue, so the draft itself carries no hold.
const requeued = draft('requeued', 1)
@@ -147,15 +127,6 @@ describe('queued message cards', () => {
])
})
it('a paused queue holds every waiting card, in order', () => {
const cards = projectQueuedMessageCards([draft('held', 1), draft('typed-after', 2)], [], {
queuePaused: true
})
expect(cards.map((card) => card.hold)).toEqual(['queue-paused', 'queue-paused'])
// Still Steer: the header row, not the card, says it waits.
expect(cards.map((card) => queuedMessageCardSteers(card))).toEqual([true, true])
})
it("the header names the queue's pause while it holds a card, and none over cards Resume would not send", () => {
const stopped = { reason: 'stopped' } as const
const project = (messages: AgentSessionQueuedMessage[], queuePaused = true) =>
@@ -187,12 +158,6 @@ describe('queued message cards', () => {
expect(cards.map((card) => card.hold)).toEqual(['paused', 'turn', 'paused', 'turn'])
})
it('steers the newest card', () => {
const cards = projectQueuedMessageCards([draft('a', 1), draft('b', 2)], [], IDLE)
expect(newestSteerableQueuedMessageCard(cards)?.messageId).toBe('b')
expect(newestSteerableQueuedMessageCard([])).toBeNull()
})
it('marks a command card, which the chord never steers', () => {
const compact: AgentSessionQueuedMessage = {
...draft('c', 2),
@@ -218,25 +183,3 @@ describe('queued message cards', () => {
expect(cards[1]).not.toHaveProperty('waitsForAgent')
})
})
describe("another agent's card", () => {
it('carries who it is from, read through the shared reader', () => {
const from = {
kind: 'agent' as const,
senders: [
{
party: { address: 'term_a', terminalHandle: 'term_a', orcaSessionId: null },
name: 'Coder'
}
],
orchestration: null
}
const agentDraft = draft('a', 1)
const cards = projectQueuedMessageCards(
[{ ...agentDraft, body: { ...agentDraft.body, from } }, draft('b', 2)],
[],
IDLE
)
expect(cards.map((card) => card.from)).toEqual([from, undefined])
})
})
-146
View File
@@ -5,47 +5,6 @@ import {
} from './terminal-composer-draft'
describe('detectTerminalComposerDraft', () => {
it('separates a cursor-right suggestion from the composer line', () => {
expect(
detectTerminalComposerDraft({
rows: ['────────', '❯ proceed with the release'],
typedRows: ['────────', '❯'],
promptGlyphBoldRows: [false, false],
rowsBelow: [],
typedRowsBelow: [],
beforeCursor: '❯ ',
afterCursor: '',
rawAfterCursor: 'proceed with the release',
cursorHidden: false,
cursorViewportRow: 8
})
).toEqual({
text: 'proceed with the release',
promptRow: 8,
cursorRow: 8,
endRow: 8,
promptGlyph: '❯'
})
})
it('keeps stock dim placeholders out of draft metadata', () => {
const context = {
rows: ['› Ask Codex to do anything'],
typedRows: ['›'],
promptGlyphBoldRows: [true],
rowsBelow: ['', 'gpt-5.6 · ~/repo'],
typedRowsBelow: ['', 'gpt-5.6 · ~/repo'],
beforeCursor: '› ',
afterCursor: '',
rawAfterCursor: 'Ask Codex to do anything',
cursorHidden: false,
cursorViewportRow: 4
}
expect(detectTerminalComposerDraft(context)).toBeNull()
expect(hasTerminalComposerPlaceholder(context)).toBe(true)
})
it('keeps a typed draft whose stock placeholder is still rendered to its right', () => {
// Repaints can leave the placeholder beside typed text; do not mask that user draft.
const context = {
@@ -71,23 +30,6 @@ describe('detectTerminalComposerDraft', () => {
expect(hasTerminalComposerPlaceholder(context)).toBe(false)
})
it('does not duplicate real typed text left of the cursor', () => {
expect(
detectTerminalComposerDraft({
rows: ['────────', '❯ review the change'],
typedRows: ['────────', '❯ review the change'],
promptGlyphBoldRows: [false, false],
rowsBelow: [],
typedRowsBelow: [],
beforeCursor: '❯ review the change',
afterCursor: '',
rawAfterCursor: '',
cursorHidden: false,
cursorViewportRow: 2
})?.text
).toBe('review the change')
})
it('preserves a shell prompt that happens to use the Claude glyph', () => {
expect(
detectTerminalComposerDraft({
@@ -145,58 +87,6 @@ describe('detectTerminalComposerDraft', () => {
})
})
it('recognizes the bold Codex ultra composer glyph', () => {
expect(
detectTerminalComposerDraft({
rows: ['» review the change'],
typedRows: ['» review the change'],
promptGlyphBoldRows: [true],
rowsBelow: ['gpt-5.6 · ~/repo'],
typedRowsBelow: ['gpt-5.6 · ~/repo'],
beforeCursor: '» review the change',
afterCursor: '',
rawAfterCursor: '',
cursorHidden: false,
cursorViewportRow: 4
})
).toMatchObject({ text: 'review the change', promptGlyph: '»' })
})
it('recognizes the bold Codex composer when its footer is visible', () => {
expect(
detectTerminalComposerDraft({
rows: ['› review the change'],
typedRows: ['› review the change'],
promptGlyphBoldRows: [true],
rowsBelow: ['gpt-5.6 · ~/repo'],
typedRowsBelow: ['gpt-5.6 · ~/repo'],
beforeCursor: '› review the change',
afterCursor: '',
rawAfterCursor: '',
cursorHidden: false,
cursorViewportRow: 4
})
).toMatchObject({ text: 'review the change', promptGlyph: '›' })
})
it('recognizes a Codex composer with a context-only status footer', () => {
expect(
detectTerminalComposerDraft({
rows: ['› review the change'],
typedRows: ['› review the change'],
promptGlyphBoldRows: [true],
rowsBelow: ['', ' Context 12% used'],
typedRowsBelow: ['', ''],
rowsBelowWrapped: [false, false],
beforeCursor: '› review the change',
afterCursor: '',
rawAfterCursor: '',
cursorHidden: false,
cursorViewportRow: 4
})
).toMatchObject({ text: 'review the change', promptGlyph: '›' })
})
it('recognizes a Codex composer with an arbitrary dimmed thread-title footer', () => {
expect(
detectTerminalComposerDraft({
@@ -233,23 +123,6 @@ describe('detectTerminalComposerDraft', () => {
expect(hasTerminalComposerPlaceholder(context)).toBe(false)
})
it('keeps the side-thread placeholder out of draft metadata', () => {
expect(
detectTerminalComposerDraft({
rows: ['› Ask a follow-up question'],
typedRows: ['›'],
promptGlyphBoldRows: [true],
rowsBelow: [],
typedRowsBelow: [],
beforeCursor: '› ',
afterCursor: '',
rawAfterCursor: 'Ask a follow-up question',
cursorHidden: false,
cursorViewportRow: 4
})
).toBeNull()
})
it('keeps a wrapped stock placeholder out of draft metadata', () => {
expect(
detectTerminalComposerDraft({
@@ -267,25 +140,6 @@ describe('detectTerminalComposerDraft', () => {
).toBeNull()
})
it('joins soft-wrapped continuation rows without inserting a newline', () => {
expect(
detectTerminalComposerDraft({
rows: ['────────', '❯ proceed with the'],
typedRows: ['────────', '❯'],
promptGlyphBoldRows: [false, false],
rowsWrapped: [false, false],
rowsBelow: ['release'],
typedRowsBelow: [''],
rowsBelowWrapped: [true],
beforeCursor: '❯ ',
afterCursor: '',
rawAfterCursor: 'proceed with the ',
cursorHidden: false,
cursorViewportRow: 8
})?.text
).toBe('proceed with the release')
})
it('keeps a draft continuation containing a middle dot', () => {
expect(
detectTerminalComposerDraft({
@@ -4,13 +4,6 @@ import { TerminalKittyKeyboardModeTracker } from './terminal-kitty-keyboard-mode
import { CONFIRMED_SHELL_MODE_RESET } from './terminal-mode-reset-profiles'
describe('TerminalKittyKeyboardModeTracker', () => {
it('starts inactive and ignores non-kitty sequences', () => {
const tracker = new TerminalKittyKeyboardModeTracker()
expect(tracker.flags).toBe(0)
tracker.scan('plain output \x1b[?2004h\x1b[38;5;10mcolored\x1b[0m')
expect(tracker.flags).toBe(0)
})
// Missing snapshot data must not reset already observed mode flags.
it('treats a nullish chunk as a no-op', () => {
const tracker = new TerminalKittyKeyboardModeTracker()
@@ -23,12 +16,6 @@ describe('TerminalKittyKeyboardModeTracker', () => {
expect(tracker.snapshotFlags).toBe(5)
})
it('does not treat CSI u (restore cursor) or the CSI ? u query as kitty state', () => {
const tracker = new TerminalKittyKeyboardModeTracker()
tracker.scan('\x1b[u\x1b[?u')
expect(tracker.flags).toBe(0)
})
it('tracks push and pop like xterm, including the pop-to-empty zeroing', () => {
const tracker = new TerminalKittyKeyboardModeTracker()
tracker.scan('\x1b[>1u')
@@ -57,17 +44,6 @@ describe('TerminalKittyKeyboardModeTracker', () => {
expect(tracker.flags).toBe(4)
})
it("clears state for Orca's defensive reset sequence and RIS", () => {
const tracker = new TerminalKittyKeyboardModeTracker()
tracker.scan('\x1b[>1u')
tracker.scan('\x1b[<99u\x1b[=0u')
expect(tracker.flags).toBe(0)
tracker.scan('\x1b[>1u')
tracker.scan('\x1bc')
expect(tracker.flags).toBe(0)
})
// Why: a confirmed-shell reset lands between live chunks in both records, so they must agree.
it('agrees with xterm when the confirmed-shell reset interrupts a split live sequence', async () => {
const term = new Terminal({ allowProposedApi: true, vtExtensions: { kittyKeyboard: true } })
@@ -95,21 +71,6 @@ describe('TerminalKittyKeyboardModeTracker', () => {
term.dispose()
})
it('keeps per-screen flags across alternate-screen switches', () => {
const tracker = new TerminalKittyKeyboardModeTracker()
tracker.scan('\x1b[>1u')
expect(tracker.flags).toBe(1)
tracker.scan('\x1b[?1049h')
expect(tracker.hasObservedAlternateScreenSwitch).toBe(true)
expect(tracker.isAlternateScreen).toBe(true)
expect(tracker.flags).toBe(0)
tracker.scan('\x1b[>2u')
expect(tracker.flags).toBe(2)
tracker.scan('\x1b[?1049l')
expect(tracker.isAlternateScreen).toBe(false)
expect(tracker.flags).toBe(1)
})
it('handles sequences split across chunks and C1 CSI', () => {
const tracker = new TerminalKittyKeyboardModeTracker()
tracker.scan('\x1b[>')
@@ -122,22 +83,6 @@ describe('TerminalKittyKeyboardModeTracker', () => {
expect(tracker.flags).toBe(7)
})
it('leaves negotiated state unchanged for plain output chunks', () => {
const tracker = new TerminalKittyKeyboardModeTracker()
tracker.scan('\x1b[>1u')
tracker.scan('shell output '.repeat(100))
expect(tracker.flags).toBe(1)
expect(tracker.snapshotFlags).toBe(1)
})
it('caps the mirrored stack without losing the current flags', () => {
const tracker = new TerminalKittyKeyboardModeTracker()
for (let i = 0; i < 40; i++) {
tracker.scan(`\x1b[>${(i % 3) + 1}u`)
}
expect(tracker.flags).toBe((39 % 3) + 1)
})
it('reset() returns to the inactive state', () => {
const tracker = new TerminalKittyKeyboardModeTracker()
tracker.scan('\x1b[>1u\x1b[?1049h\x1b[>2u')
@@ -206,19 +151,6 @@ describe('TerminalKittyKeyboardModeTracker', () => {
expect(fresh.snapshotFlags).toBeUndefined()
})
it('restores known 0 and known 8 onto the active screen', () => {
const inactive = new TerminalKittyKeyboardModeTracker()
inactive.resetForSnapshot()
inactive.restoreSnapshotFlags(0)
expect(inactive.snapshotFlags).toBe(0)
const negotiated = new TerminalKittyKeyboardModeTracker()
negotiated.resetForSnapshot()
negotiated.restoreSnapshotFlags(8)
expect(negotiated.flags).toBe(8)
expect(negotiated.snapshotFlags).toBe(8)
})
it('ignores values that are not non-negative safe integers', () => {
const tracker = new TerminalKittyKeyboardModeTracker()
tracker.resetForSnapshot()
@@ -322,16 +254,6 @@ describe('TerminalKittyKeyboardModeTracker', () => {
tracker.restoreSnapshotFlags(8)
expect(tracker.hasProvenBaseline).toBe(true)
})
it('grounds on RIS and DECSTR arriving in the stream', () => {
const ris = new TerminalKittyKeyboardModeTracker()
ris.scan('\x1bc')
expect(ris.hasProvenBaseline).toBe(true)
const softReset = new TerminalKittyKeyboardModeTracker()
softReset.scan('\x1b[!p')
expect(softReset.hasProvenBaseline).toBe(true)
})
})
// Why: xterm ignores CSI u while the protocol is withheld, so the mirror must stay at 0 too.