docs: regenerate catalogs and sync bilingual READMEs for the permission surfaces

gen-cordis-catalog/api, config/persistence catalogs, module graph, and doc
graphs pick up the ui-permission package, the permissions projection key,
and the /permission command; KnobState and PermissionSelect join the
type-link exemptions (owned by the permission package's own docs), and
ui-permission joins the sentence Model Experience allowlist (indirect via
the host command). The ui-conversation and dsh-permission READMEs gain
their zh halves for the approval/chip and projection/command paragraphs;
all three touched pairs re-record.
This commit is contained in:
imccyu
2026-07-28 23:55:00 +08:00
parent ff06272774
commit db0292ffdb
14 changed files with 57 additions and 21 deletions

View File

@@ -832,7 +832,7 @@ export interface PresetSpec {
Depends on: [`ApprovalPolicy`](core-data-structures/approval.md) · [`SandboxMode`](core-data-structures/sandbox.md)
Source: [`packages/ui/permission/src/index.ts:83`](../packages/ui/permission/src/index.ts)
Source: [`packages/ui/permission/src/index.ts:130`](../packages/ui/permission/src/index.ts)
## `@deepseek-ai/dsh-plan-mode`
@@ -1971,7 +1971,7 @@ export interface Config {
export type ApprovalPolicy = 'ask' | 'never'
```
Source: [`packages/ui/user-approval/src/index.ts:183`](../packages/ui/user-approval/src/index.ts)
Source: [`packages/ui/user-approval/src/index.ts:198`](../packages/ui/user-approval/src/index.ts)
## `@deepseek-ai/dsh-web`
@@ -2154,6 +2154,7 @@ These load from a `cordis.yml` entry with no `config:` block; they declare no co
- `@deepseek-ai/dsh-client-ui-layout` ([`packages/client/ui-layout/src/index.ts`](../packages/client/ui-layout/src/index.ts))
- `@deepseek-ai/dsh-client-ui-model` ([`packages/client/ui-model/src/index.ts`](../packages/client/ui-model/src/index.ts))
- `@deepseek-ai/dsh-client-ui-models` ([`packages/client/ui-models/src/index.ts`](../packages/client/ui-models/src/index.ts))
- `@deepseek-ai/dsh-client-ui-permission` ([`packages/client/ui-permission/src/index.ts`](../packages/client/ui-permission/src/index.ts))
- `@deepseek-ai/dsh-client-ui-question` — requires `tools` · `userInteraction` ([`packages/client/ui-question/src/index.ts`](../packages/client/ui-question/src/index.ts))
- `@deepseek-ai/dsh-client-ui-settings` ([`packages/client/ui-settings/src/index.ts`](../packages/client/ui-settings/src/index.ts))
- `@deepseek-ai/dsh-client-ui-settings-general` ([`packages/client/ui-settings-general/src/index.ts`](../packages/client/ui-settings-general/src/index.ts))

View File

@@ -815,6 +815,14 @@ Owns the deployment's permission presets and their write path. Requires a confin
*/
current(events: readonly SessionEvent[]): string
/**
* Build the whole select value for one folded knob state: every table
* option in declaration order, `custom` appended exactly while derived.
* @param state - the folded knob overrides.
* @returns the `permissions` projection payload.
*/
selectFor(state: KnobState): PermissionSelect
/**
* Resolve a preset's knob bundle.
* @param name - the preset name to resolve.
@@ -843,7 +851,7 @@ set(session: Session, name: string): void
Types: [Session](../core-data-structures/session.md) · [SessionEvent](../core-data-structures/core.md)
Source: [`packages/ui/permission/src/index.ts:97`](../../packages/ui/permission/src/index.ts)
Source: [`packages/ui/permission/src/index.ts:144`](../../packages/ui/permission/src/index.ts)
## `ctx.planMode` — `PlanModeService`

View File

@@ -23,7 +23,7 @@ This matrix shows which packages dispatch each harness-owned event and which pac
| `agent/status` | `emit` | [`packages/core/agent/src/types.ts:236`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emitAgentEvent`) | [`agent`](../packages/core/agent), `apiproxy`, [`goal-session`](../packages/goal/goal-session), [`tui`](../packages/ui/tui) |
| `agent/step` | `serial` | [`packages/core/agent/src/types.ts:326`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`serial`) | [`compact-basic`](../packages/compact/compact-basic), [`plan-mode`](../packages/plan/plan-mode), [`session-checkpoint-policy`](../packages/session-persistence/session-checkpoint-policy), [`time-context`](../packages/context/time-context), [`tool-skill`](../packages/skill/tool-skill), [`user-approval`](../packages/ui/user-approval), [`workspace-context`](../packages/context/workspace-context) |
| `agent/turn-stopping` | `serial` | [`packages/core/agent/src/types.ts:373`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`serial`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex) |
| `approval/request` | `waterfall` | [`packages/ui/user-approval/src/index.ts:30`](../packages/ui/user-approval/src/index.ts) | [`user-approval`](../packages/ui/user-approval) (`waterfall`) | [`acp`](../packages/acp/acp) |
| `approval/request` | `waterfall` | [`packages/ui/user-approval/src/index.ts:30`](../packages/ui/user-approval/src/index.ts) | [`user-approval`](../packages/ui/user-approval) (`waterfall`) | [`acp`](../packages/acp/acp), `apiproxy` |
| `commands/change` | `emit` | [`packages/ui/commands/src/index.ts:154`](../packages/ui/commands/src/index.ts) | [`commands`](../packages/ui/commands) (`events.dispatch`) | `apiproxy`, [`tui`](../packages/ui/tui) |
| `domain/changed` | `emit` | [`packages/storage/storage-domain/src/events.ts:46`](../packages/storage/storage-domain/src/events.ts) | [`storage-domain`](../packages/storage/storage-domain) (`emit`) | `apiproxy`, [`storage-domain`](../packages/storage/storage-domain), [`workspace`](../packages/workspace/workspace) |
| `fs/edit-intent` | `waterfall` | [`packages/fs/fs/src/index.ts:62`](../packages/fs/fs/src/index.ts) | [`tool-fs`](../packages/fs/tool-fs) (`waterfall`) | [`fs-policy`](../packages/fs/fs-policy) |
@@ -63,8 +63,8 @@ This matrix shows which packages dispatch each harness-owned event and which pac
| Event string | Dispatchers | Listeners |
| --- | --- | --- |
| `commands/changed` | `runtime` (`emit`) | - |
| `connection/reset` | `runtime` (`emit`) | - |
| `commands/changed` | `runtime` (`emit`) | `ui-command` |
| `connection/reset` | `runtime` (`emit`) | `ui-command` |
| `internal/dispatch` | - | [`commands`](../packages/ui/commands), [`compact`](../packages/compact/compact), [`fs`](../packages/fs/fs), [`goal`](../packages/goal/goal), [`goal-session`](../packages/goal/goal-session), [`hook-protocol`](../packages/hooks/hook-protocol), [`llm-retry`](../packages/llm/llm-retry), [`permission`](../packages/ui/permission), [`plan-mode`](../packages/plan/plan-mode), [`pty-local`](../packages/pty/pty-local), `runtime`, [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`time-context`](../packages/context/time-context), [`tool-todo`](../packages/todo/tool-todo), [`tools`](../packages/core/tools), [`user-approval`](../packages/ui/user-approval), [`workflow`](../packages/workflow/workflow) |
| `internal/plugin` | - | `hmr`, `modules`, `webserver` |
| `internal/status` | - | [`agent`](../packages/core/agent) |

View File

@@ -146,6 +146,7 @@ flowchart TD
pkg_client_ui_layout["client-ui-layout"]
pkg_client_ui_model["client-ui-model"]
pkg_client_ui_models["client-ui-models"]
pkg_client_ui_permission["client-ui-permission"]
pkg_client_ui_primitives["client-ui-primitives"]
pkg_client_ui_question["client-ui-question"]
pkg_client_ui_settings["client-ui-settings"]
@@ -562,10 +563,12 @@ flowchart TD
pkg_acp --> pkg_session
pkg_acp --> pkg_user_approval
pkg_permission --> pkg_bash
pkg_permission --> pkg_commands
pkg_permission --> pkg_invariants
pkg_permission --> pkg_sandbox
pkg_permission --> pkg_sandbox_policy
pkg_permission --> pkg_session
pkg_permission --> pkg_session_projection
pkg_permission --> pkg_user_approval
pkg_pty_local --> pkg_agent
pkg_pty_local --> pkg_invariants
@@ -712,6 +715,11 @@ flowchart TD
pkg_tool_ask_user --> pkg_invariants
pkg_tool_ask_user --> pkg_tools
pkg_tool_ask_user --> pkg_user_interaction
pkg_client_ui_permission --> pkg_client_runtime
pkg_client_ui_permission --> pkg_client_ui_command
pkg_client_ui_permission --> pkg_client_ui_slash
pkg_client_ui_permission --> pkg_invariants
pkg_client_ui_permission --> pkg_permission
pkg_session_reference --> pkg_agent
pkg_session_reference --> pkg_compact
pkg_session_reference --> pkg_invariants
@@ -1015,7 +1023,7 @@ flowchart TD
| [`session-query`](../packages/session-query/session-query) | `session-query` | [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence), [`session-title`](../packages/session-title/session-title) |
| [`session-title-llm`](../packages/session-title/session-title-llm) | `session-title` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-title`](../packages/session-title/session-title), [`timeout`](../packages/util/timeout) |
| [`acp`](../packages/acp/acp) | `acp` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`session`](../packages/core/session), [`user-approval`](../packages/ui/user-approval) |
| [`permission`](../packages/ui/permission) | `ui` | [`bash`](../packages/bash/bash), [`invariants`](../packages/support/invariants), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session`](../packages/core/session), [`user-approval`](../packages/ui/user-approval) |
| [`permission`](../packages/ui/permission) | `ui` | [`bash`](../packages/bash/bash), [`commands`](../packages/ui/commands), [`invariants`](../packages/support/invariants), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session`](../packages/core/session), [`session-projection`](../packages/session-projection/session-projection), [`user-approval`](../packages/ui/user-approval) |
| [`pty-local`](../packages/pty/pty-local) | `pty` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`pty`](../packages/pty/pty), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session`](../packages/core/session), [`subprocess`](../packages/subprocess/subprocess) |
| [`tasks-local`](../packages/tasks/tasks-local) | `tasks` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`tasks`](../packages/tasks/tasks), [`timeout`](../packages/util/timeout) |
| [`session-telemetry-otel`](../packages/telemetry/session-telemetry-otel) | `telemetry` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-telemetry`](../packages/telemetry/session-telemetry) |
@@ -1040,6 +1048,7 @@ flowchart TD
| [`session-title-first-message-llm`](../packages/session-title/session-title-first-message-llm) | `session-title` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-title`](../packages/session-title/session-title), [`session-title-llm`](../packages/session-title/session-title-llm) |
| [`agent-loop-testkit`](../packages/support/agent-loop-testkit) | `support` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
| [`tool-ask-user`](../packages/ui/tool-ask-user) | `ui` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`tools`](../packages/core/tools), [`user-interaction`](../packages/ui/user-interaction) |
| [`client-ui-permission`](../packages/client/ui-permission) | `client` | [`client-runtime`](../packages/client/runtime), [`client-ui-command`](../packages/client/ui-command), [`client-ui-slash`](../packages/client/ui-slash), [`invariants`](../packages/support/invariants), [`permission`](../packages/ui/permission) |
| [`session-reference`](../packages/context/session-reference) | `context` | [`agent`](../packages/core/agent), [`compact`](../packages/compact/compact), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`retention`](../packages/util/retention), [`session`](../packages/core/session), [`session-query`](../packages/session-query/session-query) |
| [`workspace-context`](../packages/context/workspace-context) | `context` | [`agent`](../packages/core/agent), [`fs`](../packages/fs/fs), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`paths`](../packages/util/paths), [`session`](../packages/core/session), [`tools`](../packages/core/tools) |
| [`repeat-tool-guard`](../packages/guard/repeat-tool-guard) | `guard` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`tools`](../packages/core/tools) |

View File

@@ -105,7 +105,7 @@ Sources: [`packages/core/session/src/types.ts:256`](../packages/core/session/src
Types: [CallId](core-data-structures/core.md)
Source: [`packages/ui/user-approval/src/index.ts:45`](../packages/ui/user-approval/src/index.ts)
Source: [`packages/ui/user-approval/src/index.ts:44`](../packages/ui/user-approval/src/index.ts)
#### `approval/decided` — log-only
@@ -121,7 +121,7 @@ Source: [`packages/ui/user-approval/src/index.ts:45`](../packages/ui/user-approv
}
```
Source: [`packages/ui/user-approval/src/index.ts:56`](../packages/ui/user-approval/src/index.ts)
Source: [`packages/ui/user-approval/src/index.ts:55`](../packages/ui/user-approval/src/index.ts)
#### `approval/policy` — log-only
@@ -137,7 +137,7 @@ Source: [`packages/ui/user-approval/src/index.ts:56`](../packages/ui/user-approv
'approval/policy': { policy: ApprovalPolicy }
```
Source: [`packages/ui/user-approval/src/index.ts:68`](../packages/ui/user-approval/src/index.ts)
Source: [`packages/ui/user-approval/src/index.ts:67`](../packages/ui/user-approval/src/index.ts)
### `assistant/*`
@@ -342,7 +342,7 @@ Source: [`packages/llm/llm-retry/src/index.ts:18`](../packages/llm/llm-retry/src
'permission/preset': { preset: string }
```
Source: [`packages/ui/permission/src/index.ts:36`](../packages/ui/permission/src/index.ts)
Source: [`packages/ui/permission/src/index.ts:49`](../packages/ui/permission/src/index.ts)
### `plan/*`

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/client/ui-conversation/README.md
README.md: 51ddecf93240c2196483d3fb2bcfaca4104da31a
README.zh.md: d98cbcc69b875d2f426d9bdd9f2fa81874ec614a
README.md: 9f96883ad34d52e75211b9bea16f7273ded370ae
README.zh.md: ee766a23378a7ff21ceae4015addc19900c7c2b9

View File

@@ -8,7 +8,7 @@ The resident conversation shell survives no-session and session transitions. Wit
The view ring IS a slot: the conversation registration declares the `'conversation.view'` list slot (session scope) in its `children` table, ConversationRoot renders the active entry through its renderSlot share (`only: <active id>`), and view tabs project from the ring ledger's registration options (`id`/`order`/`label`). The chat view is this package's own ring entry; other plugins (ui-trajectory) contribute tabs through plain `ctx.slots.register` — the former package-local view registry (`registerView`/`ViewEntry`/`ConversationViewMap` and the chrome attachment table) is retired, with per-view chrome dissolved into the view components themselves.
Approvals take over the composer through the chain this package declares: `ApprovalPanel` registers as a selector-routed `'conversation.composer'` entry (the ui-question pattern) and occupies the composer in place of the InputBar while an approval wait is pending (amber strip, justification headline, paired command line from the running call's args, one-shot refuse/allow). The `PendingApproval` domain face in `contract/slots.ts` owns the wire encoding — the `ApprovalResponsePayload` value with the audit correlation — over the runtime's `PendingWait` carrier; the broadcast `approval/resolved` frame settles the wait and restores the composer. The sidebar mirrors the blocked state through the manager-tracked `waitingApproval` list bit (lit for uninstantiated sessions too), which outranks the running ring until the question resolves. Question placeholders remain in the message flow as display-only PendingCards while ui-question owns the answering takeover.
Approvals take over the composer through the chain this package declares: `ApprovalPanel` registers as a selector-routed `'conversation.composer'` entry (the ui-question pattern) and occupies the composer in place of the InputBar while an approval wait is pending (amber strip, justification headline, paired command line from the running call's args, one-shot refuse/allow). The `PendingApproval` domain face in `contract/slots.ts` owns the wire encoding — the `ApprovalResponsePayload` value with the audit correlation — over the runtime's `PendingWait` carrier; the broadcast `approval/resolved` frame settles the wait and restores the composer. The sidebar mirrors the blocked state through the manager-tracked `waitingApproval` list bit (lit for uninstantiated sessions too), which outranks the running ring until the question resolves. Question placeholders remain in the message flow as display-only PendingCards while ui-question owns the answering takeover. The composer's bottom-row Access seat mounts `PermissionSelect`, fed by the host-computed `permissions` projection through the standard-kit `useProjection` (key absence hides the chip); a pick submits the `/permission <preset>` command line through the bar's injected `command` callback.
Generic tool rows classify the built-in bash, read, search, write, edit, and run_code names into dedicated visual variants. The filesystem variants render the edit icon and a path summary; that path is a hover-underline link that opens the file with the host OS default application (`host.openPath`, relative paths resolve against the session cwd). Tool rows are not whole-row click targets and do not open the details panel. The code variant summarizes with the model-authored `description` and expands to the program itself; its logged sub-dispatches render as always-visible nested rows through the SAME keyed toolview hole (custom registrations and the GenericToolCard fallback apply to sub-rows unchanged). Cordis lifecycle tools reuse those generic variants while presenting `Inspect`, `Mount temporary Plugin`, and `Unmount temporary Plugin` with a shared Cordis accent; mount keeps the code variant's expandable source rendering.

View File

@@ -12,6 +12,8 @@
工具行同样是 slot独立工具环`ToolViewRegistry``ctx.toolviews`outlet已经退役。聊天配置项声明键控的 `'conversation.chat.toolview'` 空位Session scopekey 空间在运行时开放);其渲染点逐行通过 `entryKey: toolName` 分发,并以 `GenericToolCard` 作为调用点 `fallback`。owner 载荷是统一的 `ToolRowOwnerProps``callId``toolName``block``openFile``ToolRowProps` 则预先将其与 Session 标准工具包组合。注册方只是普通插件:`ctx.slots.register({ name: 'conversation.chat.toolview', key: '<tool>', inject? }, Row)`,以 `inject: ['slots', 'conversation']` 作为加载顺序 seamapply 在聊天注册后挂载 ConversationService因此服务存在即可保证 slot 已声明Session 区分在组件内部完成(`useSessions` 读取 `parentId`bash 示例是第三方姿态的范例。Trajectory/waterfall 工具视图 slot 共享此形状并随各自的渲染点落地RendersCheck 会拒绝没有任何渲染方的声明)。
审批经由本包声明的链接管编辑器:`ApprovalPanel` 注册为按选择器路由的 `'conversation.composer'` 配置项ui-question 模式),在审批等待未决期间取代 InputBar 占据编辑器(琥珀色条、理由标题、来自运行中调用参数的配对命令行、一次性的拒绝/允许)。`contract/slots.ts` 中的 `PendingApproval` 领域面在运行时 `PendingWait` 载体之上拥有 wire 编码——带审计关联的 `ApprovalResponsePayload` 值;广播的 `approval/resolved` 帧使等待落定并恢复编辑器。侧边栏通过 manager 跟踪的 `waitingApproval` 列表位(未实例化会话同样点亮)镜像该阻塞状态,其优先级高于运行中圆环,直至问题解决。问题占位符仍以只读 PendingCard 形式留在消息流中,应答接管归 ui-question 所有。编辑器底行的 Access 席位挂载 `PermissionSelect`,由 host 计算的 `permissions` 投影经标准工具包 `useProjection` 供数key 缺席即隐藏 chip选中会经由输入栏注入的 `command` 回调提交 `/permission <preset>` 命令行。
todo 两个面就是在该形状上的两个注册项,都是普通注册方插件,`inject: ['slots', 'conversation']``TodoRow` 占用 `'conversation.chat.toolview'``todo_write` key摘要该次调用「试图写入」的内容从其 args 解析出 `<已完成>/<总数> 已完成 · <进行中条目>`;模型 JSON 残缺或形状不对时回落到通用摘要;非 ok 执行状态保留通用状态点,使被取消的调用绝不读成一次已完成的更新)。`TodoDock``order: -1` 占用 `'conversation.input.dock'` 列表 slot位于队列行之上是计划条它经 `useProjection` 读取 host 计算的 `todos` 投影(站立计划:其后没有更晚 `turn/start` 的最近一次 `todo/write`)并渲染 `TodoPanel`,后者接收纯列表,在列表为空时自我隐藏,折叠时收成标题加 `"<已完成>/<总数> tasks · <n> in progress"` 的表头(状态图标为 figma 的勾选/进行中/虚线未开始一组)。选取由 dock 适配器负责,因此面板保持为其 props 的纯函数;站立列表放在此处而非行内,行才能保持单行。输入区 composer 链隐藏的一切(例如 ui-question 对 `conversation.composer` 的接管)也会隐藏整个 dock包括这条计划条。
逐 Session UI 状态中的选择与活跃视图位于已声明的聊天 store`stores.ts` `createChatStore`InputHub 拥有输入区状态机,并将草稿镜像到该 store 以便持久化。apply 将同一个 store handle 传给严格限定于会话的子树、聊天视图和详情注册,因此每个会话内共享一个实例,框架拥有其生命周期。组件保持纯粹:框架标准工具包提供 `useSession``sessionId`、全局 `useSessions``useWorkspaces`,以及输入状态机的 `useInput``inputActions`store 表层与 inject factory 提供其余状态和回调。
@@ -34,5 +36,5 @@ todo 两个面就是在该形状上的两个注册项,都是普通注册方插
- **详情面板是最小形态**以原始形式显示已选择调用的参数结果Input/Output/Metadata 切换、Prev/Next 步进与 See-in-trajectory 深链接暂缓实现。
- **assistant footer 扩展IconActions 行、逐消息分页)是预留 slot**:设计中已有图稿,尚未实现。
- **others 工具行的闪光图标是手绘近似版本**:无法在本地导出设计字形的矢量几何;等到存在精确导出后再将其提升到 ui-primitives。
- **审批卡片只是只读占位符**问题请求通过编辑器链回答ui-questionWeb 侧审批回答属于 P-II 审批项目
- **审批面板的「始终允许此类」暂缓**:持久授权需要授权存储设计;今天只能回答允许一次/拒绝
- **TodoPanel 将过长条目截成单行省略号**figma 条没有换行或展开入口,完整文本无法在行内读完。

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/client/ui-permission/README.md
README.md: '0000000000000000000000000000000000000000'
README.zh.md: '0000000000000000000000000000000000000000'
README.md: 1782f89c0909ea80f8554bb9b271947a39ae7f8f
README.zh.md: 6c750329df5bfb25f738869eeb82ea26fa1b8634

View File

@@ -410,6 +410,10 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
signature: 'current(events: readonly SessionEvent[]): string',
jsDoc: '/**\n * Resolve the preset matching the effective knob values. A still-matching\n * last selection wins shared-bundle ties; otherwise the first table match\n * wins, or {@link CUSTOM_PRESET} when no entry matches.\n * @param events - the session\'s events in log order.\n * @returns the effective preset name, or `custom` when nothing matches.\n */',
},
{
signature: 'selectFor(state: KnobState): PermissionSelect',
jsDoc: '/**\n * Build the whole select value for one folded knob state: every table\n * option in declaration order, `custom` appended exactly while derived.\n * @param state - the folded knob overrides.\n * @returns the `permissions` projection payload.\n */',
},
{
signature: 'resolve(name: string): PresetSpec',
jsDoc: '/**\n * Resolve a preset\'s knob bundle.\n * @param name - the preset name to resolve.\n * @returns the configured bundle.\n * @throws when `name` is not in the table.\n */',
@@ -1767,6 +1771,10 @@ export const TYPE_API: readonly TypeApiEntry[] = [
name: 'JsonValue',
declaration: 'export type JsonValue = null | boolean | number | string | JsonValue[] | {\n [key: string]: JsonValue;\n};',
},
{
name: 'KnobState',
declaration: 'export interface KnobState {\n preset: string | null;\n sandbox: SandboxMode | null;\n approval: ApprovalPolicy | null;\n}',
},
{
name: 'KvTable',
declaration: 'export interface KvTable<K extends string, V> {\n get(key: K): V | undefined;\n entries(): IterableIterator<[\n K,\n V\n ]>;\n keys(): IterableIterator<K>;\n readonly size: number;\n put(key: K, value: V): Promise<void>;\n delete(key: K): Promise<boolean>;\n update(key: K, fn: (current: V) => V): Promise<V>;\n}',
@@ -1835,6 +1843,10 @@ export const TYPE_API: readonly TypeApiEntry[] = [
name: 'ObjectJsonSchema',
declaration: 'export type ObjectJsonSchema = JsonSchemaNode & {\n type: \'object\';\n};',
},
{
name: 'PermissionSelect',
declaration: 'export interface PermissionSelect {\n options: PresetOption[];\n currentValue: string;\n}',
},
{
name: 'PreparedLlmCall',
declaration: 'export interface PreparedLlmCall {\n readonly config: LlmCallConfig;\n stream(options: GenerateOptions): AsyncIterable<StreamChunk>;\n}',

View File

@@ -1,6 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write
README.md: 6a59ad9425bf5bfeb89e9798304a2eb90ee55bfa
README.zh.md: 0e7db1bd41a15ac4be18d33db7b9011a5bc24e7e
# pnpm run verify-translation-pairing --write packages/ui/permission/README.md
README.md: 814085ed6f2c9650854f377e1c97e442fc4211a4
README.zh.md: 36880d6b8c3f0b39b88db1abb02534f30e3355fa

View File

@@ -8,6 +8,8 @@
该服务要求存在具有约束能力的 `ctx.bash` 执行器和 `ctx.approval`。表中名为 `custom` 的条目会在加载时抛出异常;如果组合在表外指定默认值,则零事件会话会推导出 `custom`。详见[沙箱切换设计](../../../.agents/notes/implemented/feature/2026-07-06-sandbox.md)。
两个可选子件在同一服务之上交付产品界面:`permissions` 会话投影单元(`src/types.ts` 声明该 key单元折叠三个全量值旋钮事件在组合默认值之上视图出 select——表内选项加仅作当前值的 `custom`)与 `/permission` 命令(裸调用报告当前预设与表;预设参数经 `set` 切换)。每个子件仅在其注册表(`ctx.sessionProjections` / `ctx.commands`)被组合时激活。
## 模型体验
间接地,通过 `dsh-user-approval``dsh-tool-bash`:二者会渲染由此服务的调节项事件所选择的审批策略提示词、切换通知和沙箱工具结果;`permission/preset` 本身只写入日志。
@@ -18,7 +20,6 @@
## 已知限制与延期工作
- **当前没有已交付的组合挂载此服务**:在 [ACP 变为仅用于自动化](../../../.agents/notes/implemented/simplification/2026-07-23-acp-automation-only-protocol.md)之前ACP 桥接层是唯一的选择器preset 表为下一个公开运行时策略切换的交互式入口保留。
- **只组合两个机制调节项**preset 选择沙箱模式和审批策略agent智能体profile 选择尚未纳入 `PresetSpec`
- **`custom` 只能推导得出**:调用方可以从不匹配的调节项组合切换出去,但无法通过此服务选中或持久化一个具名 custom preset。
- **preset 表位于进程级别**:配置在插件生命周期内固定;更改可用 preset 必须重新加载插件。

View File

@@ -249,6 +249,8 @@ const TYPE_LINK_EXEMPTIONS: Readonly<Record<string, string>> = {
InvariantRegistration: 'service-local lifecycle handle is owned by packages/support/invariants/README.md',
PresetOption: 'deployment menu metadata is owned by packages/ui/permission/README.md',
PresetSpec: 'deployment preset composition is owned by packages/ui/permission/README.md',
KnobState: 'projection unit state shape is owned by packages/ui/permission/README.md',
PermissionSelect: 'permissions projection payload is owned by packages/ui/permission/src/types.ts',
PromptAssembly: 'assembly result is owned by packages/core/system-prompt/README.md',
ResumeAgentOptions: 'agent resume contract is owned by packages/core/agent/README.md',
SessionForkSource: 'service-local fork input is owned by packages/core/session/src/index.ts',

View File

@@ -58,6 +58,7 @@ const SENTENCE_MODEL_EXPERIENCE: Readonly<Record<string, SentenceContract>> = {
'packages/client/ui-slash': { kind: 'none', reason: 'Browser-side UI plugin layer; registers no model surface.' },
'packages/client/ui-command': { kind: 'indirect', reason: 'The dispatch paths trigger the host command.execute RPC; each command handler\'s host package owns any model-visible effect.' },
'packages/client/ui-model': { kind: 'indirect', reason: 'Selection routes session.selectModel; the host snapshots the target at the next prompt-assembly boundary and owns the model-visible effect.' },
'packages/client/ui-permission': { kind: 'indirect', reason: 'The picker submits the host /permission command; the knob events it appends own the model-visible effect through the sandbox/approval consumers.' },
'packages/client/ui-question': { kind: 'indirect', reason: 'The package mounts dsh-tool-ask-user; that tool owns the model-visible schema and answer rendering.' },
'packages/client/ui-trajectory': { kind: 'none', reason: 'Browser-side UI plugin layer; registers no model surface.' },
'packages/client/ui-workspace': { kind: 'none', reason: 'Browser-side UI plugin layer; registers no model surface.' },