Merge origin/master (SessionFace contract) into web-permission-sandbox-merge-master

Three ui-conversation spec conflicts resolve to master's SlotTestRuntime
rewrites. Adaptation to the new outward session face: ISession gains the
command verb (the composer chip and the /permission picker submit through
it), FixtureSession grows the matching fail-loud stub plus the
waitingApproval summary default, and the picker reads the projection
through projections.faceOf (the ProjectionsFace shape) instead of the
retired store getter.
This commit is contained in:
imccyu
2026-07-29 01:41:54 +08:00
323 changed files with 8217 additions and 3509 deletions

View File

@@ -10,7 +10,7 @@
* the `/permission <preset>` command line, so both surfaces write through
* one path and the pushed projection frame is the one confirmation.
*/
import type { ClientContext, Session } from '@deepseek-ai/dsh-client-runtime/client'
import type { ClientContext, SessionFace } from '@deepseek-ai/dsh-client-runtime/client'
import type { CommandServiceContract, SelectOption } from '@deepseek-ai/dsh-client-ui-command/client'
import type { ClientSessionContext } from '@deepseek-ai/dsh-client-ui-slash/client'
import type { PermissionSelect } from '@deepseek-ai/dsh-permission/client'
@@ -19,8 +19,8 @@ import type { PermissionSelect } from '@deepseek-ai/dsh-permission/client'
export const inject = ['command', 'sessions']
/** Read one session's current permissions projection value (undefined = capability absent). */
function selectOf(session: Session | undefined): PermissionSelect | undefined {
return session?.projections.get('permissions') as PermissionSelect | undefined
function selectOf(session: SessionFace | undefined): PermissionSelect | undefined {
return session?.projections.faceOf('permissions').getSnapshot() as PermissionSelect | undefined
}
/** Flatten the projection select into popup rows; `custom` is display state, never a target. */
@@ -43,7 +43,7 @@ function optionsOf(value: PermissionSelect): SelectOption[] {
export function apply(ctx: ClientContext): void {
const command = ctx.get('command') as CommandServiceContract
const sessions = ctx.sessions
const sessionFor = (session: ClientSessionContext): Session | undefined =>
const sessionFor = (session: ClientSessionContext): SessionFace | undefined =>
sessions.binding(session.sessionId)?.session
ctx.effect(() => command.register({
name: 'permission',