* feat(release): publish package source, declaration maps, and documentation Every release member publishes its TypeScript source and the declaration maps that resolve into it, and @deepseek-ai/dsh publishes the repository Markdown documentation staged from docs/ at prepack time. The ./src/* export most members already declared now resolves for an installed consumer, and a consumer editor follows a declaration to the implementation. Bundled JavaScript maps stay unpublished; the vendored family and the Desktop runtime file policy are unchanged. Rationale: .agents/notes/implemented/process/2026-10-08-published-source-and-docs.md * feat(release): publish JavaScript maps and compress bundles Every emitted JavaScript map ships beside the bundle it describes, and the workspace build and the client preset compress bundles without mangling identifiers. The documentation payload now mirrors the website publication manifest and is removed again by `postpack`; Desktop and the Python executable exclude the published source, documentation, and maps; `clean` removes a staged copy. Typert's publication contract gains the Remote declaration map. * fix(release): keep node bundles readable for the worker image The browser worker image lowers `yield*` only as a whole statement and rewrites `for await` loops by their source layout, so compressed node-side entries either fail that lowering or lower to unparseable code. Only the browser bundles keep compression, which removes about a third of their text. The bundle-purity assertion now matches the module-loader call regardless of the quote style compression picks, and the release-pack fixture exercises the installed package's new documentation requirement. * feat(release): publish the whole documentation tree `@deepseek-ai/dsh` copies `docs/` in full instead of the website's page set: the maintainer documents, the generated migration records, the translation guidelines, and the `*.i18n.yaml` consistency records ship with the installed package, so the documentation's own links resolve without a checkout. * feat(release): publish the upgrade guides with the documentation The staged documentation keeps the website's page set and adds every `docs/upgrade-guide/` document, which is what an installed reader consults when a released change breaks something. The rest of the maintainer tree stays out. * test(release): expect source and maps in master's new payload cases * feat(release): keep installed docs and source readable in Desktop Desktop keeps the published src/ and docs/ trees inside app.asar, and every model shell call receives DSH_INSTALL_DIR and DSH_NODE_EXECUTABLE so an agent can read them through Electron's Node mode. Staging also generates docs/upgrade-guide/README.md, an index of the upgrade guides grouped by the release they upgrade from. Minified client bundles print string literals with backticks: the worker image packer now recognizes those chunk requests, client license banners are prepended after minification so their text survives, and the affected artifact tests accept either quote. * test(desktop): read archived docs through the Windows PowerShell form Regenerate the config catalog for the shifted shell-env source line. * test(desktop): wait for the GUI-subsystem Electron process from PowerShell * build(release): publish source and maps from the message-quotes package * build(release): publish source and maps from packages new on master * build(release): publish source and maps from the tool-office package
description, kind
| description | kind |
|---|---|
| Web skill references and the dedicated skill tool row for the dsh web client: the /-triggered skill source and the skill call card. | package-reference |
@deepseek-ai/dsh-client-ui-skill
English | 中文
Summary
dsh-client-ui-skill lets users invoke a skill by choosing it from the / suggestions or typing /name directly. The same literal command loads the skill consistently from the Web composer, TUI, and ACP, while a name shared with a host command continues to resolve as that command. Skill calls appear in the conversation as expandable Instructions cards whose settled contents remain stable when the installed skill catalog changes.
Table of Contents
- Use this package
- Understand the implementation
- Further Exploration
- Model Experience
- Known Limitations and Deferred Work
- Dev Note
Use this package
Type / in the composer and pick a skill from the suggestions, or type /name directly; the sent message carries the literal text, and the host loads the skill the same way for a menu pick or a hand-typed token. A name shared with a host command still resolves to the command — adjudication claims the line client-side before it ever becomes a prompt.
What the source offers
Ordinary-session candidates come from the skills/list Remote; the host serves every user-invocable skill, and 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. Results rank through the / menu's shared name ranker, rankByName from ui-primitives: the query matches a case-insensitive ordered subsequence of the skill name, prefix hits rank first, and ties keep the host order (ranking decision). A failed skills/list call is logged and folded into a silent menu-group drop — the menu shows only pending/ready states.
The skill tool row
The preparing stage shows only the skill icon and title, with no requested skill name or expansion. The start and result stages use the recorded arguments and output described below; preparation does not consult the installed catalog.
A collapsed row renders the skill glyph, Skill title, and requested skill name on the same secondary font-size axis, line height, row height, and glyph scaling as ordinary Tool rows. Every lifecycle state retains the ordinary skill glyph; running calls carry one left-to-right highlight across the title, separator, and skill name, while failures replace the name with the first error line and interruptions retain their explicit status text. A settled row expands into a bounded Instructions card containing the exact durable tool output, with the standard trajectory Inspect affordance when available; this expanded card keeps its own typography. The row derives its name, lifecycle, and body only from the frozen call/result slice supplied by ui-tool, never from the current catalog, so replay stays stable when installed skills or their descriptions change. Text and icons are tertiary at rest and secondary on hover; error and interruption text retains its semantic color.
Hovering over /name highlights the entire reference. Clicking a known skill opens its provider-supplied SKILL.md path in the right Sidebar while keeping the token editable. An uncached click shares the per-Session catalog fetch and opens when it completes, retaining the clicked Session address. Preset changes, plugin manager operations, connection resets, and plugin disposal cancel pending previews; a later click fetches the current catalog again. Skills without a file path remain invocable but have no file preview.
Understand the implementation
Implementation internals — click to expand
The source implements no adjudication hooks and no reference codec: the pick lands literal text and the prompt ships the same literal, so determinism lives host-side (slash pipeline note).
Candidate flow
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), the forwarded plugin-manager/changed event clears everything (a manager operation may add or remove skill providers that every session reads), and connection/reset clears everything. 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. The list RPC rides the plugin's root-context connection captured at registration; draft chip visuals derive from the lexicon scan.
Each catalog fetch requires an existing retained Client Session and waits for its initial history open to succeed before sending skills/list. A temporary skillCatalog reference holds that Session until the fetch settles. An unretained Session or a failed open rejects without sending the RPC; preset invalidation, plugin manager operations, connection reset, and plugin disposal also cancel a pending history wait.
Registration
The /client exports are the plugin body (apply/inject) only; the source object is internal to the registration effect. The tool row registers the skill wire name in ui-tool's keyed tool.call.toolview slot.
For sent text, the plugin registers a UserText matcher that returns one next original-text candidate using caller-confirmed skillNames and owns the skill entry in conversation.user.text.node. The renderer receives openSkill from its own Session-bound injection and delegates to this source’s preview operation, not to Chat owner props. Non-interactive previews remain labels. UserText owns evaluation and node dispatch.
Further Exploration
These pages cover the input machinery, the tool row host, and the host-side skill tool.
- ui-input-trigger — the inline suggestion machinery the source registers into.
- ui-tool — the tool-call presentation layer hosting the
tool.call.toolviewslot. - tool-skill — the host-side
skilltool owning the pre-step gesture boundary. - Web input machine and slash pipeline — how references and commands share the input machine.
Model Experience
User-explicit skill invocation
What the model sees
The user's message reaches the model verbatim, /name literal included. The host's pre-step boundary (dsh-tool-skill) then appends the canonical <skill_content> block — the same renderSkillContent output the skill tool returns — as injected instructions context at the end of that step's injections, closest to the model's answer. Loading is deterministic: the model receives the full body without being asked to call the skill tool, and the catalog tells it not to re-load an inline-injected skill.
Token effect
One invocation adds the rendered skill body to that turn as injected context — the same cost as the model loading the skill through the tool, paid unconditionally instead of at the model's discretion. Menu browsing and the candidate fetch add zero model tokens.
KV Cache effect
Append-only: the injected message lands after the reusable history prefix. This package never edits earlier request tokens.
Known Limitations and Deferred Work
These limits define where the reference and the row fall back to generic behavior; they are current package constraints.
- Result-only history pages use the generic row — keyed dispatch needs the paired call in the runtime window; pagination that leaves the call outside has no tool identity. This client presentation feature does not extend the history wire contract to recover it.
- Text is the truth — the reference is plain draft text; a hand-typed identical token is the same reference, and the host gesture boundary judges the sent text, not the menu interaction. Chip visuals derive from the lexicon scan; no occurrence identity, position tracking, or structured reference payload exists on the prompt wire.
- A menu opened before the prewarm settles shows no skill candidates for that keystroke; the next keystroke re-polls the settled cache.
- Catalog changes without a forwarded event keep cached catalogs — an HMR reload after a CLI or hand edit announces no
plugin-manager/changedevent, and adding or removing aSKILL.mdon disk forwards no event at all, so an open session lists its previous skills until a preset switch, plugin manager operation, or connection reset. - Draft skill highlighting waits for the next catalog fetch — a preset switch, plugin manager operation, or connection reset empties the session's lexicon, so with the menu closed an existing
/namein the draft loses its skill highlight until the/menu fetches the catalog again; an open menu fetches it immediately.
Dev Note
Working context for maintainers — click to expand
None.