refactor(web): drop the permission RPC pair and turn-anchoring machinery
The session.permissions/setPermission unary pair, the PermissionOption wire DTO, the client Session wrappers, and the fixture/fake mirrors all leave the wire: the read side moves to the 'permissions' session projection and the write side moves to the /permission command in follow-up commits, so the web protocol gains no permission methods at all. The pendingSwitches + prompt-submit flush + hasOpenTurn move also goes. Knob events no longer need turn enclosure: the persistence scanner keeps standalone events after the last turn/end as part of the preserved prefix (remove-synthetic-log-only-turns), none of the three knob invariants demand an open turn, and the setters append bare events. An idle switch commits immediately; hasOpenTurn stays a user-approval private fold (its audit pair is the one contract that still requires enclosure). The old PermissionSelect chip and its mount-time fetch die with the RPCs (the resident composer broke the mount-once assumption); the projection-fed replacement lands with the Access seat swap.
This commit is contained in:
@@ -63,12 +63,6 @@ export class FakeApiClient implements IApiClient {
|
||||
payload => Promise.resolve(ok({ selected: { provider: payload.provider, model: payload.model } }))
|
||||
onPrompt: (payload: unknown) => Promise<RpcResponse<{ accepted: true }>> = () => Promise.resolve(ok({ accepted: true as const }))
|
||||
onCancel: (payload: unknown) => Promise<RpcResponse<{ accepted: true }>> = () => Promise.resolve(ok({ accepted: true as const }))
|
||||
onPermissions: (payload: unknown) =>
|
||||
Promise<RpcResponse<{ options: { value: string; name: string; description?: string }[]; currentValue: string }>> =
|
||||
() => Promise.resolve(ok({ options: [], currentValue: 'custom' }))
|
||||
|
||||
onSetPermission: (payload: { sessionId: SessionId; value: string }) => Promise<RpcResponse<{ currentValue: string }>> =
|
||||
payload => Promise.resolve(ok({ currentValue: payload.value }))
|
||||
onDescribe: (payload: unknown) => Promise<RpcResponse<{ version: string; cwd: string; attachedSessions: number }>> =
|
||||
() => Promise.resolve(ok({ version: '0-fake', cwd: '/f', attachedSessions: 0 }))
|
||||
onPickDirectory: (payload: unknown) => Promise<RpcResponse<{ path: string | null }>> =
|
||||
@@ -92,8 +86,6 @@ export class FakeApiClient implements IApiClient {
|
||||
this.record('session.selectModel', payload, this.onSelectModel(payload)),
|
||||
prompt: (payload: unknown) => this.record('session.prompt', payload, this.onPrompt(payload)),
|
||||
cancel: (payload: unknown) => this.record('session.cancel', payload, this.onCancel(payload)),
|
||||
permissions: (payload: unknown) => this.record('session.permissions', payload, this.onPermissions(payload)),
|
||||
setPermission: (payload: { sessionId: SessionId; value: string }) => this.record('session.setPermission', payload, this.onSetPermission(payload)),
|
||||
}
|
||||
|
||||
readonly host: IApiClient['host'] = {
|
||||
|
||||
@@ -345,23 +345,6 @@ describe('createFixtureApi', () => {
|
||||
expect(replayed.some(f => f.type === 'approval/requested')).toBe(false)
|
||||
})
|
||||
|
||||
it('permissions/setPermission mirror the host select: read, switch, validation', async () => {
|
||||
const api = createFixtureApi()
|
||||
const read = await api.sessions.permissions(req({ sessionId: sid('fx-alpha') }))
|
||||
expect(read.result).toMatchObject({ ok: true, value: { currentValue: 'workspace-write' } })
|
||||
const switched = await api.sessions.setPermission(req({ sessionId: sid('fx-alpha'), value: 'danger-full-access' }))
|
||||
expect(switched.result).toMatchObject({ ok: true, value: { currentValue: 'danger-full-access' } })
|
||||
const reread = await api.sessions.permissions(req({ sessionId: sid('fx-alpha') }))
|
||||
expect(reread.result).toMatchObject({ ok: true, value: { currentValue: 'danger-full-access' } })
|
||||
// Validation: ghost session and unknown value.
|
||||
const ghostRead = await api.sessions.permissions(req({ sessionId: sid('fx-ghost') }))
|
||||
expect(ghostRead.result.ok).toBe(false)
|
||||
const ghostSwitch = await api.sessions.setPermission(req({ sessionId: sid('fx-ghost'), value: 'workspace-write' }))
|
||||
expect(ghostSwitch.result.ok).toBe(false)
|
||||
const unknown = await api.sessions.setPermission(req({ sessionId: sid('fx-alpha'), value: 'nope' }))
|
||||
expect(unknown.result.ok).toBe(false)
|
||||
})
|
||||
|
||||
it('describe answers the fixture identity', async () => {
|
||||
const api = createFixtureApi()
|
||||
const response = await api.host.describe(req({}))
|
||||
@@ -739,8 +722,6 @@ describe('FixtureApiClient (protocol-level fake carrier)', () => {
|
||||
expect((await client.sessions.history({ sessionId: id })).result.ok).toBe(true)
|
||||
expect((await client.sessions.prompt({ sessionId: id, mode: 'queue', content: [{ type: 'text', text: '嗨' }] })).result.ok).toBe(true)
|
||||
expect((await client.sessions.cancel({ sessionId: id })).result.ok).toBe(true)
|
||||
expect((await client.sessions.permissions({ sessionId: id })).result.ok).toBe(true)
|
||||
expect((await client.sessions.setPermission({ sessionId: id, value: 'danger-full-access' })).result.ok).toBe(true)
|
||||
expect((await client.host.describe({})).result.ok).toBe(true)
|
||||
expect((await client.workspace.list({})).result.ok).toBe(true)
|
||||
const workspace = await client.workspace.create({ name: 'via-client' })
|
||||
|
||||
Reference in New Issue
Block a user