refactor: apply repository naming contract

Apply the accepted pre-release package, service, type, directory, and role renames as one repository-wide change.
This commit is contained in:
Tianyi Cui
2026-08-13 00:36:22 +08:00
parent 101df7cf58
commit a2d0f7f411
3281 changed files with 21730 additions and 21592 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 packages/client/ui-skill/README.md
README.md: f6818ae9f44a7d0a484302fe8e294ee2159890ec
README.zh.md: 2def01566d6ab388f3501a4f8e24075f073d4e22
README.md: f2e2ec8a3061f2cd8617123013d63fad63abf237
README.zh.md: 0d450b224a7cddcbaef008c7639075cb9f60ece9

View File

@@ -2,7 +2,7 @@
English | [中文](README.zh.md)
Skill invocation source, browser half: registers the `/`-trigger `skill` source into `ctx.slash`. Ordinary-session candidates come from the `skill.list` RPC addressed by the per-call `ClientSessionContext` projection's `{sessionId}`, with the host resolving `cwd` from the session header. The host serves every user-invocable skill; a `modelInvocable: false` entry (a `disable-model-invocation` skill, whose only entry point is this path) wears the user-only marker as a description prefix in the active language. Catalog-addressed continuable children resolve no skill candidates locally because the existing skill RPC requires an attached session; viewing their persisted history must not activate them. Catalogs cache per ordinary session with a single-flight fetch; the scope-birth `warm` hook prewarms the session's entry, the forwarded `agent-preset/selected` owner event drops that one session's entry (the catalog belongs to the preset, and a blank session may switch after the warm), and `connection/reset` clears everything. Results filter by `startsWith(query)`.
Skill invocation source, browser half: registers the `/`-trigger `skill` source into `ctx.inputTriggers`. Ordinary-session candidates come from the `skill.list` RPC addressed by the per-call `ClientSessionContext` projection's `{sessionId}`, with the host resolving `cwd` from the session header. The host serves every user-invocable skill; a `modelInvocable: false` entry (a `disable-model-invocation` skill, whose only entry point is this path) wears the user-only marker as a description prefix in the active language. Catalog-addressed continuable children resolve no skill candidates locally because the existing skill RPC requires an attached session; viewing their persisted history must not activate them. Catalogs cache per ordinary session with a single-flight fetch; the scope-birth `warm` hook prewarms the session's entry, the forwarded `agent-preset/selected` owner event drops that one session's entry (the catalog belongs to the preset, and a blank session may switch after the warm), and `connection/reset` clears everything. Results filter by `startsWith(query)`.
A pick lands the literal `/name ` text and the prompt ships the same literal ([slash-pipeline Agent Note](../../../.agents/notes/implemented/architecture/2026-07-25-web-input-machine-and-slash-pipeline.md)) — this source implements no adjudication hooks and no reference codec. Determinism lives host-side: the pre-step gesture boundary (`dsh-tool-skill`) recognizes whitespace-bounded `/name` tokens naming user-invocable skills anywhere in a user message and injects the rendered `<skill_content>` for every entry point, so a menu pick, a hand-typed token, and a TUI/ACP prompt all load the skill the same way. A name shared with a host command still resolves to the command: adjudication claims the line client-side before it ever becomes a prompt — deliberate precedence, matching peer products. The list RPC rides the plugin's root-context connection captured at registration — the source never reads services off a per-call argument; draft chip visuals derive from the `lexicon` scan.

View File

@@ -2,7 +2,7 @@
[English](README.md) | 中文
skill技能调用 source 的浏览器端:把 `/` 触发的 `skill` source 注册进 `ctx.slash`。普通会话的候选来自 `skill.list` RPC以每次调用的 `ClientSessionContext` 投影中的 `{sessionId}` 寻址host 从会话 header 解析 `cwd`。宿主提供每一个用户可调用的 skill`modelInvocable: false` 的条目(即 `disable-model-invocation` skill此路径是其唯一入口会以当前语言把仅限用户标记作为描述前缀带上。由目录寻址的可继续 subagent 在客户端解析为没有 skill 候选,因为现有 skill RPC 要求会话已挂载;查看其持久化历史不得激活它。目录按普通会话缓存,拉取走 single-flightscope 创建时的 `warm` 钩子预热该会话的缓存项,转发的 owner 事件 `agent-preset/selected` 丢弃该会话这一项(目录属于 preset而空会话可能在预热之后才切换`connection/reset` 清空全部缓存。结果按 `startsWith(query)` 过滤。
skill技能调用 source 的浏览器端:把 `/` 触发的 `skill` source 注册进 `ctx.inputTriggers`。普通会话的候选来自 `skill.list` RPC以每次调用的 `ClientSessionContext` 投影中的 `{sessionId}` 寻址host 从会话 header 解析 `cwd`。宿主提供每一个用户可调用的 skill`modelInvocable: false` 的条目(即 `disable-model-invocation` skill此路径是其唯一入口会以当前语言把仅限用户标记作为描述前缀带上。由目录寻址的可继续 subagent 在客户端解析为没有 skill 候选,因为现有 skill RPC 要求会话已挂载;查看其持久化历史不得激活它。目录按普通会话缓存,拉取走 single-flightscope 创建时的 `warm` 钩子预热该会话的缓存项,转发的 owner 事件 `agent-preset/selected` 丢弃该会话这一项(目录属于 preset而空会话可能在预热之后才切换`connection/reset` 清空全部缓存。结果按 `startsWith(query)` 过滤。
pick 会落下字面文本 `/name `,发出的提示词中也是同一段字面文本([slash 流水线 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-25-web-input-machine-and-slash-pipeline.md))——本 source 不实现任何裁决钩子,也没有引用 codec。确定性在宿主侧pre-step 手势边界(`dsh-tool-skill`)识别用户消息中任意位置、以空白为界、指名用户可调用 skill 的 `/name` token并为每个入口注入渲染后的 `<skill_content>`,因此菜单 pick、手动键入的 token 与 TUI/ACPAgent Client Protocol提示词都以同一种方式加载 skill。与宿主命令同名的名称仍解析为命令裁决在客户端把该行认领走它根本不会成为提示词——这是有意的优先级与同类产品一致。列表 RPC 使用插件注册时捕获的根上下文连接——source 绝不从每次调用的参数上读取服务;草稿 chip 视觉由 `lexicon` 扫描派生。

View File

@@ -35,7 +35,7 @@
"@deepseek-ai/dsh-client-runtime",
"@deepseek-ai/dsh-client-locale",
"@deepseek-ai/dsh-client-ui-tool",
"@deepseek-ai/dsh-client-ui-slash",
"@deepseek-ai/dsh-client-ui-input-trigger",
"@deepseek-ai/dsh-api-remotes"
],
"platform": "web"
@@ -52,7 +52,7 @@
"@deepseek-ai/dsh-client-locale": "workspace:^",
"@deepseek-ai/dsh-client-runtime": "workspace:^",
"@deepseek-ai/dsh-client-ui-primitives": "workspace:^",
"@deepseek-ai/dsh-client-ui-slash": "workspace:^",
"@deepseek-ai/dsh-client-ui-input-trigger": "workspace:^",
"@deepseek-ai/dsh-client-ui-slots": "workspace:^",
"@deepseek-ai/dsh-client-ui-tool": "workspace:^",
"@deepseek-ai/dsh-invariants": "workspace:^",
@@ -66,7 +66,7 @@
"@deepseek-ai/dsh-client-runtime": "workspace:^",
"@deepseek-ai/dsh-client-test-runtime": "workspace:^",
"@deepseek-ai/dsh-client-ui-primitives": "workspace:^",
"@deepseek-ai/dsh-client-ui-slash": "workspace:^",
"@deepseek-ai/dsh-client-ui-input-trigger": "workspace:^",
"@deepseek-ai/dsh-client-ui-slots": "workspace:^",
"@deepseek-ai/dsh-client-ui-tool": "workspace:^",
"@deepseek-ai/dsh-invariants": "workspace:^",

View File

@@ -14,7 +14,7 @@
* services off a per-call argument. Draft chip visuals derive from
* the lexicon scan; this source implements no reference codec.
*
* Catalog fetches are cached per session (the small twin of the ui-command
* Catalog fetches are cached per session (the small twin of the ui-commands
* directory): the per-keystroke candidates re-poll filters a settled
* snapshot locally, so one session costs one RPC. The scope-birth warm hook
* prewarms the session's key; a preset switch drops that one key (the
@@ -32,7 +32,7 @@
// Type-only: the carrier types, the forwarded Host-event face and the ctx.remote merge.
import type { ConnectionHandle, SessionId, SkillEntry } from '@deepseek-ai/dsh-api-remotes/client'
import type { ClientContext, ISessions } from '@deepseek-ai/dsh-client-runtime/client'
import type { SlashServiceContract, SlashSource } from '@deepseek-ai/dsh-client-ui-slash/client'
import type { InputTriggerServiceContract, InputTriggerSource } from '@deepseek-ai/dsh-client-ui-input-trigger/client'
// Type-only: pulls the locale plugin's Context merge (ctx.locale).
import type {} from '@deepseek-ai/dsh-client-locale/client'
import { SkillRow } from './SkillRow.tsx'
@@ -54,7 +54,7 @@ interface CatalogFetch {
}
/** Required services: reference source faces plus the tool-row and locale registries. */
export const inject = ['slash', 'connection', 'sessions', 'slots', 'locale', 'remote']
export const inject = ['inputTriggers', 'connection', 'sessions', 'slots', 'locale', 'remote']
/**
* Client plugin body: register the '/' source, dictionaries, and keyed tool row.
@@ -130,7 +130,7 @@ export function apply(ctx: ClientContext): void {
// locale service's own fallback ladder; candidate-time reads stay plain text.
const t = ctx.locale.bind(NS)
const source: SlashSource = {
const source: InputTriggerSource = {
trigger: '/',
name: 'skill',
order: 2,
@@ -176,13 +176,13 @@ export function apply(ctx: ClientContext): void {
return { text: `/${candidate.name} ` }
},
}
const slash = ctx.get('slash') as SlashServiceContract
const inputTriggers = ctx.get('inputTriggers') as InputTriggerServiceContract
// A preset decides which skill providers an agent reads, so a switched
// session's cached catalog belongs to the composition it no longer runs.
ctx.remote.$on('agent-preset/selected', invalidate)
ctx.on('connection/reset', clearAll)
ctx.effect(() => {
const unregister = slash.registerSource(source)
const unregister = inputTriggers.registerSource(source)
return () => {
unregister()
clearAll()

View File

@@ -1,7 +1,7 @@
/**
* ui-skill browser half: source and keyed toolview registration +
* locale dictionaries + source duplicate-name proof +
* fiber-teardown removal (HMR safety) against the real SlashService, then
* fiber-teardown removal (HMR safety) against the real InputTriggerService, then
* the source behavior contract driven directly on the captured source with
* real ClientSessionContext projections — sessionId addressing, the
* session-keyed catalog cache (single-flight per key, scope-birth warm
@@ -16,10 +16,10 @@
import { Context } from '@deepseek-ai/cordis'
import { describe, expect, it, vi } from 'vitest'
import type { SessionId } from '@deepseek-ai/dsh-client-runtime/client'
import { SlotsService } from '@deepseek-ai/dsh-client-runtime/client'
import { SlashService } from '@deepseek-ai/dsh-client-ui-slash/client'
import { SlotRegistry } from '@deepseek-ai/dsh-client-runtime/client'
import { InputTriggerService } from '@deepseek-ai/dsh-client-ui-input-trigger/client'
import { TestRemote } from '@deepseek-ai/dsh-client-test-runtime'
import type { ClientSessionContext, SlashSource } from '@deepseek-ai/dsh-client-ui-slash/client'
import type { ClientSessionContext, InputTriggerSource } from '@deepseek-ai/dsh-client-ui-input-trigger/client'
import { apply, inject } from '../src/client/index.ts'
import { SkillRow as SkillToolRow } from '../src/client/SkillRow.tsx'
@@ -34,14 +34,14 @@ type InvokeResult =
type InvokeFn = (payload: object) => Promise<{ result: InvokeResult }>
interface PresentationCapture {
slots: SlotsService
slots: SlotRegistry
dictionaries: Array<{ namespace: string; dictionaries: unknown }>
localeDisposed: boolean
}
/** Provide the presentation registries and capture the plugin's registrations. */
function providePresentation(ctx: Context): PresentationCapture {
const slots = new SlotsService(ctx)
const slots = new SlotRegistry(ctx)
slots.register({
name: 'root',
children: { 'tool.call.toolview': { kind: 'keyed', scope: 'session' } },
@@ -65,8 +65,8 @@ function providePresentation(ctx: Context): PresentationCapture {
/** Boot the plugin over fake slash/connection faces; returns the captured source and its ctx. */
async function bench(list: ListFn, addressed?: SessionId, invoke?: InvokeFn) {
const ctx = new Context()
let captured: SlashSource | undefined
ctx.provide('slash', { registerSource: (src: SlashSource) => { captured = src; return () => {} } })
let captured: InputTriggerSource | undefined
ctx.provide('inputTriggers', { registerSource: (src: InputTriggerSource) => { captured = src; return () => {} } })
const defaultInvoke: InvokeFn = () => Promise.resolve({ result: { ok: true as const, value: { accepted: true as const } } })
ctx.provide('connection', { api: { skills: { list, invoke: invoke ?? defaultInvoke } } })
ctx.provide('sessions', {
@@ -107,12 +107,12 @@ const req = (query: string, signal?: AbortSignal) =>
describe('apply', () => {
it('declares the services it binds', () => {
expect(inject).toEqual(['slash', 'connection', 'sessions', 'slots', 'locale', 'remote'])
expect(inject).toEqual(['inputTriggers', 'connection', 'sessions', 'slots', 'locale', 'remote'])
})
it('registers the dedicated skill row and its locale dictionaries', async () => {
const ctx = new Context()
ctx.provide('slash', { registerSource: () => () => {} })
ctx.provide('inputTriggers', { registerSource: () => () => {} })
ctx.provide('connection', { api: { skills: { list: listOk(CATALOG) } } })
ctx.provide('sessions', { subagentAddress: () => undefined })
new TestRemote(ctx)
@@ -144,15 +144,15 @@ describe('apply', () => {
it('registers the "/" skill source; disposal frees the name (HMR safety)', async () => {
const ctx = new Context()
// SlashService itself injects 'sessions'; the stub unblocks its fiber.
// InputTriggerService itself injects 'sessions'; the stub unblocks its fiber.
ctx.provide('sessions', {})
await ctx.plugin(SlashService).await()
await ctx.plugin(InputTriggerService).await()
ctx.provide('connection', { api: { skills: { list: listOk(CATALOG) } } })
new TestRemote(ctx)
const presentation = providePresentation(ctx)
const fiber = ctx.plugin({ inject: [...inject], apply })
await fiber.await()
const slash = ctx.get('slash') as SlashService
const inputTriggers = ctx.get('inputTriggers') as InputTriggerService
const rival = {
trigger: '/' as const,
name: 'skill',
@@ -160,10 +160,10 @@ describe('apply', () => {
onPick: () => undefined,
}
// Live registration holds the (trigger, name) seat…
expect(() => slash.registerSource(rival)).toThrow(/already registered/)
expect(() => inputTriggers.registerSource(rival)).toThrow(/already registered/)
// …and fiber teardown releases it.
await fiber.dispose()
expect(() => slash.registerSource(rival)).not.toThrow()
expect(() => inputTriggers.registerSource(rival)).not.toThrow()
expect(presentation.slots.entries('tool.call.toolview')).toHaveLength(0)
expect(presentation.localeDisposed).toBe(true)
})

View File

@@ -27,13 +27,13 @@
"path": "../ui-primitives"
},
{
"path": "../ui-slash"
"path": "../ui-input-trigger"
},
{
"path": "../ui-slots"
},
{
"path": "../../support/invariants"
"path": "../../runtime-diagnostics/invariants"
},
{
"path": "../../api/remotes/tsconfig.client.json"