fix demo readline terminal editing

This commit is contained in:
Yichen Jiang
2026-06-19 09:58:39 +08:00
parent c5049d1c3f
commit 5189c99543
6 changed files with 79 additions and 3 deletions
+2
View File
@@ -12,3 +12,5 @@ coverage/
.doc-typecheck-*/
.vscode/
.DS_Store
.idea
mise.toml
+5 -1
View File
@@ -53,7 +53,11 @@ export function apply(ctx: Context) {
})
ctx.effect(() => {
const reader = createInterface({ input: process.stdin })
const reader = createInterface({
input: process.stdin,
output: process.stdout,
terminal: process.stdin.isTTY && process.stdout.isTTY,
})
// Piped-input exit, once stdin reaches EOF:
// - If no line ever submitted work (empty stdin, blank-only lines), exit
// immediately — no turn will ever start, so there is nothing to wait
@@ -0,0 +1,33 @@
import { EventEmitter } from 'node:events'
import type { Context } from 'cordis'
import { describe, expect, test, vi } from 'vitest'
const createInterface = vi.hoisted(() => vi.fn(() => {
const reader = new EventEmitter() as EventEmitter & { close(): void }
reader.close = vi.fn()
return reader
}))
vi.mock('node:readline', () => ({ createInterface }))
function fakeContext(): Context {
return {
agents: { get: vi.fn() },
on: vi.fn(() => vi.fn()),
effect: vi.fn((callback: () => () => void) => callback()),
} as unknown as Context
}
describe('coding-agent stdio chat', () => {
test('creates a terminal readline interface so TTY editing keys work', async () => {
const { apply } = await import('../src/stdio-chat.ts')
apply(fakeContext())
expect(createInterface).toHaveBeenCalledWith({
input: process.stdin,
output: process.stdout,
terminal: process.stdin.isTTY && process.stdout.isTTY,
})
})
})
+5 -1
View File
@@ -35,7 +35,11 @@ export function apply(ctx: Context) {
})
ctx.effect(() => {
const reader = createInterface({ input: process.stdin })
const reader = createInterface({
input: process.stdin,
output: process.stdout,
terminal: process.stdin.isTTY && process.stdout.isTTY,
})
reader.on('line', (line) => {
const text = line.trim()
if (!text) return
@@ -0,0 +1,33 @@
import { EventEmitter } from 'node:events'
import type { Context } from 'cordis'
import { describe, expect, test, vi } from 'vitest'
const createInterface = vi.hoisted(() => vi.fn(() => {
const reader = new EventEmitter() as EventEmitter & { close(): void }
reader.close = vi.fn()
return reader
}))
vi.mock('node:readline', () => ({ createInterface }))
function fakeContext(): Context {
return {
agents: { get: vi.fn() },
on: vi.fn(() => vi.fn()),
effect: vi.fn((callback: () => () => void) => callback()),
} as unknown as Context
}
describe('echo-agent stdio chat', () => {
test('creates a terminal readline interface so TTY editing keys work', async () => {
const { apply } = await import('../src/stdio-chat.ts')
apply(fakeContext())
expect(createInterface).toHaveBeenCalledWith({
input: process.stdin,
output: process.stdout,
terminal: process.stdin.isTTY && process.stdout.isTTY,
})
})
})
+1 -1
View File
@@ -19,7 +19,7 @@ export default defineConfig({
// instead applies the one root map to every importer.
plugins: [tsconfigPaths({ projects: ['./tsconfig.test.json'] })],
test: {
include: ['packages/*/tests/**/*.spec.ts'],
include: ['packages/*/tests/**/*.spec.ts', 'examples/*/tests/**/*.spec.ts'],
coverage: {
provider: 'v8',
// Coverage measures OUR runtime source. Types-only files carry no