docs: fix test and docs conflicts
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
*/
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { act, render } from '@testing-library/react'
|
||||
import type { StoredEntry } from '@deepseek-ai/dsh-client-ui-slots'
|
||||
import type { SessionMaybeProvideInfo, StoredEntry } from '@deepseek-ai/dsh-client-ui-slots'
|
||||
import { createSlotRenderer, type SlotRendererHost } from '@deepseek-ai/dsh-client-web-react'
|
||||
|
||||
function observable<T>(initial: T) {
|
||||
@@ -25,7 +25,8 @@ function observable<T>(initial: T) {
|
||||
type UseProjectionProp = (key: string, selector?: (v: unknown) => unknown) => unknown
|
||||
|
||||
function makeHost() {
|
||||
const current = observable<string | undefined>(undefined)
|
||||
const absentInfo: SessionMaybeProvideInfo = { sessionId: undefined, hooks: { session: undefined }, props: {} }
|
||||
const provide = observable<SessionMaybeProvideInfo>(absentInfo)
|
||||
const cells = new Map<string, ReturnType<typeof observable<unknown>>>()
|
||||
/** Store-parallel face: always defined per key; an unseen key snapshots undefined. */
|
||||
const absent = { getSnapshot: () => undefined, subscribe: () => () => {} }
|
||||
@@ -37,7 +38,7 @@ function makeHost() {
|
||||
options: {},
|
||||
children: { 'k.session': { kind: 'single', scope: 'session' } },
|
||||
}
|
||||
const info = (id: string) => ({
|
||||
const info = (id: string): SessionMaybeProvideInfo => ({
|
||||
sessionId: id,
|
||||
hooks: { session: { getSnapshot: () => ({ sid: id }), subscribe: () => () => {} } },
|
||||
props: {},
|
||||
@@ -52,16 +53,16 @@ function makeHost() {
|
||||
storeOf: () => undefined,
|
||||
sessions: {
|
||||
list: observable<unknown>({ ids: [] }),
|
||||
current,
|
||||
provideInfo: id => info(id),
|
||||
maybeProvideInfo: id => (id === undefined
|
||||
? { sessionId: undefined, hooks: { session: undefined }, props: {} }
|
||||
: info(id)),
|
||||
provideInfo: provide,
|
||||
},
|
||||
workspaces: { list: observable<unknown>({ items: [] }) },
|
||||
}
|
||||
return {
|
||||
host, current, cells,
|
||||
host,
|
||||
cells,
|
||||
// Same driver surface as before the atomic provide source: set(id)
|
||||
// publishes the resolved bundle (or the absent projection) through it.
|
||||
current: { set: (id: string | undefined) => { provide.set(id === undefined ? absentInfo : info(id)) } },
|
||||
dropFace: () => { withFace = false },
|
||||
registerSession: (entry: StoredEntry) => { sessionEntries.push(entry) },
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [
|
||||
},
|
||||
{
|
||||
signature: 'async execute( agent: Agent, line: string, signal: AbortSignal, ): Promise<CommandExecution | undefined>',
|
||||
jsDoc: '/**\n * Parse and execute a known command without sending it to the model.\n *\n * A resolved command\'s lifecycle is durably logged: `command/run` is\n * appended before the handler is invoked and `command/done` after\n * settlement (a thrown or aborted handler settles as `kind: \'error\'`).\n * Admission misses (syntax or unknown name) log nothing — they never\n * entered a handler. A `command/run` append failure fails the execution\n * loud; a `command/done` append failure on the handler-failure path is\n * contained so the handler\'s own error stays the reported failure.\n *\n * @param agent - exact receiving agent.\n * @param line - complete slash-command line.\n * @param signal - cancellation signal owned by the UI request.\n * @returns the settled execution (result + lifecycle pairing id), or\n * `undefined` when syntax or name does not resolve.\n */',
|
||||
jsDoc: '/**\n * Parse and execute a known command without sending it to the model.\n *\n * A resolved command\'s lifecycle is logged: `command/run` is appended\n * before the handler is invoked and `command/done` after settlement (a\n * thrown or aborted handler settles as `kind: \'error\'`). Both are direct\n * log-only appends — no turn wraps them, and persistence drains them at\n * ordinary checkpoints. Admission misses (syntax or unknown name) log\n * nothing — they never entered a handler. A `command/run` append failure\n * fails the execution loud; a `command/done` append failure on the\n * handler-failure path is contained so the handler\'s own error stays the\n * reported failure.\n *\n * @param agent - exact receiving agent.\n * @param line - complete slash-command line.\n * @param signal - cancellation signal owned by the UI request.\n * @returns the settled execution (result + lifecycle pairing id), or\n * `undefined` when syntax or name does not resolve.\n */',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -26,10 +26,6 @@ declare module '@deepseek-ai/dsh-session' {
|
||||
interface SessionEventMap {
|
||||
'test/mark': { marks: string[] }
|
||||
}
|
||||
|
||||
interface OutOfBandSessionEventMap {
|
||||
'test/mark': true
|
||||
}
|
||||
}
|
||||
|
||||
/** Whole-value unit: latest test/mark event wins; unrelated events return the same reference. */
|
||||
|
||||
@@ -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/ui/commands/README.md
|
||||
README.md: 139a21857b41c7e352ee6a0746e4959b218881e8
|
||||
README.zh.md: 466c02ab3699b26e5c946b3442c28e6f0fc93d89
|
||||
README.md: 4ad72cf9e232c8d41e525f42eecde5637032a391
|
||||
README.zh.md: bace8f6346ac737a838d802dfc5c6ffe52c56edd
|
||||
|
||||
@@ -8,7 +8,7 @@ Plugin-owned human-command registry consumed by interactive UI adapters. The [pl
|
||||
|
||||
`ctx.commands.register(definition)` registers one lowercase command name, description, optional unstructured-input hint, and abortable handler. A registered command is available to every composed command adapter; a plugin that is incompatible with a deployment does not register there. A plain-context registration is global. A command-producing plugin mounted beneath `agent.ctx` declares its own `commands` injection and creates an exact agent-scoped definition; it shadows a global definition with the same name. This child-injection shape preserves the agent scope without making the core agent loop depend on a UI service. Duplicate names within one layer fail during registration. Every disposer is the exact Cordis effect disposer, and registration or removal notifies every `commands/change` observer so live adapters can refresh discovery; observer failures are logged and cannot veto the registry mutation or starve later observers.
|
||||
|
||||
`list(agent)` returns immutable, name-sorted descriptors after scoped shadowing. `find(agent, name)` returns the corresponding definition. `execute(agent, line, signal)` uses `parseCommand()` and runs only a known command, returning the settled `CommandExecution` (the normalized result plus the lifecycle pairing `commandId`) or `undefined` for invalid syntax or unknown names. A resolved command's lifecycle is durably logged on the receiving agent's session as the log-only pair `command/run` (before the handler, with a minted `commandId`, the parser's structured `name`/`args` split, and the issuing `CommandSource`) and `command/done` (at settlement, with the outcome kind and verbatim text; a thrown or aborted handler settles as `kind: 'error'`). Admission misses log nothing. Lifecycle appends are serialized per session through `SessionStore.appendOutOfBand`, so the service requires a composed `sessions` service.
|
||||
`list(agent)` returns immutable, name-sorted descriptors after scoped shadowing. `find(agent, name)` returns the corresponding definition. `execute(agent, line, signal)` uses `parseCommand()` and runs only a known command, returning the settled `CommandExecution` (the normalized result plus the lifecycle pairing `commandId`) or `undefined` for invalid syntax or unknown names. A resolved command's lifecycle is logged on the receiving agent's session as the log-only pair `command/run` (before the handler, with a minted `commandId`, the parser's structured `name`/`args` split, and the issuing `CommandSource`) and `command/done` (at settlement, with the outcome kind and verbatim text; a thrown or aborted handler settles as `kind: 'error'`). Admission misses log nothing. Both are direct standalone appends on the receiving agent's session: no turn wraps them, and persistence drains them through ordinary checkpoints and teardown.
|
||||
|
||||
`parseCommand()` recognizes a slash at byte zero, a lowercase name containing letters, digits, `_`, or `-`, and either end-of-input or whitespace. It returns every byte after the name as `rawInput`, including separator whitespace; consumers own their command-specific grammar and may normalize only what that grammar permits.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
`ctx.commands.register(definition)` 注册一个小写命令名称、描述、可选的非结构化输入提示,以及可中止的处理器。每个已注册命令都可供所有已组合的命令适配器使用;与某项部署不兼容的插件不会在此注册。普通上下文中的注册全局生效。在 `agent.ctx` 下挂载的命令生产插件会声明自身的 `commands` 注入,并创建精确限定到该 agent 的定义;该定义会遮蔽同名的全局定义。这种子级注入形态保留了 agent 作用域,同时不会让核心 agent loop 依赖 UI 服务。同一层中的名称重复会在注册时失败。每个 disposer 都是 Cordis effect 返回的确切 disposer;注册或移除命令时,系统会通知每个 `commands/change` 观察者,使实时适配器能够刷新发现结果。观察者失败会写入日志,既不能否决注册表变更,也不能阻止后续观察者运行。
|
||||
|
||||
`list(agent)` 在应用作用域遮蔽后,返回按名称排序的不可变描述符。`find(agent, name)` 返回相应定义。`execute(agent, line, signal)` 使用 `parseCommand()`,且只运行已知命令,返回已结算的 `CommandExecution`(规范化结果加生命周期配对 `commandId`);语法无效或名称未知时返回 `undefined`。已解析命令的生命周期会以 log-only 事件对的形式持久记录在接收 agent 的会话日志中:`command/run`(进入处理器前记录,携带铸造的 `commandId`、解析器的结构化 `name`/`args` 切分和发起方 `CommandSource`)与 `command/done`(结算时记录,携带结局种类与原样文本;处理器抛出或被中止时以 `kind: 'error'` 结算)。未通过准入的输入不记录任何事件。生命周期落账通过 `SessionStore.appendOutOfBand` 按会话串行化,因此本服务要求组合中存在 `sessions` 服务。
|
||||
`list(agent)` 在应用作用域遮蔽后,返回按名称排序的不可变描述符。`find(agent, name)` 返回相应定义。`execute(agent, line, signal)` 使用 `parseCommand()`,且只运行已知命令,返回已结算的 `CommandExecution`(规范化结果加生命周期配对 `commandId`);语法无效或名称未知时返回 `undefined`。已解析命令的生命周期会以 log-only 事件对的形式记录在接收 agent 的会话日志中:`command/run`(进入处理器前记录,携带铸造的 `commandId`、解析器的结构化 `name`/`args` 切分和发起方 `CommandSource`)与 `command/done`(结算时记录,携带结局种类与原样文本;处理器抛出或被中止时以 `kind: 'error'` 结算)。未通过准入的输入不记录任何事件。两者都是直接独立追加:没有轮次包裹它们,持久化在常规检查点与 teardown 时排空它们。
|
||||
|
||||
`parseCommand()` 识别位于字节零位置的斜杠、由小写字母、数字、`_` 或 `-` 构成的名称,以及名称后紧接输入末尾或空白的形式。它将名称后的每个字节作为 `rawInput` 返回,其中包括分隔空白;消费方拥有各命令专用的语法,只能执行该语法允许的规范化。
|
||||
|
||||
|
||||
@@ -314,10 +314,9 @@ describe('CommandService', () => {
|
||||
expect(ids[0]).toBe(ids[1])
|
||||
// The execution's pairing id is the logged one (RPC-level correlation).
|
||||
expect(execution?.commandId).toBe(ids[0])
|
||||
// Zero-step wrap: the pair stays turn-enclosed on an idle log.
|
||||
// Direct log-only appends: no turn is opened for the pair on an idle log.
|
||||
expect(agent.session.events.map(event => event.type)).toEqual([
|
||||
'turn/start', 'command/run', 'turn/end',
|
||||
'turn/start', 'command/done', 'turn/end',
|
||||
'command/run', 'command/done',
|
||||
])
|
||||
})
|
||||
|
||||
|
||||
@@ -16,54 +16,54 @@ buffer
|
||||
5| "Model wait 0.0s · Completed 2026-07-21 15:05:00 "
|
||||
style 0-46 dim
|
||||
6| <blank>
|
||||
7| "provider stream failed after partial output "
|
||||
style 0-42 fg=red
|
||||
8| <blank>
|
||||
9| "The previous process ended during this turn. "
|
||||
style 0-43 fg=yellow
|
||||
10| <blank>
|
||||
11| "Turn stopped: the agent was disposed. "
|
||||
style 0-36 fg=yellow
|
||||
12| <blank>
|
||||
13| "Turn ended: plugin-policy. "
|
||||
style 0-25 fg=yellow
|
||||
14| <blank>
|
||||
15| "Unknown command: /unknown-advanced-command "
|
||||
style 0-41 fg=yellow
|
||||
16| <blank>
|
||||
17| "Keyboard shortcuts "
|
||||
7| "Keyboard shortcuts "
|
||||
style 0-17 fg=bright-blue bold
|
||||
18| "Enter send • Shift/Alt+Enter newline • Up/Down prompt history "
|
||||
8| "Enter send • Shift/Alt+Enter newline • Up/Down prompt history "
|
||||
style 0-60 fg=bright-black
|
||||
19| "Esc cancel active turn • Ctrl+O toggle tool cards • Ctrl+R toggle reasoning "
|
||||
9| "Esc cancel active turn • Ctrl+O toggle tool cards • Ctrl+R toggle reasoning "
|
||||
style 0-74 fg=bright-black
|
||||
20| "Ctrl+C cancel while running; clear input or exit while idle • Ctrl+D exit "
|
||||
10| "Ctrl+C cancel while running; clear input or exit while idle • Ctrl+D exit "
|
||||
style 0-72 fg=bright-black
|
||||
21| " "
|
||||
22| "/clear — Clear the transcript view (session history is unchanged) "
|
||||
11| " "
|
||||
12| "/clear — Clear the transcript view (session history is unchanged) "
|
||||
style 0-64 fg=bright-black
|
||||
23| "/exit — Exit after the active turn reaches idle "
|
||||
13| "/exit — Exit after the active turn reaches idle "
|
||||
style 0-46 fg=bright-black
|
||||
24| "/help — Show keyboard shortcuts and commands "
|
||||
14| "/help — Show keyboard shortcuts and commands "
|
||||
style 0-43 fg=bright-black
|
||||
25| "/model [[provider/]model] — Show or switch this session's model "
|
||||
15| "/model [[provider/]model] — Show or switch this session's model "
|
||||
style 0-62 fg=bright-black
|
||||
26| "/quit — Exit after the active turn reaches idle "
|
||||
16| "/quit — Exit after the active turn reaches idle "
|
||||
style 0-46 fg=bright-black
|
||||
27| "/reasoning — Toggle reasoning blocks "
|
||||
17| "/reasoning — Toggle reasoning blocks "
|
||||
style 0-35 fg=bright-black
|
||||
28| "/redraw — Invalidate components and redraw the terminal "
|
||||
18| "/redraw — Invalidate components and redraw the terminal "
|
||||
style 0-54 fg=bright-black
|
||||
29| "/reload — EXPERIMENTAL (dev): re-read loader config files and apply the diff (idle only) "
|
||||
19| "/reload — EXPERIMENTAL (dev): re-read loader config files and apply the diff (idle only) "
|
||||
style 0-87 fg=bright-black
|
||||
30| "/resume — List this workspace's resumable sessions "
|
||||
20| "/resume — List this workspace's resumable sessions "
|
||||
style 0-49 fg=bright-black
|
||||
31| "/status — Show session diagnostics, system prompt, and registered tools "
|
||||
21| "/status — Show session diagnostics, system prompt, and registered tools "
|
||||
style 0-70 fg=bright-black
|
||||
32| "/tools — Expand or collapse all tool cards "
|
||||
22| "/tools — Expand or collapse all tool cards "
|
||||
style 0-41 fg=bright-black
|
||||
33| "/skill:<name> [instructions] — load a skill into the conversation "
|
||||
23| "/skill:<name> [instructions] — load a skill into the conversation "
|
||||
style 0-64 fg=bright-black
|
||||
24| <blank>
|
||||
25| "provider stream failed after partial output "
|
||||
style 0-42 fg=red
|
||||
26| <blank>
|
||||
27| "The previous process ended during this turn. "
|
||||
style 0-43 fg=yellow
|
||||
28| <blank>
|
||||
29| "Turn stopped: the agent was disposed. "
|
||||
style 0-36 fg=yellow
|
||||
30| <blank>
|
||||
31| "Turn ended: plugin-policy. "
|
||||
style 0-25 fg=yellow
|
||||
32| <blank>
|
||||
33| "Unknown command: /unknown-advanced-command "
|
||||
style 0-41 fg=yellow
|
||||
34| <blank>
|
||||
35| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
|
||||
style 0-17 fg=bright-blue bold
|
||||
|
||||
@@ -16,54 +16,54 @@ buffer
|
||||
5| "Model wait 0.0s · Completed 2026-07-21 15:05:00 "
|
||||
style 0-46 dim
|
||||
6| <blank>
|
||||
7| "provider stream failed after partial output "
|
||||
style 0-42 fg=red
|
||||
8| <blank>
|
||||
9| "The previous process ended during this turn. "
|
||||
style 0-43 fg=yellow
|
||||
10| <blank>
|
||||
11| "Turn stopped: the agent was disposed. "
|
||||
style 0-36 fg=yellow
|
||||
12| <blank>
|
||||
13| "Turn ended: plugin-policy. "
|
||||
style 0-25 fg=yellow
|
||||
14| <blank>
|
||||
15| "Unknown command: /unknown-advanced-command "
|
||||
style 0-41 fg=yellow
|
||||
16| <blank>
|
||||
17| "Keyboard shortcuts "
|
||||
7| "Keyboard shortcuts "
|
||||
style 0-17 fg=bright-blue bold
|
||||
18| "Enter send • Shift/Alt+Enter newline • Up/Down prompt history "
|
||||
8| "Enter send • Shift/Alt+Enter newline • Up/Down prompt history "
|
||||
style 0-60 fg=bright-black
|
||||
19| "Esc cancel active turn • Ctrl+O toggle tool cards • Ctrl+R toggle reasoning "
|
||||
9| "Esc cancel active turn • Ctrl+O toggle tool cards • Ctrl+R toggle reasoning "
|
||||
style 0-74 fg=bright-black
|
||||
20| "Ctrl+C cancel while running; clear input or exit while idle • Ctrl+D exit "
|
||||
10| "Ctrl+C cancel while running; clear input or exit while idle • Ctrl+D exit "
|
||||
style 0-72 fg=bright-black
|
||||
21| " "
|
||||
22| "/clear — Clear the transcript view (session history is unchanged) "
|
||||
11| " "
|
||||
12| "/clear — Clear the transcript view (session history is unchanged) "
|
||||
style 0-64 fg=bright-black
|
||||
23| "/exit — Exit after the active turn reaches idle "
|
||||
13| "/exit — Exit after the active turn reaches idle "
|
||||
style 0-46 fg=bright-black
|
||||
24| "/help — Show keyboard shortcuts and commands "
|
||||
14| "/help — Show keyboard shortcuts and commands "
|
||||
style 0-43 fg=bright-black
|
||||
25| "/model [[provider/]model] — Show or switch this session's model "
|
||||
15| "/model [[provider/]model] — Show or switch this session's model "
|
||||
style 0-62 fg=bright-black
|
||||
26| "/quit — Exit after the active turn reaches idle "
|
||||
16| "/quit — Exit after the active turn reaches idle "
|
||||
style 0-46 fg=bright-black
|
||||
27| "/reasoning — Toggle reasoning blocks "
|
||||
17| "/reasoning — Toggle reasoning blocks "
|
||||
style 0-35 fg=bright-black
|
||||
28| "/redraw — Invalidate components and redraw the terminal "
|
||||
18| "/redraw — Invalidate components and redraw the terminal "
|
||||
style 0-54 fg=bright-black
|
||||
29| "/reload — EXPERIMENTAL (dev): re-read loader config files and apply the diff (idle only) "
|
||||
19| "/reload — EXPERIMENTAL (dev): re-read loader config files and apply the diff (idle only) "
|
||||
style 0-87 fg=bright-black
|
||||
30| "/resume — List this workspace's resumable sessions "
|
||||
20| "/resume — List this workspace's resumable sessions "
|
||||
style 0-49 fg=bright-black
|
||||
31| "/status — Show session diagnostics, system prompt, and registered tools "
|
||||
21| "/status — Show session diagnostics, system prompt, and registered tools "
|
||||
style 0-70 fg=bright-black
|
||||
32| "/tools — Expand or collapse all tool cards "
|
||||
22| "/tools — Expand or collapse all tool cards "
|
||||
style 0-41 fg=bright-black
|
||||
33| "/skill:<name> [instructions] — load a skill into the conversation "
|
||||
23| "/skill:<name> [instructions] — load a skill into the conversation "
|
||||
style 0-64 fg=bright-black
|
||||
24| <blank>
|
||||
25| "provider stream failed after partial output "
|
||||
style 0-42 fg=red
|
||||
26| <blank>
|
||||
27| "The previous process ended during this turn. "
|
||||
style 0-43 fg=yellow
|
||||
28| <blank>
|
||||
29| "Turn stopped: the agent was disposed. "
|
||||
style 0-36 fg=yellow
|
||||
30| <blank>
|
||||
31| "Turn ended: plugin-policy. "
|
||||
style 0-25 fg=yellow
|
||||
32| <blank>
|
||||
33| "Unknown command: /unknown-advanced-command "
|
||||
style 0-41 fg=yellow
|
||||
34| <blank>
|
||||
35| "/workspace/project (tui-staging) deepseek-v4-flash ↑0 ↓0 0% context"
|
||||
style 0-17 fg=bright-blue bold
|
||||
|
||||
@@ -2182,8 +2182,8 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
||||
|
||||
expect(result.terminal.output).toContain('untitled')
|
||||
expect(result.terminal.output).toContain('unset (effort unset; reasoning blocks shown)')
|
||||
// An empty log gains the /status invocation's zero-step wrap: turn/start + command/run + turn/end.
|
||||
expect(result.terminal.output).toContain('idle · 3 events · 1 turn · 0 steps · 0 tool calls')
|
||||
// The /status invocation's command/run lands directly on the empty log — no turn wraps it.
|
||||
expect(result.terminal.output).toContain('idle · 1 event · 0 turns · 0 steps · 0 tool calls')
|
||||
expect(result.terminal.output).toContain('n/a (0 read + 0 write)')
|
||||
expect(result.terminal.output).toContain('7 used · capacity unknown')
|
||||
expect(result.terminal.output).toContain('2026-07-22 10:11:12 UTC')
|
||||
|
||||
Reference in New Issue
Block a user