Merge branch 'master' into docs/cordis-tutorial

This commit is contained in:
Tianyi Cui
2026-07-22 20:42:26 +08:00
committed by GitHub
587 changed files with 40998 additions and 924 deletions

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
architecture.md: b3e2db14727c299562f9b061459547d147ec1d70
architecture.zh.md: 6fd2a7e161a10ac5f2dcee6859b0d6251671676f
architecture.md: d7555368b583203cee664da3615c4fb4fb680c30
architecture.zh.md: bafe59dee0559d5969c7400bdae85be0d012b3b5

View File

@@ -37,6 +37,7 @@ Harnesses are [Cordis](cordis-primer.md) contexts whose packages contribute serv
| `ctx.web` | [`web/`](../packages/web/README.md) | search/fetch provider registries |
| `ctx.compact`, `ctx.toolResultPrune` | [`compact/`](../packages/compact/README.md)/[`compact-tool-result-prune`](../packages/compact/compact-tool-result-prune/README.md) | summary compaction; optional model-free result pruning |
| `ctx.subagents` | [`subagent/`](../packages/subagent/README.md) | named delegation providers |
| `ctx.planMode` | [`plan/`](../packages/plan/README.md) | logged plan collaboration state |
| `ctx.tasks` | [`tasks/`](../packages/tasks/README.md) | background task registry + generic `task_*` control tools |
| `ctx.workflows` | [`workflow/`](../packages/workflow/README.md) | script-driven multi-agent orchestration |
| `ctx.goals` | [`goal/`](../packages/goal/README.md) | persisted same-session goals |

View File

@@ -37,6 +37,7 @@
| `ctx.web` | [`web/`](../packages/web/README.md) | 搜索与抓取提供方注册表 |
| `ctx.compact``ctx.toolResultPrune` | [`compact/`](../packages/compact/README.md)/[`compact-tool-result-prune`](../packages/compact/compact-tool-result-prune/README.md) | 摘要压缩compaction可选的无模型结果裁剪 |
| `ctx.subagents` | [`subagent/`](../packages/subagent/README.md) | 具名委托提供方 |
| `ctx.planMode` | [`plan/`](../packages/plan/README.md) | 落日志的 plan 协作状态 |
| `ctx.tasks` | [`tasks/`](../packages/tasks/README.md) | 后台任务注册表和通用 `task_*` 控制工具 |
| `ctx.workflows` | [`workflow/`](../packages/workflow/README.md) | 脚本驱动的多 agent 编排 |
| `ctx.goals` | [`goal/`](../packages/goal/README.md) | 持久化的同会话目标 |

View File

@@ -54,6 +54,8 @@ flowchart LR
pkg_user_interaction["user-interaction"]
svc_userInteraction["ctx.userInteraction<br/>Human question/answer seam"]
pkg_tui["tui"]
pkg_plan_mode["plan-mode"]
svc_planMode["ctx.planMode<br/>Plan collaboration state"]
pkg_commands["commands"]
svc_commands["ctx.commands<br/>Human command registry"]
pkg_skill["skill"]
@@ -136,6 +138,7 @@ flowchart LR
pkg_llm_pi_ai --> svc_llm
pkg_llm_replay --> svc_llm
pkg_permission --> svc_permission
pkg_plan_mode --> svc_planMode
pkg_sandbox --> svc_sandbox
pkg_sandbox_local --> svc_sandbox
pkg_sandbox_policy --> svc_sandboxPolicy
@@ -192,6 +195,7 @@ flowchart LR
svc_llm --> pkg_agent_loop
svc_llm --> pkg_compact_basic
svc_permission --> pkg_acp
svc_planMode --> pkg_acp
svc_sandbox --> pkg_bash_sandbox
svc_sandboxPolicy --> pkg_bash_sandbox
svc_sandboxPolicy --> pkg_fs_sandbox
@@ -252,6 +256,7 @@ flowchart LR
| `ctx.systemPrompt` | `core` | [`system-prompt`](../packages/core/system-prompt) | - | [`agent-loop`](../packages/core/agent-loop), [`tools`](../packages/core/tools), [`tool-fs`](../packages/fs/tool-fs), [`tool-web`](../packages/web/tool-web) | - | Collects prompt sections and model-facing tool schemas for each step. |
| `ctx.tools` | `core` | [`tools`](../packages/core/tools) | - | [`agent-loop`](../packages/core/agent-loop), [`tool-ask-user`](../packages/ui/tool-ask-user), [`tool-bash`](../packages/bash/tool-bash), [`tool-cordis`](../packages/cordis/tool-cordis), [`tool-fs`](../packages/fs/tool-fs), [`tool-skill`](../packages/skill/tool-skill), [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-todo`](../packages/todo/tool-todo), [`tool-web`](../packages/web/tool-web), [`acp`](../packages/ui/acp) | - | Registers capabilities, owns Code Mode transport, and routes calls through pre-policy, monotonic guards, around dispatch, post-policy, and final-result observation. |
| `ctx.userInteraction` | `seam` | [`user-interaction`](../packages/ui/user-interaction) | [`tui`](../packages/ui/tui), [`acp`](../packages/ui/acp) | [`tool-ask-user`](../packages/ui/tool-ask-user), [`tui`](../packages/ui/tui), [`acp`](../packages/ui/acp) | - | UI front doors provide the active human-answer provider; tool-ask-user pauses a tool call on the provider-neutral ask() promise. |
| `ctx.planMode` | `core` | [`plan-mode`](../packages/plan/plan-mode) | - | [`acp`](../packages/ui/acp) | - | Folds logged plan/mode state, flushes user selections at turn boundaries, renders deployment-owned guidance, registers /plan, and keeps the plan-exit schema stable across transitions. |
| `ctx.commands` | `core` | [`commands`](../packages/ui/commands) | - | [`tui`](../packages/ui/tui), [`acp`](../packages/ui/acp) | - | Plugins register direct human commands; TUI and ACP consume the same effective per-agent catalog without sending invocations to the model. |
| `ctx.skills` | `seam` | [`skill`](../packages/skill/skill) | [`skill-local`](../packages/skill/skill-local) | [`tool-skill`](../packages/skill/tool-skill) | - | Merges provider skill catalogs; tool-skill renders the session-prefix catalog and loads complete skill bodies. |
| `ctx.agents` | `core` | [`agent`](../packages/core/agent) | - | [`agent-loop`](../packages/core/agent-loop), [`acp`](../packages/ui/acp), [`cli-demo`](../packages/examples/cli-demo), [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`tui-demo`](../packages/examples/tui-demo) | - | Owns live Agent handles, the create/resume factory seam, and process-local initiator propagation. |

View File

@@ -27,7 +27,7 @@ export interface AcpConfig {
Depends on: `Stream` (`@agentclientprotocol/sdk`)
Source: [`packages/ui/acp/src/index.ts:254`](../packages/ui/acp/src/index.ts)
Source: [`packages/ui/acp/src/index.ts:275`](../packages/ui/acp/src/index.ts)
## `@deepseek-ai/dsh-acp-demo`
@@ -786,6 +786,20 @@ Depends on: [`ApprovalPolicy`](core-data-structures/approval.md) · [`SandboxMod
Source: [`packages/ui/permission/src/index.ts:83`](../packages/ui/permission/src/index.ts)
## `@deepseek-ai/dsh-plan-mode`
Requires: `tools` · `systemPrompt`
```ts config-catalog
/** Deployment-owned plan guidance. */
export interface PlanModeConfig {
/** Guidance rendered as the `plan:policy` prompt section while plan mode is active. */
section: string
}
```
Source: [`packages/plan/plan-mode/src/index.ts:57`](../packages/plan/plan-mode/src/index.ts)
## `@deepseek-ai/dsh-repeat-tool-guard`
```ts config-catalog
@@ -1572,7 +1586,7 @@ export interface Config {
export type ApprovalPolicy = 'ask' | 'never'
```
Source: [`packages/ui/user-approval/src/index.ts:214`](../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`
@@ -1738,6 +1752,14 @@ Source: [`packages/context/workspace-context/src/config.ts:16`](../packages/cont
These load from a `cordis.yml` entry with no `config:` block; they declare no config surface.
- `@deepseek-ai/dsh-agent` ([`packages/core/agent/src/index.ts`](../packages/core/agent/src/index.ts))
- `@deepseek-ai/dsh-client-connection` ([`packages/client/connection/src/index.ts`](../packages/client/connection/src/index.ts))
- `@deepseek-ai/dsh-client-i18n` ([`packages/client/i18n/src/index.ts`](../packages/client/i18n/src/index.ts))
- `@deepseek-ai/dsh-client-runtime` ([`packages/client/runtime/src/index.ts`](../packages/client/runtime/src/index.ts))
- `@deepseek-ai/dsh-client-ui-conversation` ([`packages/client/ui-conversation/src/index.ts`](../packages/client/ui-conversation/src/index.ts))
- `@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-sidebar` ([`packages/client/ui-sidebar/src/index.ts`](../packages/client/ui-sidebar/src/index.ts))
- `@deepseek-ai/dsh-client-ui-theme` ([`packages/client/ui-theme/src/index.ts`](../packages/client/ui-theme/src/index.ts))
- `@deepseek-ai/dsh-client-ui-trajectory` ([`packages/client/ui-trajectory/src/index.ts`](../packages/client/ui-trajectory/src/index.ts))
- `@deepseek-ai/dsh-command-goal` — requires `commands` · `goals` ([`packages/goal/command-goal/src/index.ts`](../packages/goal/command-goal/src/index.ts))
- `@deepseek-ai/dsh-commands` ([`packages/ui/commands/src/index.ts`](../packages/ui/commands/src/index.ts))
- `@deepseek-ai/dsh-fs-policy` ([`packages/fs/fs-policy/src/index.ts`](../packages/fs/fs-policy/src/index.ts))
@@ -1774,8 +1796,15 @@ Imported as libraries by other packages; a `cordis.yml` cannot load them.
- `@deepseek-ai/dsh-agent-loop-testkit` ([`packages/support/agent-loop-testkit/src/index.ts`](../packages/support/agent-loop-testkit/src/index.ts))
- `@deepseek-ai/dsh-app-boot` ([`packages/ui/app-boot/src/index.ts`](../packages/ui/app-boot/src/index.ts))
- `@deepseek-ai/dsh-brand` ([`packages/util/brand/src/index.ts`](../packages/util/brand/src/index.ts))
- `@deepseek-ai/dsh-client-ui-primitives` ([`packages/client/ui-primitives/src/index.ts`](../packages/client/ui-primitives/src/index.ts))
- `@deepseek-ai/dsh-client-ui-slots` ([`packages/client/ui-slots/src/index.ts`](../packages/client/ui-slots/src/index.ts))
- `@deepseek-ai/dsh-client-web` ([`packages/client/web/src/index.ts`](../packages/client/web/src/index.ts))
- `@deepseek-ai/dsh-client-web-react` ([`packages/client/web-react/src/index.ts`](../packages/client/web-react/src/index.ts))
- `@deepseek-ai/dsh-helper` ([`packages/sdk/helper/src/index.ts`](../packages/sdk/helper/src/index.ts))
- `@deepseek-ai/dsh-hook-protocol` ([`packages/hooks/hook-protocol/src/index.ts`](../packages/hooks/hook-protocol/src/index.ts))
- `@deepseek-ai/dsh-host-apiproxy` ([`packages/host/apiproxy/src/index.ts`](../packages/host/apiproxy/src/index.ts))
- `@deepseek-ai/dsh-host-runtime` ([`packages/host/runtime/src/index.ts`](../packages/host/runtime/src/index.ts))
- `@deepseek-ai/dsh-host-webserver` ([`packages/host/webserver/src/index.ts`](../packages/host/webserver/src/index.ts))
- `@deepseek-ai/dsh-jsonrpc-demo` ([`packages/examples/jsonrpc-demo/src/index.ts`](../packages/examples/jsonrpc-demo/src/index.ts))
- `@deepseek-ai/dsh-loader-smoke` ([`packages/support/loader-smoke/src/index.ts`](../packages/support/loader-smoke/src/index.ts))
- `@deepseek-ai/dsh-paths` ([`packages/util/paths/src/index.ts`](../packages/util/paths/src/index.ts))

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
extension-cookbook.md: a1f6d2f0d27b2258ae06236721bbd80cbd3af80e
extension-cookbook.zh.md: f7729492b68bfef50d5e289581028d0c0c4164cf
extension-cookbook.md: 8873cac21960e2e2efe0e8c6c5868c3a8e7ee75c
extension-cookbook.zh.md: f34e9f2fa707be69b13ac408cc1ede1a86310fae

View File

@@ -87,7 +87,7 @@ export function apply(ctx: Context) {
## Runnable wirings
Four runnable leaves load their plugin trees from `cordis.yml`: [`examples/tui-agent`](../../examples/tui-agent) (DeepSeek coding tools through the full-screen TUI, `pnpm run demo:tui`), [`examples/headless-agent`](../../examples/headless-agent) (the coding capabilities behind a one-shot task and DSH-native output, `pnpm run demo:headless "task"`), [`examples/cordis-agent`](../../examples/cordis-agent) (self-inspection and dynamic plugin mounting through the TUI, `pnpm run demo:cordis`), and [`examples/acp-agent`](../../examples/acp-agent) (an ACP server over JSON-RPC stdio, `pnpm run demo:acp`). Interactive leaves load [`@deepseek-ai/dsh-tui-demo`](../../packages/examples/tui-demo), non-interactive leaves load [`@deepseek-ai/dsh-cli-demo`](../../packages/examples/cli-demo), the ACP leaf loads [`@deepseek-ai/dsh-acp-demo`](../../packages/examples/acp-demo), and all three app packages share [`@deepseek-ai/dsh-agent-spine-demo`](../../packages/examples/agent-spine-demo).
Runnable leaves load their plugin trees from `examples/*/cordis.yml`; the root `demo:*` scripts and those leaf directories are the authoritative inventory. Interactive leaves use [`@deepseek-ai/dsh-tui-demo`](../../packages/examples/tui-demo), non-interactive leaves use [`@deepseek-ai/dsh-cli-demo`](../../packages/examples/cli-demo), ACP leaves use [`@deepseek-ai/dsh-acp-demo`](../../packages/examples/acp-demo), and the app packages share [`@deepseek-ai/dsh-agent-spine-demo`](../../packages/examples/agent-spine-demo).
## The feature → mechanism map
@@ -113,7 +113,7 @@ Every product feature maps to a listener on a documented extension seam — the
| Monotonic terminal turn policy | return `{ action: 'stop' }` from serial `agent/turn-stop`, after continuation and steering have already been folded |
| Subprocess sandbox (landlock / sandbox-exec) | use a `ctx.sandbox` backend through `dsh-bash-sandbox`; use `tools/pre-execute` for capability-level denial |
| Permission system / AskUserQuestion | return `ask` from `tools/pre-execute` and answer through `ctx.approval`; register a separate model-facing ask tool for ordinary user questions |
| Plan mode | `tools/pre-execute` (deny writes) + a mode prompt section via `ctx.systemPrompt.section()` or `agent.inject()` (model-visible ⟺ logged: `agent/request` shapes call config only) |
| Plan mode | Shipped: [`@deepseek-ai/dsh-plan-mode`](../../packages/plan/plan-mode/README.md) — logged `plan/mode` state, the `plan:policy` guidance section, `/plan [message]`, and the user-reviewed `exit_plan_mode` exit; enforcement stays on the independent sandbox/approval axes |
| Sub-agent delegation | the `ctx.subagents` provider registry (`dsh-subagent-spawn`/`-fork`/`-acp`) + `dsh-tool-subagent` exposing one configured provider to the model |
| MCP | one plugin per server: discover tools → `ctx.tools.register()` |
| Skills | section + tool registration; `inject()` skill content on invocation |

View File

@@ -87,7 +87,7 @@ export function apply(ctx: Context) {
## 可运行的组装示例
四个可运行叶子从 `cordis.yml` 加载各自的插件树:[`examples/tui-agent`](../../examples/tui-agent)(通过全屏 TUI 运行的 DeepSeek coding 工具,`pnpm run demo:tui`)、[`examples/headless-agent`](../../examples/headless-agent)(通过单次任务和 DSH 原生输出运行的 coding 能力,`pnpm run demo:headless "task"`)、[`examples/cordis-agent`](../../examples/cordis-agent)(通过 TUI 进行自我检查和动态插件挂载,`pnpm run demo:cordis`)与 [`examples/acp-agent`](../../examples/acp-agent)(通过 JSON-RPC stdio 暴露的 ACP 服务器,`pnpm run demo:acp`。交互式叶子加载 [`@deepseek-ai/dsh-tui-demo`](../../packages/examples/tui-demo),非交互式叶子加载 [`@deepseek-ai/dsh-cli-demo`](../../packages/examples/cli-demo)ACP 叶子加载 [`@deepseek-ai/dsh-acp-demo`](../../packages/examples/acp-demo)三个 app 包都通过 [`@deepseek-ai/dsh-agent-spine-demo`](../../packages/examples/agent-spine-demo) 共享主干
可运行叶子从 `examples/*/cordis.yml` 加载各自的插件树;根目录的 `demo:*` 脚本和这些叶子目录是权威清单。交互式叶子使用 [`@deepseek-ai/dsh-tui-demo`](../../packages/examples/tui-demo),非交互式叶子使用 [`@deepseek-ai/dsh-cli-demo`](../../packages/examples/cli-demo)ACP 叶子使用 [`@deepseek-ai/dsh-acp-demo`](../../packages/examples/acp-demo)应用包共享 [`@deepseek-ai/dsh-agent-spine-demo`](../../packages/examples/agent-spine-demo)。
## 功能→机制映射
@@ -113,7 +113,7 @@ export function apply(ctx: Context) {
| 单调终端轮次策略 | 从串行 `agent/turn-stop` 返回 `{ action: 'stop' }`,此时 continuation 和 steering 已折叠完毕 |
| 子进程沙箱landlock / sandbox-exec | 通过 `dsh-bash-sandbox` 使用 `ctx.sandbox` 后端;能力级别的拒绝使用 `tools/pre-execute` |
| 权限系统 / AskUserQuestion | 从 `tools/pre-execute` 返回 `ask` 并通过 `ctx.approval` 应答;为普通用户提问注册一个独立的面向模型的 ask 工具 |
| Plan mode | `tools/pre-execute`(拒绝写操作)+ 通过 `ctx.systemPrompt.section()``agent.inject()` 注入模式提示词段model-visible ⟺ logged`agent/request` 仅塑形调用配置) |
| Plan mode | 已交付:[`@deepseek-ai/dsh-plan-mode`](../../packages/plan/plan-mode/README.md) — 落日志的 `plan/mode` 状态、`plan:policy` 引导段、`/plan [message]`,以及经用户评审的 `exit_plan_mode` 出口;强制约束留在独立的沙箱/审批轴上 |
| 子 agent 委派 | `ctx.subagents` 提供方注册表(`dsh-subagent-spawn`/`-fork`/`-acp`+ `dsh-tool-subagent` 向模型暴露一个已配置的提供方 |
| MCP | 每个服务器一个插件:发现工具 → `ctx.tools.register()` |
| Skill技能 | section + 工具注册;调用时通过 `inject()` 注入 skill 内容 |

View File

@@ -417,7 +417,7 @@ Ask composed answerers for one decision. Return an outcome to claim the request
Types: [ApprovalOutcome](../core-data-structures/approval.md) · [ApprovalRequest](../core-data-structures/approval.md) · [ApprovalService](../core-data-structures/approval.md) · [Scoped](../core-data-structures/scope.md)
Source: [`packages/ui/user-approval/src/index.ts:31`](../../packages/ui/user-approval/src/index.ts)
Source: [`packages/ui/user-approval/src/index.ts:30`](../../packages/ui/user-approval/src/index.ts)
## `commands/*`

View File

@@ -246,7 +246,7 @@ async request(req: ApprovalRequest): Promise<ApprovalOutcome>
Types: [ApprovalOutcome](../core-data-structures/approval.md) · [ApprovalRequest](../core-data-structures/approval.md)
Source: [`packages/ui/user-approval/src/index.ts:229`](../../packages/ui/user-approval/src/index.ts)
Source: [`packages/ui/user-approval/src/index.ts:213`](../../packages/ui/user-approval/src/index.ts)
## `ctx.bash` — `BashExecutor` (abstract seam)
@@ -733,6 +733,33 @@ Types: [Session](../core-data-structures/session.md) · [SessionEvent](../core-d
Source: [`packages/ui/permission/src/index.ts:97`](../../packages/ui/permission/src/index.ts)
## `ctx.planMode` — `PlanModeService`
`ctx.planMode`: owns logged plan state, boundary application and narration, the `plan:policy` section, the `/plan` command, and the stable exit tool. UIs observe committed flips through `session/event`; there is no live mirror.
```ts cordis-catalog
/**
* Read the logged plan state and any selected state awaiting a boundary.
*
* @param agent The agent to read.
* @returns Current logged state plus a pending selection, when present.
*/
get(agent: Agent): { active: boolean; pending?: boolean }
/**
* Select whether plan mode should be active from the next turn boundary.
* Repeated selection of the current or already-pending state is a no-op.
*
* @param agent The agent to switch.
* @param active Whether plan mode should be active.
*/
set(agent: Agent, active: boolean): void
```
Types: [Agent](../core-data-structures/core.md)
Source: [`packages/plan/plan-mode/src/index.ts:141`](../../packages/plan/plan-mode/src/index.ts)
## `ctx.sandbox` — `SandboxProvider` (abstract seam)
Abstract process-sandbox service. confine must return enforcing argv or fail closed at wrap or runner-execution time; silent unconfined passthrough is forbidden. Functional probes arbitrate multi-runner chains and may be skipped for a sole candidate, whose own refusal remains the fail-closed end.
@@ -1482,7 +1509,7 @@ async ask(request: AskUserQuestionRequest): Promise<AskUserQuestionAnswer>
Types: [AskUserQuestionAnswer](../core-data-structures/user-interaction.md) · [AskUserQuestionRequest](../core-data-structures/user-interaction.md) · [UserInteractionProvider](../core-data-structures/user-interaction.md)
Source: [`packages/ui/user-interaction/src/index.ts:82`](../../packages/ui/user-interaction/src/index.ts)
Source: [`packages/ui/user-interaction/src/index.ts:50`](../../packages/ui/user-interaction/src/index.ts)
## `ctx.web` — `WebService`

View File

@@ -235,6 +235,12 @@ interface GenerateOptions {
* it; replay uses it to keep concurrent parent and child cursors independent.
*/
sessionId?: Branded<'SessionId'>
/**
* Provider-neutral classification for an auxiliary model call. Adapters may
* map the purpose to model-hidden transport metadata. Ordinary conversation
* requests leave it unset.
*/
purpose?: 'compaction'
}
```
@@ -424,7 +430,7 @@ interface Agent {
}
```
`AgentStatus` is `'idle' | 'running' | 'disposed'`, and `SessionId` is branded. `running` describes the driver-wide drain interval, which can span turn close, its durability checkpoint, and consecutive queued turns; it does not prove a turn is still open. `AgentOptions` is merge-extensible and currently includes `provider?` and `model?`; dispatch requires both after `agent/request`. Persona belongs to `dsh-system-prompt`: an agent-scoped `deployment:persona` may shadow the global default.
`AgentStatus` is `'idle' | 'running' | 'disposed'`, and `SessionId` is branded. `running` describes the driver-wide drain interval, which can span turn close, its durability checkpoint, and consecutive queued turns; it does not prove a turn is still open. `AgentOptions` is merge-extensible: core declares `provider?` and `model?` (dispatch requires both after `agent/request`). Persona belongs to `dsh-system-prompt`: an agent-scoped `deployment:persona` may shadow the global default.
The cause is a TypeScript-enforced same-process input. An active holder copies its discriminant into the runtime-only `AbortSignal.reason`; it is retired before `turn/end` publication. `agentInterruptReasonOf(signal)` recognizes `user`, `parent`, and lifecycle-only `disposed` without consulting ambient initiator state. Durable `turn/end` retains the coarse `{ kind: 'aborted' }` outcome; request provenance would require a separate durable event rather than overloading the terminal result.

View File

@@ -20,15 +20,17 @@ interface AskUserQuestionOption {
## Question item
`AskUserQuestionItem` is one question in a request. The model supplies a stable `id`, which is echoed back with the answer so batched questions remain routable.
`AskUserQuestionItem` is one question in a request. The caller supplies a stable `id`, which is echoed back with the answer so batched questions remain routable. Optional `detail` carries supporting text that providers render with the question but keep out of selectable option labels.
```ts type-equiv
/** One question in an ask_user_question request. */
/** One question in a user-interaction request. */
interface AskUserQuestionItem {
/** Stable model-provided question id, echoed in the answer. */
/** Stable caller-provided question id, echoed in the answer. */
id: string
/** The question to display. */
question: string
/** Optional supporting detail rendered with the question but kept out of option labels. */
detail?: string
/** Optional short heading/group label. */
header?: string
/** Optional choices the UI can render as a menu. */

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
development.md: f0db7fbcb4a9df98e83d6c1edd5610e5cc4dd517
development.zh.md: 62e16479a49d5548e1fbd773dabca5bd741a24fe
development.md: 10406cebae1bf83fff663903b1478c9acb8476a1
development.zh.md: 50051ffd631518b37c3ad96f5fd3830cf6893ec9

View File

@@ -35,13 +35,13 @@ pnpm run typecheck
That first typecheck runs the package/vendor build graph and the root no-emit `tsconfig.json` graph for examples, tests, and scripts. The root graph uses the same source `paths` map but relies on project references so vendored code is checked under its own tsconfig settings.
If you are preparing to push from a fresh clone or worktree, also build once:
If a relevant local check consumes built package output, build once first:
```sh
pnpm run build
```
`pnpm run hygiene` includes `publint`, which validates package entrypoints against the built `lib/*.js` files, and `verify-node-next-types`, which validates built declarations against a temporary NodeNext consumer. A fresh worktree has no bundled JS or declarations until `pnpm run build` runs.
`pnpm run hygiene` includes `publint`, which validates package entrypoints against the built `lib/*.js` files, and `verify-node-next-types`, which validates built declarations against a temporary NodeNext consumer. A fresh worktree has no bundled JS or declarations until `pnpm run build` runs; ordinary commits and pushes do not require that build unless their selected checks consume it.
## Environment variables
@@ -56,14 +56,14 @@ DEEPSEEK_BASE_URL=https://... # optional
## Git hooks
lefthook is configured in `lefthook.yml` as an early local checkpoint before review:
lefthook is configured in `lefthook.yml` as a fast local checkpoint:
- `pre-commit` runs staged-file ESLint fixes, `pnpm run typecheck`, and the vendor manifest guard.
- `pre-push` runs `pnpm run check:pre-push`, whose scheduler runs runtime-closure verification, unit tests, duplication detection, snapshot tests, build, module-graph freshness, and the member gates of `pnpm run hygiene` and `pnpm run doc-sync` concurrently.
- `pre-commit` runs staged-file ESLint fixes, checks the staged diff for whitespace errors, and runs the vendor manifest guard.
- `pre-push` runs only the incremental repository typecheck.
The vendor manifest guard checks that changes under `vendor/*/src` are staged with the matching `vendor/README.md` manifest update. See `vendor/README.md` before editing vendored code.
These hooks do not exactly mirror CI. Notably, `pre-push` runs unit tests without coverage, while CI runs `pnpm run test:coverage`; CI also runs built-bin smoke tests and exercises the compatibility matrix on Node 22.19, 24, and 26.
The hooks intentionally do not run tests, snapshots, documentation checks, builds, or hygiene. Contributors run the [checks relevant to the changed behavior](../AGENTS.md#run-relevant-checks-locally) once; CI owns exhaustive coverage, built-artifact smokes, and the Node 22.19, 24, and 26 compatibility matrix.
## CI gates

View File

@@ -35,13 +35,13 @@ pnpm run typecheck
首次类型检查会执行 package/vendor 的构建图,以及根目录下用于示例、测试和脚本的 no-emit `tsconfig.json` 项目图。根图使用同一份源码 `paths` 映射,但依赖 project references因此 vendor 代码在它自己的 tsconfig 设置下被检查。
如果准备从新克隆或新 worktree 推送,还需要构建一次:
如果相关的本地检查需要使用构建后的包产物,请先构建一次:
```sh
pnpm run build
```
`pnpm run hygiene` 包含 `publint`(用构建出的 `lib/*.js` 文件校验 package 入口点)和 `verify-node-next-types`(用一个临时的 NodeNext 消费方校验构建出的声明文件)。新 worktree 在 `pnpm run build` 运行之前没有打包的 JS 和声明文件。
`pnpm run hygiene` 包含 `publint`(用构建出的 `lib/*.js` 文件校验 package 入口点)和 `verify-node-next-types`(用一个临时的 NodeNext 消费方校验构建出的声明文件)。新 worktree 在 `pnpm run build` 运行之前没有打包的 JS 和声明文件;普通提交和推送无需构建,除非所选检查会使用这些产物
## 环境变量
@@ -56,14 +56,14 @@ DEEPSEEK_BASE_URL=https://... # optional
## Git 钩子
lefthook 在 `lefthook.yml` 中配置,作为评审前的本地早期检查点:
lefthook 在 `lefthook.yml` 中配置,作为快速的本地检查点:
- `pre-commit` 运行对暂存文件的 ESLint 修复`pnpm run typecheck` vendor manifest元数据清单守卫
- `pre-push` 运行 `pnpm run check:pre-push`,其调度器并发运行 runtime-closure 校验、单元测试、重复代码检查、快照测试、构建、module-graph 新鲜度,以及 `pnpm run hygiene``pnpm run doc-sync` 的各成员门禁
- `pre-commit` 运行对暂存文件的 ESLint 修复,检查暂存 diff 中的空白错误,并运行 vendor manifest元数据清单守卫
- `pre-push` 运行仓库增量类型检查
vendor manifest 守卫检查 `vendor/*/src` 下的改动是否连同对应的 `vendor/README.md` manifest 更新一起暂存。请在编辑 vendor 代码前先阅读 `vendor/README.md`
这些钩子并不与 CI 完全一致。特别是:`pre-push` 运行不带覆盖率的单元测试,而 CI 运行 `pnpm run test:coverage`CI 还会运行 built-bin 冒烟测试,并在 Node 22.19、24 和 26 上执行兼容性矩阵。
这些钩子有意不运行测试、快照、文档检查、构建或 `hygiene`。贡献者只运行一次[与改动行为相关的检查](../AGENTS.md#run-relevant-checks-locally)CI 负责全量覆盖率门禁、构建产物冒烟测试,以及 Node 22.19、24 和 26 兼容性矩阵。
## CI 门禁

View File

@@ -11,29 +11,29 @@ This matrix shows which packages dispatch each harness-owned event and which pac
| `agent/cancel-requested` | `emit` | [`packages/core/agent/src/types.ts:201`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`goal-session`](../packages/goal/goal-session) |
| `agent/created` | `emit` | [`packages/core/agent/src/types.ts:163`](../packages/core/agent/src/types.ts) | [`agent`](../packages/core/agent) (`events.dispatch`) | [`goal-session`](../packages/goal/goal-session), [`tui`](../packages/ui/tui) |
| `agent/disposed` | `emit` | [`packages/core/agent/src/types.ts:172`](../packages/core/agent/src/types.ts) | [`agent`](../packages/core/agent) (`events.dispatch`) | [`agent-loop`](../packages/core/agent-loop), [`goal-session`](../packages/goal/goal-session), [`tui`](../packages/ui/tui) |
| `agent/error` | `emit` | [`packages/core/agent/src/types.ts:346`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`goal-session`](../packages/goal/goal-session), [`tui`](../packages/ui/tui) |
| `agent/error` | `emit` | [`packages/core/agent/src/types.ts:346`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`goal-session`](../packages/goal/goal-session), `runtime`, [`tui`](../packages/ui/tui) |
| `agent/post-step` | `serial` | [`packages/core/agent/src/types.ts:296`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`serial`) | [`compact-basic`](../packages/compact/compact-basic) |
| `agent/pre-step` | `serial` | [`packages/core/agent/src/types.ts:230`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`serial`) | [`time-context`](../packages/context/time-context), [`user-approval`](../packages/ui/user-approval) |
| `agent/prompt-submit` | `waterfall` | [`packages/core/agent/src/types.ts:243`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`acp`](../packages/ui/acp), [`goal-session`](../packages/goal/goal-session), [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard) |
| `agent/prompt-submit` | `waterfall` | [`packages/core/agent/src/types.ts:243`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`acp`](../packages/ui/acp), [`goal-session`](../packages/goal/goal-session), [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`plan-mode`](../packages/plan/plan-mode), [`repeat-tool-guard`](../packages/guard/repeat-tool-guard) |
| `agent/queued` | `emit` | [`packages/core/agent/src/types.ts:191`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`goal-session`](../packages/goal/goal-session) |
| `agent/request` | `waterfall` | [`packages/core/agent/src/types.ts:257`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`agent`](../packages/core/agent) |
| `agent/request-error` | `waterfall` | [`packages/core/agent/src/types.ts:311`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`compact-basic`](../packages/compact/compact-basic), [`llm-retry`](../packages/llm/llm-retry) |
| `agent/request-error` | `waterfall` | [`packages/core/agent/src/types.ts:311`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`compact-basic`](../packages/compact/compact-basic), [`llm-retry`](../packages/llm/llm-retry), [`plan-mode`](../packages/plan/plan-mode) |
| `agent/session-prefix` | `waterfall` | [`packages/core/agent/src/types.ts:272`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`tool-skill`](../packages/skill/tool-skill), [`workspace-context`](../packages/context/workspace-context) |
| `agent/session-start` | `emit` | [`packages/core/agent/src/types.ts:214`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`goal`](../packages/goal/goal), [`goal-session`](../packages/goal/goal-session), [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex) |
| `agent/status` | `emit` | [`packages/core/agent/src/types.ts:181`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`agent`](../packages/core/agent), [`goal-session`](../packages/goal/goal-session), [`tui`](../packages/ui/tui) |
| `agent/status` | `emit` | [`packages/core/agent/src/types.ts:181`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`agent`](../packages/core/agent), [`goal-session`](../packages/goal/goal-session), `runtime`, [`tui`](../packages/ui/tui) |
| `agent/step-result` | `waterfall` | [`packages/core/agent/src/types.ts:284`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | - |
| `agent/turn-continuation` | `waterfall` | [`packages/core/agent/src/types.ts:322`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex) |
| `agent/turn-continuation` | `waterfall` | [`packages/core/agent/src/types.ts:322`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`plan-mode`](../packages/plan/plan-mode) |
| `agent/turn-stop` | `serial` | [`packages/core/agent/src/types.ts:333`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`serial`) | [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`tool-goal`](../packages/goal/tool-goal) |
| `approval/request` | `waterfall` | [`packages/ui/user-approval/src/index.ts:31`](../packages/ui/user-approval/src/index.ts) | [`user-approval`](../packages/ui/user-approval) (`waterfall`) | [`acp`](../packages/ui/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/ui/acp) |
| `commands/change` | `emit` | [`packages/ui/commands/src/index.ts:103`](../packages/ui/commands/src/index.ts) | [`commands`](../packages/ui/commands) (`events.dispatch`) | [`acp`](../packages/ui/acp), [`tui`](../packages/ui/tui) |
| `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) |
| `fs/observed` | `emit` | [`packages/fs/fs/src/index.ts:71`](../packages/fs/fs/src/index.ts) | [`tool-fs`](../packages/fs/tool-fs) (`emit`) | [`fs-policy`](../packages/fs/fs-policy) |
| `fs/write-intent` | `waterfall` | [`packages/fs/fs/src/index.ts:54`](../packages/fs/fs/src/index.ts) | [`tool-fs`](../packages/fs/tool-fs) (`waterfall`) | [`fs-policy`](../packages/fs/fs-policy) |
| `goal/changed` | `emit` | [`packages/goal/goal/src/types.ts:167`](../packages/goal/goal/src/types.ts) | [`goal`](../packages/goal/goal) (`emit`) | [`goal-session`](../packages/goal/goal-session) |
| `llm/stream` | `waterfall` | [`packages/llm/llm/src/index.ts:52`](../packages/llm/llm/src/index.ts) | [`llm`](../packages/llm/llm) (`waterfall`) | [`agent-loop`](../packages/core/agent-loop), [`llm`](../packages/llm/llm), [`llm-replay`](../packages/support/llm-replay), [`session-title`](../packages/session-title/session-title) |
| `session/created` | `emit` | [`packages/core/session/src/index.ts:68`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`compact`](../packages/compact/compact), [`goal`](../packages/goal/goal), [`hook-protocol`](../packages/hooks/hook-protocol), [`jsonrpc`](../packages/ui/jsonrpc), [`llm-retry`](../packages/llm/llm-retry), [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence), [`user-approval`](../packages/ui/user-approval) |
| `session/disposed` | `emit` | [`packages/core/session/src/index.ts:78`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`agent-loop`](../packages/core/agent-loop), [`session-persistence`](../packages/session-persistence/session-persistence), [`session-title`](../packages/session-title/session-title) |
| `session/event` | `emit` | [`packages/core/session/src/index.ts:90`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`acp`](../packages/ui/acp), [`cli-demo`](../packages/examples/cli-demo), [`compact`](../packages/compact/compact), [`goal`](../packages/goal/goal), [`goal-session`](../packages/goal/goal-session), [`hook-protocol`](../packages/hooks/hook-protocol), [`jsonrpc`](../packages/ui/jsonrpc), [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence), [`session-title`](../packages/session-title/session-title), [`token-meter`](../packages/llm/token-meter), [`tui`](../packages/ui/tui), [`user-approval`](../packages/ui/user-approval), [`workspace-context`](../packages/context/workspace-context) |
| `session/created` | `emit` | [`packages/core/session/src/index.ts:68`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`compact`](../packages/compact/compact), [`goal`](../packages/goal/goal), [`hook-protocol`](../packages/hooks/hook-protocol), [`jsonrpc`](../packages/ui/jsonrpc), [`llm-retry`](../packages/llm/llm-retry), `runtime`, [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence), [`user-approval`](../packages/ui/user-approval) |
| `session/disposed` | `emit` | [`packages/core/session/src/index.ts:78`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`agent-loop`](../packages/core/agent-loop), `runtime`, [`session-persistence`](../packages/session-persistence/session-persistence), [`session-title`](../packages/session-title/session-title) |
| `session/event` | `emit` | [`packages/core/session/src/index.ts:90`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`acp`](../packages/ui/acp), [`cli-demo`](../packages/examples/cli-demo), [`compact`](../packages/compact/compact), [`goal`](../packages/goal/goal), [`goal-session`](../packages/goal/goal-session), [`hook-protocol`](../packages/hooks/hook-protocol), [`jsonrpc`](../packages/ui/jsonrpc), `runtime`, [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence), [`session-title`](../packages/session-title/session-title), [`token-meter`](../packages/llm/token-meter), [`tui`](../packages/ui/tui), [`user-approval`](../packages/ui/user-approval), [`workspace-context`](../packages/context/workspace-context) |
| `session/flush` | `parallel` | [`packages/core/session/src/index.ts:100`](../packages/core/session/src/index.ts) | [`session`](../packages/core/session) (`events.dispatch`) | [`session-persistence`](../packages/session-persistence/session-persistence) |
| `subagent/end` | `emit` | [`packages/subagent/subagent/src/index.ts:139`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`jsonrpc`](../packages/ui/jsonrpc), [`subagent`](../packages/subagent/subagent) |
| `subagent/provider-added` | `emit` | [`packages/subagent/subagent/src/index.ts:113`](../packages/subagent/subagent/src/index.ts) | [`subagent`](../packages/subagent/subagent) (`emit`) | [`subagent`](../packages/subagent/subagent), [`tool-subagent`](../packages/subagent/tool-subagent) |
@@ -57,7 +57,9 @@ This matrix shows which packages dispatch each harness-owned event and which pac
| Event string | Dispatchers | Listeners |
| --- | --- | --- |
| `internal/dispatch` | - | [`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), [`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/dispatch` | - | [`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), `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` | - | `webserver` |
| `internal/status` | - | [`agent`](../packages/core/agent) |
| `slots/changed` | `runtime` (`emit`) | - |
Maintenance mode: generated: Cordis event declarations and producer/listener edges are resolved from the repository TypeScript Program.

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
README.md: bd5d8c08a4c474a13342b6b60800cfe0d31e110b
README.zh.md: a53ab8d9d6053b39def34505038504fefc80a3f9
README.md: c4ddf44ad2497b4ff371918356ab1ec0698c7049
README.zh.md: 4a31af4fdee4db2d0362cf9117a6eef4fea32393

View File

@@ -21,7 +21,7 @@ This repo's documentation is read by people and agents both inside and outside t
## The gate: verify-translation-pairing
`pnpm run verify-translation-pairing` (part of `doc-sync`, so CI and the pre-push hook run it) enforces the contract mechanically:
`pnpm run verify-translation-pairing` (part of `doc-sync`, which contributors run locally for documentation changes and CI runs exhaustively) enforces the contract mechanically:
1. Every file listed as `required` in [scripts/translation-pairing.manifest.json](../../scripts/translation-pairing.manifest.json) has a complete pair.
2. Every pair that exists at all — required or not — is complete and consistent: all three files present, each side's current blob hash equals the recorded one (editing either side without re-confirming the pair goes red), both sides carry the language switcher, and the structural signatures match in order — heading depths, verbatim code blocks (info string and content), table row and column counts, list kinds, ordered-list starts, item counts, and every link target apart from the switcher.

View File

@@ -21,7 +21,7 @@
## 门禁verify-translation-pairing
`pnpm run verify-translation-pairing``doc-sync`(文档同步门禁)的一环,因此 CI 和 pre-push 钩子都会运行)机械地强制执行这份契约:
`pnpm run verify-translation-pairing``doc-sync`(文档同步门禁)的一环,贡献者会针对文档变更在本地运行CI 则会完整运行)机械地强制执行这份契约:
1. [scripts/translation-pairing.manifest.json](../../scripts/translation-pairing.manifest.json) 中 `required` 列出的每个文件都有完整配对。
2. 任何已存在的配对——无论是否 required——都完整且一致三个文件齐全、每一侧的当前 blob hash 等于记录值(改了任一侧而没重新确认配对就变红)、双方都带语言切换行、结构签名按序一致——标题深度、逐字节一致的代码块(信息字符串与内容)、表格行列数、列表类型、有序列表起始编号、列表项数量,以及除切换行之外的每个链接目标。

View File

@@ -86,6 +86,9 @@ flowchart TD
subgraph group_todo["packages/todo"]
pkg_tool_todo["tool-todo"]
end
subgraph group_plan["packages/plan"]
pkg_plan_mode["plan-mode"]
end
subgraph group_cordis["packages/cordis"]
pkg_tool_cordis["tool-cordis"]
end
@@ -126,6 +129,20 @@ flowchart TD
pkg_user_approval["user-approval"]
pkg_user_interaction["user-interaction"]
end
subgraph group_client["packages/client"]
pkg_client_connection["client-connection"]
pkg_client_i18n["client-i18n"]
pkg_client_runtime["client-runtime"]
pkg_client_ui_conversation["client-ui-conversation"]
pkg_client_ui_layout["client-ui-layout"]
pkg_client_ui_primitives["client-ui-primitives"]
pkg_client_ui_sidebar["client-ui-sidebar"]
pkg_client_ui_slots["client-ui-slots"]
pkg_client_ui_theme["client-ui-theme"]
pkg_client_ui_trajectory["client-ui-trajectory"]
pkg_client_web["client-web"]
pkg_client_web_react["client-web-react"]
end
subgraph group_code_runtime["packages/code-runtime"]
pkg_code_runtime["code-runtime"]
pkg_code_runtime_worker["code-runtime-worker"]
@@ -144,6 +161,11 @@ flowchart TD
subgraph group_guard["packages/guard"]
pkg_repeat_tool_guard["repeat-tool-guard"]
end
subgraph group_host["packages/host"]
pkg_host_apiproxy["host-apiproxy"]
pkg_host_runtime["host-runtime"]
pkg_host_webserver["host-webserver"]
end
subgraph group_lsp["packages/lsp"]
pkg_lsp["lsp"]
pkg_lsp_local["lsp-local"]
@@ -182,8 +204,23 @@ flowchart TD
pkg_acp_snapshot --> pkg_invariants
pkg_loader_smoke --> pkg_invariants
pkg_app_boot --> pkg_invariants
pkg_client_connection --> pkg_invariants
pkg_client_i18n --> pkg_invariants
pkg_client_runtime --> pkg_invariants
pkg_client_ui_conversation --> pkg_invariants
pkg_client_ui_layout --> pkg_invariants
pkg_client_ui_primitives --> pkg_invariants
pkg_client_ui_sidebar --> pkg_invariants
pkg_client_ui_slots --> pkg_invariants
pkg_client_ui_theme --> pkg_invariants
pkg_client_ui_trajectory --> pkg_invariants
pkg_client_web --> pkg_invariants
pkg_client_web_react --> pkg_invariants
pkg_code_runtime --> pkg_invariants
pkg_jsonrpc_demo --> pkg_invariants
pkg_host_apiproxy --> pkg_invariants
pkg_host_runtime --> pkg_invariants
pkg_host_webserver --> pkg_invariants
pkg_llm --> pkg_brand
pkg_llm --> pkg_invariants
pkg_code_runtime_worker --> pkg_code_runtime
@@ -462,6 +499,13 @@ flowchart TD
pkg_tool_todo --> pkg_invariants
pkg_tool_todo --> pkg_session
pkg_tool_todo --> pkg_tools
pkg_plan_mode --> pkg_agent
pkg_plan_mode --> pkg_commands
pkg_plan_mode --> pkg_invariants
pkg_plan_mode --> pkg_session
pkg_plan_mode --> pkg_system_prompt
pkg_plan_mode --> pkg_tools
pkg_plan_mode --> pkg_user_interaction
pkg_tool_cordis --> pkg_invariants
pkg_tool_cordis --> pkg_scope
pkg_tool_cordis --> pkg_tools
@@ -478,21 +522,6 @@ flowchart TD
pkg_agent_loop_testkit --> pkg_session
pkg_agent_loop_testkit --> pkg_system_prompt
pkg_agent_loop_testkit --> pkg_tools
pkg_acp --> pkg_agent
pkg_acp --> pkg_bash
pkg_acp --> pkg_commands
pkg_acp --> pkg_invariants
pkg_acp --> pkg_llm
pkg_acp --> pkg_llm_retry
pkg_acp --> pkg_permission
pkg_acp --> pkg_sandbox
pkg_acp --> pkg_session
pkg_acp --> pkg_session_persistence
pkg_acp --> pkg_session_title
pkg_acp --> pkg_system_prompt
pkg_acp --> pkg_tools
pkg_acp --> pkg_user_approval
pkg_acp --> pkg_user_interaction
pkg_tool_ask_user --> pkg_agent
pkg_tool_ask_user --> pkg_invariants
pkg_tool_ask_user --> pkg_tools
@@ -554,6 +583,22 @@ flowchart TD
pkg_hooks_claude --> pkg_session_persistence
pkg_hooks_claude --> pkg_subagent
pkg_hooks_claude --> pkg_tools
pkg_acp --> pkg_agent
pkg_acp --> pkg_bash
pkg_acp --> pkg_commands
pkg_acp --> pkg_invariants
pkg_acp --> pkg_llm
pkg_acp --> pkg_llm_retry
pkg_acp --> pkg_permission
pkg_acp --> pkg_plan_mode
pkg_acp --> pkg_sandbox
pkg_acp --> pkg_session
pkg_acp --> pkg_session_persistence
pkg_acp --> pkg_session_title
pkg_acp --> pkg_system_prompt
pkg_acp --> pkg_tools
pkg_acp --> pkg_user_approval
pkg_acp --> pkg_user_interaction
pkg_jsonrpc --> pkg_agent
pkg_jsonrpc --> pkg_invariants
pkg_jsonrpc --> pkg_llm
@@ -666,8 +711,23 @@ flowchart TD
| [`acp-snapshot`](../packages/support/acp-snapshot) | `support` | [`invariants`](../packages/support/invariants) |
| [`loader-smoke`](../packages/support/loader-smoke) | `support` | [`invariants`](../packages/support/invariants) |
| [`app-boot`](../packages/ui/app-boot) | `ui` | [`invariants`](../packages/support/invariants) |
| [`client-connection`](../packages/client/connection) | `client` | [`invariants`](../packages/support/invariants) |
| [`client-i18n`](../packages/client/i18n) | `client` | [`invariants`](../packages/support/invariants) |
| [`client-runtime`](../packages/client/runtime) | `client` | [`invariants`](../packages/support/invariants) |
| [`client-ui-conversation`](../packages/client/ui-conversation) | `client` | [`invariants`](../packages/support/invariants) |
| [`client-ui-layout`](../packages/client/ui-layout) | `client` | [`invariants`](../packages/support/invariants) |
| [`client-ui-primitives`](../packages/client/ui-primitives) | `client` | [`invariants`](../packages/support/invariants) |
| [`client-ui-sidebar`](../packages/client/ui-sidebar) | `client` | [`invariants`](../packages/support/invariants) |
| [`client-ui-slots`](../packages/client/ui-slots) | `client` | [`invariants`](../packages/support/invariants) |
| [`client-ui-theme`](../packages/client/ui-theme) | `client` | [`invariants`](../packages/support/invariants) |
| [`client-ui-trajectory`](../packages/client/ui-trajectory) | `client` | [`invariants`](../packages/support/invariants) |
| [`client-web`](../packages/client/web) | `client` | [`invariants`](../packages/support/invariants) |
| [`client-web-react`](../packages/client/web-react) | `client` | [`invariants`](../packages/support/invariants) |
| [`code-runtime`](../packages/code-runtime/code-runtime) | `code-runtime` | [`invariants`](../packages/support/invariants) |
| [`jsonrpc-demo`](../packages/examples/jsonrpc-demo) | `examples` | [`invariants`](../packages/support/invariants) |
| [`host-apiproxy`](../packages/host/apiproxy) | `host` | [`invariants`](../packages/support/invariants) |
| [`host-runtime`](../packages/host/runtime) | `host` | [`invariants`](../packages/support/invariants) |
| [`host-webserver`](../packages/host/webserver) | `host` | [`invariants`](../packages/support/invariants) |
| [`llm`](../packages/llm/llm) | `llm` | [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants) |
| [`code-runtime-worker`](../packages/code-runtime/code-runtime-worker) | `code-runtime` | [`code-runtime`](../packages/code-runtime/code-runtime), [`invariants`](../packages/support/invariants) |
| [`helper`](../packages/sdk/helper) | `sdk` | [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants) |
@@ -735,10 +795,10 @@ flowchart TD
| [`spill-policy`](../packages/spill/spill-policy) | `spill` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`retention`](../packages/util/retention), [`session`](../packages/core/session), [`spill`](../packages/spill/spill), [`tools`](../packages/core/tools) |
| [`timeout-policy`](../packages/timeout/timeout-policy) | `timeout` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`timeout`](../packages/util/timeout), [`tools`](../packages/core/tools) |
| [`tool-todo`](../packages/todo/tool-todo) | `todo` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`session`](../packages/core/session), [`tools`](../packages/core/tools) |
| [`plan-mode`](../packages/plan/plan-mode) | `plan` | [`agent`](../packages/core/agent), [`commands`](../packages/ui/commands), [`invariants`](../packages/support/invariants), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`user-interaction`](../packages/ui/user-interaction) |
| [`tool-cordis`](../packages/cordis/tool-cordis) | `cordis` | [`invariants`](../packages/support/invariants), [`scope`](../packages/core/scope), [`tools`](../packages/core/tools) |
| [`hooks-codex`](../packages/hooks/hooks-codex) | `hooks` | [`agent`](../packages/core/agent), [`hook-protocol`](../packages/hooks/hook-protocol), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence), [`tools`](../packages/core/tools) |
| [`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) |
| [`acp`](../packages/ui/acp) | `ui` | [`agent`](../packages/core/agent), [`bash`](../packages/bash/bash), [`commands`](../packages/ui/commands), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`permission`](../packages/ui/permission), [`sandbox`](../packages/sandbox/sandbox), [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence), [`session-title`](../packages/session-title/session-title), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`user-approval`](../packages/ui/user-approval), [`user-interaction`](../packages/ui/user-interaction) |
| [`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) |
| [`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) |
@@ -750,6 +810,7 @@ flowchart TD
| [`subagent-inprocess`](../packages/subagent/subagent-inprocess) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
| [`tool-subagent`](../packages/subagent/tool-subagent) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`tasks`](../packages/tasks/tasks), [`tools`](../packages/core/tools) |
| [`hooks-claude`](../packages/hooks/hooks-claude) | `hooks` | [`agent`](../packages/core/agent), [`hook-protocol`](../packages/hooks/hook-protocol), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
| [`acp`](../packages/ui/acp) | `ui` | [`agent`](../packages/core/agent), [`bash`](../packages/bash/bash), [`commands`](../packages/ui/commands), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`permission`](../packages/ui/permission), [`plan-mode`](../packages/plan/plan-mode), [`sandbox`](../packages/sandbox/sandbox), [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence), [`session-title`](../packages/session-title/session-title), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`user-approval`](../packages/ui/user-approval), [`user-interaction`](../packages/ui/user-interaction) |
| [`jsonrpc`](../packages/ui/jsonrpc) | `ui` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`llm-deepseek`](../packages/llm/llm-deepseek), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) |
| [`tui`](../packages/ui/tui) | `ui` | [`agent`](../packages/core/agent), [`agent-loop`](../packages/core/agent-loop), [`commands`](../packages/ui/commands), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`session`](../packages/core/session), [`session-title`](../packages/session-title/session-title), [`system-prompt`](../packages/core/system-prompt), [`token-meter`](../packages/llm/token-meter), [`tools`](../packages/core/tools), [`user-interaction`](../packages/ui/user-interaction) |
| [`agent-spine-demo`](../packages/examples/agent-spine-demo) | `examples` | [`agent`](../packages/core/agent), [`agent-loop`](../packages/core/agent-loop), [`goal`](../packages/goal/goal), [`goal-session`](../packages/goal/goal-session), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`paths`](../packages/util/paths), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-title`](../packages/session-title/session-title), [`skill`](../packages/skill/skill), [`skill-local`](../packages/skill/skill-local), [`system-prompt`](../packages/core/system-prompt), [`tasks`](../packages/tasks/tasks), [`tool-bash`](../packages/bash/tool-bash), [`tool-goal`](../packages/goal/tool-goal), [`tool-skill`](../packages/skill/tool-skill), [`tool-tasks`](../packages/tasks/tool-tasks), [`tools`](../packages/core/tools), [`workspace-context`](../packages/context/workspace-context) |

View File

@@ -106,7 +106,7 @@ Sources: [`packages/core/session/src/types.ts:276`](../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
@@ -122,7 +122,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
@@ -138,7 +138,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/*`
@@ -328,6 +328,21 @@ Source: [`packages/llm/llm-retry/src/index.ts:18`](../packages/llm/llm-retry/src
Source: [`packages/ui/permission/src/index.ts:36`](../packages/ui/permission/src/index.ts)
### `plan/*`
#### `plan/mode` — log-only
```ts persistence-catalog
/**
* Whether plan mode is in force from this point on: log-only, non-surface,
* whole-value replace. The last `plan/mode` wins; a log with none folds to
* inactive through {@link foldPlanMode}.
*/
'plan/mode': { active: boolean }
```
Source: [`packages/plan/plan-mode/src/index.ts:40`](../packages/plan/plan-mode/src/index.ts)
### `prompt/*`
#### `prompt/blocked` — log-only

View File

@@ -17,6 +17,7 @@ This table connects model-visible tool names to the plugin package and service s
| --- | --- | --- | --- | --- | --- |
| `@deepseek-ai/dsh-tool-ask-user` | `ask_user_question` | `ctx.tools`, `ctx.userInteraction` | `tool/call`, `tool/result after a UI/provider answers the question` | - | ask_user_question pauses the tool call until the active UI provider returns a human answer. |
| `@deepseek-ai/dsh-tools` | `run_code` | `ctx.tools`, `ctx.codeRuntime (execution time)`, `ctx.systemPrompt` | `tool/call`, `one tool/code-dispatch per bridged sub-call`, `tool/result` | - | Owned by the tool registry as a reserved transport outside filterable capability layers under `mode: code` / `mode: both` (see the Code Mode Agent Note). Under `code` it is the registry's only wire contribution; the other visible capabilities are declared in a generated TypeScript SDK section, and a program calls them through serialized bindings that re-enter the complete guarded tool pipeline and link each nested execution to this outer result. |
| `@deepseek-ai/dsh-plan-mode` | `exit_plan_mode` | `ctx.tools`, `ctx.systemPrompt`, `ctx.userInteraction (execution time, opportunistic)` | `tool/call`, `plan/mode inactive on an approved review`, `tool/result` | - | exit_plan_mode stays in the model-facing schema while planning is inactive so transitions add no tool-catalog churn on top of the plan-policy change. Its execute path rejects calls outside plan mode; in plan mode it presents the plan over the user-interaction seam (approve / keep planning with feedback), and approval logs plan mode inactive at the step boundary. |
| `@deepseek-ai/dsh-tool-bash` | `bash` | `ctx.tools`, `ctx.bash`, `ctx.tasks at call time for run_in_background` | `tool/call`, `tool/result` | - | The bash tool is the model-facing consumer of the bash executor seam. A `run_in_background` run registers with the generic `ctx.tasks` runtime and is collected/stopped through the `task_*` tools from `@deepseek-ai/dsh-tool-tasks`; the `enableRunInBackground` config (default true) removes the parameter entirely when disabled. |
| `@deepseek-ai/dsh-tool-cordis` | `cordis_inspect`, `cordis_mount`, `cordis_unmount` | `ctx.tools` | `tool/call`, `tool/result`, `live plugin-tree mutations (mount/unmount)` | - | Ships in examples/cordis-agent only (a deliberate opt-in — mounted code gets the real ctx, see .agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md). Plugins the model mounts may register ADDITIONAL model-visible tools at runtime; a full changed request header logs those tool-set changes. |
| `@deepseek-ai/dsh-tool-fs` | `edit`, `read`, `write` | `ctx.tools`, `ctx.fs`, `ctx.systemPrompt` | `tool/call`, `fs/write-intent or fs/edit-intent for mutations`, `fs/observed after successful file operations`, `tool/result` | - | The read-before-write/edit policy is added by `@deepseek-ai/dsh-fs-policy` (an `fs/*` event-gate plugin, no schema change); a deployment that loads these tools is expected to also load it. The tool schemas above are identical with or without the policy plugin. |
@@ -126,6 +127,31 @@ Source: [`packages/core/tools/src/code-mode.ts`](../packages/core/tools/src/code
Owned by the tool registry as a reserved transport outside filterable capability layers under `mode: code` / `mode: both` (see the Code Mode Agent Note). Under `code` it is the registry's only wire contribution; the other visible capabilities are declared in a generated TypeScript SDK section, and a program calls them through serialized bindings that re-enter the complete guarded tool pipeline and link each nested execution to this outer result.
## `@deepseek-ai/dsh-plan-mode`
### `exit_plan_mode`
Use only in plan mode. Present your plan for the user's review and, on approval, leave plan mode. Send the COMPLETE plan as markdown, starting with a # heading that names it. The user may approve (carry out the plan from your next step) or keep planning — their feedback comes back in the tool result; revise and present again.
```json
{
"type": "object",
"properties": {
"plan": {
"type": "string",
"description": "The complete plan, as markdown, starting with a # heading that names it."
}
},
"required": [
"plan"
]
}
```
Source: [`packages/plan/plan-mode/src/index.ts`](../packages/plan/plan-mode/src/index.ts)
exit_plan_mode stays in the model-facing schema while planning is inactive so transitions add no tool-catalog churn on top of the plan-policy change. Its execute path rejects calls outside plan mode; in plan mode it presents the plan over the user-interaction seam (approve / keep planning with feedback), and approval logs plan mode inactive at the step boundary.
## `@deepseek-ai/dsh-tool-bash`
### `bash`

107
docs/web-styling.md Normal file
View File

@@ -0,0 +1,107 @@
# Web GUI 样式规范
> **【token 体系已换代——§1 表格仅历史参考】** 本文的 `--bg-*`/`--text-*`/`--accent` token 族与其宿主包 `packages/client/web-ui` 已随插件化重构退役。现行 token 唯一来源=`packages/client/ui-theme/src/styles/` 的 `--dsw-*` 体系static 色阶+alias 语义层,暗色=`body[data-ds-dark-theme]` 覆写);组件对账基准=`missions/tasks/20260721-1520-web-plugin-rfc/style-spec.md`。**仍然有效**工程约束CSS Modules + clsx、无组件库、无 tailwind、组件禁 hardcode 色值)、字号成对写行高、间距 4 倍数、代码字体栈末位不放 monospace——这些已收编进 architecture.md §15。
> 状态:原「活文档」(随 `packages/client/web-ui` 演进)。视觉基线源自对 deepseekchat 前端仓的实测调研。框架决策与工程约束由 [web-styling-system RFC](../.agents/notes/implemented/process/2026-07-19-web-styling-system.md) 拍板,本文不重复论证。
## 1. 设计 token 表(权威定义)
所有 token 住 `packages/client/web-ui/src/style/global.css``:root` 亮色实值,`[data-theme='dark']` 块覆盖同名变量(未补全前列为占位)。组件 CSS 只引 token不出现字面量色值。
### 1.1 颜色(两层:注释里是 base 色板出处,变量名即语义别名)
| token | 亮色实值 | 暗色(占位) | 用途 |
| --- | --- | --- | --- |
| `--bg-base` | `#ffffff` | `#151517` | 页面底 |
| `--bg-layer` | `#ffffff` | `#232324` | 浮层/面板 |
| `--bg-sidebar` | `#f9fafb` | `#1b1b1c` | 侧边栏底 |
| `--text-primary` | `#0f1115` | `#f9fafb` | 正文 |
| `--text-secondary` | `#61666b` | `#cfd3d6` | 次要文字 |
| `--text-tertiary` | `#81858c` | `#adb2b8` | 辅助/说明 |
| `--border-l1` | `rgba(0,0,0,.04)` | `rgba(255,255,255,.06)` | 弱分隔(侧边栏右缘) |
| `--border-l2` | `rgba(0,0,0,.1)` | `rgba(255,255,255,.12)` | 常规边框 |
| `--hover-bg` | `rgba(38,49,72,.06)` | `rgba(255,255,255,.08)` | hover 态底 |
| `--active-bg` | `rgba(38,49,72,.1)` | `rgba(255,255,255,.14)` | 按压/激活态底 |
| `--accent` | `#3964fe` | `#5686fe` | 品牌蓝deepseek-500暗提亮一档 |
| `--accent-soft` | `#edf3fe` | `#28313f` | 淡品牌底(强调块) |
| `--accent-item` | `#e4edfd` | `#35363a` | 侧边栏选中条目底 |
| `--bubble-bg` | `#edf3fe` | `#2c2c2e` | 用户消息气泡底 |
| `--ok` / `--error` / `--warn` | `#22c55e` / `#ec1313` / `#f59e0b` | 同值 | 语义状态色 |
| `--text-on-solid` | `#ffffff` | 同值 | 实色底accent/error 徽标等)上的文字 |
| `--ok-soft` / `--error-soft` | `#e6faed` / `#fee2e2` | `#233c2c` / `#570c0c` | 语义状态软底徽章green-100/red-100暗为 900 档 |
| `--color-frame-mux` / `--color-frame-host` | `#8250df` / `#0969da` | 同值 | RPC 调试面板方向色(自有,非基线) |
| `--frame-mux-soft` / `--frame-host-soft` | `rgba(130,80,223,.1)` / `rgba(9,105,218,.1)` | 同色 `.24` | 方向色软底(徽章) |
| `--scroll-color` / `--scroll-color-hover` | `rgba(0,0,0,.08)` / `.15` | `rgba(255,255,255,.15)` / `.24` | 滚动条(`.scrollable` 专用) |
### 1.2 非颜色
| token | 值 | 说明 |
| --- | --- | --- |
| `--font-ui` | `Inter, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif` | 正文栈 |
| `--font-mono` | `Menlo, Monaco, Consolas, 'JetBrains Mono', 'Courier New', sans-serif` | 代码栈;**末位不放 monospace**(防 Windows 中文回退宋体) |
| `--fw-strong` | `600` | 粗体统一权重 |
| `--ease` | `cubic-bezier(.4,0,.2,1)` | 唯一缓动曲线 |
| `--dur` / `--dur-fast` / `--dur-slow` | `.2s` / `.1s` / `.3s` | 过渡三档 |
| `--radius-s` / `--radius-m` / `--radius-l` / `--radius-bubble` / `--radius-xl` | `8px` / `12px` / `16px` / `22px` / `24px` | 圆角语义档:小控件 / 列表条目与面板内块 / 浮层 / 气泡 / 输入卡片(基线 inputWrapper 同值);胶囊直接写 `999px` |
| `--shadow-panel` | `0 0 1px rgba(0,0,0,.2), 0 0 4px rgba(0,0,0,.02), 0 12px 32px rgba(0,0,0,.08)` | 浮层阴影(基线 lv3 |
| `--shadow-float` | `0 0 1px rgba(0,0,0,.24), 0 4px 12px rgba(0,0,0,.06), 0 16px 48px rgba(0,0,0,.16)` | 强浮动面板lv3 加强档,如 RPC 调试浮层) |
| `--shadow-card` | `0 4px 10px rgba(0,0,0,.02), 0 2px 4px rgba(0,0,0,.04)`;暗色 `none` | 输入卡片微阴影(基线:亮色同底靠边框+微影区分,暗色靠提亮底、阴影关闭) |
字号与间距**不 token 化**(基线仓同款决策):字号在组件里写 px 且**成对写行高**,常用对 16/24气泡、14/22UI 默认、12/18辅助间距用 4 的倍数。
## 2. 视觉基线(源自 deepseekchat
- 侧边栏:宽 `260px + 1px` 右边框(`--border-l1`);底色 `--bg-sidebar`
- 侧边栏条目:高 `40px`、圆角 `--radius-m`、字号 14pxhover 底 `--hover-bg` 或 sidebar 专属灰、**选中底 `--accent-item` 且不改文字色**。
- 侧边栏分组标题12px / weight 500 / `--text-tertiary` / sticky 顶部(底色同侧边栏遮滚动内容)。
- 会话列:`max-width: 840px` 居中,<1024px 降 712px。
- 消息流:**仅用户侧有气泡**——`--bubble-bg` 底、圆角 `--radius-bubble`、padding `10px 16px`、字号 16px/24px、`max-width: calc(100% - 88px)`**助手侧纯文档流无底色**。
- 消息操作条:默认 `opacity: 0`,父块 hover/focus-within 淡入(`--dur` + `--ease`)。
- 输入卡片与会话列同宽840px<1024px 降 712px)居中悬浮(距底留白带);圆角 `--radius-xl`、边框 `--border-l2`、底 `--bg-base`、阴影 `--shadow-card`;内部上下两段=textarea16px/24pxmin 2 行 max 14 行=336px镜像 div 自增高)+ 操作行(右下嵌 34px 主圆钮focus 无边框/阴影变化(基线同款)。
- 输入主按钮(拍板 2026-07-20 三连,视觉参照 Codex App32px 实心正圆图标钮(内联 SVG——空闲=`--accent` 底白↑箭头「发送」,运行中原地变 `--accent-soft` 底 accent ■「停止」(同色系不告警、不用红)。**运行中锁输入**(拍板 3取代早先 hover 菜单方案textarea disabled灰、草稿内容保留可见、无任何排队/插话菜单停止是唯一动作turn 结束解禁并 refocus。键盘 Enter=发送、Ctrl/Meta+Enter=换行(运行中键盘路径随锁失效)。
- 滚动条近隐形、hover 加深、`scrollbar-gutter: stable` 不占布局(统一走 `.scrollable`,见 §3-9
- RPC 四象限方向符(官方视觉词汇,空间隐喻:上=去 server、下=来自 server单线=unary、双线=SSE
| 符号 | 象限 | 徽章配色 |
| --- | --- | --- |
| `↑` | client-requestunary 出站) | `--accent` / `--accent-soft` |
| `↓` | server-responseunary 回包) | ok `--ok`/`--ok-soft`error `--error`/`--error-soft` |
| `⇟` | server-requestSSE 帧推送) | mux `--color-frame-mux`/`--frame-mux-soft`host `--color-frame-host`/`--frame-host-soft` |
| `⇞` | client-responseSSE 侧回应) | `--accent`/`--accent-soft` 降透明度 |
## 3. 样式编码规范review 对照打勾)
1. 颜色/圆角/动效/字体栈只引 §1 token组件 CSS 出现字面量色值即打回(渐变遮罩等特效除外,须注释说明)。
2. 组件 CSS 禁止出现 `[data-theme]` 选择器;暗色差异只在 global.css token 表做。确需按主题换非 token 值(渐变端点等),组件定义局部 CSS 变量、主题块只覆写变量(变量桥)。
3. 类名 camelCase状态类用单形容词`.active` `.show`),由 clsx 挂载:`clsx(styles.x, cond && styles.active, className)`
4. 对外组件必须透传 `className` 并合入根元素。
5. 禁用 `composes`;复用靠 token 与组件抽取。
6. `:global` 仅用于穿透第三方/跨包类名;禁止用它定义新全局类。
7. 交互过渡一律 `var(--dur*) var(--ease)`,只过渡 opacity / transform / 背景色 / 阴影;纯 hover 展示型元素包 `@media (hover: hover)`
8. hover/active 底色优先用透明度制 token叠任意海拔底色都成立不新造实色灰。
9. 滚动容器统一挂 global.css 的 `.scrollable` 工具类;组件内禁写 `::-webkit-scrollbar`
10. 媒体查询写在组件 css 尾部、贴着被覆盖规则;断点当前仅 1024px 一档(会话列降档),加第二档需先记入本文档。
11. 动态样式 JS 侧只写 CSS 变量(`style={{'--x': v}}`),规则留在 CSS禁止在 TSX 里拼接样式对象做主题/状态分支。
12. 文字灰阶只用 `--text-primary/secondary/tertiary` 三级,不新造灰色。
## 4. 文件组织
- `src/style/global.css` 固定分区顺序:① token 表(`:root` + `[data-theme='dark']`)② 全局基础box-sizing、body、button reset③ 全局工具类(`.scrollable` 等,总数保持个位数)。
- `*.module.css` 与组件同目录同名;一个组件一个 module 文件。
- 类型声明用现有 `css-modules.d.ts` 通配;组件数超 20 再评估引入 tcm 生成精确 `.css.d.ts`
- PostCSS 特性白名单:当前**零插件**(平铺 CSS + 原生嵌套按需);引入 nested/custom-media 需先记入本文档。
## 5. 演进规则与偏离记录
- **加新 token**:先进 §1 表含暗色占位列再在组件使用review 见到未入表的 `--` 新变量即打回(组件局部变量桥除外)。
- **偏离基线**:与 §2 任一常数不一致的实现,须在下方偏离表记一行(日期/项/理由)。
- **暗色表补全验收**`[data-theme='dark']` 覆盖 §1 全部占位列后,用 RPC 面板 + 侧边栏 + 会话流三个界面人工/截图核对一遍,无组件级主题选择器即达标。
| 日期 | 偏离项 | 理由 |
| --- | --- | --- |
| (空) | | |
## 6. 相关文档
- [web-styling-system RFC](../.agents/notes/implemented/process/2026-07-19-web-styling-system.md)(框架五条与工程约束的裁决记录)
- 客户端消费架构与分层协议:[Web 客户端架构 RFC](../.agents/notes/implemented/architecture/2026-07-19-gui-web-client-architecture.md)、[GUI 分层与 RPC 协议 RFC](../.agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.md)