feat(web): project plan mode through host API

This commit is contained in:
fz
2026-07-24 12:09:04 +08:00
parent bc7a89b81f
commit bc63b5fe00
34 changed files with 515 additions and 16 deletions

View File

@@ -31,6 +31,8 @@ function scriptedApi(overrides: {
history: r => ok(r, { events: [], hasMore: false }),
prompt: r => ok(r, { accepted: true as const }),
cancel: r => ok(r, { accepted: true as const }),
planMode: r => ok(r, null),
setPlanMode: r => ok(r, null),
...overrides.sessions,
},
host: { describe: r => ok(r, { version: '0-test', cwd: '/t', attachedSessions: 0 }), ...overrides.host },

View File

@@ -36,6 +36,12 @@ function fakeApi(overrides: Partial<{ muxFrames: MuxFrame[]; hostFrames: HostFra
async cancel(request) {
return { rpcId: request.rpcId, result: { ok: true, value: { accepted: true as const } } }
},
async planMode(request) {
return { rpcId: request.rpcId, result: { ok: true, value: null } }
},
async setPlanMode(request) {
return { rpcId: request.rpcId, result: { ok: true, value: null } }
},
},
host: {
async describe(request) {
@@ -75,11 +81,13 @@ describe('unary round trip (handler ⇄ client, no network)', () => {
if (!response.result.ok) expect(response.result.error.code).toBe('session-not-found')
})
it('covers create/prompt/cancel/describe passthrough', async () => {
it('covers create/prompt/cancel/plan/describe passthrough', async () => {
const c = client()
expect((await c.sessions.create({})).result.ok).toBe(true)
expect((await c.sessions.prompt({ sessionId: 's' as never, mode: 'queue', content: [{ type: 'text', text: 'x' }] })).result.ok).toBe(true)
expect((await c.sessions.cancel({ sessionId: 's' as never })).result.ok).toBe(true)
expect((await c.sessions.planMode({ sessionId: 's' as never })).result).toEqual({ ok: true, value: null })
expect((await c.sessions.setPlanMode({ sessionId: 's' as never, active: true })).result).toEqual({ ok: true, value: null })
expect((await c.host.describe({})).result.ok).toBe(true)
})
})

View File

@@ -9,7 +9,8 @@ import {
contentBlockSchema, sessionCancelRequestSchema, sessionCancelValueSchema, sessionCreateRequestSchema,
sessionCreateValueSchema, sessionEventSchema, sessionHistoryRequestSchema, sessionHistoryValueSchema,
sessionIdSchema, sessionListRequestSchema, sessionListValueSchema, sessionPromptRequestSchema,
sessionPromptValueSchema, sessionSummarySchema,
sessionPlanModeRequestSchema, sessionPlanModeValueSchema, sessionPromptValueSchema,
sessionSetPlanModeRequestSchema, sessionSetPlanModeValueSchema, sessionSummarySchema,
} from '../src/api/sessions.schema.ts'
import { hostDescribeRequestSchema, hostDescribeValueSchema } from '../src/api/host.schema.ts'
import { hostFrameSchema, muxFrameSchema, askUserQuestionItemSchema } from '../src/api/events.schema.ts'
@@ -106,6 +107,13 @@ describe('sessions domain schemas', () => {
expect(sessionPromptValueSchema.parse({ accepted: true }).accepted).toBe(true)
expect(sessionCancelRequestSchema.parse({ sessionId: 's1' }).sessionId).toBe('s1')
expect(sessionCancelValueSchema.parse({ accepted: true }).accepted).toBe(true)
expect(sessionPlanModeRequestSchema.parse({ sessionId: 's1' }).sessionId).toBe('s1')
expect(sessionPlanModeValueSchema.parse({ active: false, pending: true })).toEqual({ active: false, pending: true })
expect(sessionPlanModeValueSchema.parse(null)).toBeNull()
expect(sessionSetPlanModeRequestSchema.parse({ sessionId: 's1', active: true }).active).toBe(true)
expect(sessionSetPlanModeValueSchema.parse({ active: true })).toEqual({ active: true })
expect(() => sessionSetPlanModeRequestSchema.parse({ sessionId: 's1', active: 'yes' })).toThrow()
expect(() => sessionPlanModeValueSchema.parse({ active: 'yes' })).toThrow()
expect(contentBlockSchema.parse({ type: 'text', text: 'x', extra: 1 })).toMatchObject({ extra: 1 })
})
})