177 lines
5.1 KiB
TypeScript
177 lines
5.1 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import { RuntimeRpcFailureError } from './runtime-client'
|
|
import { formatCliError, formatTerminalRead, formatWorktreeList } from './format'
|
|
import type { RuntimeWorktreeRecord } from '../shared/runtime-types'
|
|
|
|
function worktree(overrides: Partial<RuntimeWorktreeRecord> = {}): RuntimeWorktreeRecord {
|
|
const base: RuntimeWorktreeRecord = {
|
|
id: 'repo::/tmp/repo/child',
|
|
repoId: 'repo',
|
|
path: '/tmp/repo/child',
|
|
head: 'abc123',
|
|
branch: 'feature/child',
|
|
isBare: false,
|
|
isMainWorktree: false,
|
|
parentWorktreeId: null,
|
|
childWorktreeIds: [],
|
|
lineage: null,
|
|
linkedIssue: null,
|
|
linkedPR: null,
|
|
linkedLinearIssue: null,
|
|
isArchived: false,
|
|
isUnread: false,
|
|
isPinned: false,
|
|
sortOrder: 0,
|
|
lastActivityAt: 0,
|
|
git: {
|
|
path: '/tmp/repo/child',
|
|
head: 'abc123',
|
|
branch: 'feature/child',
|
|
isBare: false,
|
|
isMainWorktree: false
|
|
},
|
|
displayName: '',
|
|
comment: ''
|
|
}
|
|
return { ...base, ...overrides }
|
|
}
|
|
|
|
describe('formatCliError', () => {
|
|
it('prints runtime next steps for structured lineage errors', () => {
|
|
const error = new RuntimeRpcFailureError({
|
|
id: 'req_1',
|
|
ok: false,
|
|
error: {
|
|
code: 'LINEAGE_PARENT_NOT_FOUND',
|
|
message: 'Parent workspace was not found.',
|
|
data: {
|
|
nextSteps: [
|
|
'Run `orca worktree list` and pass a valid --parent-worktree selector.',
|
|
'Retry with --no-parent to create without lineage.',
|
|
123
|
|
]
|
|
}
|
|
},
|
|
_meta: { runtimeId: 'runtime-1' }
|
|
})
|
|
|
|
expect(formatCliError(error)).toBe(
|
|
[
|
|
'Parent workspace was not found.',
|
|
'Next step: Run `orca worktree list` and pass a valid --parent-worktree selector.',
|
|
'Next step: Retry with --no-parent to create without lineage.'
|
|
].join('\n')
|
|
)
|
|
})
|
|
})
|
|
|
|
describe('formatWorktreeList', () => {
|
|
it('includes parent and child workspace relationships in text output', () => {
|
|
const output = formatWorktreeList({
|
|
worktrees: [
|
|
worktree({
|
|
id: 'repo::/tmp/repo/parent',
|
|
path: '/tmp/repo/parent',
|
|
branch: 'feature/parent',
|
|
childWorktreeIds: ['repo::/tmp/repo/child']
|
|
}),
|
|
worktree({
|
|
parentWorktreeId: 'repo::/tmp/repo/parent'
|
|
})
|
|
],
|
|
totalCount: 2,
|
|
truncated: false
|
|
})
|
|
|
|
expect(output).toContain('parentWorktreeId: null')
|
|
expect(output).toContain('childWorktreeIds: repo::/tmp/repo/child')
|
|
expect(output).toContain('parentWorktreeId: repo::/tmp/repo/parent')
|
|
expect(output).toContain('childWorktreeIds: []')
|
|
})
|
|
})
|
|
|
|
describe('formatTerminalRead', () => {
|
|
it('warns limited cursor reads to continue with the next cursor', () => {
|
|
const output = formatTerminalRead({
|
|
terminal: {
|
|
handle: 'term_1',
|
|
status: 'running',
|
|
tail: ['line 1'],
|
|
truncated: false,
|
|
limited: true,
|
|
oldestCursor: '0',
|
|
nextCursor: '50',
|
|
latestCursor: '150',
|
|
returnedLineCount: 1
|
|
}
|
|
})
|
|
|
|
expect(output).toContain('cursor: 50')
|
|
expect(output).toContain('oldest cursor: 0')
|
|
expect(output).toContain('latest cursor: 150')
|
|
expect(output).toContain('warning: output limited; continue with --cursor 50')
|
|
})
|
|
|
|
it('warns limited tail previews to page retained output from the oldest cursor', () => {
|
|
const output = formatTerminalRead({
|
|
terminal: {
|
|
handle: 'term_1',
|
|
status: 'running',
|
|
tail: ['line 100'],
|
|
truncated: false,
|
|
limited: true,
|
|
oldestCursor: '0',
|
|
nextCursor: '150',
|
|
latestCursor: '150',
|
|
returnedLineCount: 1
|
|
}
|
|
})
|
|
|
|
expect(output).toContain('cursor: 150')
|
|
expect(output).toContain('oldest cursor: 0')
|
|
expect(output).toContain('latest cursor: 150')
|
|
expect(output).toContain(
|
|
'warning: output limited; page retained output with --cursor 0 --limit <count>'
|
|
)
|
|
})
|
|
|
|
it('uses a generic limited warning when only partial output is retained', () => {
|
|
const output = formatTerminalRead({
|
|
terminal: {
|
|
handle: 'term_1',
|
|
status: 'running',
|
|
tail: [],
|
|
truncated: false,
|
|
limited: true,
|
|
oldestCursor: '150',
|
|
nextCursor: '150',
|
|
latestCursor: '150',
|
|
returnedLineCount: 0
|
|
}
|
|
})
|
|
|
|
expect(output).toContain('cursor: 150')
|
|
expect(output).toContain('oldest cursor: 150')
|
|
expect(output).toContain('latest cursor: 150')
|
|
expect(output).toContain('warning: output limited')
|
|
expect(output).not.toContain('page retained output')
|
|
})
|
|
|
|
it('keeps older runtime read responses readable', () => {
|
|
const output = formatTerminalRead({
|
|
terminal: {
|
|
handle: 'term_1',
|
|
status: 'running',
|
|
tail: ['old server output'],
|
|
truncated: true,
|
|
nextCursor: '12'
|
|
}
|
|
})
|
|
|
|
expect(output).toContain('cursor: 12')
|
|
expect(output).toContain('warning: older output is no longer retained')
|
|
expect(output).toContain('old server output')
|
|
expect(output).not.toContain('undefined')
|
|
})
|
|
})
|