Merge commit 'refs/codex-unblock/20260723/master' into worktree/pty-review-fixes

# Conflicts:
#	.agents/notes/implemented/feature/2026-06-30-interception-seams.md
#	docs/config-catalog.md
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/tools.md
#	docs/event-producer-consumer.md
#	examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl
#	examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/stdout.expected.jsonl
#	packages/cordis/tool-cordis/src/api-catalog.ts
#	packages/core/tools/README.md
#	packages/core/tools/src/index.ts
#	packages/core/tools/src/schema.ts
#	packages/core/tools/tests/tools.spec.ts
#	packages/pty/tool-pty/README.md
#	packages/pty/tool-pty/src/index.ts
#	packages/pty/tool-pty/src/render.ts
#	packages/tasks/tool-tasks/README.md
#	packages/tasks/tool-tasks/src/index.ts
This commit is contained in:
Tianyi Cui
2026-07-23 20:50:45 +08:00
584 changed files with 27686 additions and 9816 deletions

View File

@@ -122,7 +122,16 @@ describe('task_output', () => {
ctx.tasks.start(producer({ readOutput: () => chunks.shift() ?? '' }).spec)
// A body already ending in a newline gets no doubled separator.
expect(text(await call(ctx, 'task_output', { task_id: 'bash-1' }))).toBe('line one\n[status: running]')
const first = await call(ctx, 'task_output', { task_id: 'bash-1' })
if (first.isError) throw new Error('expected task_output success')
const firstValue = first.value as { text: string; task: Record<string, unknown> }
expect(firstValue).toMatchObject({
text: 'line one\n',
task: { id: 'bash-1', kind: 'bash', label: 'sleep 60', status: 'running' },
})
expect(firstValue.task).not.toHaveProperty('ownerSession')
expect(firstValue.task).not.toHaveProperty('reported')
expect(text(first)).toBe('line one\n[status: running]')
expect(text(await call(ctx, 'task_output', { task_id: 'bash-1' }))).toBe('(no new output)\n[status: running]')
})
@@ -175,7 +184,18 @@ describe('task_output', () => {
})
ctx.on('tools/execute', async (exec, next) => {
const taskId = (exec.arguments as { task_id?: unknown }).task_id
if (taskId === 'bash-2') return { content: [{ type: 'text', text: 'a'.repeat(1_000) }], isError: false }
if (taskId === 'bash-2') {
return {
content: [],
isError: false,
value: {
text: 'a'.repeat(1_000),
task: {
id: 'bash-2', kind: 'bash', label: 'sleep 60', status: 'running', startedAt: 0,
},
},
}
}
if (taskId === 'bash-4') throw new Error(`around failed: ${'e'.repeat(1_000)}`)
return next()
})
@@ -193,7 +213,7 @@ describe('task_output', () => {
const shortCircuited = await call(ctx, 'task_output', { task_id: 'bash-2' })
expect(shortCircuited.isError).toBe(false)
expect(Buffer.byteLength(text(shortCircuited))).toBeLessThanOrEqual(64)
expect(text(shortCircuited)).toContain('[result truncated]')
expect(text(shortCircuited)).toContain('[output truncated]')
const failures = [
await call(ctx, 'task_output', { task_id: 'bash-3' }),
@@ -249,7 +269,17 @@ describe('task_list', () => {
p.settle({ status: 'completed', detail: 'exit code: 0' })
await tick()
expect(text(await call(ctx, 'task_list', {}, alice))).toBe([
const listed = await call(ctx, 'task_list', {}, alice)
if (listed.isError) throw new Error('expected task_list success')
const listedValue = listed.value as Array<Record<string, unknown>>
expect(listedValue).toHaveLength(3)
expect(listedValue[0]).toMatchObject({ id: 'bash-1', kind: 'bash', label: 'pnpm test', status: 'running' })
expect(listedValue[2]).toMatchObject({ id: 'bash-2', kind: 'bash', label: 'build', status: 'completed', detail: 'exit code: 0' })
for (const task of listedValue) {
expect(task).not.toHaveProperty('ownerSession')
expect(task).not.toHaveProperty('reported')
}
expect(text(listed)).toBe([
'bash-1 [bash] running — pnpm test',
'subagent-1 [subagent] running — open research',
'bash-2 [bash] completed — build',
@@ -267,6 +297,14 @@ describe('task_kill', () => {
ctx.tasks.start(p.spec)
const result = await call(ctx, 'task_kill', { task_id: 'bash-1', reason: 'superseded' })
if (result.isError) throw new Error('expected task_kill success')
const killValue = result.value as { outcome: string; task: Record<string, unknown> }
expect(killValue).toMatchObject({
outcome: 'cancellation-requested',
task: { id: 'bash-1', kind: 'bash', label: 'sleep 60', status: 'stopping' },
})
expect(killValue.task).not.toHaveProperty('ownerSession')
expect(killValue.task).not.toHaveProperty('reported')
expect(text(result)).toBe('requested cancellation of task bash-1')
expect(p.cancels).toEqual(['superseded'])
})
@@ -346,8 +384,13 @@ describe('task_kill', () => {
p.settle({ status: 'completed', detail: 'exit code: 0' })
await tick()
expect(text(await call(ctx, 'task_kill', { task_id: 'bash-1' })))
.toBe('task bash-1 had already finished [status: completed, exit code: 0]')
const killed = await call(ctx, 'task_kill', { task_id: 'bash-1' })
if (killed.isError) throw new Error('expected task_kill success')
expect(killed.value).toMatchObject({
outcome: 'already-finished',
task: { id: 'bash-1', kind: 'bash', label: 'sleep 60', status: 'completed', detail: 'exit code: 0' },
})
expect(text(killed)).toBe('task bash-1 had already finished [status: completed, exit code: 0]')
// The kill described the task via a non-consuming snapshot: the delta is intact.
expect(text(await call(ctx, 'task_output', { task_id: 'bash-1' }))).toBe('unread tail\n[status: completed, exit code: 0]')
})