feat(agent-preset): progressive creator skills and profile shell facts (#4836)
* feat(tool-cordis): inspect live plugin Config schemas Replace the Host `Builtin` inspect provider, which described a dynamic Host half the model can no longer define, with a `Config` provider that lists every live Loader entry with its Config status and projects one entry's native Schemastery Config into a self-contained JSON Schema document. app-boot exports its projector, native-schema check, and the shared `loaderExpression` definition for the live walk; the CLI dump keeps its profile-composition path. * fix(tool-cordis): refresh config catalog pointer and presets e2e provider list * feat(agent-preset): progressive creator skills and profile shell facts Split `cordis-plugin-development` into a short procedure with `references/` read on demand and copyable `templates/`, replace the source-reading ban in both creator skills with an ordered list of knowledge sources, and add the `cordis-composition-reference` skill with the Loader patch dialect and a generated, doc-sync-gated list of loadable plugin packages. `shell-env` exposes `DSH_PROFILE` and `DSH_PROFILE_DIR` so skills can address the installed profile. * chore(agent-preset): regenerate plugin package list after merging master * fix(tool-cordis): resolve the Loader at Config query time A Host composed programmatically without a Loader keeps registering the inspect providers; `Config.listConfigs` reports the missing Loader when queried. Refresh the advanced-toolchain recordings whose provider list now carries `Config` in place of `Builtin`. * chore(agent-preset): regenerate plugin package list after merging master * docs: regenerate module graph for the tool-cordis app-boot dependency * docs: regenerate module graph for the shell-env app-boot dependency * docs: regenerate event graph pointer for app-boot exports * fix(agent-preset): address review on creator skills `Config.listConfigs` reports each entry's resolved `packageDir` through the profile package lookup, and the skills read READMEs and built declarations there instead of guessing `$DSH_PROFILE_DIR/node_modules`, which holds only profile-installed packages. Skills name the PowerShell variable syntax and the no-profile omission; the composition reference no longer attributes `overridden` to `list_plugins`; references point at the templates instead of pasting them. The skills spec renders every skill and bounds it by the pruner threshold in code points, checks referenced files and the source-reading ban across all skill files. * fix(tool-cordis): address review on the Config inspect provider Report the Loader entry id (unique across include trees) beside the tree-local patch id, classify group and include carriers as `tree`, treat disabled and disposed fibers as `inactive`, and drop the unreachable boolean-schema branch by narrowing the projector's root type. The presets e2e now queries `Config.listConfigs` over the booted Web profile and projects the shipped `tools` row; the advanced-toolchain recordings carry the updated manifest. * fix(tool-cordis): page the Config directory and filter it by plugin name A full directory of a shipped Web profile exceeds the 50000-byte spill cap once rows carry more fields, and the spilled preview is no longer JSON. `Config.listConfigs` now returns pages (`offset`, `limit` up to 100, default 25) with `total` and `nextOffset`, and an exact plugin `name` filter; the presets e2e reads the shipped rows through the filter. * chore(agent-preset): refresh skill recordings after the paged Config query * docs(agent-preset): teach the composition skill to migrate legacy presets A preset authored before declaration rows lived in `$DSH_HOME/.agent-presets/<id>/` as `preset.yml` plus `agent.cordis.yml`; the skill now maps those files onto a declaration bundle and re-checks plugin names against the package list. * docs(agent-preset): read skill files through the file-read tool only Desktop ships the skill directory inside app.asar, which the Host process can open but shell commands, node, and pnpm cannot. The skills now say to read references and templates with the file-read tool and copy templates into the workspace before installing or checking them; the spec rejects shell reads of skill files. * docs(agent-preset): document bundle display metadata and package.json icon in the host-plugin reference
This commit is contained in:
1 parent
8b993f43e0
commit
b13bbc027c
46 files changed
+1036
-138
No files matched your search
+6
@@ -0,0 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-09-21-creator-skills-progressive-disclosure.md
|
||||
2026-09-21-creator-skills-progressive-disclosure.md: bdd70beda7c92584a336cda856d196ac23d1f968
|
||||
2026-09-21-creator-skills-progressive-disclosure.zh.md: 265d9db21a5288b4d589078ff85a75eb74f3b237
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
# Agent Note: Creator skills disclose progressively and may read sources
|
||||
|
||||
Status: implemented
|
||||
|
||||
English | [中文](2026-09-21-creator-skills-progressive-disclosure.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
The shipped `cordis-plugin-development` skill carried three mutually exclusive recipes and a verification checklist in one 8.7 KB file, above the 8192-character threshold at which the standard preset's tool-result pruner keeps only the head and tail. Both creator skills forbade reading DSH package sources, which made the skill text the only knowledge source and left the agent guessing whenever it did not cover a case. The skills also addressed the profile as `$DSH_HOME/profiles/<profile>`, a name the agent's shell never received.
|
||||
|
||||
## Decision
|
||||
|
||||
`SKILL.md` keeps the procedure, the knowledge-source order, and an index table; recipes move to `references/` files and copyable bundles to `templates/`, all resolved through the skill's base directory that the `skill` tool already reports. A test keeps the leading file under the pruner head and checks that every referenced file exists and every template parses.
|
||||
|
||||
Knowledge sources are ordered, never forbidden: inspection through `cordis_inspect_query`, the package README under the `packageDir` that `Config.listConfigs` resolves through the profile package lookup, then built `lib/` declarations or checkout sources when a question remains. Bundled packages resolve from the dsh installation and profile-installed ones from the profile, so skills never derive a package path from the profile directory. The shell registry exposes `DSH_PROFILE` and `DSH_PROFILE_DIR` as reserved built-ins whenever the launcher provided a profile context.
|
||||
|
||||
A third skill, `cordis-composition-reference`, holds the Loader patch dialect and a generated list of loadable plugin packages, freshness-gated in `doc-sync`, so procedure skills stop growing.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
Adding creator-mode text to the system prompt is paid every turn; the skill catalog already routes on demand. Shipping `docs/` to the agent would dilute maintainer material into a runtime context that needs installed-profile facts. Keeping the source-reading ban would have required the skills to restate every declaration they might need.
|
||||
|
||||
## Consequences
|
||||
|
||||
The first skill load costs about 3.9 KB, and each recipe 1 to 3 KB more. Recorded sessions that load `editing-cordis-compositions` refresh when its text changes. Compositions booted without a profile omit the two profile variables, and the skills say so.
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
# Agent Note: 创造模式 skill 渐进式披露并允许读源码
|
||||
|
||||
Status: implemented
|
||||
|
||||
[English](2026-09-21-creator-skills-progressive-disclosure.md) | 中文
|
||||
|
||||
## Problem
|
||||
|
||||
出货的 `cordis-plugin-development` skill 把三个互斥的配方和一份验证清单放在一个 8.7 KB 的文件里,超过了标准 preset 工具结果修剪器只保留头尾的 8192 字符阈值。两个创造模式 skill 都禁止读取 DSH 包源码,使 skill 文本成为唯一知识来源,未覆盖的情况只能靠猜。skill 还用 `$DSH_HOME/profiles/<profile>` 指代 profile,而 agent 的 shell 从未拿到这个名字。
|
||||
|
||||
## Decision
|
||||
|
||||
`SKILL.md` 只保留流程、知识来源顺序和索引表;配方移入 `references/`,可复制的组合包移入 `templates/`,都通过 `skill` 工具已报告的 skill 基目录解析。一个测试保证开头文件在修剪器头部之内,并检查每个被引用的文件存在、每个模板可解析。
|
||||
|
||||
知识来源有顺序而不禁止:先通过 `cordis_inspect_query` 检查,再读 `Config.listConfigs` 经 profile 包查找解析出的 `packageDir` 下的包 README,仍有疑问时读构建后的 `lib/` 声明或 checkout 源码。自带包从 dsh 安装目录解析,profile 自行安装的包从 profile 解析,所以 skill 不再从 profile 目录推导包路径。启动器提供 profile 上下文时,shell 注册表把 `DSH_PROFILE` 与 `DSH_PROFILE_DIR` 作为保留内置变量暴露。
|
||||
|
||||
第三个 skill `cordis-composition-reference` 承载 Loader patch 方言和生成的可加载插件包清单,并在 `doc-sync` 中做新鲜度门禁,让流程 skill 不再增长。
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
在系统提示里加创造模式文本每轮都要付费;skill 目录已能按需路由。把 `docs/` 出货给 agent 会把维护者材料稀释进需要安装态 profile 事实的运行时上下文。保留禁读源码则要求 skill 复述它可能需要的每一条声明。
|
||||
|
||||
## Consequences
|
||||
|
||||
首次加载 skill 约 3.9 KB,每个配方再加 1 到 3 KB。加载 `editing-cordis-compositions` 的录制会话在其文本变化时需要刷新。不带 profile 启动的组合没有这两个 profile 变量,skill 对此有说明。
|
||||
@@ -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 docs/config-catalog.md
|
||||
config-catalog.md: 713c9888cc83e9bc6dee2965d2ec12b9f9df2b90
|
||||
config-catalog.zh.md: 61ac6f63c6d4a80fe07d18c9a2959854fc7ce8c2
|
||||
config-catalog.md: f99cb7dc0f1dd13fc4e034277abdc9c4cb095339
|
||||
config-catalog.zh.md: 72b2952f6f8b04e0bb89266baa1ae1f7a800c7cc
|
||||
@@ -2607,7 +2607,7 @@ export interface Config {
|
||||
}
|
||||
```
|
||||
|
||||
Source: [`packages/shell/shell-env/src/index.ts:28`](../packages/shell/shell-env/src/index.ts)
|
||||
Source: [`packages/shell/shell-env/src/index.ts:30`](../packages/shell/shell-env/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-skill"></a>
|
||||
|
||||
|
||||
@@ -2609,7 +2609,7 @@ export interface Config {
|
||||
}
|
||||
```
|
||||
|
||||
来源: [`packages/shell/shell-env/src/index.ts:28`](../packages/shell/shell-env/src/index.ts)
|
||||
来源: [`packages/shell/shell-env/src/index.ts:30`](../packages/shell/shell-env/src/index.ts)
|
||||
|
||||
<a id="deepseek-aidsh-skill"></a>
|
||||
|
||||
|
||||
@@ -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 docs/module-graph.md
|
||||
module-graph.md: 4647cbdcd6a1333b6e2c50f3ec93f549b633f1d2
|
||||
module-graph.zh.md: d5f09b6932e0f4466b782db3de8cc37f283c5348
|
||||
module-graph.md: 868a51d96e818b6e815defd6acce758ab7251d0b
|
||||
module-graph.zh.md: aa8edca41eeff8d8a05c03e3310e09ed7b3eaabd
|
||||
@@ -928,6 +928,7 @@ flowchart TD
|
||||
pkg_session_title_first_prompt_llm --> pkg_session
|
||||
pkg_session_title_first_prompt_llm --> pkg_session_title
|
||||
pkg_session_title_first_prompt_llm --> pkg_session_title_llm
|
||||
pkg_shell_env --> pkg_app_boot
|
||||
pkg_shell_env --> pkg_home_paths
|
||||
pkg_shell_env --> pkg_shell
|
||||
pkg_shell_env --> pkg_tools
|
||||
@@ -1576,7 +1577,7 @@ flowchart TD
|
||||
| [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy) | `session` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`tools`](../packages/core/tools) |
|
||||
| [`session-title-all-prompts-llm`](../packages/session/session-title-all-prompts-llm) | `session` | [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-title`](../packages/session/session-title), [`session-title-llm`](../packages/session/session-title-llm) |
|
||||
| [`session-title-first-prompt-llm`](../packages/session/session-title-first-prompt-llm) | `session` | [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-title`](../packages/session/session-title), [`session-title-llm`](../packages/session/session-title-llm) |
|
||||
| [`shell-env`](../packages/shell/shell-env) | `shell` | [`home-paths`](../packages/util/home-paths), [`shell`](../packages/shell/shell), [`tools`](../packages/core/tools) |
|
||||
| [`shell-env`](../packages/shell/shell-env) | `shell` | [`app-boot`](../packages/boot/app-boot), [`home-paths`](../packages/util/home-paths), [`shell`](../packages/shell/shell), [`tools`](../packages/core/tools) |
|
||||
| [`tool-bash-persistent`](../packages/shell/tool-bash-persistent) | `shell` | [`agent`](../packages/core/agent), [`terminal`](../packages/terminal/terminal), [`timeout`](../packages/util/timeout), [`tools`](../packages/core/tools) |
|
||||
| [`tool-pwsh-persistent`](../packages/shell/tool-pwsh-persistent) | `shell` | [`agent`](../packages/core/agent), [`terminal`](../packages/terminal/terminal), [`timeout`](../packages/util/timeout), [`tools`](../packages/core/tools) |
|
||||
| [`ssh`](../packages/ssh/ssh) | `ssh` | [`brand`](../packages/util/brand), [`fs`](../packages/fs/fs), [`fs-local`](../packages/fs/fs-local), [`fs-sandbox`](../packages/fs/fs-sandbox), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-local`](../packages/sandbox/sandbox-local), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session-projection`](../packages/session/session-projection), [`subprocess`](../packages/subprocess/subprocess), [`subprocess-local`](../packages/subprocess/subprocess-local) |
|
||||
|
||||
@@ -930,6 +930,7 @@ flowchart TD
|
||||
pkg_session_title_first_prompt_llm --> pkg_session
|
||||
pkg_session_title_first_prompt_llm --> pkg_session_title
|
||||
pkg_session_title_first_prompt_llm --> pkg_session_title_llm
|
||||
pkg_shell_env --> pkg_app_boot
|
||||
pkg_shell_env --> pkg_home_paths
|
||||
pkg_shell_env --> pkg_shell
|
||||
pkg_shell_env --> pkg_tools
|
||||
@@ -1578,7 +1579,7 @@ flowchart TD
|
||||
| [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy) | `session` | [`agent`](../packages/core/agent), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`tools`](../packages/core/tools) |
|
||||
| [`session-title-all-prompts-llm`](../packages/session/session-title-all-prompts-llm) | `session` | [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-title`](../packages/session/session-title), [`session-title-llm`](../packages/session/session-title-llm) |
|
||||
| [`session-title-first-prompt-llm`](../packages/session/session-title-first-prompt-llm) | `session` | [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-title`](../packages/session/session-title), [`session-title-llm`](../packages/session/session-title-llm) |
|
||||
| [`shell-env`](../packages/shell/shell-env) | `shell` | [`home-paths`](../packages/util/home-paths), [`shell`](../packages/shell/shell), [`tools`](../packages/core/tools) |
|
||||
| [`shell-env`](../packages/shell/shell-env) | `shell` | [`app-boot`](../packages/boot/app-boot), [`home-paths`](../packages/util/home-paths), [`shell`](../packages/shell/shell), [`tools`](../packages/core/tools) |
|
||||
| [`tool-bash-persistent`](../packages/shell/tool-bash-persistent) | `shell` | [`agent`](../packages/core/agent), [`terminal`](../packages/terminal/terminal), [`timeout`](../packages/util/timeout), [`tools`](../packages/core/tools) |
|
||||
| [`tool-pwsh-persistent`](../packages/shell/tool-pwsh-persistent) | `shell` | [`agent`](../packages/core/agent), [`terminal`](../packages/terminal/terminal), [`timeout`](../packages/util/timeout), [`tools`](../packages/core/tools) |
|
||||
| [`ssh`](../packages/ssh/ssh) | `ssh` | [`brand`](../packages/util/brand), [`fs`](../packages/fs/fs), [`fs-local`](../packages/fs/fs-local), [`fs-sandbox`](../packages/fs/fs-sandbox), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-local`](../packages/sandbox/sandbox-local), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session-projection`](../packages/session/session-projection), [`subprocess`](../packages/subprocess/subprocess), [`subprocess-local`](../packages/subprocess/subprocess-local) |
|
||||
|
||||
@@ -163,6 +163,8 @@
|
||||
"verify-tool-catalog": "tsx scripts/gen-tool-catalog.ts --check",
|
||||
"gen-config-catalog": "tsx scripts/gen-config-catalog.ts",
|
||||
"verify-config-catalog": "tsx scripts/gen-config-catalog.ts --check",
|
||||
"gen-plugin-packages": "tsx scripts/gen-plugin-packages.ts",
|
||||
"verify-plugin-packages": "tsx scripts/gen-plugin-packages.ts --check",
|
||||
"gen-dependency-catalog": "tsx scripts/gen-dependency-catalog.ts",
|
||||
"verify-dependency-catalog": "tsx scripts/gen-dependency-catalog.ts --check",
|
||||
"gen-doc-graphs": "tsx scripts/gen-doc-graphs.ts",
|
||||
|
||||
@@ -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/extensions/tool-cordis/README.md
|
||||
README.md: 3a676d152c58d543b4381da880ba60481ccfc18c
|
||||
README.zh.md: dba19ed26a94bc940c7f0a6e142d366c1502bc83
|
||||
README.md: 23e2d4a3d047c1442769e07be045f7da4a24a783
|
||||
README.zh.md: da855b7b1d4b4287a1f8d3a5ea7a1fb0c9407f2f
|
||||
@@ -25,7 +25,7 @@ Inspect Host and Client runtime APIs before writing plugin code. Creator mode pr
|
||||
<a id="use-this-package"></a>
|
||||
## Use this package
|
||||
|
||||
Creator mode includes this toolset. Other compositions mount `@deepseek-ai/dsh-tool-cordis/host` once in the host composition beside the host runner that provides `cordisInspect`, and `@deepseek-ai/dsh-tool-cordis` in each agent preset that exposes the tools; a preset row alone registers no Host providers. Call `cordis_inspect_list` to discover providers, then `cordis_inspect_query` for a provider's exact methods and types. The Host `Config` provider lists live Loader entries in pages (`offset`, `limit` up to 100, optional exact plugin `name`; `total` and `nextOffset` bound the walk) with each entry's Loader id, the tree-local id patches address, and its Config status (`schema`, `absent`, `unsupported`, `tree` for group and include carriers, `inactive` for disabled, never imported, or disposed entries), and projects one entry's native Config into a self-contained JSON Schema document. Use [Plugin Manager](../../boot/plugin-manager/README.md) to install bundles containing plugin code or MCP configuration.
|
||||
Creator mode includes this toolset. Other compositions mount `@deepseek-ai/dsh-tool-cordis/host` once in the host composition beside the host runner that provides `cordisInspect`, and `@deepseek-ai/dsh-tool-cordis` in each agent preset that exposes the tools; a preset row alone registers no Host providers. Call `cordis_inspect_list` to discover providers, then `cordis_inspect_query` for a provider's exact methods and types. The Host `Config` provider lists live Loader entries in pages (`offset`, `limit` up to 100, optional exact plugin `name`; `total` and `nextOffset` bound the walk) with each entry's Loader id, the tree-local id patches address, and its Config status (`schema`, `absent`, `unsupported`, `tree` for group and include carriers, `inactive` for disabled, never imported, or disposed entries), and projects one entry's native Config into a self-contained JSON Schema document beside the entry's `packageDir`, the resolved directory holding the package README and built `lib/`, when the profile package lookup resolves it. Use [Plugin Manager](../../boot/plugin-manager/README.md) to install bundles containing plugin code or MCP configuration.
|
||||
|
||||
-----
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ kind: "package-reference"
|
||||
<a id="use-this-package"></a>
|
||||
## 使用本包
|
||||
|
||||
创造模式包含这组工具。其他组合需要在宿主组合里、提供 `cordisInspect` 的 host runner 旁挂载一次 `@deepseek-ai/dsh-tool-cordis/host`,并在每个要暴露这些工具的 agent preset 里挂载 `@deepseek-ai/dsh-tool-cordis`;仅有 preset 行不会注册任何 Host provider。调用 `cordis_inspect_list` 发现 provider,再用 `cordis_inspect_query` 查询其具体方法和类型。Host 的 `Config` provider 分页列出运行中的 Loader entry(`offset`、最多 100 的 `limit`、可选的精确插件 `name`;`total` 与 `nextOffset` 界定遍历),每个 entry 带 Loader id、patch 所寻址的树内 id 及其 Config 状态(`schema`、`absent`、`unsupported`、group 与 include 载体为 `tree`、禁用、未导入或已销毁的 entry 为 `inactive`),并把单个 entry 的原生 Config 投影为自包含的 JSON Schema 文档。通过 [Plugin Manager](../../boot/plugin-manager/README.zh.md) 安装包含插件代码或 MCP 配置的组合包。
|
||||
创造模式包含这组工具。其他组合需要在宿主组合里、提供 `cordisInspect` 的 host runner 旁挂载一次 `@deepseek-ai/dsh-tool-cordis/host`,并在每个要暴露这些工具的 agent preset 里挂载 `@deepseek-ai/dsh-tool-cordis`;仅有 preset 行不会注册任何 Host provider。调用 `cordis_inspect_list` 发现 provider,再用 `cordis_inspect_query` 查询其具体方法和类型。Host 的 `Config` provider 分页列出运行中的 Loader entry(`offset`、最多 100 的 `limit`、可选的精确插件 `name`;`total` 与 `nextOffset` 界定遍历),每个 entry 带 Loader id、patch 所寻址的树内 id 及其 Config 状态(`schema`、`absent`、`unsupported`、group 与 include 载体为 `tree`、禁用、未导入或已销毁的 entry 为 `inactive`),并把单个 entry 的原生 Config 投影为自包含的 JSON Schema 文档,同时在 profile 包查找能解析时给出该 entry 的 `packageDir`,即包 README 与构建产物 `lib/` 所在目录。通过 [Plugin Manager](../../boot/plugin-manager/README.zh.md) 安装包含插件代码或 MCP 配置的组合包。
|
||||
|
||||
-----
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import type { Context } from '@deepseek-ai/cordis'
|
||||
import type { Entry } from '@deepseek-ai/cordis-plugin-loader'
|
||||
// Declares `Context.pluginPackages`, the profile package lookup that resolves an entry's package directory.
|
||||
import { createConfigProjector, isNativeConfigSchema, LOADER_EXPRESSION_SCHEMA, type NativeConfigSchema } from '@deepseek-ai/dsh-app-boot'
|
||||
import type { JsonValue } from '@deepseek-ai/dsh-util-values'
|
||||
|
||||
@@ -68,6 +69,13 @@ function parseQuery(input: JsonValue | undefined): ConfigQuery {
|
||||
return { entry: text('entry'), name: text('name'), offset, limit }
|
||||
}
|
||||
|
||||
/** Resolve the package directory behind an entry's plugin name through the profile package lookup. */
|
||||
function packageDir(ctx: Context, entry: Entry): { packageDir?: string } {
|
||||
const baseUrl = entry.parent.tree.ctx.baseUrl
|
||||
const dir = baseUrl === undefined ? undefined : ctx.get('pluginPackages')?.packageOf(entry.options.name, baseUrl)?.dir
|
||||
return dir === undefined ? {} : { packageDir: dir }
|
||||
}
|
||||
|
||||
/** Projection output is JSON by construction; the CLI schema dump serializes the same values. */
|
||||
function toJson(value: object): JsonValue {
|
||||
return JSON.parse(JSON.stringify(value)) as JsonValue
|
||||
@@ -77,8 +85,10 @@ function toJson(value: object): JsonValue {
|
||||
* Answer the `Config.listConfigs` inspect query from the live Loader tree.
|
||||
* Without `entry`, return one page of the directory: each entry's Loader id, patch id, plugin name, and Config
|
||||
* status, optionally filtered to one exact plugin `name`, with `total` and `nextOffset` (null on the last page).
|
||||
* With `entry`, project that entry's native Config into one self-contained JSON Schema 2020-12 document whose
|
||||
* `$defs` carry the shared and `loaderExpression` definitions, plus omission acceptance and projection limitations.
|
||||
* With `entry`, return that entry with its resolved `packageDir` (the directory holding the package README and
|
||||
* built `lib/`, when the profile package lookup resolves it) and project its native Config into one self-contained
|
||||
* JSON Schema 2020-12 document whose `$defs` carry the shared and `loaderExpression` definitions, plus omission
|
||||
* acceptance and projection limitations.
|
||||
* Validators and transform callbacks are not executed; runtime-created Agent preset trees are outside the Loader.
|
||||
* @param ctx - Host context; its `loader`, when the profile was mounted by one, owns the entry tree.
|
||||
* @param input - model-supplied query: `entry` (Loader entry id), or `name`, `offset` (default 0), and `limit` (1 to 100, default 25).
|
||||
@@ -98,7 +108,7 @@ export async function queryLiveConfig(ctx: Context, input: JsonValue | undefined
|
||||
}
|
||||
const entry = entries.find(candidate => candidate.id === query.entry)
|
||||
if (entry === undefined) throw new Error(`unknown entry id ${JSON.stringify(query.entry)}`)
|
||||
const listed = listing(entry)
|
||||
const listed = { ...listing(entry), ...packageDir(ctx, loader.resolve(query.entry)) }
|
||||
if (entry.native === undefined) return listed
|
||||
const project = await createConfigProjector()
|
||||
const { schema, definitions, acceptsMissing, limitations } = project(entry.native, 'config')
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { pathToFileURL } from 'node:url'
|
||||
import { Context } from '@deepseek-ai/cordis'
|
||||
import Group from '@deepseek-ai/cordis-plugin-group'
|
||||
import Loader from '@deepseek-ai/cordis-plugin-loader'
|
||||
import { PluginPackages } from '@deepseek-ai/dsh-app-boot'
|
||||
import z from '@deepseek-ai/schemastery'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { describe, expect, it, onTestFinished, vi } from 'vitest'
|
||||
import { queryLiveConfig } from '../src/config.ts'
|
||||
|
||||
/** The Config provider reads the running Loader tree: only live fibers expose a Config, carriers never do. */
|
||||
@@ -22,8 +27,16 @@ interface Ids {
|
||||
group: string
|
||||
}
|
||||
|
||||
async function loaded(): Promise<{ ctx: Context; ids: Ids }> {
|
||||
/** A Loader tree whose base directory holds `node_modules/with-schema/package.json`, so the package lookup resolves that plugin. */
|
||||
async function loaded(): Promise<{ ctx: Context; ids: Ids; packageDir: string }> {
|
||||
const dir = mkdtempSync(join(tmpdir(), 'dsh-tool-cordis-config-'))
|
||||
onTestFinished(() => { rmSync(dir, { recursive: true, force: true }) })
|
||||
const packageDir = join(dir, 'node_modules', 'with-schema')
|
||||
mkdirSync(packageDir, { recursive: true })
|
||||
writeFileSync(join(packageDir, 'package.json'), '{"name":"with-schema","version":"1.0.0"}\n')
|
||||
const ctx = new Context()
|
||||
ctx.baseUrl = `${pathToFileURL(dir).href}/`
|
||||
await ctx.plugin(PluginPackages)
|
||||
await ctx.plugin(Loader)
|
||||
vi.spyOn(ctx.loader, 'import').mockImplementation((name: string) => Promise.resolve(modules[name]))
|
||||
const ids: Ids = {
|
||||
@@ -34,7 +47,7 @@ async function loaded(): Promise<{ ctx: Context; ids: Ids }> {
|
||||
group: await ctx.loader.create({ name: 'cordis:group', group: true, config: [{ id: 'nested', name: 'no-config' }] }),
|
||||
}
|
||||
await ctx.loader.await()
|
||||
return { ctx, ids }
|
||||
return { ctx, ids, packageDir }
|
||||
}
|
||||
|
||||
interface Page { entries: Array<{ id: string; name: string }>; total: number; nextOffset: number | null }
|
||||
@@ -88,11 +101,11 @@ describe('the Config inspect provider', () => {
|
||||
await ctx.fiber.dispose()
|
||||
})
|
||||
|
||||
it('projects one entry into JSON Schema and reports status alone without a native Config', async () => {
|
||||
const { ctx, ids } = await loaded()
|
||||
it('projects one entry with its package directory and reports status alone without a native Config', async () => {
|
||||
const { ctx, ids, packageDir } = await loaded()
|
||||
const projected = await queryLiveConfig(ctx, { entry: ids.withSchema })
|
||||
expect(projected).toMatchObject({
|
||||
id: ids.withSchema, status: 'schema', acceptsMissing: true, limitations: [],
|
||||
id: ids.withSchema, status: 'schema', packageDir, acceptsMissing: true, limitations: [],
|
||||
schema: {
|
||||
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
||||
$defs: { loaderExpression: { type: 'object', required: ['__jsExpr'] } },
|
||||
@@ -102,7 +115,8 @@ describe('the Config inspect provider', () => {
|
||||
],
|
||||
},
|
||||
})
|
||||
expect(await queryLiveConfig(ctx, { entry: ids.off })).toEqual({ id: ids.off, patchId: ids.off, name: 'with-schema', status: 'inactive' })
|
||||
expect(await queryLiveConfig(ctx, { entry: ids.off })).toEqual({ id: ids.off, patchId: ids.off, name: 'with-schema', status: 'inactive', packageDir })
|
||||
expect(await queryLiveConfig(ctx, { entry: ids.noConfig })).not.toHaveProperty('packageDir')
|
||||
expect(await queryLiveConfig(ctx, { entry: ids.group })).toEqual({ id: ids.group, patchId: ids.group, name: 'cordis:group', status: 'tree' })
|
||||
await expect(queryLiveConfig(ctx, { entry: 'missing' })).rejects.toThrow('unknown entry id "missing"')
|
||||
await ctx.fiber.dispose()
|
||||
|
||||
@@ -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/preset/agent-preset/README.md
|
||||
README.md: b9274969b5c219e9120ba754864e87c03c409bcb
|
||||
README.zh.md: aba74e630713291d1f17a4fe5668aed8985521ea
|
||||
README.md: 99802e2592e046c0580a77b5891a5b79c1e3f1f5
|
||||
README.zh.md: 1130b015a8f7bafcf9b675abd3ca6d654d8e2d7f
|
||||
@@ -47,6 +47,8 @@ Define an Agent’s child plugins in ordinary Cordis YAML. Declare several prese
|
||||
|
||||
The declaration row’s `id` addresses Loader edits; `config.id` is the preset identity saved by sessions. Child entry IDs may be omitted and assigned by Loader.
|
||||
|
||||
The package also ships the `skills/` directory that creator mode mounts through `skill-filesystem`: `cordis-plugin-development` (a short procedure with `references/` read on demand and copyable `templates/` bundles), `editing-cordis-compositions`, and `cordis-composition-reference`, whose `references/packages.md` is generated by `scripts/gen-plugin-packages.ts` and freshness-gated in `doc-sync`. The two procedure skills tell the agent to read inspection results first, then the package README under the `packageDir` that `Config.listConfigs` reports, then built `lib/` or checkout sources. Every shipped `SKILL.md`, rendered as a `skill` tool result, stays under the 8192-character threshold above which the standard preset's tool-result pruner trims results.
|
||||
|
||||
<a id="understand-the-implementation"></a>
|
||||
## Understand the implementation
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@ kind: "package-reference"
|
||||
|
||||
声明行的 `id` 是 Loader 编辑地址;`config.id` 是会话保存的 preset 标识符。子插件可省略行 ID,由 Loader 分配。
|
||||
|
||||
本包还随包出货创造模式通过 `skill-filesystem` 挂载的 `skills/` 目录:`cordis-plugin-development`(简短流程,配合按需读取的 `references/` 与可复制的 `templates/` 组合包)、`editing-cordis-compositions`,以及 `cordis-composition-reference`,后者的 `references/packages.md` 由 `scripts/gen-plugin-packages.ts` 生成并在 `doc-sync` 中做新鲜度门禁。两个流程 skill 让 agent 先读检查结果,再读 `Config.listConfigs` 报告的 `packageDir` 下的包 README,最后读构建后的 `lib/` 或 checkout 源码。每个出货的 `SKILL.md` 作为 `skill` 工具结果渲染后都保持在 8192 字符阈值之下,标准 preset 的工具结果修剪器超过该阈值才会裁剪。
|
||||
|
||||
<a id="understand-the-implementation"></a>
|
||||
## 理解实现
|
||||
|
||||
|
||||
@@ -37,8 +37,13 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/cordis-plugin-include": "workspace:^",
|
||||
"@deepseek-ai/cordis-plugin-loader": "workspace:^",
|
||||
"@deepseek-ai/dsh-agent-preset-registry": "workspace:^",
|
||||
"@deepseek-ai/schemastery": "workspace:^"
|
||||
"@deepseek-ai/dsh-compaction-tool-result-pruner": "workspace:^",
|
||||
"@deepseek-ai/dsh-skill": "workspace:^",
|
||||
"@deepseek-ai/schemastery": "workspace:^",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"js-yaml": "^4.2.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
name: cordis-composition-reference
|
||||
description: Use when writing or reading a Cordis bundle patch or agent preset for this harness and you need the Loader YAML dialect (insert, override by id, group, disabled, isolate, !!js) or the list of installable Harness plugin packages and what each provides.
|
||||
---
|
||||
|
||||
# Cordis composition reference
|
||||
|
||||
Reference material for bundle patches and preset plugin lists. Procedures live in `cordis-plugin-development` and `editing-cordis-compositions`.
|
||||
|
||||
## Loader patch dialect
|
||||
|
||||
A profile composes an ordered list of patch layers over the bundle entry lists. Each patch is a mapping:
|
||||
|
||||
- `insert: [rows]` appends rows; with an `id` naming an existing `group: true` row, the rows are appended inside that group's `config` list.
|
||||
- A patch with an `id` and no `insert` targets the existing row with that id. Supplied fields replace the row's fields; `config` is replaced wholesale, never deep-merged, so restate every field the row needs. A truthy `name` asserts the existing plugin name rather than renaming it.
|
||||
- Non-insert patches without a nonempty `id`, and targets that match no row, are warned about and skipped.
|
||||
|
||||
A row has `id`, `name` (the plugin package specifier; inserted relative paths are anchored beside their patch file), optional `config`, and optional `disabled`, `inject`, `intercept`, and `isolate`.
|
||||
|
||||
- `group: true` with `name: cordis:group` makes `config` a nested entry list and allows patches to insert into it by id. `cordis:include` loads a literal YAML or JSON entry list from `config.path`.
|
||||
- `disabled` accepts a boolean, null, or a `!!js` expression evaluated against the Loader context at every mount decision. A disabled row omits required `config` unless `group: true` forces activation.
|
||||
- `!!js` scalars are Loader expressions, never `!js`. Inside `config` they are evaluated after the row's declared injections activate, against that plugin's context (`ctx.<service>`), so `!!js dshHomePath('sessions')` and `!!js "!ctx.get('profileContext')"` are valid. Other row metadata stays literal.
|
||||
- `isolate` maps service names to `true` or a realm label; a preset plugin that provides a service isolates the provider and all consumers together. Scope controls contributions and event visibility; `isolate` controls service instances.
|
||||
|
||||
`plugin_manager` `list_plugins` reports each row's `enabled` flag and `fiberPhase`; `set_plugin` and `set_bundle` answer `overridden` when a higher-priority layer wins.
|
||||
|
||||
## Installable plugin packages
|
||||
|
||||
`references/packages.md` lists every workspace package that exports a Cordis plugin, grouped by package group, with whether its row takes `config`. Search it with `grep -n <keyword>` rather than reading it whole. Plugins outside this list come from installed bundles; `plugin_manager` `list_bundles` names them.
|
||||
+498
@@ -0,0 +1,498 @@
|
||||
# Loadable Harness plugin packages
|
||||
|
||||
This file is GENERATED from workspace manifests (`scripts/gen-plugin-packages.ts`) and verified fresh by `pnpm run verify-plugin-packages` (part of `doc-sync`); do not edit it by hand.
|
||||
|
||||
Every package below exports a Cordis plugin that a bundle patch can name in a Loader row. `Config` marks packages whose row accepts a `config` mapping; query `Config.listConfigs` through `cordis_inspect_query` (filter by `name`, then query the `entry` id) for the mounted schema. Packages under `experimental` are pre-stable.
|
||||
|
||||
## acp
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-acp` | yes | Automation-only Agent Client Protocol server for driving DeepSeek Harness agents over JSON-RPC stdio |
|
||||
|
||||
## api
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-api-gateway` | yes | Typert Remote Host dispatcher and Client API endpoint |
|
||||
| `@deepseek-ai/dsh-api-job-controller` | yes | Job Remote observation stream and the reference-counted client job-output service |
|
||||
| `@deepseek-ai/dsh-api-remotes` | no | Remote BFF assembly for application-selected Host capabilities |
|
||||
| `@deepseek-ai/dsh-api-session-controller` | yes | Session Remote commands, cold reads, and live control transport |
|
||||
| `@deepseek-ai/dsh-api-settings-controller` | yes | Remote owner for the configuration surfaces over the settings-domain seams |
|
||||
| `@deepseek-ai/dsh-api-terminal-controller` | yes | Session-owned interactive terminals with shell discovery, screen recovery and typed Remote control |
|
||||
| `@deepseek-ai/dsh-api-workspace-controller` | yes | Workspace Remote commands and reconnect-safe state transport |
|
||||
| `@deepseek-ai/dsh-api-workspace-files` | yes | Workspace file service and Client resource provider: bounded reads, directory listing, and live metadata over the workspaceFiles Remote namespace |
|
||||
|
||||
## attachment
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-attachment-local` | yes | Private content-addressed DSH_HOME attachment storage |
|
||||
|
||||
## boot
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-config-editor` | no | Persist plugin configuration through profile patches and Loader reconciliation |
|
||||
| `@deepseek-ai/dsh-hmr` | yes | Coordinated module and profile configuration hot reload |
|
||||
| `@deepseek-ai/dsh-plugin-manager` | yes | Current-profile plugin and bundle management shared by dsh CLI, Web and agent tools |
|
||||
|
||||
## browser-use
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-browser-use` | no | Exclusive named browser-use provider registration |
|
||||
|
||||
## bundle
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-acp-app` | no | The dsh ACP profile bundle: automation-only JSON-RPC stdio and process lifecycle over dsh-base |
|
||||
| `@deepseek-ai/dsh-headless` | yes | The dsh one-shot bundle: a direct core Agent/Session runner over dsh-base with no Host, HTTP, or browser layer |
|
||||
| `@deepseek-ai/dsh-sdk-app` | yes | The dsh SDK profile bundle: stdio JSON-RPC serving and process lifecycle over dsh-base |
|
||||
| `@deepseek-ai/dsh-web-app` | yes | The dsh browser-surface bundle: the web patch layer over dsh-base plus the runtime glue plugin (frontend dist serving, web-surface prompt, bash runtime variables, URL line) |
|
||||
|
||||
## client
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-client-connection` | yes | Authenticated RPC transport and generation lifecycle |
|
||||
| `@deepseek-ai/dsh-client-file-upload` | no | Agent-scoped browser file upload, streaming intake, and staged receipt service |
|
||||
| `@deepseek-ai/dsh-client-hmr` | yes | Web client graph synchronization and rebuilt-bundle reload transport |
|
||||
| `@deepseek-ai/dsh-client-locale` | no | Locale plugin: Host-backed preference, extensible language catalog, browser fallback, and typed built-in dictionaries |
|
||||
| `@deepseek-ai/dsh-client-modules` | no | Client module system, dual-face: node half composes the __DSH_BOOT__ entry graph (incremental dsh.client scan, bundle route, index tap, webPlugins service); browser half is the lazy-CJS module table the vendored cordis Loader consumes as its internal seam |
|
||||
| `@deepseek-ai/dsh-client-resources` | no | Unified client resource model: protocol-registered providers turn URL addresses into live values, consumed through the useResource global standard hook |
|
||||
| `@deepseek-ai/dsh-client-ui-agent-preset` | no | Agent-preset surfaces: the default for later sessions, this session's seat, and the composition editor |
|
||||
| `@deepseek-ai/dsh-client-ui-approval` | no | Approval composer takeover over the scoped Remote Event waterfall |
|
||||
| `@deepseek-ai/dsh-client-ui-attachment` | no | Dynamic attachment presentation plugin for conversation input, message-image, and trajectory image slots |
|
||||
| `@deepseek-ai/dsh-client-ui-brand-official` | no | Official DeepSeek Harness brand occupants for the Web client's sidebar slots |
|
||||
| `@deepseek-ai/dsh-client-ui-chat` | no | Chat Conversation target, node definitions, renderers, and details surface |
|
||||
| `@deepseek-ai/dsh-client-ui-commands` | no | Client command surface: global directory cache, '/' source, three command UI kinds, popupSelect registry |
|
||||
| `@deepseek-ai/dsh-client-ui-conversation` | no | Target-neutral Conversation assembly, shell, composer, queue, and view navigation |
|
||||
| `@deepseek-ai/dsh-client-ui-deliverables` | no | Changed-files card with per-file comparison tabs, delivery cards, and clickable final-response file references for Web |
|
||||
| `@deepseek-ai/dsh-client-ui-directory-picker-browse` | no | In-app directory browsing surface: the workspace directory-flow owner rendering the host's listing and creation primitives |
|
||||
| `@deepseek-ai/dsh-client-ui-directory-picker-native` | no | Native directory-picker surface: the renderless workspace directory-flow occupant driving the local Desktop or Host OS chooser |
|
||||
| `@deepseek-ai/dsh-client-ui-goal` | no | Session goal surface: GoalBar docked above the composer, read from the goal session projection |
|
||||
| `@deepseek-ai/dsh-client-ui-input-trigger` | no | Input trigger pipeline: '/' and '@' detection, candidate menu, pick routing to registered sources |
|
||||
| `@deepseek-ai/dsh-client-ui-jobs` | no | Session-header background-job list with on-demand streaming record panels |
|
||||
| `@deepseek-ai/dsh-client-ui-layout` | no | Shell plugin: three-column AppFrame with drag handles, ctx.layout viewing-state service (navigation + panels) |
|
||||
| `@deepseek-ai/dsh-client-ui-message-feedback` | no | The Web feedback surface: per-message Like/Dislike in the assistant-message action strip and the feedback dialog behind both ratings and /feedback, backed by the messageFeedback and sessionFeedback Host Remotes |
|
||||
| `@deepseek-ai/dsh-client-ui-model-selection` | no | Model selection over the shared model catalog, Session projection, and session.selectModel |
|
||||
| `@deepseek-ai/dsh-client-ui-open-in-app` | no | Web "Open In..." controls: the Session-header split button opening the workspace directory in an installed application, and the document preview's default-application controls for one file |
|
||||
| `@deepseek-ai/dsh-client-ui-permission-presets` | no | Permission surfaces: a new-session default in General settings and a current-session /permission popup over the permissions projection |
|
||||
| `@deepseek-ai/dsh-client-ui-plan` | no | Plan mode controls, persistent transcript plan cards, and sidebar Markdown previews |
|
||||
| `@deepseek-ai/dsh-client-ui-plugin-manager` | no | Plugin management for the dsh web client: the sidebar Plugins panel installs, enables, disables, retries, and composes installed plugin packages |
|
||||
| `@deepseek-ai/dsh-client-ui-reference` | no | Unified Web @file and @session reference source |
|
||||
| `@deepseek-ai/dsh-client-ui-renderer` | no | Browser UI renderer: React slot bindings, ctx.uiRenderer, and the assembled application root |
|
||||
| `@deepseek-ai/dsh-client-ui-schedule` | no | Read-only active Schedule catalog in the Web Session header |
|
||||
| `@deepseek-ai/dsh-client-ui-session` | no | Session Controller adapter for React and session-scoped slots |
|
||||
| `@deepseek-ai/dsh-client-ui-settings` | no | Settings domain base plugin: shared configuration forms and the canonical settings slot-type contract |
|
||||
| `@deepseek-ai/dsh-client-ui-settings-agent-loop` | no | Settings page of the agent loop on the dsh web client's Plugins page: the parallel tool-call cap of the agent-loop namespace |
|
||||
| `@deepseek-ai/dsh-client-ui-settings-general` | no | Settings ownerless-copy and product onboarding plugin: the General section, shell trigger/header chrome content, settings dictionaries, and the versioned welcome notice |
|
||||
| `@deepseek-ai/dsh-client-ui-settings-models` | no | Models settings and shared product-onboarding dialogs over existing settings and credential joins |
|
||||
| `@deepseek-ai/dsh-client-ui-settings-plugin-inventory` | no | Read-only Cordis Loader inventory tab in Web Plugins settings |
|
||||
| `@deepseek-ai/dsh-client-ui-settings-plugins` | no | Built-in plugins settings section for the dsh web client: the Settings navigation entry and the tab chrome feature-owned tabs register into |
|
||||
| `@deepseek-ai/dsh-client-ui-settings-shell` | no | Settings page of the shell executor on the dsh web client's Plugins page: the command timeout and the per-stream output cap of the shell namespace |
|
||||
| `@deepseek-ai/dsh-client-ui-settings-subagent` | no | Settings page of Subagent delegation on the dsh web client's Plugins page: recursion depth, parallel capacity, and the models agents may choose for subagents |
|
||||
| `@deepseek-ai/dsh-client-ui-settings-web-search` | no | Settings page of the DeepSeek web-search provider on the dsh web client's Plugins page: its API key, endpoint, and per-request search budget |
|
||||
| `@deepseek-ai/dsh-client-ui-sidebar` | no | Sidebar plugin: session multi-level tree, search, grouping, state dots |
|
||||
| `@deepseek-ai/dsh-client-ui-sidebar-browser` | no | Sandboxed Web browser tabs for the right Sidebar |
|
||||
| `@deepseek-ai/dsh-client-ui-sidebar-documentpreview` | yes | Extensible Sidebar previews for Office documents, spreadsheets, Markdown, code, images, PDF, HTML, and plain text |
|
||||
| `@deepseek-ai/dsh-client-ui-sidebar-files` | no | Workspace file tree tab type for the right Sidebar: lazy directory listing over the workspaceFiles Remote namespace, opening files into the Sidebar |
|
||||
| `@deepseek-ai/dsh-client-ui-sidebar-right` | no | Right Sidebar: the docking surface's session-bound state, its panel and header expand control, and the navigation service over it |
|
||||
| `@deepseek-ai/dsh-client-ui-sidebar-terminal` | no | Interactive shell tabs for the right Sidebar |
|
||||
| `@deepseek-ai/dsh-client-ui-skill` | no | Web skill references and the dedicated skill tool row |
|
||||
| `@deepseek-ai/dsh-client-ui-subagent` | no | Subagent conversation catalog, continuation routing UI, and '@' reference source |
|
||||
| `@deepseek-ai/dsh-client-ui-theme` | yes | Theme plugin: Host bootstrap for the pre-plugin palette; DOM-free ThemeRuntime for light/dark/system state; --dsw-* token styles and Appearance settings row |
|
||||
| `@deepseek-ai/dsh-client-ui-tool` | no | Client Tool call-tree renderer and keyed per-tool presentation slot |
|
||||
| `@deepseek-ai/dsh-client-ui-trajectory` | no | Trajectory event ledger with an interactive timing overview: pure-consumer plugin registering into the conversation ViewMap (no service) |
|
||||
| `@deepseek-ai/dsh-client-ui-user-questions` | no | Web ask_user_question composer takeover and plan-review presentation UI |
|
||||
| `@deepseek-ai/dsh-client-ui-workflow-run` | no | Durable workflow-run Conversation Node and nested member disclosure for dsh web |
|
||||
| `@deepseek-ai/dsh-client-ui-workspace` | no | Workspace picker plugin: one WorkspacePicker registered into the sidebar and empty-state workspace slots |
|
||||
|
||||
## compaction
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-command-compact` | no | Human-facing slash command for explicit session compaction |
|
||||
| `@deepseek-ai/dsh-compaction-basic` | yes | Token-meter-driven compaction policy and LLM summarization backend for the DeepSeek Harness |
|
||||
| `@deepseek-ai/dsh-compaction-image-offload` | no | Durable image offload for image-capable routes: replace over-budget request images with placeholders and retry |
|
||||
| `@deepseek-ai/dsh-compaction-tool-result-pruner` | yes | Replay-safe model-free head/middle/tail pruning for tool-result surface nodes |
|
||||
|
||||
## computer-use
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-computer-use` | no | Exclusive named computer-use provider registration |
|
||||
|
||||
## context
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-agent-instructions` | yes | Workspace context loader for AGENTS.md/CLAUDE.md instruction files |
|
||||
| `@deepseek-ai/dsh-file-reference-local` | yes | Local-filesystem ctx.fileReferences provider with bounded fuzzy indexes |
|
||||
| `@deepseek-ai/dsh-session-reference` | yes | Cross-session snapshot references and durable untrusted model context (ctx.sessionReferenceResolver) |
|
||||
| `@deepseek-ai/dsh-time-context` | yes | Opt-in durable per-step context with the current time and elapsed time |
|
||||
| `@deepseek-ai/dsh-tmux-context` | yes | Opt-in durable per-step context with this agent's tmux pane and window location |
|
||||
|
||||
## core
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-agent` | no | Agent interface, registry, initiator scope, and event vocabulary for the DeepSeek Harness |
|
||||
| `@deepseek-ai/dsh-agent-default-model` | yes | Default model selection shared by Agent entry points |
|
||||
| `@deepseek-ai/dsh-agent-loop` | yes | The concrete agent loop plugin for the DeepSeek Harness |
|
||||
| `@deepseek-ai/dsh-agent-tool-presentation` | yes | Agent-plane presentation selector: composes one agent's tools as PTC mode, native, or both |
|
||||
| `@deepseek-ai/dsh-session` | no | Event-sourced session store for the DeepSeek Harness |
|
||||
| `@deepseek-ai/dsh-system-prompt` | yes | System prompt assembly registry for the DeepSeek Harness |
|
||||
| `@deepseek-ai/dsh-tools` | yes | Tool registry and execution pipeline for the DeepSeek Harness |
|
||||
|
||||
## credentials
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-authorization` | no | Authorization seam (ctx.authorization): plugin-owned flows that obtain a credential through a conversation with the human |
|
||||
| `@deepseek-ai/dsh-credentials-local` | yes | File-backed credentials provider ($DSH_HOME/.env under the live process environment) for the DeepSeek Harness |
|
||||
|
||||
## deliverables
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-tool-present` | yes | Explicit workspace file delivery declarations for the DeepSeek Harness |
|
||||
| `@deepseek-ai/dsh-workspace-changes` | yes | Per-turn workspace file changes recorded from git working-tree snapshots and whole-file captures, with per-file comparisons, for the DeepSeek Harness |
|
||||
|
||||
## document
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-office-to-pdf` | yes | Shared Office-to-PDF conversion with bounded queues and caching |
|
||||
|
||||
## experimental
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-experimental-agent-team` | yes | Implicit-root Agent Teams roster, durable peer mailbox, and shared task DAG |
|
||||
| `@deepseek-ai/dsh-experimental-api-speech-to-text` | yes | Authenticated experimental speech transcription for browser clients |
|
||||
| `@deepseek-ai/dsh-experimental-auto-review` | no | Per-tool LLM authorization review for the DeepSeek Harness Auto permission preset |
|
||||
| `@deepseek-ai/dsh-experimental-browser-use-chrome-devtools-mcp` | yes | Experimental per-Session Chromium browser tools through chrome-devtools-mcp |
|
||||
| `@deepseek-ai/dsh-experimental-browser-use-playwright-mcp` | yes | Experimental per-Session Chromium browser tools through @playwright/mcp |
|
||||
| `@deepseek-ai/dsh-experimental-browser-use-stagehand-native` | yes | Experimental Stagehand browser tools with separately configured native models |
|
||||
| `@deepseek-ai/dsh-experimental-client-ui-agent-team` | no | Web Agent Teams roster, task board, and teammate navigation |
|
||||
| `@deepseek-ai/dsh-experimental-client-ui-voice-input` | no | Record speech and insert editable text into the conversation draft |
|
||||
| `@deepseek-ai/dsh-experimental-computer-use-cua-driver-mcp` | yes | Experimental computer use through an installed Cua Driver MCP executable |
|
||||
| `@deepseek-ai/dsh-experimental-computer-use-cua-driver-native` | no | Experimental computer-use provider embedding the Cua Driver native npm SDK |
|
||||
| `@deepseek-ai/dsh-experimental-inspector` | yes | Experimental cross-realm CDP hub for Host debugging and Client Runtime inspection |
|
||||
| `@deepseek-ai/dsh-experimental-ptc-runtime-python` | yes | CPython subprocess implementation of the DeepSeek Harness PTC execution seam |
|
||||
| `@deepseek-ai/dsh-experimental-speech-to-text` | yes | Experimental speech recognition with independently selectable providers |
|
||||
| `@deepseek-ai/dsh-experimental-speech-to-text-sensevoice` | yes | Local SenseVoice ONNX transcription with a managed sherpa-onnx process |
|
||||
| `@deepseek-ai/dsh-experimental-tool-agent-team` | yes | Scoped model-facing Agent Teams tools over ctx.agentTeams |
|
||||
|
||||
## extensions
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-client-ui-cordis` | no | Cordis dynamic-plugin definition card: the keyed cordis_define tool row with its run/stop switch |
|
||||
| `@deepseek-ai/dsh-cordis-client-runner` | no | Browser half of dynamic dual-half plugin packages: event subscription, closure evaluation, guard facade, and loader entries |
|
||||
| `@deepseek-ai/dsh-cordis-host-runner` | yes | Dynamic package definition registry, host-half sandbox lifecycle, and invoke handler table for model-mounted dual-half packages |
|
||||
| `@deepseek-ai/dsh-tool-cordis` | no | Read-only runtime API inspection for Harness plugin development |
|
||||
|
||||
## feedback
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-command-feedback` | no | Log-only session feedback: the record event, the sessionFeedback Host Remote, and the human-facing slash command |
|
||||
| `@deepseek-ai/dsh-message-feedback` | yes | Canonical Session-log ratings and notes for finalized assistant messages |
|
||||
|
||||
## fs
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-fs-local` | yes | Local-filesystem implementation of the DeepSeek Harness filesystem seam (ctx.fs) |
|
||||
| `@deepseek-ai/dsh-fs-observation-policy` | no | File-context policy plugin for the DeepSeek Harness — observed-state, read-before-edit, and version-guarded write/edit added over the ctx.fs provider seam through the fs/* event gate (no service API) |
|
||||
| `@deepseek-ai/dsh-fs-sandbox` | yes | Sandbox-enforcing implementation of the DeepSeek Harness filesystem seam: fences write/edit by the per-call sandbox mode (read-only denies mutation, workspace-write contains it to the workspace + temp roots) while reads pass through |
|
||||
| `@deepseek-ai/dsh-tool-fs` | yes | Model-facing filesystem tools (read, write, edit) over the DeepSeek Harness filesystem seam (ctx.fs) |
|
||||
| `@deepseek-ai/dsh-tool-fs-search` | yes | Model-facing filesystem discovery tools (glob, grep) backed by the packaged ripgrep binary (@vscode/ripgrep) |
|
||||
| `@deepseek-ai/dsh-tool-str-replace-editor` | yes | Model-facing view, create, literal replace, and line insert tool over the Harness filesystem service |
|
||||
|
||||
## goal
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-command-goal` | no | Human-facing slash command for persisted same-session goals |
|
||||
| `@deepseek-ai/dsh-goal` | yes | Event-sourced same-session goal state and lifecycle service for the DeepSeek Harness |
|
||||
| `@deepseek-ai/dsh-goal-round-driver` | no | Race-fenced same-session goal-round driver |
|
||||
| `@deepseek-ai/dsh-tool-goal` | yes | Model-facing same-session goal tools with execution-time authority checks |
|
||||
|
||||
## guard
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-repeat-tool-reminder` | yes | Repeat-tool-call guard plugin: advisory reminders when an agent loops on identical tool calls |
|
||||
| `@deepseek-ai/dsh-tool-call-timeout-policy` | no | Tool-call timeout policy: a tools/execute wrapper that arms a per-tool deadline on exec.signal and returns TOOL_TIMEOUT when it wins |
|
||||
|
||||
## hooks
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-hooks-claude-code` | yes | Bridge plugin: run a Claude Code hooks.json / settings hook config on the DeepSeek Harness interception seams |
|
||||
| `@deepseek-ai/dsh-hooks-codex` | yes | Bridge plugin: run a Codex hooks.json hook config on the DeepSeek Harness interception seams |
|
||||
|
||||
## host
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-host-directory-picker-auto` | no | Adaptive chooser of the directory-picker seam: resolves the host situation at boot and mounts the native or browse backend for the DeepSeek Harness web GUI host |
|
||||
| `@deepseek-ai/dsh-host-directory-picker-browse` | yes | In-app browsing backend of the directory-picker seam (listing/creation primitives over the host filesystem) |
|
||||
| `@deepseek-ai/dsh-host-directory-picker-native` | no | Native-OS-chooser backend of the directory-picker seam for the DeepSeek Harness web GUI host |
|
||||
| `@deepseek-ai/dsh-host-frontend-static` | yes | SPA dist server for the Web shell: owns the webserver fallback seat, serving explicit index entries and static assets with traversal rejection and 404 misses |
|
||||
| `@deepseek-ai/dsh-host-open-in-app` | yes | Host half of open-in-app: resolved application catalog, icons, and the launch endpoint as three webServer routes |
|
||||
| `@deepseek-ai/dsh-host-plugin-inventory` | no | Read-only Remote projection of current Cordis Loader plugin state |
|
||||
| `@deepseek-ai/dsh-host-product-telemetry-otel` | yes | Explicit product usage events exported through OpenTelemetry HTTP logs |
|
||||
| `@deepseek-ai/dsh-host-webserver` | yes | Web route-registration plugin: HTTP and upgrade routes, index transform taps, and static dist fallback; knows no harness concepts |
|
||||
|
||||
## interaction
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-commands` | no | Plugin-owned human command registry for DeepSeek Harness UIs |
|
||||
| `@deepseek-ai/dsh-permission-presets` | yes | User-facing permission presets (ctx.permissionPresets) for the DeepSeek Harness: one product-level Permissions select bundling the sandbox-mode and approval-policy knobs, written through to their own session events |
|
||||
| `@deepseek-ai/dsh-tool-ask-user` | no | Model-facing ask_user_question tool over the ctx.userQuestions seam |
|
||||
| `@deepseek-ai/dsh-user-approval` | yes | User-approval seam (ctx.approval) for the DeepSeek Harness: one-shot permission decisions dispatched to composed answerers over the approval/request waterfall, fail-closed by default |
|
||||
| `@deepseek-ai/dsh-user-questions` | no | Abstract user-questions seam (ctx.userQuestions) for asking the human during agent runs |
|
||||
|
||||
## jobs
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-jobs-local` | yes | Process-local implementation of the DeepSeek Harness background job registry seam |
|
||||
| `@deepseek-ai/dsh-tool-jobs` | yes | Model-facing background job control tools (job_output, job_list, job_kill) over the ctx.jobs registry |
|
||||
|
||||
## llm
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-deepseek-llm-api-extensions` | no | Additive request-field registry for the official DeepSeek LLM API adapter |
|
||||
| `@deepseek-ai/dsh-llm` | no | Provider-neutral LLM service interface for the DeepSeek Harness |
|
||||
| `@deepseek-ai/dsh-llm-deepseek` | yes | DeepSeek Messages adapter |
|
||||
| `@deepseek-ai/dsh-llm-pi-ai` | yes | pi-ai-backed DeepSeek adapter for the DeepSeek Harness LLM seam (design-verification twin of dsh-llm-deepseek) |
|
||||
| `@deepseek-ai/dsh-llm-retry` | yes | Provider-routed LLM request retry policy for the DeepSeek Harness |
|
||||
| `@deepseek-ai/dsh-plugin-package-inventory-deepseek` | yes | Active Loader-backed plugin package inventory for official DeepSeek LLM API requests |
|
||||
| `@deepseek-ai/dsh-token-meter` | yes | Replay-aware token measurement service (ctx.tokenMeter) for the DeepSeek Harness |
|
||||
|
||||
## lsp
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-lsp` | no | Abstract LSP capability seam (ctx.lsp) for the DeepSeek Harness — language-server provider registry keyed by branded id and extension mapping, order-independent per-query selection, normalized definition/references/implementation/hover requests and results, and the LspError taxonomy |
|
||||
| `@deepseek-ai/dsh-lsp-stdio` | yes | Generic stdio language-server provider for the DeepSeek Harness LSP capability seam (ctx.lsp) — spawns configured servers, translates JSON-RPC, and serves transient-open goToDefinition/findReferences/goToImplementation/hover queries in the host filesystem namespace |
|
||||
| `@deepseek-ai/dsh-tool-lsp` | yes | Model-facing lsp tool over the DeepSeek Harness LSP capability seam (ctx.lsp) — one read-only tool with goToDefinition/findReferences/goToImplementation/hover operations, one-based UTF-16 cursor coordinates, bounded location rendering, and hover normalization |
|
||||
|
||||
## mcp
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-mcp-client` | yes | MCP client bridge: connects to MCP servers and registers their tools on ctx.tools |
|
||||
| `@deepseek-ai/dsh-mcp-resources` | no | Scoped MCP resource discovery and reading through shared model tools |
|
||||
|
||||
## plan
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-plan-mode` | yes | Logged per-agent plan mode with deployment guidance, a direct slash command, and a user-reviewed exit |
|
||||
|
||||
## preset
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-agent-preset` | yes | Declare an Agent capability composition in Cordis YAML |
|
||||
| `@deepseek-ai/dsh-agent-preset-registry` | yes | Declarative Agent preset registry and profile-backed editing |
|
||||
| `@deepseek-ai/dsh-persona` | yes | Composition-authored deployment persona section for the DeepSeek Harness |
|
||||
|
||||
## ptc-runtime
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-ptc-runtime-node` | yes | Sandboxed Node process implementation of the DeepSeek Harness PTC execution capability |
|
||||
|
||||
## runtime-diagnostics
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-invariants` | yes | Registry service for package-owned DeepSeek Harness runtime invariants |
|
||||
|
||||
## sandbox
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-sandbox-local` | yes | Local process-sandbox backends for the DeepSeek Harness sandbox seam: bwrap, the npm-distributed landlock-run launcher, macOS Seatbelt, or the Windows ACL restricted-token runner — functionally probed, fail-closed |
|
||||
| `@deepseek-ai/dsh-sandbox-policy` | yes | Per-call sandbox policy resolver and current model context: deployment fallbacks plus each session's mode and workspace root, shared by every enforcing capability family |
|
||||
|
||||
## schedule
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-schedule` | no | Agent-scoped durable after, at, and fixed-rate reminders over the session event log |
|
||||
|
||||
## sdk
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-sdk-jsonrpc-server` | yes | Stdio JSON-RPC server plugin for out-of-process DeepSeek Harness SDK clients |
|
||||
|
||||
## session
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-session-checkpoint-policy` | no | Semantic session durability checkpoints before model requests and tool side effects |
|
||||
| `@deepseek-ai/dsh-session-log-deepseek` | yes | Incremental lossless session-log request extension for the official DeepSeek LLM API |
|
||||
| `@deepseek-ai/dsh-session-persistence-jsonl` | yes | JSONL durable session persistence backend for the DeepSeek Harness |
|
||||
| `@deepseek-ai/dsh-session-projection` | no | Session-projection seam: the merge-extensible projection type table, the provider contract, and the ctx.sessionProjections registry serving whole current values of log-derived per-session state |
|
||||
| `@deepseek-ai/dsh-session-projection-cache` | yes | Persisted projection cache (ctx.sessionProjectionCache): durable per-session checkpoint records on the session_projcache storage domain (per-record layout), throttled write-behind, and the cached listing read |
|
||||
| `@deepseek-ai/dsh-session-stats` | no | Whole-log conversation counts and wall times projection (sessionStats) for the DeepSeek Harness |
|
||||
| `@deepseek-ai/dsh-session-telemetry-otel` | yes | OpenTelemetry backend for the DeepSeek Harness telemetry seam: hands captured session records to the OTel JS SDK's log pipeline |
|
||||
| `@deepseek-ai/dsh-session-title` | yes | Log-backed session title service and provider registry for the DeepSeek Harness |
|
||||
| `@deepseek-ai/dsh-session-title-all-prompts-llm` | yes | All-user-messages LLM provider plugin for DeepSeek Harness session titles |
|
||||
| `@deepseek-ai/dsh-session-title-first-prompt-llm` | yes | First-message LLM provider plugin for DeepSeek Harness session titles |
|
||||
| `@deepseek-ai/dsh-session-turn-outline` | no | Whole-log turn outline projection (turnOutline) for the DeepSeek Harness |
|
||||
|
||||
## session-query
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-session-log-export` | yes | Web Session-log export command and shared download dialog |
|
||||
| `@deepseek-ai/dsh-session-query-sqlite` | yes | Concrete ctx.sessionQuery backend with SQLite FTS5 search |
|
||||
| `@deepseek-ai/dsh-tool-session-query` | yes | Workspace-authorized model-facing session history search, trace, and event read tools |
|
||||
|
||||
## settings
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-settings` | no | Abstract user-settings seam (ctx.settings) for the DeepSeek Harness |
|
||||
|
||||
## shell
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-bash-local` | yes | Local-subprocess implementation of the DeepSeek Harness bash executor seam |
|
||||
| `@deepseek-ai/dsh-bash-sandbox` | yes | Sandbox-consuming implementation of the DeepSeek Harness bash executor seam (confines every command via ctx.sandbox, reports denial/enforcement result facts) |
|
||||
| `@deepseek-ai/dsh-pwsh-local` | yes | Local PowerShell implementation of the DeepSeek Harness bash executor seam |
|
||||
| `@deepseek-ai/dsh-pwsh-sandbox` | yes | Sandbox-consuming implementation of the DeepSeek Harness PowerShell executor seam (confines every command via ctx.sandbox, reports denial/enforcement result facts) |
|
||||
| `@deepseek-ai/dsh-shell-env` | yes | Tool-independent managed DSH_* shell environment registry |
|
||||
| `@deepseek-ai/dsh-tool-bash` | yes | Model-facing bash tool with optional generic background-job and sandbox-escalation support |
|
||||
| `@deepseek-ai/dsh-tool-bash-persistent` | yes | Model-facing owner-scoped persistent Bash tool backed by the Harness PTY service |
|
||||
| `@deepseek-ai/dsh-tool-pwsh` | yes | Model-facing pwsh tool over the bash executor seam |
|
||||
| `@deepseek-ai/dsh-tool-pwsh-persistent` | yes | Model-facing owner-scoped persistent PowerShell tool backed by the Harness PTY service |
|
||||
|
||||
## skill
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-skill` | yes | Agent skill provider registry for the DeepSeek Harness |
|
||||
| `@deepseek-ai/dsh-skill-badge` | no | Bundled dsh badge skill provider for DeepSeek Harness |
|
||||
| `@deepseek-ai/dsh-skill-filesystem` | yes | Local filesystem skill provider for the DeepSeek Harness |
|
||||
| `@deepseek-ai/dsh-skill-office` | yes | Bundled Word, PowerPoint, and Excel workflows and structural checks |
|
||||
| `@deepseek-ai/dsh-tool-skill` | yes | Model-facing skill loading tool for the DeepSeek Harness |
|
||||
| `@deepseek-ai/dsh-tool-workspace-dependencies` | yes | The load_workspace_dependencies tool: absolute paths into a bundled Python, Node.js, and pnpm payload |
|
||||
|
||||
## spill
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-spill-local` | yes | Local-filesystem implementation of the DeepSeek Harness spill storage seam (private session-scoped files) |
|
||||
| `@deepseek-ai/dsh-spill-policy` | yes | Tool-result spill policy for the DeepSeek Harness — replaces oversized plain-text tool results with a retained preview plus a spill-file path (no service API) |
|
||||
|
||||
## ssh
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-fs-ssh` | no | Filesystem provider over the shared POSIX SSH helper |
|
||||
| `@deepseek-ai/dsh-sandbox-ssh` | no | Remote POSIX sandbox argv provider over the shared SSH helper |
|
||||
| `@deepseek-ai/dsh-ssh` | yes | Shared OpenSSH connection and versioned POSIX remote helper |
|
||||
| `@deepseek-ai/dsh-subprocess-ssh` | no | Subprocess and terminal provider over the shared POSIX SSH helper |
|
||||
|
||||
## storage
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-storage` | no | Storage hub (ctx.storage): named backend registry plus mounted data-form facilities for the DeepSeek Harness |
|
||||
| `@deepseek-ai/dsh-storage-domain` | yes | Domain data form (ctx.storage.domain): schema-validated, event-emitting KV domains over storage backends for the DeepSeek Harness |
|
||||
| `@deepseek-ai/dsh-storage-json` | yes | JSON file KV storage backend for the DeepSeek Harness storage hub |
|
||||
| `@deepseek-ai/dsh-storage-sqlite` | yes | SQLite storage backend (kv facet) for the DeepSeek Harness storage hub |
|
||||
|
||||
## subagent
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-subagent` | yes | Abstract subagent seam (ctx.subagents): named-provider registry for delegating to child agents |
|
||||
| `@deepseek-ai/dsh-subagent-acp` | yes | Out-of-process ACP subagent backend: drives a child agent in a spawned subprocess over the Agent Client Protocol |
|
||||
| `@deepseek-ai/dsh-subagent-claude-code` | yes | One-shot Claude Code subagent provider over the official Agent SDK |
|
||||
| `@deepseek-ai/dsh-subagent-codex` | yes | One-shot Codex subagent provider over the official app-server protocol |
|
||||
| `@deepseek-ai/dsh-subagent-dsh-sdk` | yes | Out-of-process SDK subagent backend: drives a child DeepSeek Harness runtime subprocess over stdio JSON-RPC through the TypeScript SDK client |
|
||||
| `@deepseek-ai/dsh-subagent-fork-in-process` | yes | In-process fork subagent backend: runs a child agent seeded with a prefix of the parent's log |
|
||||
| `@deepseek-ai/dsh-subagent-spawn-in-process` | yes | In-process spawn subagent backend: runs a fresh child agent on ctx.agents |
|
||||
| `@deepseek-ai/dsh-tool-subagent` | yes | Model-facing subagent delegation tool over the ctx.subagents seam |
|
||||
| `@deepseek-ai/dsh-tool-subagent-control` | no | Globally named send_message, interrupt_agent, and list_agents tools over ctx.subagents continuations |
|
||||
|
||||
## subprocess
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-subprocess-local` | no | Local-subprocess implementation of the DeepSeek Harness subprocess seam |
|
||||
|
||||
## terminal
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-terminal` | no | Persistent PTY session seam for the DeepSeek Harness — owner-scoped ids, backend registry, interactive sends, reads, signals, and awaited cleanup |
|
||||
| `@deepseek-ai/dsh-terminal-bash` | yes | Persistent shell PTY backend over the DeepSeek Harness subprocess terminal primitive |
|
||||
| `@deepseek-ai/dsh-tool-terminal` | yes | Six model-facing persistent PTY tools with owner isolation and generic background-job integration |
|
||||
|
||||
## test-support
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-llm-replay` | yes | Replay LLM plugin: short-circuits llm/stream with model chunks reconstructed from a recorded session JSONL (keyless snapshot tests) |
|
||||
|
||||
## todo
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-tool-todo` | yes | Model-facing todo_write tool over the DeepSeek Harness event-sourced session log |
|
||||
|
||||
## typert
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-typert-loader` | yes | Loader integration for generated Typert package contributions |
|
||||
|
||||
## web
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-tool-web` | yes | Model-facing web tools (web_search, web_fetch) over the DeepSeek Harness web capability seam (ctx.web) |
|
||||
| `@deepseek-ai/dsh-web` | yes | Abstract web access capability seam (ctx.web) for the DeepSeek Harness — search/fetch provider registry, registration-order-independent selection, request/result vocabulary, and the WebError taxonomy |
|
||||
| `@deepseek-ai/dsh-web-fetch-http` | yes | Anonymous public HTTP(S) fetch provider for the DeepSeek Harness web capability seam (ctx.web) |
|
||||
| `@deepseek-ai/dsh-web-search-deepseek` | yes | DeepSeek-backed search provider (native web_search via the Anthropic-compatible API) for the DeepSeek Harness web capability seam (ctx.web) |
|
||||
| `@deepseek-ai/dsh-web-search-exa` | yes | Exa-backed search provider for the DeepSeek Harness web capability seam (ctx.web) |
|
||||
| `@deepseek-ai/dsh-web-search-perplexity` | yes | Perplexity-backed search provider for the DeepSeek Harness web capability seam (ctx.web) |
|
||||
|
||||
## webhook
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-webhook` | no | Fire-and-forget webhook rule runtime that creates Workspace-backed DeepSeek Harness Sessions |
|
||||
| `@deepseek-ai/dsh-webhook-github` | yes | Signed GitHub HTTP webhook adapter for the DeepSeek Harness webhook runtime |
|
||||
|
||||
## workflow
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-tool-ralph` | yes | Model-facing fresh-agent Ralph loop over the workflow and subagent seams |
|
||||
| `@deepseek-ai/dsh-tool-workflow` | yes | Model-facing workflow tool: run a JavaScript orchestration script over ctx.workflowEngine |
|
||||
| `@deepseek-ai/dsh-workflow-ptc` | yes | Workflow orchestration in the shared sandboxed Node PTC runtime |
|
||||
|
||||
## workspace
|
||||
|
||||
| Package | Config | Description |
|
||||
|---|---|---|
|
||||
| `@deepseek-ai/dsh-workspace` | no | Workspace entity registry (ctx.workspaceRegistry): durable workspace records with validated session attachment over the domain data form for the DeepSeek Harness |
|
||||
@@ -5,104 +5,33 @@ description: Use when authoring, installing, configuring, or debugging persisten
|
||||
|
||||
# Persistent Harness plugins
|
||||
|
||||
Use ordinary workspace files to author a bundle, then `plugin_manager install_bundle` to install it in the current profile. Changes affect every session in that profile and survive restart. Load `editing-cordis-compositions` for agent preset changes.
|
||||
Use ordinary workspace files to author a bundle, then `plugin_manager` with `action: install_bundle` and the absolute package directory as `target` to install it in the current profile. Changes affect every session in that profile and survive restart. Load `editing-cordis-compositions` for agent preset changes.
|
||||
|
||||
## Deliver a working plugin first
|
||||
|
||||
1. Resolve the requested result and destination. An unspecified visual destination is the current Harness Web UI; a standalone image or HTML file does not complete such a request. Choose reasonable visual details and implement a small first version; install it before visual refinement.
|
||||
2. Discover only the APIs needed for that version: `cordis_inspect_list`, then targeted `cordis_inspect_query` calls. For UI, query Client `Slots.listSubTree` and the selected slot's registration options and props. Treat the recipes below and returned API declarations as the supported implementation path. Once the chosen slot and registration API are known, write the plugin. Before the first installation, resolve missing declarations through inspection; do not re-check these recipes by reading Loader, manifest-parser, package-manager, React, or slot implementation source. Source-level diagnosis starts from a concrete installation or runtime failure.
|
||||
3. The first files you write are the installable package, patch, and required Host/Client files in one workspace directory. Check JavaScript syntax and the manifest, then install it. Before that first installation, do not create preview HTML, mock shells, design variants, screenshot scripts, or rasterizer tooling. Use the installed plugin itself as the first preview.
|
||||
2. Discover only the APIs needed for that version: `cordis_inspect_list`, then targeted `cordis_inspect_query` calls. For UI, query Client `Slots.listSubTree` and the selected slot's registration options and props. Once the chosen slot and registration API are known, write the plugin.
|
||||
3. Read the matching template under `templates/` with the file-read tool and write its copies into one workspace directory, or write the installable package, patch, and required Host/Client files there yourself. Check JavaScript syntax and the manifest, then install it. Before that first installation, do not create preview HTML, mock shells, design variants, screenshot scripts, or rasterizer tooling. Use the installed plugin itself as the first preview.
|
||||
4. Read the installation result. After `application: applied`, exercise the capability or inspect the live Client registration. Use the connected page for visual verification when browser control is available. State any verification limitation explicitly; installation and slot registration alone do not establish what the user can see.
|
||||
5. Fix observed defects in the same plugin. When the requested result works, finish with its location and verification status. Do not continue speculative visual variants, optional features, or a new mock preview. Close any task list you created.
|
||||
|
||||
## Package and install
|
||||
## Knowledge sources, in order
|
||||
|
||||
A bundle declares `dsh.bundle.patch` in `package.json`. Its YAML patch inserts plugin entries. Give the package and rows unique names; use the Loader's existing YAML syntax, including `!!js` where expressions are needed. Read an existing patch before editing it: a matching override replaces the complete config.
|
||||
1. Inspection: `cordis_inspect_query` answers exact Service methods and Event modes (`Service`, `Event`), a mounted plugin's Config JSON Schema (`Config.listConfigs`: filter the paged directory by `name`, then query the `entry` id), the Tools this Agent can call (`Tool`), and live Client Slots and theme tokens (`Slots`, `Theme`).
|
||||
2. Package documentation: `Config.listConfigs` with `name` set to the package finds its entries; querying one `entry` returns its `packageDir`, the resolved package directory. Read `<packageDir>/README.md`. Bundled packages resolve from the dsh installation and profile-installed bundles from the profile, so never guess the path from `$DSH_PROFILE_DIR`.
|
||||
3. Source: installed packages ship built `lib/index.js` and `lib/types/**/*.d.ts` with JSDoc under that same `packageDir`, not `src/`; a source checkout of DSH has `packages/<group>/<name>/src`. Read them when inspection and the README leave a question open, and start source-level diagnosis from a concrete installation or runtime failure.
|
||||
|
||||
For a simple drawing, prefer a slot with allocated space, such as `conversation.composer.dock` when available. Keep the first version within that slot’s flow; do not plan a motion path around host controls. This minimal package needs no dependencies, install scripts, or build tool:
|
||||
`DSH_PROFILE` (profile name) and `DSH_PROFILE_DIR` (its directory, whose `node_modules` holds only profile-installed bundles) are set in every shell call of a profile-launched Harness and absent when the Harness was booted without a profile. Bash reads them as `$DSH_PROFILE`; PowerShell, which the Windows preset uses, reads them as `$env:DSH_PROFILE`. With `dsh` on the PATH, `dsh --profile "$DSH_PROFILE" --dump-config` prints the composed profile.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@local/my-decoration",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"exports": { ".": "./index.js", "./client": "./client.js" },
|
||||
"dsh": {
|
||||
"bundle": { "patch": "./cordis.patch.yml" },
|
||||
"client": {
|
||||
"platform": "web",
|
||||
"immediately": true,
|
||||
"inject": ["@deepseek-ai/dsh-client-ui-conversation"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
## Read next
|
||||
|
||||
`index.js` exports `export function apply() {}`. A Host plugin with behavior exports either a service class as default or named `apply`, `inject`, and optional `Config`; do not mix these forms. The bundle's `cordis.patch.yml`:
|
||||
The files below live in this skill's base directory, which the `skill` tool reported. Read them with the file-read tool only: in Desktop that directory sits inside `app.asar`, which the Host process can open but shell commands (`cat`, `cp`, `ls`), `node`, and pnpm cannot. Never install or syntax-check a template in place; copy its contents into the workspace first.
|
||||
|
||||
```yaml
|
||||
- insert:
|
||||
- id: my-decoration
|
||||
name: '@local/my-decoration'
|
||||
```
|
||||
|
||||
Call `plugin_manager` with `action: install_bundle` and the absolute package directory as `target`. It performs package installation and bundle selection; do not reproduce those steps with shell commands. Only pass `approvedBuilds` after the user explicitly approves the reported pending build scripts. Preserve returned failures and pending states; report success only after observing the requested capability.
|
||||
|
||||
Use `list_plugins` or `list_bundles` to obtain exact identifiers for existing installations. `set_plugin` and `set_bundle` toggle them; `remove_bundle` removes a bundle. Inspect saved-state and activation outcomes separately: `failed` requires diagnosis, `overridden` means a higher-priority layer wins, and `restart-required` means the change is not live. Installing a new bundle can activate through HMR; replacing an installed package requires restart to load a fresh JavaScript module generation. Do not infer updated browser code from an unchanged slot id.
|
||||
|
||||
## Client implementation
|
||||
|
||||
The browser artifact registers a lazy factory whose id equals the package name. React comes from the browser module table; no duplicate React installation, CDN script, or UMD search is needed. For compiled sources, use the deployment's Client build tooling to emit this format; declare non-baseline runtime imports in `dsh.client.external`.
|
||||
|
||||
This `client.js` example uses `conversation.composer.dock` for a small drawing below the composer. Replace the artwork with the requested drawing. Follow the selected slot's props and options. Do not read another plugin's DOM, stylesheet, or component source to estimate placement; choose a slot that already allocates space. Use `shell.overlay` only when the request needs an overlay and its placement is known.
|
||||
|
||||
```js
|
||||
window.__ModuleLoader__.load({
|
||||
id: '@local/my-decoration',
|
||||
factory(require) {
|
||||
const React = require('react');
|
||||
const h = React.createElement;
|
||||
function Decoration() {
|
||||
return h('svg', {
|
||||
viewBox: '0 0 64 64', width: 48, height: 48,
|
||||
'aria-hidden': true,
|
||||
style: { display: 'block', pointerEvents: 'none' },
|
||||
}, h('circle', { cx: 32, cy: 32, r: 24, fill: '#247bbf' }));
|
||||
}
|
||||
return {
|
||||
inject: ['slots'],
|
||||
apply(ctx) {
|
||||
ctx.slots.inject('conversation.composer.dock', () => ctx.slots.register({
|
||||
name: 'conversation.composer.dock', id: 'my-decoration', order: 5,
|
||||
}, Decoration));
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Keep factories free of side effects. Register styles, timers, listeners and other resources inside `apply` with `ctx.effect`/`ctx.on` and return their cleanup functions. Component-local styles can render as React elements so unmounting removes them. Verify disposal for resources you add. Inherit the host theme for containers and controls; artwork may use its own colors. Route visible UI text through the Client locale service. Do not replace the app root or append a second application to `document.body`.
|
||||
|
||||
## Verify in the available environment
|
||||
|
||||
Prefer the authenticated page already connected to Harness. Do not launch a separate browser from shell commands, change `HOME`, inspect personal browser profiles, search for authentication tokens, or alter keychains to obtain a screenshot. For a visual-only request without browser control, limit verification to JavaScript syntax, manifest validation, and the live Client slot, then report that visual verification remains unavailable. Before or after installation, do not search for rasterizers, invoke Quick Look, extract SVG into preview files, emulate React/DOM, or implement a custom renderer to compensate for missing browser control. A screenshot of a mock page is not verification of the running plugin.
|
||||
|
||||
For any test subprocess or temporary resource, use a unique owned directory, bound execution, and await cleanup. A failed optional preview must not turn into environment repair or block installation.
|
||||
|
||||
## Connect an MCP server
|
||||
|
||||
Create a configuration-only bundle: its manifest needs a unique name, version, and `dsh.bundle.patch`, but no Host/Client entry files. Insert the already installed MCP client in its patch:
|
||||
|
||||
```yaml
|
||||
- insert:
|
||||
- id: demo-mcp
|
||||
name: '@deepseek-ai/dsh-mcp-client'
|
||||
config:
|
||||
serverName: demo
|
||||
transport: streamable-http
|
||||
url: http://127.0.0.1:3000/mcp
|
||||
failOnStartupError: true
|
||||
```
|
||||
|
||||
Replace the endpoint, install the bundle through `plugin_manager`, then call `mcp__demo__ping` or another newly available `mcp__<serverName>__<tool>` tool to verify the connection. For stdio, use `transport: stdio`, `command`, and optional `args`, `env`, and `cwd`. Ambient credentials are scrubbed; reference existing credentials with Loader `!!js` rather than copying secrets into conversation text. Repair the same bundle on failure instead of creating duplicates.
|
||||
| Task | File |
|
||||
|---|---|
|
||||
| Bundle manifest, display metadata and icon, install and enable semantics, Host plugin export forms, Config | `references/host-plugin.md` |
|
||||
| A UI plugin rendered in the Web page: Client manifest, module loader, slot registration | `references/ui-plugin.md` |
|
||||
| Connecting an MCP server through a configuration-only bundle | `references/mcp-bundle.md` |
|
||||
| Verification limits when no browser control is available | `references/verification.md` |
|
||||
| Starting points to read and copy into the workspace | `templates/decoration/` (UI plugin), `templates/mcp/` (MCP bundle) |
|
||||
| Loader patch dialect and the list of installable plugin packages | the `cordis-composition-reference` skill |
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
# Bundles and Host plugins
|
||||
|
||||
A bundle is a package whose `package.json` declares `dsh.bundle.patch`; the YAML patch inserts plugin entries. Give the package and rows unique names; use the Loader's existing YAML syntax, including `!!js` where expressions are needed. Read an existing patch before editing it: a matching override replaces the complete `config`.
|
||||
|
||||
## Manifest
|
||||
|
||||
A Host-only bundle needs no dependencies, install scripts, or build tool:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@local/my-plugin",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"exports": { ".": "./index.js" },
|
||||
"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }
|
||||
}
|
||||
```
|
||||
|
||||
`cordis.patch.yml`:
|
||||
|
||||
```yaml
|
||||
- insert:
|
||||
- id: my-plugin
|
||||
name: '@local/my-plugin'
|
||||
config: {}
|
||||
```
|
||||
|
||||
## Display metadata and icon
|
||||
|
||||
Plugin Manager cards, bundle details, component rows, and the Settings plugin inventory read display text and an icon from the manifest without activating the plugin. Put the title and description in `locale/en.json` (other languages such as `locale/zh.json` use the same fields), and declare the icon as a top-level `icon` in `package.json`:
|
||||
|
||||
```json
|
||||
{ "meta": { "title": "My Decoration", "description": "Draws a badge under the composer." } }
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"icon": "./icon.svg",
|
||||
"exports": { "./package.json": "./package.json", "./locale/*.json": "./locale/*.json" },
|
||||
"files": ["locale/*.json", "icon.svg"]
|
||||
}
|
||||
```
|
||||
|
||||
`icon` is a path relative to the manifest directory; SVG, PNG, JPEG, and WebP up to 256 KiB are accepted, while absolute paths, URLs, paths outside the directory, and symlinks leaving it are rejected. Missing fields fall back to `package.json` `name` and `description` and to the panel's default artwork; malformed metadata produces a diagnostic and keeps the valid text.
|
||||
|
||||
## Host plugin export forms
|
||||
|
||||
`index.js` exports one of these forms; do not mix them:
|
||||
|
||||
- `export function apply(ctx, config) {}` with optional `export const inject = ['tools']` and `export const Config`.
|
||||
- A service class as the default export.
|
||||
|
||||
Register every resource inside `apply` with `ctx.effect` or `ctx.on` and return its cleanup. A plugin that declares `Config` validates the row's `config` at activation; query `Config.listConfigs` for an installed plugin's schema before writing its `config`, and follow `$defs` references in the returned document.
|
||||
|
||||
## Install, enable, and observe
|
||||
|
||||
`plugin_manager` `install_bundle` performs package installation and bundle selection; do not reproduce those steps with shell commands. Only pass `approvedBuilds` after the user explicitly approves the reported pending build scripts. Preserve returned failures and pending states; report success only after observing the requested capability.
|
||||
|
||||
`list_plugins` and `list_bundles` return exact identifiers for existing installations. `set_plugin` and `set_bundle` toggle them; `remove_bundle` removes a bundle. Inspect saved-state and activation outcomes separately: `failed` requires diagnosis, `overridden` means a higher-priority layer wins, and `restart-required` means the change is not live. Installing a new bundle can activate through HMR; replacing an installed package requires restart to load a fresh JavaScript module generation. Do not infer updated browser code from an unchanged slot id.
|
||||
@@ -0,0 +1,5 @@
|
||||
# Connect an MCP server
|
||||
|
||||
Read `templates/mcp/` with the file-read tool and write its files into your bundle directory. A configuration-only bundle's manifest needs a unique name, version, and `dsh.bundle.patch`, but no Host/Client entry files. Its patch, `templates/mcp/cordis.patch.yml`, inserts the already installed `@deepseek-ai/dsh-mcp-client` with `serverName`, `transport: streamable-http`, `url`, and `failOnStartupError: true`.
|
||||
|
||||
Replace the endpoint, install the bundle through `plugin_manager`, then call `mcp__demo__ping` or another newly available `mcp__<serverName>__<tool>` tool to verify the connection. For stdio, use `transport: stdio`, `command`, and optional `args`, `env`, and `cwd`; `Config.listConfigs` on the installed row returns the complete client schema. Ambient credentials are scrubbed; reference existing credentials with Loader `!!js` rather than copying secrets into conversation text. Repair the same bundle on failure instead of creating duplicates.
|
||||
@@ -0,0 +1,13 @@
|
||||
# UI plugins in the Web page
|
||||
|
||||
Read `templates/decoration/` with the file-read tool and write its files into your bundle directory: its `package.json` adds a `dsh.client` section (`platform`, `immediately`, `inject`) and a `./client` export beside the bundle patch.
|
||||
|
||||
`index.js` exports `export function apply() {}`; the patch inserts one row named after the package. For a simple drawing, prefer a slot with allocated space, such as `conversation.composer.dock` when available. Keep the first version within that slot's flow; do not plan a motion path around host controls. Use `shell.overlay` only when the request needs an overlay and its placement is known.
|
||||
|
||||
## Client module
|
||||
|
||||
The browser artifact registers a lazy factory whose id equals the package name. React comes from the browser module table; no duplicate React installation, CDN script, or UMD search is needed. For compiled sources, use the deployment's Client build tooling to emit this format; declare non-baseline runtime imports in `dsh.client.external`.
|
||||
|
||||
`templates/decoration/client.js` registers a lazy factory into `conversation.composer.dock` through `ctx.slots.inject` and `ctx.slots.register`; follow the selected slot's props and options from `Slots.listSubTree` when you change the slot.
|
||||
|
||||
Keep factories free of side effects. Register styles, timers, listeners and other resources inside `apply` with `ctx.effect`/`ctx.on` and return their cleanup functions. Component-local styles can render as React elements so unmounting removes them. Verify disposal for resources you add. Inherit the host theme for containers and controls; artwork may use its own colors. Route visible UI text through the Client locale service. Do not replace the app root or append a second application to `document.body`. Do not read another plugin's DOM, stylesheet, or component source to estimate placement; choose a slot that already allocates space.
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
# Verify in the available environment
|
||||
|
||||
Prefer the authenticated page already connected to Harness. Do not launch a separate browser from shell commands, change `HOME`, inspect personal browser profiles, search for authentication tokens, or alter keychains to obtain a screenshot. For a visual-only request without browser control, limit verification to JavaScript syntax, manifest validation, and the live Client slot, then report that visual verification remains unavailable. Before or after installation, do not search for rasterizers, invoke Quick Look, extract SVG into preview files, emulate React/DOM, or implement a custom renderer to compensate for missing browser control. A screenshot of a mock page is not verification of the running plugin.
|
||||
|
||||
For any test subprocess or temporary resource, use a unique owned directory, bound execution, and await cleanup. A failed optional preview must not turn into environment repair or block installation.
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
window.__ModuleLoader__.load({
|
||||
id: '@local/my-decoration',
|
||||
factory(require) {
|
||||
const React = require('react');
|
||||
const h = React.createElement;
|
||||
function Decoration() {
|
||||
return h('svg', {
|
||||
viewBox: '0 0 64 64', width: 48, height: 48,
|
||||
'aria-hidden': true,
|
||||
style: { display: 'block', pointerEvents: 'none' },
|
||||
}, h('circle', { cx: 32, cy: 32, r: 24, fill: '#247bbf' }));
|
||||
}
|
||||
return {
|
||||
inject: ['slots'],
|
||||
apply(ctx) {
|
||||
ctx.slots.inject('conversation.composer.dock', () => ctx.slots.register({
|
||||
name: 'conversation.composer.dock', id: 'my-decoration', order: 5,
|
||||
}, Decoration));
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
- insert:
|
||||
- id: my-decoration
|
||||
name: '@local/my-decoration'
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
/** Host half of the decoration bundle; the Client module owns the rendering. */
|
||||
export function apply() {}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "@local/my-decoration",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"exports": { ".": "./index.js", "./client": "./client.js" },
|
||||
"dsh": {
|
||||
"bundle": { "patch": "./cordis.patch.yml" },
|
||||
"client": {
|
||||
"platform": "web",
|
||||
"immediately": true,
|
||||
"inject": ["@deepseek-ai/dsh-client-ui-conversation"]
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
- insert:
|
||||
- id: demo-mcp
|
||||
name: '@deepseek-ai/dsh-mcp-client'
|
||||
config:
|
||||
serverName: demo
|
||||
transport: streamable-http
|
||||
url: http://127.0.0.1:3000/mcp
|
||||
failOnStartupError: true
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "@local/demo-mcp",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }
|
||||
}
|
||||
@@ -5,11 +5,11 @@ description: Use when creating, changing, or validating an agent preset or other
|
||||
|
||||
# Editing Cordis compositions
|
||||
|
||||
Agent presets are ordinary `@deepseek-ai/dsh-agent-preset` declarations carried by bundle patches. Nothing edits a declaration in place: a preset is created or changed by installing a bundle whose patch declares or overrides it. This file is the complete contract; do not read DSH package sources to infer formats.
|
||||
Agent presets are ordinary `@deepseek-ai/dsh-agent-preset` declarations carried by bundle patches. Nothing edits a declaration in place: a preset is created or changed by installing a bundle whose patch declares or overrides it. This file states the declaration format; when it leaves a question open, read the `@deepseek-ai/dsh-agent-preset` README and `lib/types` declarations under the `packageDir` that `cordis_inspect_query` `Config.listConfigs` returns when queried with a `preset-<id>` row's `entry` id, or `packages/preset/agent-preset/src` in a source checkout.
|
||||
|
||||
## Where declarations live
|
||||
|
||||
The shipped Web presets are `presets/<id>.patch.yml` files of the `@deepseek-ai/dsh-web-app` bundle, ids `standard`, `ptc`, `minimal` and `cordis`. Installed, that bundle sits at `$DSH_HOME/profiles/<profile>/node_modules/@deepseek-ai/dsh-web-app/`; in a source checkout of DSH it is `packages/bundle/web-app/`. Read one file with `cat` when you need a template; `minimal.patch.yml` is the shortest.
|
||||
The shipped Web presets are `presets/<id>.patch.yml` files of the `@deepseek-ai/dsh-web-app` bundle, ids `standard`, `ptc`, `minimal` and `cordis`. Installed, the bundle resolves from the dsh installation, not the profile; querying `Config.listConfigs` with the `entry` id of any `preset-<id>` row it declares returns that `packageDir`. In a source checkout of DSH it is `packages/bundle/web-app/`. Read one file with the file-read tool when you need a template; `minimal.patch.yml` is the shortest. In Desktop the bundle sits inside `app.asar`, which shell commands cannot open. Load `cordis-composition-reference` for the patch dialect and the list of plugin packages a preset can mount.
|
||||
|
||||
A declaration row has these `config` fields: `id` (required, lowercase letters, digits and hyphens), `plugins` (required Cordis entry list), and optional `name`, `description` and `order` (roster position). The Loader row `id` is `preset-<id>` by convention.
|
||||
|
||||
@@ -65,6 +65,10 @@ Override the declaration by its Loader row id instead of inserting. The override
|
||||
# the shipped list with your changes
|
||||
```
|
||||
|
||||
## Migrate a legacy preset
|
||||
|
||||
Before declaration rows, a user preset was a directory `$DSH_HOME/.agent-presets/<id>/` holding `preset.yml` (display `name`, `description`, `order`) and `agent.cordis.yml` (the plugin entry list). Nothing reads that directory any more. To migrate one, create a bundle as above whose declaration takes `id` from the directory name, `name`, `description`, and `order` from `preset.yml`, and `plugins` from `agent.cordis.yml` verbatim; check each plugin name against `cordis-composition-reference` because packages renamed since the preset was written fail at activation. Install it, verify the row, then delete the legacy directory.
|
||||
|
||||
## Verify
|
||||
|
||||
`plugin_manager` `list_bundles` lists the installed bundle; `list_plugins` shows the `preset-<id>` row with its activation state. A declaration whose activation fails stays on the roster with its diagnostic and cannot compose a session until the bundle is fixed and reinstalled. Existing sessions and their children keep the plugin revision they started with; validate changed behavior in a new session. Installing a bundle executes plugin code in the Host process, so it requires Full access or approval.
|
||||
@@ -77,4 +81,4 @@ A preset plugin that supplies a service must isolate the provider and all its co
|
||||
|
||||
## Extend the Host
|
||||
|
||||
For new plugin code or profile-wide capabilities, load `cordis-plugin-development`, author a workspace bundle, and install it with `plugin_manager`. Inspect available APIs through `cordis_inspect_list` and `cordis_inspect_query`; those tools do not invoke Remote methods. Verify the installed capability before reporting completion.
|
||||
For new plugin code or profile-wide capabilities, load `cordis-plugin-development`, author a workspace bundle, and install it with `plugin_manager`. Inspect available APIs through `cordis_inspect_list` and `cordis_inspect_query`, including a mounted plugin's Config schema through the Host `Config` provider; those tools do not invoke Remote methods. Verify the installed capability before reporting completion.
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Shipped creator skills: every rendered skill stays below the pruner threshold, referenced
|
||||
* files exist, templates parse, and no skill bans reading DSH sources.
|
||||
*/
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import { readdirSync, readFileSync, statSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import * as yaml from 'js-yaml'
|
||||
import { entryListSchema } from '@deepseek-ai/cordis-plugin-include'
|
||||
import { codePointLength } from '@deepseek-ai/dsh-compaction-tool-result-pruner'
|
||||
import { renderSkillContent } from '@deepseek-ai/dsh-skill'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
const skills = fileURLToPath(new URL('../skills/', import.meta.url))
|
||||
const names = readdirSync(skills)
|
||||
|
||||
/**
|
||||
* `packages/bundle/web-app/presets/standard.patch.yml` prunes a tool result only above `thresholdChars: 8192`
|
||||
* code points; a skill result below it reaches the model intact.
|
||||
*/
|
||||
const PRUNER_THRESHOLD_CHARS = 8192
|
||||
|
||||
/** The body the `skill` tool returns: the file without its YAML frontmatter. */
|
||||
function body(name: string): string {
|
||||
const text = readFileSync(join(skills, name, 'SKILL.md'), 'utf8')
|
||||
const end = text.indexOf('\n---\n', 4)
|
||||
return text.slice(end + '\n---\n'.length)
|
||||
}
|
||||
|
||||
function markdownFiles(dir: string): string[] {
|
||||
return readdirSync(dir, { recursive: true, encoding: 'utf8' })
|
||||
.filter(file => file.endsWith('.md'))
|
||||
.map(file => join(dir, file))
|
||||
}
|
||||
|
||||
describe('the shipped creator skills', () => {
|
||||
it('render below the pruner threshold and name only files that exist', () => {
|
||||
for (const name of names) {
|
||||
const rendered = renderSkillContent({
|
||||
name, provider: 'filesystem', resourceBase: { kind: 'directory', path: join(skills, name) }, content: body(name),
|
||||
})
|
||||
expect(codePointLength(rendered), name).toBeLessThan(PRUNER_THRESHOLD_CHARS)
|
||||
const referenced = [...body(name).matchAll(/`((?:references|templates)\/[^`]+)`/g)].map(match => match[1] ?? match[0])
|
||||
for (const path of referenced) expect(() => statSync(join(skills, name, path)), `${name}: ${path}`).not.toThrow()
|
||||
}
|
||||
})
|
||||
|
||||
it('ship templates whose manifest, patch, and JavaScript parse', () => {
|
||||
const templates = join(skills, 'cordis-plugin-development', 'templates')
|
||||
for (const name of readdirSync(templates)) {
|
||||
const dir = join(templates, name)
|
||||
const manifest = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')) as { dsh: { bundle: { patch: string } } }
|
||||
const patch = yaml.load(readFileSync(join(dir, manifest.dsh.bundle.patch), 'utf8'), { schema: entryListSchema })
|
||||
expect(Array.isArray(patch)).toBe(true)
|
||||
for (const file of readdirSync(dir).filter(entry => entry.endsWith('.js'))) {
|
||||
execFileSync(process.execPath, ['--check', join(dir, file)])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('never forbid reading DSH package sources and never route skill files through the shell', () => {
|
||||
for (const name of names) {
|
||||
for (const file of markdownFiles(join(skills, name))) {
|
||||
const text = readFileSync(file, 'utf8')
|
||||
expect(text, file).not.toMatch(/do not read (DSH |package |DSH package )?sources/i)
|
||||
// Desktop ships the skill directory inside app.asar, which only the Host process can open.
|
||||
expect(text, file).not.toMatch(/`(cat|cp|ls) /)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -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/shell/shell-env/README.md
|
||||
README.md: f85fb0005e94dc59939cfd2e9f0d69e5cdc7d133
|
||||
README.zh.md: b9f763a247fc792335326d8945dfeb2db1690fc7
|
||||
README.md: 6557049c8287348507e2f5fc8a824366949c2861
|
||||
README.zh.md: 32bd5e744af98ca84e426490765d15dd1701851c
|
||||
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
|
||||
|
||||
## Summary
|
||||
|
||||
`dsh-shell-env` provides the trusted `DSH_*` environment that every model shell call — bash or pwsh — runs with: built-in facts such as `DSH_HOME`, `DSH_SHELL=1`, and the agent's `DSH_SESSION_ID`. Plugin authors can register their own facts with declared keys, collected per execution and disposed with their plugin; duplicate ownership or undeclared runtime keys fail loudly instead of silently overwriting. The registry changes nothing else the model sees — the shell tools own their own schemas and prompts. Choose it in any composition that mounts a model shell tool; configuration only picks the Harness home directory.
|
||||
`dsh-shell-env` provides the trusted `DSH_*` environment that every model shell call — bash or pwsh — runs with: built-in facts such as `DSH_HOME`, `DSH_SHELL=1`, the agent's `DSH_SESSION_ID`, and the launched profile's `DSH_PROFILE` and `DSH_PROFILE_DIR`. Plugin authors can register their own facts with declared keys, collected per execution and disposed with their plugin; duplicate ownership or undeclared runtime keys fail loudly instead of silently overwriting. The registry changes nothing else the model sees — the shell tools own their own schemas and prompts. Choose it in any composition that mounts a model shell tool; configuration only picks the Harness home directory.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
@@ -29,7 +29,7 @@ Load this plugin in any composition that mounts a model shell tool (`dsh-tool-ba
|
||||
|
||||
### What every shell call receives
|
||||
|
||||
Every call receives `DSH_HOME` (the absolute Harness home), `DSH_SHELL=1`, and, for agent calls, `DSH_SESSION_ID` (the calling session's id).
|
||||
Every call receives `DSH_HOME` (the absolute Harness home), `DSH_SHELL=1`, and, for agent calls, `DSH_SESSION_ID` (the calling session's id). When the launcher provided a profile context, every call also receives `DSH_PROFILE` (the profile name) and `DSH_PROFILE_DIR` (its absolute directory; its `node_modules` holds only profile-installed packages, while the harness's own bundles resolve from the dsh installation); compositions booted without a profile omit both.
|
||||
|
||||
### Adding your own environment facts
|
||||
|
||||
@@ -64,7 +64,7 @@ The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-a
|
||||
|
||||
### What can go wrong
|
||||
|
||||
Two contributors declaring the same key, or a contributor claiming a reserved built-in (`DSH_HOME`, `DSH_SHELL`, `DSH_SESSION_ID`), fails plugin load loudly. A `DSH_*` key must be all-caps with underscores (for example `DSH_REGION`), and a missing description fails registration.
|
||||
Two contributors declaring the same key, or a contributor claiming a reserved built-in (`DSH_HOME`, `DSH_SHELL`, `DSH_SESSION_ID`, `DSH_PROFILE`, `DSH_PROFILE_DIR`), fails plugin load loudly. A `DSH_*` key must be all-caps with underscores (for example `DSH_REGION`), and a missing description fails registration.
|
||||
|
||||
-----
|
||||
|
||||
@@ -80,7 +80,7 @@ This section explains the design decisions behind the registry and points at the
|
||||
|
||||
- **Trusted namespace, rebuilt per call.** The environment is a Harness-owned `DSH_*` namespace: the shell executor discards inherited `DSH_*` values and merges the registry's current snapshot for each execution, so nested harnesses and concurrent parent/child agents cannot leak stale identities, and `process.env` is never modified.
|
||||
- **Declared ownership, loud conflicts.** Contributors declare their keys up front so duplicate ownership is detected before the first command; resolvers may only return declared keys.
|
||||
- **Built-ins stay here.** `DSH_HOME`, `DSH_SHELL`, and `DSH_SESSION_ID` are reserved for the registry; contributors cannot claim them.
|
||||
- **Built-ins stay here.** `DSH_HOME`, `DSH_SHELL`, `DSH_SESSION_ID`, `DSH_PROFILE`, and `DSH_PROFILE_DIR` are reserved for the registry; contributors cannot claim them.
|
||||
|
||||
### Source map
|
||||
|
||||
@@ -127,7 +127,7 @@ The managed environment never enters the request prefix, so it does not invalida
|
||||
|
||||
These limits define when the registry is a poor fit or needs care. They are current package constraints, not a task backlog.
|
||||
|
||||
- **`list()` enumerates plugin-contributed variables only** — registry-owned built-ins (`DSH_HOME`, `DSH_SHELL`, `DSH_SESSION_ID`) are not included, so diagnostics, prompt, or UI code must not treat `list()` as an exhaustive environment catalog.
|
||||
- **`list()` enumerates plugin-contributed variables only** — registry-owned built-ins (`DSH_HOME`, `DSH_SHELL`, `DSH_SESSION_ID`, `DSH_PROFILE`, `DSH_PROFILE_DIR`) are not included, so diagnostics, prompt, or UI code must not treat `list()` as an exhaustive environment catalog.
|
||||
|
||||
<a id="dev-note"></a>
|
||||
### Dev Note
|
||||
|
||||
@@ -9,7 +9,7 @@ kind: "package-reference"
|
||||
|
||||
## 概述
|
||||
|
||||
`dsh-shell-env` 提供每次模型 shell 调用——bash 或 pwsh——所运行的受信 `DSH_*` 环境:内置事实如 `DSH_HOME`、`DSH_SHELL=1` 与 agent(智能体)的 `DSH_SESSION_ID`。插件作者可以注册自己的事实,带声明键、按每次执行收集,并随插件释放;重复所有权或未声明的运行时键会明确报错,而不是静默覆盖。注册表不会改变模型看到的其他任何内容——shell 工具拥有各自的 schema 与提示词。任何挂载了模型 shell 工具的组合都适合选择它;配置只决定 Harness 主目录。
|
||||
`dsh-shell-env` 提供每次模型 shell 调用——bash 或 pwsh——所运行的受信 `DSH_*` 环境:内置事实如 `DSH_HOME`、`DSH_SHELL=1`、agent(智能体)的 `DSH_SESSION_ID`,以及所启动 profile 的 `DSH_PROFILE` 与 `DSH_PROFILE_DIR`。插件作者可以注册自己的事实,带声明键、按每次执行收集,并随插件释放;重复所有权或未声明的运行时键会明确报错,而不是静默覆盖。注册表不会改变模型看到的其他任何内容——shell 工具拥有各自的 schema 与提示词。任何挂载了模型 shell 工具的组合都适合选择它;配置只决定 Harness 主目录。
|
||||
|
||||
## 目录
|
||||
|
||||
@@ -29,7 +29,7 @@ kind: "package-reference"
|
||||
|
||||
### 每次 shell 调用都会收到什么
|
||||
|
||||
每次调用都会收到 `DSH_HOME`(Harness 主目录的绝对路径)、`DSH_SHELL=1`,agent 调用还会收到 `DSH_SESSION_ID`(调用方会话的 id)。
|
||||
每次调用都会收到 `DSH_HOME`(Harness 主目录的绝对路径)、`DSH_SHELL=1`,agent 调用还会收到 `DSH_SESSION_ID`(调用方会话的 id)。启动器提供了 profile 上下文时,每次调用还会收到 `DSH_PROFILE`(profile 名)与 `DSH_PROFILE_DIR`(其绝对目录;其 `node_modules` 只存放 profile 自行安装的包,harness 自带的组合包从 dsh 安装目录解析);不带 profile 启动的组合则两者都没有。
|
||||
|
||||
### 添加你自己的环境事实
|
||||
|
||||
@@ -64,7 +64,7 @@ contributor 必须声明它返回的每个键;返回未声明或非字符串
|
||||
|
||||
### 可能出什么问题
|
||||
|
||||
两个 contributor 声明同一个键,或 contributor 声称拥有保留内置键(`DSH_HOME`、`DSH_SHELL`、`DSH_SESSION_ID`),都会导致插件加载时明确报错。`DSH_*` 键必须全大写并带下划线(例如 `DSH_REGION`),缺少描述也会让注册失败。
|
||||
两个 contributor 声明同一个键,或 contributor 声称拥有保留内置键(`DSH_HOME`、`DSH_SHELL`、`DSH_SESSION_ID`、`DSH_PROFILE`、`DSH_PROFILE_DIR`),都会导致插件加载时明确报错。`DSH_*` 键必须全大写并带下划线(例如 `DSH_REGION`),缺少描述也会让注册失败。
|
||||
|
||||
-----
|
||||
|
||||
@@ -80,7 +80,7 @@ contributor 必须声明它返回的每个键;返回未声明或非字符串
|
||||
|
||||
- **受信命名空间,每次调用重建。** 环境是归 Harness 所有的 `DSH_*` 命名空间:shell 执行器丢弃继承的 `DSH_*` 值,并为每次执行合并注册表的当前快照,因此嵌套 harness 与并发的父子 agent 无法泄漏陈旧身份,`process.env` 也永不被修改。
|
||||
- **声明所有权,冲突明确报错。** contributor 预先声明键,使重复所有权在第一条命令之前就被发现;resolver 只能返回已声明的键。
|
||||
- **内置键留在这里。** `DSH_HOME`、`DSH_SHELL` 与 `DSH_SESSION_ID` 为注册表保留;contributor 不能声称拥有它们。
|
||||
- **内置键留在这里。** `DSH_HOME`、`DSH_SHELL`、`DSH_SESSION_ID`、`DSH_PROFILE` 与 `DSH_PROFILE_DIR` 为注册表保留;contributor 不能声称拥有它们。
|
||||
|
||||
### 源码地图
|
||||
|
||||
@@ -127,7 +127,7 @@ contributor 必须声明它返回的每个键;返回未声明或非字符串
|
||||
|
||||
这些限制说明注册表何时不合适或需要小心使用。它们是当前包约束,不是任务积压。
|
||||
|
||||
- **`list()` 只枚举插件贡献的变量**——注册表自有的内置键(`DSH_HOME`、`DSH_SHELL`、`DSH_SESSION_ID`)不包含在内,因此诊断、提示词或 UI 代码不得把 `list()` 当作完整的环境目录。
|
||||
- **`list()` 只枚举插件贡献的变量**——注册表自有的内置键(`DSH_HOME`、`DSH_SHELL`、`DSH_SESSION_ID`、`DSH_PROFILE`、`DSH_PROFILE_DIR`)不包含在内,因此诊断、提示词或 UI 代码不得把 `list()` 当作完整的环境目录。
|
||||
|
||||
<a id="dev-note"></a>
|
||||
### 开发备注
|
||||
|
||||
@@ -27,20 +27,22 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-shell": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-app-boot": "workspace:^",
|
||||
"@deepseek-ai/dsh-home-paths": "workspace:^",
|
||||
"@deepseek-ai/dsh-tools": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
"@deepseek-ai/dsh-shell": "workspace:^",
|
||||
"@deepseek-ai/dsh-tools": "workspace:^"
|
||||
},
|
||||
"dependencies": {
|
||||
"@deepseek-ai/schemastery": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/cordis": "workspace:^",
|
||||
"@deepseek-ai/dsh-agent": "workspace:^",
|
||||
"@deepseek-ai/dsh-shell": "workspace:^",
|
||||
"@deepseek-ai/dsh-llm": "workspace:^",
|
||||
"@deepseek-ai/dsh-app-boot": "workspace:^",
|
||||
"@deepseek-ai/dsh-home-paths": "workspace:^",
|
||||
"@deepseek-ai/dsh-tools": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
"@deepseek-ai/dsh-llm": "workspace:^",
|
||||
"@deepseek-ai/dsh-shell": "workspace:^",
|
||||
"@deepseek-ai/dsh-tools": "workspace:^"
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,8 @@ import { DSH_ENV_PREFIX } from '@deepseek-ai/dsh-shell'
|
||||
import type { DshEnvironment, DshEnvironmentKey } from '@deepseek-ai/dsh-shell'
|
||||
import { DSH_HOME_ENV, resolveDshHome } from '@deepseek-ai/dsh-home-paths'
|
||||
import type { ToolExecution } from '@deepseek-ai/dsh-tools'
|
||||
// Declares `Context.profileContext`, the launcher-provided profile the built-ins read.
|
||||
import type {} from '@deepseek-ai/dsh-app-boot'
|
||||
|
||||
declare module '@deepseek-ai/cordis' {
|
||||
interface Context {
|
||||
@@ -69,10 +71,14 @@ export interface BashEnvVariableInfo extends BashEnvVariable {
|
||||
|
||||
const DSH_SHELL_KEY = `${DSH_ENV_PREFIX}SHELL` as const
|
||||
const DSH_SESSION_ID_KEY = `${DSH_ENV_PREFIX}SESSION_ID` as const
|
||||
const DSH_PROFILE_KEY = `${DSH_ENV_PREFIX}PROFILE` as const
|
||||
const DSH_PROFILE_DIR_KEY = `${DSH_ENV_PREFIX}PROFILE_DIR` as const
|
||||
const RESERVED_BASH_ENV_KEYS = new Set<DshEnvironmentKey>([
|
||||
DSH_HOME_ENV,
|
||||
DSH_SHELL_KEY,
|
||||
DSH_SESSION_ID_KEY,
|
||||
DSH_PROFILE_KEY,
|
||||
DSH_PROFILE_DIR_KEY,
|
||||
])
|
||||
const BASH_ENV_KEY_SUFFIX = /^[A-Z][A-Z0-9_]*$/
|
||||
|
||||
@@ -155,6 +161,11 @@ export class ShellEnvRegistry extends Service {
|
||||
if (execution.agent !== undefined) {
|
||||
values[DSH_SESSION_ID_KEY] = execution.agent.session.header.id
|
||||
}
|
||||
const profile = this.ctx.get('profileContext')
|
||||
if (profile !== undefined) {
|
||||
values[DSH_PROFILE_KEY] = profile.name
|
||||
values[DSH_PROFILE_DIR_KEY] = profile.dir
|
||||
}
|
||||
|
||||
for (const contributor of [...this.contributors.values()].sort((left, right) => left.name.localeCompare(right.name))) {
|
||||
const resolved = contributor.resolve(execution)
|
||||
|
||||
@@ -55,6 +55,21 @@ describe('ShellEnvRegistry', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('collects the launcher-provided profile name and directory when a profile context exists', () => {
|
||||
const ctx = new Context()
|
||||
ctx.provide('profileContext', {
|
||||
name: 'web', dir: '/profiles/web', patchPath: '/profiles/web/cordis.patch.yml', installAnchor: '/dsh/package.json',
|
||||
cwd: '/work', home: '/home', startedBundles: [], overlays: [], telemetryDisabledEnv: undefined,
|
||||
})
|
||||
const registry = new ShellEnvRegistry(ctx, { dshHome: './test-dsh-home' })
|
||||
expect(registry.collect(execution())).toMatchObject({ DSH_PROFILE: 'web', DSH_PROFILE_DIR: '/profiles/web' })
|
||||
expect(() => registry.register({
|
||||
name: 'profile-claimer',
|
||||
variables: { DSH_PROFILE: { description: 'Reserved key.' } },
|
||||
resolve: () => ({}),
|
||||
})).toThrow(/reserved key "DSH_PROFILE"/)
|
||||
})
|
||||
|
||||
it('resolves DSH_HOME from the ambient override or the user-home default', () => {
|
||||
vi.stubEnv('DSH_HOME', './ambient-dsh-home')
|
||||
const fromEnvironment = new ShellEnvRegistry(new Context())
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
},
|
||||
{
|
||||
"path": "../../core/tools"
|
||||
},
|
||||
{
|
||||
"path": "../../boot/app-boot"
|
||||
}
|
||||
]
|
||||
}
|
||||
Generated
+18
@@ -9382,12 +9382,27 @@ importers:
|
||||
'@deepseek-ai/cordis':
|
||||
specifier: workspace:^
|
||||
version: link:../../../vendor/cordis
|
||||
'@deepseek-ai/cordis-plugin-include':
|
||||
specifier: workspace:^
|
||||
version: link:../../../vendor/include
|
||||
'@deepseek-ai/cordis-plugin-loader':
|
||||
specifier: workspace:^
|
||||
version: link:../../../vendor/loader
|
||||
'@deepseek-ai/dsh-agent-preset-registry':
|
||||
specifier: workspace:^
|
||||
version: link:../agent-preset-registry
|
||||
'@deepseek-ai/dsh-compaction-tool-result-pruner':
|
||||
specifier: workspace:^
|
||||
version: link:../../compaction/compaction-tool-result-pruner
|
||||
'@deepseek-ai/dsh-skill':
|
||||
specifier: workspace:^
|
||||
version: link:../../skill/skill
|
||||
'@types/js-yaml':
|
||||
specifier: ^4.0.9
|
||||
version: 4.0.9
|
||||
js-yaml:
|
||||
specifier: ^4.2.0
|
||||
version: 4.3.1
|
||||
|
||||
packages/preset/agent-preset-registry:
|
||||
dependencies:
|
||||
@@ -10712,6 +10727,9 @@ importers:
|
||||
'@deepseek-ai/dsh-agent':
|
||||
specifier: workspace:^
|
||||
version: link:../../core/agent
|
||||
'@deepseek-ai/dsh-app-boot':
|
||||
specifier: workspace:^
|
||||
version: link:../../boot/app-boot
|
||||
'@deepseek-ai/dsh-home-paths':
|
||||
specifier: workspace:^
|
||||
version: link:../../util/home-paths
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Generate the loadable-plugin package list shipped inside the
|
||||
* `cordis-composition-reference` skill from the workspace manifests and the
|
||||
* config-catalog classification. `--check` exits 1 when the committed file is stale.
|
||||
*/
|
||||
|
||||
import { readFileSync, writeFileSync } from 'node:fs'
|
||||
import { resolve } from 'node:path'
|
||||
import { collectConfigCatalog, type CatalogEntry } from './gen-config-catalog.ts'
|
||||
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
const OUT = 'packages/preset/agent-preset/skills/cordis-composition-reference/references/packages.md'
|
||||
|
||||
interface Row {
|
||||
pkg: string
|
||||
group: string
|
||||
config: boolean
|
||||
description: string
|
||||
}
|
||||
|
||||
function rows(entries: readonly CatalogEntry[]): Row[] {
|
||||
const result: Row[] = []
|
||||
for (const entry of entries) {
|
||||
// Seams are abstract Service Definitions and libraries export no plugin; neither is a Loader row.
|
||||
if (entry.kind !== 'config' && entry.kind !== 'no-config') continue
|
||||
const manifest = JSON.parse(readFileSync(resolve(root, entry.dir, 'package.json'), 'utf8')) as { description: string }
|
||||
// Catalog dirs are `packages/<group>/<pkg>`, so the group segment is always present.
|
||||
const group = entry.dir.split('/')[1] ?? entry.dir
|
||||
result.push({ pkg: entry.pkg, group, config: entry.kind === 'config', description: manifest.description })
|
||||
}
|
||||
return result.sort((left, right) => left.group.localeCompare(right.group) || left.pkg.localeCompare(right.pkg))
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the package list as one Markdown document grouped by package group.
|
||||
* @param entries - config-catalog entries for every workspace package.
|
||||
* @returns the complete file content.
|
||||
*/
|
||||
export function render(entries: readonly CatalogEntry[]): string {
|
||||
const lines = [
|
||||
'# Loadable Harness plugin packages',
|
||||
'',
|
||||
'This file is GENERATED from workspace manifests (`scripts/gen-plugin-packages.ts`) and verified fresh by `pnpm run verify-plugin-packages` (part of `doc-sync`); do not edit it by hand.',
|
||||
'',
|
||||
'Every package below exports a Cordis plugin that a bundle patch can name in a Loader row. `Config` marks packages whose row accepts a `config` mapping; query `Config.listConfigs` through `cordis_inspect_query` (filter by `name`, then query the `entry` id) for the mounted schema. Packages under `experimental` are pre-stable.',
|
||||
'',
|
||||
]
|
||||
let group = ''
|
||||
for (const row of rows(entries)) {
|
||||
if (row.group !== group) {
|
||||
if (group !== '') lines.push('')
|
||||
group = row.group
|
||||
lines.push(`## ${group}`, '', '| Package | Config | Description |', '|---|---|---|')
|
||||
}
|
||||
lines.push(`| \`${row.pkg}\` | ${row.config ? 'yes' : 'no'} | ${row.description} |`)
|
||||
}
|
||||
return `${lines.join('\n')}\n`
|
||||
}
|
||||
|
||||
function main(): void {
|
||||
const content = render(collectConfigCatalog())
|
||||
if (process.argv.includes('--check')) {
|
||||
let committed: string | null
|
||||
try {
|
||||
committed = readFileSync(resolve(root, OUT), 'utf8')
|
||||
} catch {
|
||||
// A missing or unreadable file has the same remedy as a stale one: regenerate.
|
||||
committed = null
|
||||
}
|
||||
if (committed === content) {
|
||||
console.log(`gen-plugin-packages: ${OUT} is up to date.`)
|
||||
process.exit(0)
|
||||
}
|
||||
console.error(`gen-plugin-packages: ${OUT} is stale. Run \`pnpm run gen-plugin-packages\` and commit ${OUT}.`)
|
||||
process.exit(1)
|
||||
}
|
||||
writeFileSync(resolve(root, OUT), content)
|
||||
console.log(`gen-plugin-packages: wrote ${OUT}.`)
|
||||
}
|
||||
|
||||
if (process.argv[1] && import.meta.filename === resolve(process.argv[1])) {
|
||||
main()
|
||||
}
|
||||
@@ -797,6 +797,7 @@ function docSyncLeafGates(options: {
|
||||
pnpmScript('export-jsdoc', 'verify-export-jsdoc', { label: 'export jsdoc' }),
|
||||
pnpmScript('tool-catalog', 'verify-tool-catalog', { label: 'tool catalog' }),
|
||||
pnpmScript('config-catalog', 'verify-config-catalog', { label: 'config catalog' }),
|
||||
pnpmScript('plugin-packages', 'verify-plugin-packages', { label: 'skill plugin package list' }),
|
||||
pnpmScript('dependency-catalog', 'verify-dependency-catalog', { label: 'npm dependency catalog', quick: true }),
|
||||
pnpmScript('persistence-catalog', 'verify-persistence-catalog', { label: 'persistence catalog' }),
|
||||
pnpmScript('persistence-changes', 'verify-persistence-changes', { label: 'persistence type history' }),
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
{"type":"session/title","data":{"title":"Load the editing-cordis-compositions ski","messageSeqs":[8],"source":{"kind":"fallback"}}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"reasoning","text":"Load the requested skill."},{"type":"tool-call","id":"call_skill_load","name":"skill","arguments":"{\"name\":\"editing-cordis-compositions\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:5}}"},"usage":{"inputTokens":100,"outputTokens":20,"cacheReadTokens":0,"reasoningTokens":5},"stream":[{"type":"chunk","time":1788699430688,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}},{"type":"reasoning-chunks","time0":1788699430688,"index":0,"dt":[],"texts":["Load the requested skill."]},{"type":"chunk","time":1788699430688,"chunk":{"type":"block-start","index":1,"blockType":"tool-call"}},{"type":"tool-call-chunks","time0":1788699430688,"index":1,"dt":[],"id":"call_skill_load","name":"skill","args":["{\"name\":\"editing-cordis-compositions\"}"]},{"type":"chunk","time":1788699430688,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"Load the requested skill."}}},{"type":"chunk","time":1788699430688,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_skill_load","name":"skill","arguments":"{\"name\":\"editing-cordis-compositions\"}"}}},{"type":"chunk","time":1788699430688,"chunk":{"type":"usage","usage":{"inputTokens":100,"outputTokens":20,"cacheReadTokens":0,"reasoningTokens":5}}},{"type":"chunk","time":1788699430688,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}]},"surfaceOp":"append"}
|
||||
{"type":"tool/call","data":{"turn":1,"step":1,"callId":"call_skill_load","name":"skill","arguments":"{\"name\":\"editing-cordis-compositions\"}"}}
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_skill_load"},"toolCallId":"call_skill_load","content":[{"type":"text","text":"<skill_content name=\"editing-cordis-compositions\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/.dsh/skills/editing-cordis-compositions\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Editing Cordis compositions\n\nAgent presets are ordinary `@deepseek-ai/dsh-agent-preset` declarations carried by bundle patches. Nothing edits a declaration in place: a preset is created or changed by installing a bundle whose patch declares or overrides it. This file is the complete contract; do not read DSH package sources to infer formats.\n\n## Where declarations live\n\nThe shipped Web presets are `presets/<id>.patch.yml` files of the `@deepseek-ai/dsh-web-app` bundle, ids `standard`, `ptc`, `minimal` and `cordis`. Installed, that bundle sits at `$DSH_HOME/profiles/<profile>/node_modules/@deepseek-ai/dsh-web-app/`; in a source checkout of DSH it is `packages/bundle/web-app/`. Read one file with `cat` when you need a template; `minimal.patch.yml` is the shortest.\n\nA declaration row has these `config` fields: `id` (required, lowercase letters, digits and hyphens), `plugins` (required Cordis entry list), and optional `name`, `description` and `order` (roster position). The Loader row `id` is `preset-<id>` by convention.\n\n## Create a preset\n\nWrite a bundle directory in the workspace with exactly two files, then install it.\n\n`review-preset/package.json`:\n\n```json\n{\n \"name\": \"@local/dsh-review-preset\",\n \"version\": \"1.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"dsh\": { \"bundle\": { \"patch\": \"./cordis.patch.yml\" } }\n}\n```\n\n`review-preset/cordis.patch.yml`:\n\n```yaml\n- insert:\n - id: preset-review\n name: '@deepseek-ai/dsh-agent-preset'\n config:\n id: review\n name: Review\n description: Reviews changes with the shell only.\n order: 10\n plugins:\n - id: persona\n name: '@deepseek-ai/dsh-persona'\n config:\n prefix: You review software changes.\n - id: tool-bash\n name: '@deepseek-ai/dsh-tool-bash'\n```\n\nInstall with `plugin_manager`, `action: install_bundle`, `target` set to the absolute bundle directory. It runs package installation and bundle selection itself; do not reproduce those steps with shell commands.\n\n## Change a shipped preset\n\nOverride the declaration by its Loader row id instead of inserting. The override replaces the complete `config`, so restate `id`, `plugins` and every other field the shipped file carries:\n\n```yaml\n- id: preset-standard\n name: '@deepseek-ai/dsh-agent-preset'\n config:\n id: standard\n order: 1\n plugins:\n # the shipped list with your changes\n```\n\n## Verify\n\n`plugin_manager` `list_bundles` lists the installed bundle; `list_plugins` shows the `preset-<id>` row with its activation state. A declaration whose activation fails stays on the roster with its diagnostic and cannot compose a session until the bundle is fixed and reinstalled. Existing sessions and their children keep the plugin revision they started with; validate changed behavior in a new session. Installing a bundle executes plugin code in the Host process, so it requires Full access or approval.\n\n## Choose plugin placement\n\nHost plugins supply shared services: tools and prompt registries, the Agent loop, sessions, persistence, settings, sandbox policy, model routes, and subagent backends. Preset plugins contribute scoped tools, persona, prompt sections, and policies to those registries. Preset revisions are eagerly activated once and shared by their selecting Agents.\n\nA preset plugin that supplies a service must isolate the provider and all its consumers in the same realm. A service consumed by Host plugins belongs in the Host configuration. Scope controls contributions and event visibility; `isolate` controls service instances. Use ordinary Cordis groups for nested plugin lists. Keep `!!js` expressions only in plugin configuration or `disabled`; the Loader evaluates them when activating the child plugin. Resolve assets from installed packages rather than a preset directory.\n\n## Extend the Host\n\nFor new plugin code or profile-wide capabilities, load `cordis-plugin-development`, author a workspace bundle, and install it with `plugin_manager`. Inspect available APIs through `cordis_inspect_list` and `cordis_inspect_query`; those tools do not invoke Remote methods. Verify the installed capability before reporting completion.\n</skill_instructions>\n</skill_content>"}],"isError":false,"id":"{{message:6}}"}},"sourceEventSeqs":[15],"surfaceOp":"append"}
|
||||
{"type":"tool/result","data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"call_skill_load"},"toolCallId":"call_skill_load","content":[{"type":"text","text":"<skill_content name=\"editing-cordis-compositions\">\n<skill_resources>\nBase directory for this skill: {{cwd}}/.dsh/skills/editing-cordis-compositions\nResolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed.\n</skill_resources>\n\n<skill_instructions>\n# Editing Cordis compositions\n\nAgent presets are ordinary `@deepseek-ai/dsh-agent-preset` declarations carried by bundle patches. Nothing edits a declaration in place: a preset is created or changed by installing a bundle whose patch declares or overrides it. This file states the declaration format; when it leaves a question open, read the `@deepseek-ai/dsh-agent-preset` README and `lib/types` declarations under the `packageDir` that `cordis_inspect_query` `Config.listConfigs` returns when queried with a `preset-<id>` row's `entry` id, or `packages/preset/agent-preset/src` in a source checkout.\n\n## Where declarations live\n\nThe shipped Web presets are `presets/<id>.patch.yml` files of the `@deepseek-ai/dsh-web-app` bundle, ids `standard`, `ptc`, `minimal` and `cordis`. Installed, the bundle resolves from the dsh installation, not the profile; querying `Config.listConfigs` with the `entry` id of any `preset-<id>` row it declares returns that `packageDir`. In a source checkout of DSH it is `packages/bundle/web-app/`. Read one file with the file-read tool when you need a template; `minimal.patch.yml` is the shortest. In Desktop the bundle sits inside `app.asar`, which shell commands cannot open. Load `cordis-composition-reference` for the patch dialect and the list of plugin packages a preset can mount.\n\nA declaration row has these `config` fields: `id` (required, lowercase letters, digits and hyphens), `plugins` (required Cordis entry list), and optional `name`, `description` and `order` (roster position). The Loader row `id` is `preset-<id>` by convention.\n\n## Create a preset\n\nWrite a bundle directory in the workspace with exactly two files, then install it.\n\n`review-preset/package.json`:\n\n```json\n{\n \"name\": \"@local/dsh-review-preset\",\n \"version\": \"1.0.0\",\n \"private\": true,\n \"type\": \"module\",\n \"dsh\": { \"bundle\": { \"patch\": \"./cordis.patch.yml\" } }\n}\n```\n\n`review-preset/cordis.patch.yml`:\n\n```yaml\n- insert:\n - id: preset-review\n name: '@deepseek-ai/dsh-agent-preset'\n config:\n id: review\n name: Review\n description: Reviews changes with the shell only.\n order: 10\n plugins:\n - id: persona\n name: '@deepseek-ai/dsh-persona'\n config:\n prefix: You review software changes.\n - id: tool-bash\n name: '@deepseek-ai/dsh-tool-bash'\n```\n\nInstall with `plugin_manager`, `action: install_bundle`, `target` set to the absolute bundle directory. It runs package installation and bundle selection itself; do not reproduce those steps with shell commands.\n\n## Change a shipped preset\n\nOverride the declaration by its Loader row id instead of inserting. The override replaces the complete `config`, so restate `id`, `plugins` and every other field the shipped file carries:\n\n```yaml\n- id: preset-standard\n name: '@deepseek-ai/dsh-agent-preset'\n config:\n id: standard\n order: 1\n plugins:\n # the shipped list with your changes\n```\n\n## Migrate a legacy preset\n\nBefore declaration rows, a user preset was a directory `$DSH_HOME/.agent-presets/<id>/` holding `preset.yml` (display `name`, `description`, `order`) and `agent.cordis.yml` (the plugin entry list). Nothing reads that directory any more. To migrate one, create a bundle as above whose declaration takes `id` from the directory name, `name`, `description`, and `order` from `preset.yml`, and `plugins` from `agent.cordis.yml` verbatim; check each plugin name against `cordis-composition-reference` because packages renamed since the preset was written fail at activation. Install it, verify the row, then delete the legacy directory.\n\n## Verify\n\n`plugin_manager` `list_bundles` lists the installed bundle; `list_plugins` shows the `preset-<id>` row with its activation state. A declaration whose activation fails stays on the roster with its diagnostic and cannot compose a session until the bundle is fixed and reinstalled. Existing sessions and their children keep the plugin revision they started with; validate changed behavior in a new session. Installing a bundle executes plugin code in the Host process, so it requires Full access or approval.\n\n## Choose plugin placement\n\nHost plugins supply shared services: tools and prompt registries, the Agent loop, sessions, persistence, settings, sandbox policy, model routes, and subagent backends. Preset plugins contribute scopLine truncated
|
||||
{"type":"step/end","data":{"turn":1,"step":1}}
|
||||
{"type":"step/start","data":{"turn":1,"step":2}}
|
||||
{"type":"assistant/message","data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"reasoning","text":"The skill is loaded."},{"type":"text","text":"DONE"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{message:7}}"},"usage":{"inputTokens":180,"outputTokens":10,"cacheReadTokens":0,"reasoningTokens":4},"stream":[{"type":"chunk","time":1788699430709,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}},{"type":"reasoning-chunks","time0":1788699430709,"index":0,"dt":[],"texts":["The skill is loaded."]},{"type":"chunk","time":1788699430709,"chunk":{"type":"block-start","index":1,"blockType":"text"}},{"type":"text-chunks","time0":1788699430709,"index":1,"dt":[],"texts":["DONE"]},{"type":"chunk","time":1788699430709,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The skill is loaded."}}},{"type":"chunk","time":1788699430709,"chunk":{"type":"block-end","index":1,"block":{"type":"text","text":"DONE"}}},{"type":"chunk","time":1788699430709,"chunk":{"type":"usage","usage":{"inputTokens":180,"outputTokens":10,"cacheReadTokens":0,"reasoningTokens":4}}},{"type":"chunk","time":1788699430709,"chunk":{"type":"finish","reason":{"kind":"stop"}}}]},"surfaceOp":"append"}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
- button "Context injection skill-catalog"
|
||||
- button "Think"
|
||||
- button "Skill editing-cordis-compositions" [expanded]
|
||||
- region "Instructions": "Instructions <skill_content name=\"editing-cordis-compositions\"> <skill_resources> Base directory for this skill: {{cwd}}/.dsh/skills/editing-cordis-compositions Resolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed. </skill_resources> <skill_instructions> # Editing Cordis compositions Agent presets are ordinary `@deepseek-ai/dsh-agent-preset` declarations carried by bundle patches. Nothing edits a declaration in place: a preset is created or changed by installing a bundle whose patch declares or overrides it. This file is the complete contract; do not read DSH package sources to infer formats. ## Where declarations live The shipped Web presets are `presets/<id>.patch.yml` files of the `@deepseek-ai/dsh-web-app` bundle, ids `standard`, `ptc`, `minimal` and `cordis`. Installed, that bundle sits at `$DSH_HOME/profiles/<profile>/node_modules/@deepseek-ai/dsh-web-app/`; in a source checkout of DSH it is `packages/bundle/web-app/`. Read one file with `cat` when you need a template; `minimal.patch.yml` is the shortest. A declaration row has these `config` fields: `id` (required, lowercase letters, digits and hyphens), `plugins` (required Cordis entry list), and optional `name`, `description` and `order` (roster position). The Loader row `id` is `preset-<id>` by convention. ## Create a preset Write a bundle directory in the workspace with exactly two files, then install it. `review-preset/package.json`: ```json { \"name\": \"@local/dsh-review-preset\", \"version\": \"1.0.0\", \"private\": true, \"type\": \"module\", \"dsh\": { \"bundle\": { \"patch\": \"./cordis.patch.yml\" } } } ``` `review-preset/cordis.patch.yml`: ```yaml - insert: - id: preset-review name: '@deepseek-ai/dsh-agent-preset' config: id: review name: Review description: Reviews changes with the shell only. order: 10 plugins: - id: persona name: '@deepseek-ai/dsh-persona' config: prefix: You review software changes. - id: tool-bash name: '@deepseek-ai/dsh-tool-bash' ``` Install with `plugin_manager`, `action: install_bundle`, `target` set to the absolute bundle directory. It runs package installation and bundle selection itself; do not reproduce those steps with shell commands. ## Change a shipped preset Override the declaration by its Loader row id instead of inserting. The override replaces the complete `config`, so restate `id`, `plugins` and every other field the shipped file carries: ```yaml - id: preset-standard name: '@deepseek-ai/dsh-agent-preset' config: id: standard order: 1 plugins: # the shipped list with your changes ``` ## Verify `plugin_manager` `list_bundles` lists the installed bundle; `list_plugins` shows the `preset-<id>` row with its activation state. A declaration whose activation fails stays on the roster with its diagnostic and cannot compose a session until the bundle is fixed and reinstalled. Existing sessions and their children keep the plugin revision they started with; validate changed behavior in a new session. Installing a bundle executes plugin code in the Host process, so it requires Full access or approval. ## Choose plugin placement Host plugins supply shared services: tools and prompt registries, the Agent loop, sessions, persistence, settings, sandbox policy, model routes, and subagent backends. Preset plugins contribute scoped tools, persona, prompt sections, and policies to those registries. Preset revisions are eagerly activated once and shared by their selecting Agents. A preset plugin that supplies a service must isolate the provider and all its consumers in the same realm. A service consumed by Host plugins belongs in the Host configuration. Scope controls contributions and event visibility; `isolate` controls service instances. Use ordinary Cordis groups for nested plugin lists. Keep `!!js` expressions only in plugin configuration or `disabled`; the Loader evaluates them when activating the child plugin. Resolve assets from installed packages rather than a preset directory. ## Extend the Host For new plugin code or profile-wide capabilities, load `cordis-plugin-development`, author a workspace bundle, and install it with `plugin_manager`. Inspect available APIs through `cordis_inspect_list` and `cordis_inspect_query`; those tools do not invoke Remote methods. Verify the installed capability before reporting completion. </skill_instructions> </skill_content>"
|
||||
- region "Instructions": "Instructions <skill_content name=\"editing-cordis-compositions\"> <skill_resources> Base directory for this skill: {{cwd}}/.dsh/skills/editing-cordis-compositions Resolve relative paths mentioned by this skill against the base directory before using them. Load referenced resources only as needed. </skill_resources> <skill_instructions> # Editing Cordis compositions Agent presets are ordinary `@deepseek-ai/dsh-agent-preset` declarations carried by bundle patches. Nothing edits a declaration in place: a preset is created or changed by installing a bundle whose patch declares or overrides it. This file states the declaration format; when it leaves a question open, read the `@deepseek-ai/dsh-agent-preset` README and `lib/types` declarations under the `packageDir` that `cordis_inspect_query` `Config.listConfigs` returns when queried with a `preset-<id>` row's `entry` id, or `packages/preset/agent-preset/src` in a source checkout. ## Where declarations live The shipped Web presets are `presets/<id>.patch.yml` files of the `@deepseek-ai/dsh-web-app` bundle, ids `standard`, `ptc`, `minimal` and `cordis`. Installed, the bundle resolves from the dsh installation, not the profile; querying `Config.listConfigs` with the `entry` id of any `preset-<id>` row it declares returns that `packageDir`. In a source checkout of DSH it is `packages/bundle/web-app/`. Read one file with the file-read tool when you need a template; `minimal.patch.yml` is the shortest. In Desktop the bundle sits inside `app.asar`, which shell commands cannot open. Load `cordis-composition-reference` for the patch dialect and the list of plugin packages a preset can mount. A declaration row has these `config` fields: `id` (required, lowercase letters, digits and hyphens), `plugins` (required Cordis entry list), and optional `name`, `description` and `order` (roster position). The Loader row `id` is `preset-<id>` by convention. ## Create a preset Write a bundle directory in the workspace with exactly two files, then install it. `review-preset/package.json`: ```json { \"name\": \"@local/dsh-review-preset\", \"version\": \"1.0.0\", \"private\": true, \"type\": \"module\", \"dsh\": { \"bundle\": { \"patch\": \"./cordis.patch.yml\" } } } ``` `review-preset/cordis.patch.yml`: ```yaml - insert: - id: preset-review name: '@deepseek-ai/dsh-agent-preset' config: id: review name: Review description: Reviews changes with the shell only. order: 10 plugins: - id: persona name: '@deepseek-ai/dsh-persona' config: prefix: You review software changes. - id: tool-bash name: '@deepseek-ai/dsh-tool-bash' ``` Install with `plugin_manager`, `action: install_bundle`, `target` set to the absolute bundle directory. It runs package installation and bundle selection itself; do not reproduce those steps with shell commands. ## Change a shipped preset Override the declaration by its Loader row id instead of inserting. The override replaces the complete `config`, so restate `id`, `plugins` and every other field the shipped file carries: ```yaml - id: preset-standard name: '@deepseek-ai/dsh-agent-preset' config: id: standard order: 1 plugins: # the shipped list with your changes ``` ## Migrate a legacy preset Before declaration rows, a user preset was a directory `$DSH_HOME/.agent-presets/<id>/` holding `preset.yml` (display `name`, `description`, `order`) and `agent.cordis.yml` (the plugin entry list). Nothing reads that directory any more. To migrate one, create a bundle as above whose declaration takes `id` from the directory name, `name`, `description`, and `order` from `preset.yml`, and `plugins` from `agent.cordis.yml` verbatim; check each plugin name against `cordis-composition-reference` because packages renamed since the preset was written fail at activation. Install it, verify the row, then delete the legacy directory. ## Verify `plugin_manager` `list_bundles` lists the installed bundle; `list_plugins` shows the `preset-<id>` row with its activation state. A declaration whose activation fails stays on the roster with its diagnostic and cannot compose a session until the bundle is fixed and reinstalled. Existing sessions and their children keep the plugin revision they started with; validate changed behavior in a new session. Installing a bundle executes plugin code in the Host process, so it requires Full access or approval. ## Choose plugin placement Host plugins supply shared services: tools and prompt registries, the Agent loop, sessions, persistence, settings, sandbox policy, model routes, and subagent backends. Preset plugins contribute scoped tools, persona, prompt sections, and policies to those registries. Preset revisions are eagerly activated once and shared by their selecting Agents. A preset plugin that supplies a service must isolate the provider and all its consumers in the same realm. A service consumed by Host plugins belongs in the Host configuration. Scope controls contributions and event visibility; `isolate` controls service inLine truncated
|
||||
- button "Inspect"
|
||||
- button "Think"
|
||||
- paragraph: DONE
|
||||
|
||||
Reference in new issue
Block a user