mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-22 16:25:51 +00:00
refactor(acp): make bridge SDK message handling type-safe (#1265)
* refactor(acp): make bridge SDK message handling type-safe - Add BridgeSDKMessage type alias to eliminate 14 type errors from void-leaked IteratorResult - Replace 18 scattered as-casts with a single uniform as BridgeSDKMessage - Add 68 lines of unit tests covering bridge message handling - Fixes docstring coverage to pass CI threshold * fix(acp): restore IteratorResult return type to nextSdkMessageOrAbort The simplified SDKMessage | undefined return type collapsed two distinct states: generator truly done vs generator yielding undefined. This broke forwardSessionUpdates which needs to distinguish the two — when the generator yields null/undefined it should continue (calling next() again), not break out of the loop. Restored the original IteratorResult<SDKMessage, void> return type so done and yielded-null are distinct again.
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
||||
toolUpdateFromToolResult,
|
||||
toolUpdateFromEditToolResponse,
|
||||
forwardSessionUpdates,
|
||||
nextSdkMessageOrAbort,
|
||||
} from '../bridge.js'
|
||||
import { promptToQueryInput } from '../promptConversion.js'
|
||||
import { markdownEscape, toDisplayPath } from '../utils.js'
|
||||
@@ -30,6 +31,10 @@ async function* makeStream(
|
||||
for (const m of msgs) yield m
|
||||
}
|
||||
|
||||
async function* makeWaitingStream(): AsyncGenerator<SDKMessage, void, unknown> {
|
||||
await new Promise<never>(() => {})
|
||||
}
|
||||
|
||||
// ── toolInfoFromToolUse ────────────────────────────────────────────
|
||||
|
||||
describe('toolInfoFromToolUse', () => {
|
||||
@@ -692,6 +697,47 @@ describe('toDisplayPath', () => {
|
||||
|
||||
// ── forwardSessionUpdates ─────────────────────────────────────────
|
||||
|
||||
describe('nextSdkMessageOrAbort', () => {
|
||||
test('returns done:true when aborted while waiting for next message', async () => {
|
||||
const ac = new AbortController()
|
||||
const pending = nextSdkMessageOrAbort(makeWaitingStream(), ac.signal)
|
||||
ac.abort()
|
||||
|
||||
const result = await Promise.race([
|
||||
pending,
|
||||
new Promise<'timeout'>(resolve => setTimeout(resolve, 100, 'timeout')),
|
||||
])
|
||||
|
||||
expect(result).toEqual({ done: true, value: undefined })
|
||||
})
|
||||
|
||||
test('returns done:true when stream is done', async () => {
|
||||
const result = await nextSdkMessageOrAbort(
|
||||
makeStream([]),
|
||||
new AbortController().signal,
|
||||
)
|
||||
|
||||
expect(result).toEqual({ done: true, value: undefined })
|
||||
})
|
||||
|
||||
test('returns a valid SDKMessage via IteratorResult', async () => {
|
||||
const msg = {
|
||||
type: 'assistant',
|
||||
message: {
|
||||
role: 'assistant',
|
||||
content: [{ type: 'text', text: 'hello' }],
|
||||
},
|
||||
} as unknown as SDKMessage
|
||||
|
||||
const result = await nextSdkMessageOrAbort(
|
||||
makeStream([msg]),
|
||||
new AbortController().signal,
|
||||
)
|
||||
|
||||
expect(result).toEqual({ done: false, value: msg })
|
||||
})
|
||||
})
|
||||
|
||||
describe('forwardSessionUpdates', () => {
|
||||
test('returns end_turn when stream is empty', async () => {
|
||||
const conn = makeConn()
|
||||
@@ -1077,6 +1123,28 @@ describe('forwardSessionUpdates', () => {
|
||||
).toBe(0)
|
||||
})
|
||||
|
||||
test('ignores unknown message types without crashing', async () => {
|
||||
const conn = makeConn()
|
||||
const debug = console.debug
|
||||
const debugMock = mock(() => {})
|
||||
console.debug = debugMock as typeof console.debug
|
||||
|
||||
try {
|
||||
const result = await forwardSessionUpdates(
|
||||
's1',
|
||||
makeStream([{ type: 'future_message' } as unknown as SDKMessage]),
|
||||
conn,
|
||||
new AbortController().signal,
|
||||
{},
|
||||
)
|
||||
|
||||
expect(result.stopReason).toBe('end_turn')
|
||||
expect(debugMock).toHaveBeenCalled()
|
||||
} finally {
|
||||
console.debug = debug
|
||||
}
|
||||
})
|
||||
|
||||
test('re-throws unexpected errors from stream', async () => {
|
||||
const conn = makeConn()
|
||||
async function* errorStream(): AsyncGenerator<
|
||||
|
||||
Reference in New Issue
Block a user