import { describe, expect, test } from 'bun:test';
import {
parseTaskIdFromTaskOutput,
parseTaskLaunchOutput,
parseTaskResultFromOutput,
parseTaskStatusOutput,
} from './task';
describe('parseTaskIdFromTaskOutput', () => {
test('parses task_id line from successful task tool output', () => {
const output = [
'task_id: session-abc-123 (for resuming to continue this task if needed)',
'',
'',
'done',
'',
].join('\n');
expect(parseTaskIdFromTaskOutput(output)).toBe('session-abc-123');
});
test('parses task id from XML task output', () => {
const output = [
'',
'',
'done',
'',
'',
].join('\n');
expect(parseTaskIdFromTaskOutput(output)).toBe('ses_123');
});
test('returns undefined when task_id is absent', () => {
const output = ['', 'no task id here', ''].join(
'\n',
);
expect(parseTaskIdFromTaskOutput(output)).toBeUndefined();
});
});
describe('parseTaskLaunchOutput', () => {
test('parses background task launch output only when state is running', () => {
const output = [
'task_id: ses_123',
'state: running',
'',
'',
'Background task started.',
'',
].join('\n');
expect(parseTaskLaunchOutput(output)).toEqual({
taskID: 'ses_123',
state: 'running',
result: 'Background task started.',
});
});
test('parses XML background task launch output', () => {
const output = [
'',
'',
'Background task started.',
'',
'',
].join('\n');
expect(parseTaskLaunchOutput(output)).toEqual({
taskID: 'ses_123',
state: 'running',
result: 'Background task started.',
});
});
test('ignores blocking task output without running state', () => {
const output = [
'task_id: ses_123 (for resuming to continue this task if needed)',
'',
'',
'completed result',
'',
].join('\n');
expect(parseTaskLaunchOutput(output)).toBeUndefined();
});
test('ignores state lines inside task result body', () => {
const output = [
'task_id: ses_123 (for resuming to continue this task if needed)',
'',
'',
'state: running',
'',
].join('\n');
expect(parseTaskLaunchOutput(output)).toBeUndefined();
});
});
describe('parseTaskStatusOutput', () => {
test('parses completed status output with task result', () => {
const output = [
'task_id: ses_123',
'state: completed',
'',
'',
'done',
'',
].join('\n');
expect(parseTaskStatusOutput(output)).toEqual({
taskID: 'ses_123',
state: 'completed',
timedOut: false,
result: 'done',
});
});
test('parses XML completed status output with task result', () => {
const output = [
'',
'',
'done',
'',
'',
].join('\n');
expect(parseTaskStatusOutput(output)).toEqual({
taskID: 'ses_123',
state: 'completed',
timedOut: false,
result: 'done',
});
});
test('parses error status output with task_error', () => {
const output = [
'task_id: ses_123',
'state: error',
'',
'',
'failed hard',
'',
].join('\n');
expect(parseTaskStatusOutput(output)).toEqual({
taskID: 'ses_123',
state: 'error',
timedOut: false,
result: 'failed hard',
});
});
test('parses cancelled status output with task_error', () => {
const output = [
'task_id: ses_123',
'state: cancelled',
'',
'',
'cancelled by user',
'',
].join('\n');
expect(parseTaskStatusOutput(output)).toEqual({
taskID: 'ses_123',
state: 'cancelled',
timedOut: false,
result: 'cancelled by user',
});
});
test('keeps timeout as running with timedOut overlay', () => {
const output = [
'task_id: ses_123',
'state: running',
'',
'',
'Timed out after 120000ms while waiting for task completion.',
'',
].join('\n');
expect(parseTaskStatusOutput(output)).toEqual({
taskID: 'ses_123',
state: 'running',
timedOut: true,
result: 'Timed out after 120000ms while waiting for task completion.',
});
});
test('returns undefined when state is absent', () => {
expect(parseTaskStatusOutput('task_id: ses_123')).toBeUndefined();
});
});
describe('parseTaskResultFromOutput', () => {
test('extracts trimmed task result block', () => {
expect(
parseTaskResultFromOutput(
['', ' hello ', ''].join('\n'),
),
).toBe('hello');
});
test('extracts task error block', () => {
expect(
parseTaskResultFromOutput(
['', ' broken ', ''].join('\n'),
),
).toBe('broken');
});
test('returns undefined for mismatched tags', () => {
// Opening with task_result but closing with task_error
expect(
parseTaskResultFromOutput(
['', 'content', ''].join('\n'),
),
).toBeUndefined();
// Opening with task_error but closing with task_result
expect(
parseTaskResultFromOutput(
['', 'content', ''].join('\n'),
),
).toBeUndefined();
});
test('requires matching open and close tags via backreference', () => {
// Valid: task_result with task_result
expect(parseTaskResultFromOutput('data')).toBe(
'data',
);
// Valid: task_error with task_error
expect(
parseTaskResultFromOutput('error data'),
).toBe('error data');
// Invalid: mismatched
expect(
parseTaskResultFromOutput('data'),
).toBeUndefined();
expect(
parseTaskResultFromOutput('data'),
).toBeUndefined();
});
});