mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-22 08:15:53 +00:00
style: 完成所有文件的lint
This commit is contained in:
@@ -1,256 +1,276 @@
|
||||
import { describe, test, expect } from "bun:test";
|
||||
import { toClientPayload } from "../transport/client-payload";
|
||||
import type { SessionEvent } from "../transport/event-bus";
|
||||
import { describe, test, expect } from 'bun:test'
|
||||
import { toClientPayload } from '../transport/client-payload'
|
||||
import type { SessionEvent } from '../transport/event-bus'
|
||||
|
||||
function makeEvent(overrides: Partial<SessionEvent> & Pick<SessionEvent, "type" | "sessionId">): SessionEvent {
|
||||
function makeEvent(
|
||||
overrides: Partial<SessionEvent> & Pick<SessionEvent, 'type' | 'sessionId'>,
|
||||
): SessionEvent {
|
||||
return {
|
||||
id: "evt-1",
|
||||
id: 'evt-1',
|
||||
payload: null,
|
||||
direction: "inbound",
|
||||
direction: 'inbound',
|
||||
seqNum: 1,
|
||||
createdAt: Date.now(),
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// user / user_message
|
||||
// =============================================================================
|
||||
|
||||
describe("toClientPayload — user message", () => {
|
||||
test("maps user type with content", () => {
|
||||
describe('toClientPayload — user message', () => {
|
||||
test('maps user type with content', () => {
|
||||
const event = makeEvent({
|
||||
type: "user",
|
||||
sessionId: "sess-1",
|
||||
payload: { content: "hello" },
|
||||
});
|
||||
const result = toClientPayload(event);
|
||||
expect(result.type).toBe("user");
|
||||
expect(result.session_id).toBe("sess-1");
|
||||
expect((result as any).message.role).toBe("user");
|
||||
expect((result as any).message.content).toBe("hello");
|
||||
});
|
||||
type: 'user',
|
||||
sessionId: 'sess-1',
|
||||
payload: { content: 'hello' },
|
||||
})
|
||||
const result = toClientPayload(event)
|
||||
expect(result.type).toBe('user')
|
||||
expect(result.session_id).toBe('sess-1')
|
||||
expect((result as any).message.role).toBe('user')
|
||||
expect((result as any).message.content).toBe('hello')
|
||||
})
|
||||
|
||||
test("maps user_message type same as user", () => {
|
||||
test('maps user_message type same as user', () => {
|
||||
const event = makeEvent({
|
||||
type: "user_message",
|
||||
sessionId: "sess-2",
|
||||
payload: { content: "world" },
|
||||
});
|
||||
const result = toClientPayload(event);
|
||||
expect(result.type).toBe("user");
|
||||
expect(result.session_id).toBe("sess-2");
|
||||
});
|
||||
type: 'user_message',
|
||||
sessionId: 'sess-2',
|
||||
payload: { content: 'world' },
|
||||
})
|
||||
const result = toClientPayload(event)
|
||||
expect(result.type).toBe('user')
|
||||
expect(result.session_id).toBe('sess-2')
|
||||
})
|
||||
|
||||
test("falls back to message field when content is missing", () => {
|
||||
test('falls back to message field when content is missing', () => {
|
||||
const event = makeEvent({
|
||||
type: "user",
|
||||
sessionId: "sess-3",
|
||||
payload: { message: "fallback msg" },
|
||||
});
|
||||
const result = toClientPayload(event);
|
||||
expect((result as any).message.content).toBe("fallback msg");
|
||||
});
|
||||
type: 'user',
|
||||
sessionId: 'sess-3',
|
||||
payload: { message: 'fallback msg' },
|
||||
})
|
||||
const result = toClientPayload(event)
|
||||
expect((result as any).message.content).toBe('fallback msg')
|
||||
})
|
||||
|
||||
test("falls back to empty string when both content and message missing", () => {
|
||||
test('falls back to empty string when both content and message missing', () => {
|
||||
const event = makeEvent({
|
||||
type: "user",
|
||||
sessionId: "sess-4",
|
||||
type: 'user',
|
||||
sessionId: 'sess-4',
|
||||
payload: {},
|
||||
});
|
||||
const result = toClientPayload(event);
|
||||
expect((result as any).message.content).toBe("");
|
||||
});
|
||||
})
|
||||
const result = toClientPayload(event)
|
||||
expect((result as any).message.content).toBe('')
|
||||
})
|
||||
|
||||
test("includes isSynthetic when true", () => {
|
||||
test('includes isSynthetic when true', () => {
|
||||
const event = makeEvent({
|
||||
type: "user",
|
||||
sessionId: "sess-5",
|
||||
payload: { content: "auto", isSynthetic: true },
|
||||
});
|
||||
const result = toClientPayload(event);
|
||||
expect((result as any).isSynthetic).toBe(true);
|
||||
});
|
||||
type: 'user',
|
||||
sessionId: 'sess-5',
|
||||
payload: { content: 'auto', isSynthetic: true },
|
||||
})
|
||||
const result = toClientPayload(event)
|
||||
expect((result as any).isSynthetic).toBe(true)
|
||||
})
|
||||
|
||||
test("does not include isSynthetic when false", () => {
|
||||
test('does not include isSynthetic when false', () => {
|
||||
const event = makeEvent({
|
||||
type: "user",
|
||||
sessionId: "sess-6",
|
||||
payload: { content: "manual", isSynthetic: false },
|
||||
});
|
||||
const result = toClientPayload(event);
|
||||
expect((result as any).isSynthetic).toBeUndefined();
|
||||
});
|
||||
type: 'user',
|
||||
sessionId: 'sess-6',
|
||||
payload: { content: 'manual', isSynthetic: false },
|
||||
})
|
||||
const result = toClientPayload(event)
|
||||
expect((result as any).isSynthetic).toBeUndefined()
|
||||
})
|
||||
|
||||
test("uses payload.uuid when present", () => {
|
||||
test('uses payload.uuid when present', () => {
|
||||
const event = makeEvent({
|
||||
type: "user",
|
||||
sessionId: "sess-7",
|
||||
payload: { content: "hi", uuid: "custom-uuid" },
|
||||
});
|
||||
const result = toClientPayload(event);
|
||||
expect(result.uuid).toBe("custom-uuid");
|
||||
});
|
||||
type: 'user',
|
||||
sessionId: 'sess-7',
|
||||
payload: { content: 'hi', uuid: 'custom-uuid' },
|
||||
})
|
||||
const result = toClientPayload(event)
|
||||
expect(result.uuid).toBe('custom-uuid')
|
||||
})
|
||||
|
||||
test("falls back to event.id when payload.uuid is missing", () => {
|
||||
test('falls back to event.id when payload.uuid is missing', () => {
|
||||
const event = makeEvent({
|
||||
type: "user",
|
||||
sessionId: "sess-8",
|
||||
payload: { content: "hi" },
|
||||
});
|
||||
const result = toClientPayload(event);
|
||||
expect(result.uuid).toBe("evt-1");
|
||||
});
|
||||
});
|
||||
type: 'user',
|
||||
sessionId: 'sess-8',
|
||||
payload: { content: 'hi' },
|
||||
})
|
||||
const result = toClientPayload(event)
|
||||
expect(result.uuid).toBe('evt-1')
|
||||
})
|
||||
})
|
||||
|
||||
// =============================================================================
|
||||
// permission_response / control_response
|
||||
// =============================================================================
|
||||
|
||||
describe("toClientPayload — permission response", () => {
|
||||
test("approved=true maps to allow behavior", () => {
|
||||
describe('toClientPayload — permission response', () => {
|
||||
test('approved=true maps to allow behavior', () => {
|
||||
const event = makeEvent({
|
||||
type: "permission_response",
|
||||
sessionId: "sess-1",
|
||||
payload: { approved: true, request_id: "req-1" },
|
||||
});
|
||||
const result = toClientPayload(event);
|
||||
expect(result.type).toBe("control_response");
|
||||
const resp = (result as any).response;
|
||||
expect(resp.subtype).toBe("success");
|
||||
expect(resp.request_id).toBe("req-1");
|
||||
expect(resp.response.behavior).toBe("allow");
|
||||
});
|
||||
type: 'permission_response',
|
||||
sessionId: 'sess-1',
|
||||
payload: { approved: true, request_id: 'req-1' },
|
||||
})
|
||||
const result = toClientPayload(event)
|
||||
expect(result.type).toBe('control_response')
|
||||
const resp = (result as any).response
|
||||
expect(resp.subtype).toBe('success')
|
||||
expect(resp.request_id).toBe('req-1')
|
||||
expect(resp.response.behavior).toBe('allow')
|
||||
})
|
||||
|
||||
test("approved=false maps to deny behavior with error", () => {
|
||||
test('approved=false maps to deny behavior with error', () => {
|
||||
const event = makeEvent({
|
||||
type: "permission_response",
|
||||
sessionId: "sess-2",
|
||||
payload: { approved: false, request_id: "req-2" },
|
||||
});
|
||||
const result = toClientPayload(event);
|
||||
expect(result.type).toBe("control_response");
|
||||
const resp = (result as any).response;
|
||||
expect(resp.subtype).toBe("error");
|
||||
expect(resp.error).toBe("Permission denied by user");
|
||||
expect(resp.response.behavior).toBe("deny");
|
||||
});
|
||||
type: 'permission_response',
|
||||
sessionId: 'sess-2',
|
||||
payload: { approved: false, request_id: 'req-2' },
|
||||
})
|
||||
const result = toClientPayload(event)
|
||||
expect(result.type).toBe('control_response')
|
||||
const resp = (result as any).response
|
||||
expect(resp.subtype).toBe('error')
|
||||
expect(resp.error).toBe('Permission denied by user')
|
||||
expect(resp.response.behavior).toBe('deny')
|
||||
})
|
||||
|
||||
test("approved=false includes feedback message when provided", () => {
|
||||
test('approved=false includes feedback message when provided', () => {
|
||||
const event = makeEvent({
|
||||
type: "permission_response",
|
||||
sessionId: "sess-3",
|
||||
payload: { approved: false, request_id: "req-3", message: "please revise" },
|
||||
});
|
||||
const result = toClientPayload(event);
|
||||
expect((result as any).response.message).toBe("please revise");
|
||||
});
|
||||
type: 'permission_response',
|
||||
sessionId: 'sess-3',
|
||||
payload: {
|
||||
approved: false,
|
||||
request_id: 'req-3',
|
||||
message: 'please revise',
|
||||
},
|
||||
})
|
||||
const result = toClientPayload(event)
|
||||
expect((result as any).response.message).toBe('please revise')
|
||||
})
|
||||
|
||||
test("passes through existingResponse directly", () => {
|
||||
const existingResponse = { subtype: "success", custom: true };
|
||||
test('passes through existingResponse directly', () => {
|
||||
const existingResponse = { subtype: 'success', custom: true }
|
||||
const event = makeEvent({
|
||||
type: "control_response",
|
||||
sessionId: "sess-4",
|
||||
type: 'control_response',
|
||||
sessionId: 'sess-4',
|
||||
payload: { approved: true, response: existingResponse },
|
||||
});
|
||||
const result = toClientPayload(event);
|
||||
expect(result.type).toBe("control_response");
|
||||
expect((result as any).response).toBe(existingResponse);
|
||||
});
|
||||
})
|
||||
const result = toClientPayload(event)
|
||||
expect(result.type).toBe('control_response')
|
||||
expect((result as any).response).toBe(existingResponse)
|
||||
})
|
||||
|
||||
test("includes updatedInput when approved with updated_input", () => {
|
||||
const updatedInput = { file_path: "/new/path" };
|
||||
test('includes updatedInput when approved with updated_input', () => {
|
||||
const updatedInput = { file_path: '/new/path' }
|
||||
const event = makeEvent({
|
||||
type: "permission_response",
|
||||
sessionId: "sess-5",
|
||||
payload: { approved: true, request_id: "req-5", updated_input: updatedInput },
|
||||
});
|
||||
const result = toClientPayload(event);
|
||||
expect((result as any).response.response.updatedInput).toEqual(updatedInput);
|
||||
});
|
||||
type: 'permission_response',
|
||||
sessionId: 'sess-5',
|
||||
payload: {
|
||||
approved: true,
|
||||
request_id: 'req-5',
|
||||
updated_input: updatedInput,
|
||||
},
|
||||
})
|
||||
const result = toClientPayload(event)
|
||||
expect((result as any).response.response.updatedInput).toEqual(updatedInput)
|
||||
})
|
||||
|
||||
test("includes updatedPermissions when approved with updated_permissions", () => {
|
||||
const perms = [{ type: "allow", tool: "bash" }];
|
||||
test('includes updatedPermissions when approved with updated_permissions', () => {
|
||||
const perms = [{ type: 'allow', tool: 'bash' }]
|
||||
const event = makeEvent({
|
||||
type: "permission_response",
|
||||
sessionId: "sess-6",
|
||||
payload: { approved: true, request_id: "req-6", updated_permissions: perms },
|
||||
});
|
||||
const result = toClientPayload(event);
|
||||
expect((result as any).response.response.updatedPermissions).toEqual(perms);
|
||||
});
|
||||
});
|
||||
type: 'permission_response',
|
||||
sessionId: 'sess-6',
|
||||
payload: {
|
||||
approved: true,
|
||||
request_id: 'req-6',
|
||||
updated_permissions: perms,
|
||||
},
|
||||
})
|
||||
const result = toClientPayload(event)
|
||||
expect((result as any).response.response.updatedPermissions).toEqual(perms)
|
||||
})
|
||||
})
|
||||
|
||||
// =============================================================================
|
||||
// interrupt
|
||||
// =============================================================================
|
||||
|
||||
describe("toClientPayload — interrupt", () => {
|
||||
test("maps interrupt to control_request with subtype interrupt", () => {
|
||||
describe('toClientPayload — interrupt', () => {
|
||||
test('maps interrupt to control_request with subtype interrupt', () => {
|
||||
const event = makeEvent({
|
||||
type: "interrupt",
|
||||
sessionId: "sess-1",
|
||||
});
|
||||
const result = toClientPayload(event);
|
||||
expect(result.type).toBe("control_request");
|
||||
expect((result as any).request_id).toBe("evt-1");
|
||||
expect((result as any).request.subtype).toBe("interrupt");
|
||||
});
|
||||
});
|
||||
type: 'interrupt',
|
||||
sessionId: 'sess-1',
|
||||
})
|
||||
const result = toClientPayload(event)
|
||||
expect(result.type).toBe('control_request')
|
||||
expect((result as any).request_id).toBe('evt-1')
|
||||
expect((result as any).request.subtype).toBe('interrupt')
|
||||
})
|
||||
})
|
||||
|
||||
// =============================================================================
|
||||
// control_request
|
||||
// =============================================================================
|
||||
|
||||
describe("toClientPayload — control_request", () => {
|
||||
test("passes through request_id and request from payload", () => {
|
||||
describe('toClientPayload — control_request', () => {
|
||||
test('passes through request_id and request from payload', () => {
|
||||
const event = makeEvent({
|
||||
type: "control_request",
|
||||
sessionId: "sess-1",
|
||||
payload: { request_id: "req-99", request: { subtype: "permission", tool: "bash" } },
|
||||
});
|
||||
const result = toClientPayload(event);
|
||||
expect(result.type).toBe("control_request");
|
||||
expect((result as any).request_id).toBe("req-99");
|
||||
expect((result as any).request.subtype).toBe("permission");
|
||||
});
|
||||
type: 'control_request',
|
||||
sessionId: 'sess-1',
|
||||
payload: {
|
||||
request_id: 'req-99',
|
||||
request: { subtype: 'permission', tool: 'bash' },
|
||||
},
|
||||
})
|
||||
const result = toClientPayload(event)
|
||||
expect(result.type).toBe('control_request')
|
||||
expect((result as any).request_id).toBe('req-99')
|
||||
expect((result as any).request.subtype).toBe('permission')
|
||||
})
|
||||
|
||||
test("falls back request to payload when no request field", () => {
|
||||
test('falls back request to payload when no request field', () => {
|
||||
const event = makeEvent({
|
||||
type: "control_request",
|
||||
sessionId: "sess-2",
|
||||
payload: { request_id: "req-10", custom: "data" },
|
||||
});
|
||||
const result = toClientPayload(event);
|
||||
expect((result as any).request).toEqual({ request_id: "req-10", custom: "data" });
|
||||
});
|
||||
type: 'control_request',
|
||||
sessionId: 'sess-2',
|
||||
payload: { request_id: 'req-10', custom: 'data' },
|
||||
})
|
||||
const result = toClientPayload(event)
|
||||
expect((result as any).request).toEqual({
|
||||
request_id: 'req-10',
|
||||
custom: 'data',
|
||||
})
|
||||
})
|
||||
|
||||
test("falls back request_id to event.id when missing", () => {
|
||||
test('falls back request_id to event.id when missing', () => {
|
||||
const event = makeEvent({
|
||||
type: "control_request",
|
||||
sessionId: "sess-3",
|
||||
payload: { request: { subtype: "test" } },
|
||||
});
|
||||
const result = toClientPayload(event);
|
||||
expect((result as any).request_id).toBe("evt-1");
|
||||
});
|
||||
});
|
||||
type: 'control_request',
|
||||
sessionId: 'sess-3',
|
||||
payload: { request: { subtype: 'test' } },
|
||||
})
|
||||
const result = toClientPayload(event)
|
||||
expect((result as any).request_id).toBe('evt-1')
|
||||
})
|
||||
})
|
||||
|
||||
// =============================================================================
|
||||
// default fallback
|
||||
// =============================================================================
|
||||
|
||||
describe("toClientPayload — default types", () => {
|
||||
test("passes through unknown type with type/uuid/session_id/message", () => {
|
||||
describe('toClientPayload — default types', () => {
|
||||
test('passes through unknown type with type/uuid/session_id/message', () => {
|
||||
const event = makeEvent({
|
||||
type: "assistant",
|
||||
sessionId: "sess-1",
|
||||
payload: { uuid: "u-1", content: "response text" },
|
||||
});
|
||||
const result = toClientPayload(event);
|
||||
expect(result.type).toBe("assistant");
|
||||
expect(result.uuid).toBe("u-1");
|
||||
expect(result.session_id).toBe("sess-1");
|
||||
expect(result.message).toEqual({ uuid: "u-1", content: "response text" });
|
||||
});
|
||||
});
|
||||
type: 'assistant',
|
||||
sessionId: 'sess-1',
|
||||
payload: { uuid: 'u-1', content: 'response text' },
|
||||
})
|
||||
const result = toClientPayload(event)
|
||||
expect(result.type).toBe('assistant')
|
||||
expect(result.uuid).toBe('u-1')
|
||||
expect(result.session_id).toBe('sess-1')
|
||||
expect(result.message).toEqual({ uuid: 'u-1', content: 'response text' })
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user