Merge remote-tracking branch 'upstream/master' into feat/web-workspace-file-links

# Conflicts:
#	apps/cli/package.json
#	pnpm-lock.yaml
This commit is contained in:
ZiyaZhang
2026-08-06 06:24:53 -07:00
177 changed files with 5531 additions and 2395 deletions

View File

@@ -439,6 +439,20 @@ export interface Config {
Source: [`packages/credentials/credentials-local/src/index.ts:26`](../packages/credentials/credentials-local/src/index.ts)
## `@deepseek-ai/dsh-frontend-static`
Requires: `httpServer`
```ts config-catalog
/** Plugin config: the dist anchor. */
export interface Config {
/** Absolute path of index.html inside the dist root. */
distIndex: string
}
```
Source: [`packages/host/frontend-static/src/index.ts:28`](../packages/host/frontend-static/src/index.ts)
## `@deepseek-ai/dsh-fs-local`
```ts config-catalog
@@ -483,6 +497,20 @@ export interface Config {
Source: [`packages/goal/goal/src/index.ts:114`](../packages/goal/goal/src/index.ts)
## `@deepseek-ai/dsh-headless`
Requires: `apiProxy` · `httpServer`
```ts config-catalog
/** Plugin config: the task, patched in by the launcher. */
export interface Config {
/** The prompt text for the single turn. */
task: string
}
```
Source: [`packages/bundle/headless/src/index.ts:33`](../packages/bundle/headless/src/index.ts)
## `@deepseek-ai/dsh-hooks-claude`
Requires: `bash`
@@ -577,18 +605,16 @@ Source: [`packages/host/directory-picker-browse/src/index.ts:181`](../packages/h
## `@deepseek-ai/dsh-host-webserver`
```ts config-catalog
/** Gateway config: listen address plus the static dist anchor (injected by the composing app, never self-resolved). */
/** Gateway config: the listen address. */
export interface Config {
/** Listen host; the two supported values are loopback and all-interfaces. */
host: '127.0.0.1' | '0.0.0.0'
/** Listen port; zero requests an OS-assigned port. */
port: number
/** Absolute path of index.html inside the static root (dist location is workspace knowledge of the app). */
distIndex: string
}
```
Source: [`packages/host/webserver/src/index.ts:47`](../packages/host/webserver/src/index.ts)
Source: [`packages/host/webserver/src/index.ts:45`](../packages/host/webserver/src/index.ts)
## `@deepseek-ai/dsh-invariants`
@@ -2216,6 +2242,39 @@ export interface WebServiceConfig {
Source: [`packages/web/web/src/index.ts:55`](../packages/web/web/src/index.ts)
## `@deepseek-ai/dsh-web-app`
Requires: `httpServer`
```ts config-catalog
/** Plugin config: the surface facts the launcher patches over this bundle's defaults. */
export interface Config {
/** Whether this process mounted the client-plugin HMR receiver (`dsh web --dev`). */
mode: WebMode
/** Print the URL line on activation; a headless layer over this bundle turns it off. */
printUrl: boolean
/**
* Register the model-visible surface context (the `app:web-surface` prompt
* section and the `DSH_WEB_URL`/`DSH_WEB_MODE` bash variables). A one-shot
* layer turns it off: its user is not interacting through the GUI, so the
* orientation text would be false.
*/
surfaceContext: boolean
/**
* LAN IPv4 addresses sampled once by the launcher when the effective bind
* is all-interfaces — the exact snapshot the /api trust fence was
* configured with, so the printed LAN URL can never name an address the
* fence rejects. Empty on a loopback bind.
*/
lanAddresses: string[]
}
/** Web runtime mode: production, or development when the client-plugin HMR receiver is active. */
export type WebMode = 'production' | 'development'
```
Source: [`packages/bundle/web-app/src/index.ts:32`](../packages/bundle/web-app/src/index.ts)
## `@deepseek-ai/dsh-web-fetch-local`
Requires: `web`
@@ -2446,6 +2505,7 @@ Imported as libraries by other packages; a `cordis.yml` cannot load them.
- `@deepseek-ai/dsh-agent-loop-testkit` ([`packages/support/agent-loop-testkit/src/index.ts`](../packages/support/agent-loop-testkit/src/index.ts))
- `@deepseek-ai/dsh-app-boot` ([`packages/ui/app-boot/src/index.ts`](../packages/ui/app-boot/src/index.ts))
- `@deepseek-ai/dsh-atomic-write` ([`packages/util/atomic-write/src/index.ts`](../packages/util/atomic-write/src/index.ts))
- `@deepseek-ai/dsh-base` ([`packages/bundle/base/src/index.ts`](../packages/bundle/base/src/index.ts))
- `@deepseek-ai/dsh-brand` ([`packages/util/brand/src/index.ts`](../packages/util/brand/src/index.ts))
- `@deepseek-ai/dsh-client-schema-form` ([`packages/client/schema-form/src/index.ts`](../packages/client/schema-form/src/index.ts))
- `@deepseek-ai/dsh-client-test-runtime` ([`packages/client/test-runtime/src/index.ts`](../packages/client/test-runtime/src/index.ts))

View File

@@ -769,7 +769,7 @@ Source: [`packages/goal/goal/src/index.ts:181`](../../packages/goal/goal/src/ind
## `ctx.httpServer` — `HttpServerService`
The web-shape HTTP carrier service. Activation listens immediately (route registration order carries no request-facing semantics: named routes are composed to be disjoint, and the static dist fallback answers anything not yet claimed during the boot window). A listen failure throws out of init — a FAILED fiber the boot's fail-loud sweep reports.
The web-shape HTTP carrier service. Activation listens immediately (route registration order carries no request-facing semantics: named routes are composed to be disjoint, and the fallback seat answers anything not yet claimed during the boot window — 404 until its owner registers). A listen failure throws out of init — a FAILED fiber the boot's fail-loud sweep reports.
```ts cordis-catalog
/**
@@ -789,15 +789,33 @@ register(route: WebRoute): () => void
registerUpgrade(route: WebUpgradeRoute): () => void
/**
* Register an index.html transform, applied to every index response in
* registration order.
* Claim the fallback seat: the handler answering every request no named
* route matches (the SPA dist server in the shipped Web composition). One
* owner only — a second registration throws, because two fallbacks cannot
* compose.
* @param handler - owns the full response lifecycle of unmatched requests.
* @returns the disposer releasing the seat.
*/
registerFallback(handler: WebRoute['handler']): () => void
/**
* Register an index.html transform, applied by the fallback owner to every
* index response ({@link applyIndexTaps}) in registration order.
* @param transform - pure html-to-html function.
* @returns the disposer removing the transform.
*/
tapIndex(transform: (html: string) => string): () => void
/**
* Run an index.html body through the registered taps in registration order
* — called by the fallback owner on every index response it renders.
* @param html - the raw index.html body.
* @returns the transformed body.
*/
applyIndexTaps(html: string): string
```
Source: [`packages/host/webserver/src/index.ts:63`](../../packages/host/webserver/src/index.ts)
Source: [`packages/host/webserver/src/index.ts:60`](../../packages/host/webserver/src/index.ts)
## `ctx.invariants` — `InvariantService`

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write docs/cordis-tutorial/01-first-plugin.md
01-first-plugin.md: c9f4889398222793005fce6832d0917a20d0be30
01-first-plugin.zh.md: b9d6994fad8e26cdfc52db0fbcef5631d5d53b03
01-first-plugin.md: c44e7f95fb11d5337ecfaf4251c8b2f2b9b14680
01-first-plugin.zh.md: 9461884d312ad2e64af12fa42952a986e1ad5d8a

View File

@@ -48,7 +48,7 @@ The process exits on its own once nothing is left running. What happened:
2. The Loader read `cordis.yml`, resolved `./hello.ts`, and mounted it as a child plugin.
3. Cordis called your `apply(ctx)`.
There is no framework bootstrap code in your file: a plugin describes what it contributes, and `cordis.yml` composes the application. The [`dsh` base](../../apps/cli/config/base.cordis.yml), for example, is a longer plugin composition that deployment overlays patch.
There is no framework bootstrap code in your file: a plugin describes what it contributes, and `cordis.yml` composes the application. The [`dsh` base](../../packages/bundle/base/cordis.patch.yml), for example, is a longer plugin composition that deployment overlays patch.
## The two other plugin shapes

View File

@@ -48,7 +48,7 @@ hello from my first plugin
2. Loader 读取 `cordis.yml`,解析 `./hello.ts`,然后将其作为子插件挂载。
3. Cordis 调用你的 `apply(ctx)`
你的文件中没有框架启动代码:插件描述自己的贡献,`cordis.yml` 则组合应用。例如,[`dsh` base](../../apps/cli/config/base.cordis.yml) 就是一份更长的插件组合,由部署 overlay 对它进行修补。
你的文件中没有框架启动代码:插件描述自己的贡献,`cordis.yml` 则组合应用。例如,[`dsh` base](../../packages/bundle/base/cordis.patch.yml) 就是一份更长的插件组合,由部署 overlay 对它进行修补。
## 其他两种插件形态

View File

@@ -18,7 +18,7 @@ This matrix shows which packages dispatch each harness-owned event and which pac
| `agent/request` | `waterfall` | [`packages/core/agent/src/types.ts:239`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`agent`](../packages/core/agent) |
| `agent/request-error` | `waterfall` | [`packages/core/agent/src/types.ts:255`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`compact-basic`](../packages/compact/compact-basic), [`llm-retry`](../packages/llm/llm-retry) |
| `agent/session-start` | `emit` | [`packages/core/agent/src/types.ts:212`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emitAgentEvent`) | [`goal`](../packages/goal/goal), [`goal-session`](../packages/goal/goal-session), [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex) |
| `agent/status` | `emit` | [`packages/core/agent/src/types.ts:173`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`agent`](../packages/core/agent), `apiproxy`, [`compact-basic`](../packages/compact/compact-basic), [`goal-session`](../packages/goal/goal-session), [`jsonrpc`](../packages/ui/jsonrpc) |
| `agent/status` | `emit` | [`packages/core/agent/src/types.ts:173`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`agent`](../packages/core/agent), `apiproxy`, [`compact-basic`](../packages/compact/compact-basic), [`goal-session`](../packages/goal/goal-session), [`headless`](../packages/bundle/headless), [`jsonrpc`](../packages/ui/jsonrpc) |
| `agent/turn-stopping` | `serial` | [`packages/core/agent/src/types.ts:273`](../packages/core/agent/src/types.ts) | [`agent-loop`](../packages/core/agent-loop) (`serial`) | [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex) |
| `approval/request` | `waterfall` | [`packages/ui/user-approval/src/index.ts:30`](../packages/ui/user-approval/src/index.ts) | [`user-approval`](../packages/ui/user-approval) (`waterfall`) | [`acp`](../packages/acp/acp), `apiproxy` |
| `commands/change` | `emit` | [`packages/ui/commands/src/index.ts:154`](../packages/ui/commands/src/index.ts) | [`commands`](../packages/ui/commands) (`events.dispatch`) | `apiproxy` |

View File

@@ -144,6 +144,11 @@ flowchart TD
pkg_user_approval["user-approval"]
pkg_user_interaction["user-interaction"]
end
subgraph group_bundle["packages/bundle"]
pkg_base["base"]
pkg_headless["headless"]
pkg_web_app["web-app"]
end
subgraph group_client["packages/client"]
pkg_client_connection["client-connection"]
pkg_client_hmr["client-hmr"]
@@ -199,6 +204,7 @@ flowchart TD
pkg_repeat_tool_guard["repeat-tool-guard"]
end
subgraph group_host["packages/host"]
pkg_frontend_static["frontend-static"]
pkg_host_apiproxy["host-apiproxy"]
pkg_host_directory_picker["host-directory-picker"]
pkg_host_directory_picker_auto["host-directory-picker-auto"]
@@ -284,6 +290,7 @@ flowchart TD
pkg_acp_snapshot --> pkg_invariants
pkg_llm_mock_server --> pkg_invariants
pkg_loader_smoke --> pkg_invariants
pkg_base --> pkg_invariants
pkg_client_modules --> pkg_invariants
pkg_client_runtime --> pkg_invariants
pkg_client_schema_form --> pkg_invariants
@@ -326,6 +333,8 @@ flowchart TD
pkg_client_ui_trajectory --> pkg_invariants
pkg_credentials --> pkg_brand
pkg_credentials --> pkg_invariants
pkg_frontend_static --> pkg_host_webserver
pkg_frontend_static --> pkg_invariants
pkg_helper --> pkg_brand
pkg_helper --> pkg_invariants
pkg_helper --> pkg_subprocess
@@ -551,6 +560,11 @@ flowchart TD
pkg_user_interaction --> pkg_agent
pkg_user_interaction --> pkg_invariants
pkg_user_interaction --> pkg_llm
pkg_headless --> pkg_agent
pkg_headless --> pkg_host_apiproxy
pkg_headless --> pkg_host_webserver
pkg_headless --> pkg_invariants
pkg_headless --> pkg_session
pkg_time_context --> pkg_agent
pkg_time_context --> pkg_invariants
pkg_time_context --> pkg_session
@@ -949,6 +963,9 @@ flowchart TD
pkg_hooks_claude --> pkg_session_persistence
pkg_hooks_claude --> pkg_subagent
pkg_hooks_claude --> pkg_tools
pkg_web_app --> pkg_bash_env
pkg_web_app --> pkg_invariants
pkg_web_app --> pkg_system_prompt
pkg_client_ui_model --> pkg_client_connection
pkg_client_ui_model --> pkg_client_locale
pkg_client_ui_model --> pkg_client_runtime
@@ -1089,6 +1106,7 @@ flowchart TD
| [`acp-snapshot`](../packages/support/acp-snapshot) | `support` | [`invariants`](../packages/support/invariants) |
| [`llm-mock-server`](../packages/support/llm-mock-server) | `support` | [`invariants`](../packages/support/invariants) |
| [`loader-smoke`](../packages/support/loader-smoke) | `support` | [`invariants`](../packages/support/invariants) |
| [`base`](../packages/bundle/base) | `bundle` | [`invariants`](../packages/support/invariants) |
| [`client-modules`](../packages/client/modules) | `client` | [`invariants`](../packages/support/invariants) |
| [`client-runtime`](../packages/client/runtime) | `client` | [`invariants`](../packages/support/invariants) |
| [`client-schema-form`](../packages/client/schema-form) | `client` | [`invariants`](../packages/support/invariants) |
@@ -1113,6 +1131,7 @@ flowchart TD
| [`client-ui-settings`](../packages/client/ui-settings) | `client` | [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/support/invariants) |
| [`client-ui-trajectory`](../packages/client/ui-trajectory) | `client` | [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`invariants`](../packages/support/invariants) |
| [`credentials`](../packages/credentials/credentials) | `credentials` | [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants) |
| [`frontend-static`](../packages/host/frontend-static) | `host` | [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/support/invariants) |
| [`helper`](../packages/sdk/helper) | `sdk` | [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants), [`subprocess`](../packages/subprocess/subprocess) |
| [`telemetry`](../packages/sdk/telemetry) | `sdk` | [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants), [`paths`](../packages/util/paths) |
| [`settings`](../packages/settings/settings) | `settings` | [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants) |
@@ -1173,6 +1192,7 @@ flowchart TD
| [`commands`](../packages/ui/commands) | `ui` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants), [`scope`](../packages/core/scope), [`session`](../packages/core/session) |
| [`user-approval`](../packages/ui/user-approval) | `ui` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt) |
| [`user-interaction`](../packages/ui/user-interaction) | `ui` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm) |
| [`headless`](../packages/bundle/headless) | `bundle` | [`agent`](../packages/core/agent), [`host-apiproxy`](../packages/host/apiproxy), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/support/invariants), [`session`](../packages/core/session) |
| [`time-context`](../packages/context/time-context) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/support/invariants), [`session`](../packages/core/session) |
| [`tmux-context`](../packages/context/tmux-context) | `context` | [`agent`](../packages/core/agent), [`bash`](../packages/bash/bash), [`invariants`](../packages/support/invariants), [`session`](../packages/core/session) |
| [`host-directory-picker-auto`](../packages/host/directory-picker-auto) | `host` | [`host-directory-picker-browse`](../packages/host/directory-picker-browse), [`host-directory-picker-native`](../packages/host/directory-picker-native), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/support/invariants) |
@@ -1242,6 +1262,7 @@ flowchart TD
| [`tool-subagent-report`](../packages/subagent/tool-subagent-report) | `subagent` | [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
| [`repository-plugin`](../packages/cordis/repository-plugin) | `cordis` | [`invariants`](../packages/support/invariants), [`mcp-client`](../packages/mcp/mcp-client), [`paths`](../packages/util/paths), [`skill-local`](../packages/skill/skill-local) |
| [`hooks-claude`](../packages/hooks/hooks-claude) | `hooks` | [`agent`](../packages/core/agent), [`hook-protocol`](../packages/hooks/hook-protocol), [`invariants`](../packages/support/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session-persistence/session-persistence), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
| [`web-app`](../packages/bundle/web-app) | `bundle` | [`bash-env`](../packages/bash/bash-env), [`invariants`](../packages/support/invariants), [`system-prompt`](../packages/core/system-prompt) |
| [`client-ui-model`](../packages/client/ui-model) | `client` | [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-command`](../packages/client/ui-command), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slash`](../packages/client/ui-slash), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/support/invariants) |
| [`client-ui-permission`](../packages/client/ui-permission) | `client` | [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-schema-form`](../packages/client/schema-form), [`client-ui-command`](../packages/client/ui-command), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slash`](../packages/client/ui-slash), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/support/invariants), [`permission`](../packages/ui/permission) |
| [`client-ui-plan`](../packages/client/ui-plan) | `client` | [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/support/invariants), [`plan-mode`](../packages/plan/plan-mode) |

View File

@@ -31,7 +31,7 @@ This table connects model-visible tool names to the plugin package and service s
| `@deepseek-ai/dsh-tool-ralph` | `ralph` | `ctx.tools`, `ctx.workflows`, `ctx.subagents`, `ctx.systemPrompt`, `a calling Agent (exec.agent parents every fresh round)` | `tool/call`, `tool/result`, `workflow and child session events during execution` | - | A fixed foreground workflow starts one fresh structured child per round; the model selects only the immutable objective and an optional round cap. |
| `@deepseek-ai/dsh-tool-skill` | `skill` | `ctx.tools`, `ctx.agents`, `ctx.skills` | `tool/call`, `tool/result`, `user/message replacement catalogs via agent.inject()` | - | - |
| `@deepseek-ai/dsh-tool-session-query` | `session_event_read`, `session_event_search`, `session_event_trace`, `session_search`, `session_trace` | `ctx.tools`, `ctx.systemPrompt`, `ctx.sessionQuery`, `a calling Agent for workspace authority` | `tool/call`, `tool/result` | - | The five read-only tools hide provider cursors and authorize every result from the immutable calling agent session. The package is opt-in; compositions that need enforced deadlines or bounded inline output also mount the generic timeout or spill policies. |
| `@deepseek-ai/dsh-tool-subagent` | `subagent` | `ctx.tools`, `ctx.subagents` | `tool/call`, `tool/result`, `child session events through the chosen provider` | `subagent`, `subagent_fork` | The registered tool name is the load-time `toolName` config (default `subagent`); the schema above is that default. The shipped example agents load this package once per subagent backend, so the model additionally sees `subagent_fork` (bound to the fork backend) with an identical schema — see `apps/cli/config/base.cordis.yml` and `examples/acp-agent/cordis.yml`. |
| `@deepseek-ai/dsh-tool-subagent` | `subagent` | `ctx.tools`, `ctx.subagents` | `tool/call`, `tool/result`, `child session events through the chosen provider` | `subagent`, `subagent_fork` | The registered tool name is the load-time `toolName` config (default `subagent`); the schema above is that default. The shipped example agents load this package once per subagent backend, so the model additionally sees `subagent_fork` (bound to the fork backend) with an identical schema — see `packages/bundle/base/cordis.patch.yml` and `examples/acp-agent/cordis.yml`. |
| `@deepseek-ai/dsh-tool-subagent-control` | `list_agents`, `send_message` | `ctx.tools`, `ctx.subagents`, `ctx.sessionQuery (list_agents only)` | `tool/call`, `tool/result`, `child session events through ctx.subagents` | - | The globally named control tools over continuable background subagents: provider-bound `tool-subagent` instances register distinct delegation tools, while this package registers `send_message` once, plus `list_agents` from its separately loaded `/list-agents` plugin (which additionally requires session query). |
| `@deepseek-ai/dsh-tool-subagent-report` | `report` | `ctx.subagents`, `a live continuable in-process child Agent` | `tool/call`, `tool/result`, `a user-role message in the direct parent session` | - | Registered per continuable in-process child rather than globally, so this schema is visible only inside such a child and survives its global `toolFilter`. The parent-facing `send_message` tool is installed independently. |
| `@deepseek-ai/dsh-tool-tasks` | `task_kill`, `task_list`, `task_output` | `ctx.tools`, `ctx.tasks`, `ctx.systemPrompt` | `tool/call`, `tool/result`, `user/message via agent.inject() for background completion notices` | - | The kind-agnostic background-task control surface: background bash commands, PTY sends, and subagents are read, listed, and killed through the same three tools. Loading the plugin attaches the control surface that arms producers' `ctx.tasks.start()`. |
@@ -1189,7 +1189,7 @@ Delegate a self-contained task to a subagent (a separate agent that works in its
Source: [`packages/subagent/tool-subagent/src/index.ts`](../packages/subagent/tool-subagent/src/index.ts)
The registered tool name is the load-time `toolName` config (default `subagent`); the schema above is that default. The shipped example agents load this package once per subagent backend, so the model additionally sees `subagent_fork` (bound to the fork backend) with an identical schema — see `apps/cli/config/base.cordis.yml` and `examples/acp-agent/cordis.yml`.
The registered tool name is the load-time `toolName` config (default `subagent`); the schema above is that default. The shipped example agents load this package once per subagent backend, so the model additionally sees `subagent_fork` (bound to the fork backend) with an identical schema — see `packages/bundle/base/cordis.patch.yml` and `examples/acp-agent/cordis.yml`.
## `@deepseek-ai/dsh-tool-subagent-control`

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write docs/user/develop/basic/config.md
config.md: 11a2311464789f74537cc7c4435f83ec07ca26fd
config.zh.md: 4e827ecafa6bfaf87c3e3f118425e656e1254787
config.md: 02998c32415b5ba7acf82700034cabc1f7314f33
config.zh.md: 42af432b36d8f82871aa7d7b6a3a2eaf7427cdae

View File

@@ -101,5 +101,6 @@ A configuration edit hot-replaces the plugin: the framework unloads the old inst
## Next steps
- [Package and install a plugin](./publish.md) — ship the plugin as an installable package
- [Plugins and lifecycle](../framework/) — understand the full plugin lifecycle
- [Services and dependencies](../framework/service.md) — provide a service to other plugins

View File

@@ -101,5 +101,6 @@ export interface Config {
## 下一步
- [打包与安装插件](./publish.md) — 把插件以可安装包的形式交付
- [插件与生命周期](../framework/) — 深入了解插件的完整生命周期
- [服务与依赖](../framework/service.md) — 让你的插件对外提供服务

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write docs/user/develop/basic/index.md
index.md: 45c8dfe495cd99da46a7b259b407af8deff570b3
index.zh.md: 9d8ee47e6f07fb4a897f49487cb7327904573c1b
index.md: efedb07c8d757ef1f90d99fe1bf503a35c0f1a37
index.zh.md: 2293a6086dc80fa77c88ef734ae17576ea513a10

View File

@@ -56,7 +56,7 @@ Create `scratch-plugin/cordis.yml` as a Web overlay that inserts the local plugi
Start the Web UI with that overlay:
```sh
pnpm run dsh web --config ./scratch-plugin/cordis.yml
pnpm run dsh web --patch ./scratch-plugin/cordis.yml
```
Open `http://127.0.0.1:3080`. The terminal prints `[hello-plugin] plugin loaded!` during startup.

View File

@@ -56,7 +56,7 @@ export function apply(ctx: Context) {
使用该覆盖层启动 Web UI
```sh
pnpm run dsh web --config ./scratch-plugin/cordis.yml
pnpm run dsh web --patch ./scratch-plugin/cordis.yml
```
打开 `http://127.0.0.1:3080`。启动期间,终端会打印 `[hello-plugin] plugin loaded!`

View File

@@ -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 docs/user/develop/basic/publish.md
publish.md: 1d1179a78c4d3a7e9e7055e3f5ee41381e28147e
publish.zh.md: 26d1c2b737a3498bce0757d5b2d14e254fc13527

View File

@@ -0,0 +1,140 @@
# Package and install a plugin
English | [中文](publish.zh.md)
The previous tutorials loaded a local plugin through a `--patch` overlay. This tutorial packages it as an installable **bundle**, installs it into a **profile** with `dsh plugin add`, and explains the layer order that determines the composed configuration. Complete [plugin configuration](./config.md) first.
## Two concepts, two manifests
Installation is built on two concepts. Both are described by a `package.json`, but they carry different kinds of manifest under the `dsh` key, and they answer different questions:
- A **bundle** is an npm package that ships a configuration layer. Its manifest declares `dsh.bundle`, answering "what does this package contribute?": a patch file that inserts or overrides plugin rows.
- A **profile** is a directory under `$DSH_HOME/profiles/<name>` describing one runnable composition. Its manifest declares `dsh.profile`, answering "which bundles compose this setup, in what order?".
A bundle is what you author and distribute; a profile is what a user boots with `dsh --profile <name>`. Nothing is both.
### The bundle manifest
```
hello-plugin/
├── package.json # declares dsh.bundle
├── cordis.patch.yml # the layer applied when a profile lists this bundle
└── index.js # plugin modules the patch rows reference
```
```json
{
"name": "dsh-hello-plugin",
"version": "0.1.0",
"type": "module",
"main": "index.js",
"files": ["index.js", "cordis.patch.yml"],
"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }
}
```
The patch file has the same shape as the `--patch` overlays you have been writing — a YAML array of patch entries — except plugin rows reference the package by name instead of a relative source path, so Node resolution finds the installed code:
```yaml
- insert:
- id: hello
name: dsh-hello-plugin
```
A package without the `dsh.bundle` declaration still installs, but only as a plain dependency: `dsh plugin` prints a warning and activates no layer. That is the correct shape for a library that plugin packages import rather than a plugin users enable.
### The profile manifest
A profile directory holds two files:
- `package.json` — the profile's out-of-tree plugin dependencies (managed by pnpm) plus the `dsh.profile` manifest with its ordered `bundles` list.
- `cordis.patch.yml` — the user's own patch layer, applied after every bundle layer.
You never write a profile manifest by hand: `dsh plugin` creates and maintains it. The next section shows the result.
## Install into a profile
`dsh plugin --profile <name> <args...>` forwards to pnpm in the profile directory, so every pnpm verb works. Install your package from its checkout:
```sh
cd hello-plugin
dsh plugin --profile demo add .
```
The first use initializes the profile (with `@deepseek-ai/dsh-base` as its first bundle), pnpm links the checkout, and `dsh` appends the bundle to `dsh.profile.bundles` because the package declares `dsh.bundle`:
```json
{
"name": "dsh-profile-demo",
"private": true,
"dependencies": {
"dsh-hello-plugin": "link:/path/to/hello-plugin"
},
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"dsh-hello-plugin"
]
}
}
}
```
Verify the layer without booting, then boot:
```sh
dsh --profile demo --dump-config # shows a "# == dsh-hello-plugin" layer
dsh --profile demo
```
`dsh plugin --profile demo remove dsh-hello-plugin` removes both the dependency and the layer.
## The loading order
The effective configuration composes over an empty root by applying, in order:
1. Each bundle patch named in the profile's `dsh.profile.bundles` list, in list order — `@deepseek-ai/dsh-base` first, then each installed bundle in the order it was added.
2. The profile's own `cordis.patch.yml`.
3. The home-level `$DSH_HOME/cordis.patch.yml` — machine-local preferences shared by every profile.
4. Each `--patch <path>` overlay, in argv order.
5. Launcher flag patches (for example `dsh web --port`).
Later layers win per row, and a patch replaces a row's entire `config` value rather than deep-merging keys. Two consequences for bundle authors:
- Your patch can override rows from earlier layers by `id` — the same way [the `dsh-web-app` bundle](../../../../packages/bundle/web-app/cordis.patch.yml) overrides `dsh-base` rows — but must restate every key the row needs, not just the changed one.
- Users can override your rows in their profile's `cordis.patch.yml` without touching your package, so prefer configuration defaults users are likely to keep and let the schema carry the rest.
In-box bundle names always resolve from the dsh installation itself; pnpm manages only out-of-tree packages, so your bundle can rely on `@deepseek-ai/dsh-base` being present and current.
## Installing from GitHub: the build-script catch
Publishing to a registry is not required — users can install straight from a git host:
```sh
dsh plugin --profile demo add github:you/hello-plugin
```
But a git install fetches **sources, not built artifacts**: nothing runs your `build` script, so a TypeScript package arrives without its `lib/` output and fails to load. Two things must happen, one on each side:
- **The author** ships a `prepare` script — pnpm runs it after a git install — that builds the published entry points from source, self-contained: it must not assume dev-only context such as a sibling monorepo checkout. [turtle-ui](https://github.com/deepseek-harness/turtle-ui) is a working example: its `prepare` runs a dedicated tsdown config that transpiles `src/` without project references or type checking.
- **The user** allowlists the build. pnpm ≥10 refuses to run a git dependency's `prepare` script until it is explicitly allowed, so the first `add` fails; `dsh` points at the fix — copy the exact package key pnpm printed into the profile's `pnpm-workspace.yaml`:
```yaml
allowBuilds:
dsh-hello-plugin: true
```
and re-run the `add`.
Treat that allowance as what it is: **permission to execute the package's code on your machine at install time**, outside any sandbox the agent runs under. Only allow packages whose source you trust, and pin a commit (`github:you/hello-plugin#<sha>`) so a later push cannot silently change what runs.
If you would rather not ask users for the allowance, distribute built artifacts instead — neither form needs any build permission:
- **Publish to npm** with `lib/` built at `pnpm publish` time; `dsh plugin add your-package` then installs prebuilt code.
- **Ship a tarball** from `pnpm pack`; users run `dsh plugin add ./hello-plugin-0.1.0.tgz`.
## Next steps
- [Plugins and lifecycle](../framework/) — the full plugin lifecycle
- [CLI behavior reference](../../../../apps/cli/reference/README.md) — exact layer precedence, flags, and profile mechanics

View File

@@ -0,0 +1,140 @@
# 打包与安装插件
[English](publish.md) | 中文
前几篇教程通过 `--patch` overlay 加载本地插件。本教程把它打包成可安装的**组合包**bundle`dsh plugin add` 安装进一个 **profile**,并解释决定组合后配置的层顺序。请先完成[插件配置](./config.md)。
## 两个概念,两种 manifest
安装机制建立在两个概念之上。二者都由一份 `package.json` 描述,但它们在 `dsh` 键下携带的 manifest元数据清单种类不同回答的问题也不同
- **组合包**是附带一个配置层的 npm 包。它的 manifest 声明 `dsh.bundle`,回答的是"这个包贡献什么?":一个插入或覆盖插件行的 patch 文件。
- **profile** 是位于 `$DSH_HOME/profiles/<name>` 下、描述一份可启动组合的目录。它的 manifest 声明 `dsh.profile`,回答的是"这套配置由哪些组合包按什么顺序组成?"。
组合包是你编写并分发的东西profile 是用户用 `dsh --profile <name>` 启动的东西。没有东西同时是两者。
### 组合包 manifest
```
hello-plugin/
├── package.json # declares dsh.bundle
├── cordis.patch.yml # the layer applied when a profile lists this bundle
└── index.js # plugin modules the patch rows reference
```
```json
{
"name": "dsh-hello-plugin",
"version": "0.1.0",
"type": "module",
"main": "index.js",
"files": ["index.js", "cordis.patch.yml"],
"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }
}
```
patch 文件的形状与你一直在写的 `--patch` overlay 相同——一个 patch 条目的 YAML 数组——只是插件行按包名而不是相对源码路径引用这个包,这样 Node 的模块解析才能找到已安装的代码:
```yaml
- insert:
- id: hello
name: dsh-hello-plugin
```
没有 `dsh.bundle` 声明的包仍然可以安装,但只作为普通依赖:`dsh plugin` 会打印警告,且不激活任何层。这正是"供插件包 import 的库"应有的形状,区别于"供用户启用的插件"。
### profile manifest
profile 目录包含两个文件:
- `package.json` — profile 的树外插件依赖(由 pnpm 管理),加上 `dsh.profile` manifest 及其有序的 `bundles` 列表。
- `cordis.patch.yml` — 用户自己的 patch 层,在每个组合包层之后应用。
profile manifest 从不需要手写:`dsh plugin` 负责创建和维护它。下一节展示其结果。
## 安装进 profile
`dsh plugin --profile <name> <args...>` 在 profile 目录内转发给 pnpm因此所有 pnpm 子命令都可用。从 checkout 安装你的包:
```sh
cd hello-plugin
dsh plugin --profile demo add .
```
首次使用会初始化 profile`@deepseek-ai/dsh-base` 作为它的第一个组合包pnpm 链接该 checkout`dsh` 因为这个包声明了 `dsh.bundle`,把它追加进 `dsh.profile.bundles`
```json
{
"name": "dsh-profile-demo",
"private": true,
"dependencies": {
"dsh-hello-plugin": "link:/path/to/hello-plugin"
},
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"dsh-hello-plugin"
]
}
}
}
```
先不启动、只验证该层,再启动:
```sh
dsh --profile demo --dump-config # shows a "# == dsh-hello-plugin" layer
dsh --profile demo
```
`dsh plugin --profile demo remove dsh-hello-plugin` 会同时移除依赖和对应的层。
## 加载顺序
生效配置在空根之上按以下顺序逐层组合:
1. profile 的 `dsh.profile.bundles` 列表所列的各个组合包 patch按列表顺序——先是 `@deepseek-ai/dsh-base`,然后是每个已安装组合包,按其加入顺序。
2. profile 自己的 `cordis.patch.yml`
3. home 级的 `$DSH_HOME/cordis.patch.yml`——各 profile 共享的机器本地偏好。
4. 每个 `--patch <path>` overlay按 argv 顺序。
5. 启动器 flag patch例如 `dsh web --port`)。
后应用的层按行胜出,且 patch 会替换目标行的整个 `config` 值,而不是深度合并各键。这给组合包作者带来两个推论:
- 你的 patch 可以按 `id` 覆盖前面各层的行——就像 [`dsh-web-app` 组合包](../../../../packages/bundle/web-app/cordis.patch.yml)覆盖 `dsh-base` 的行那样——但必须重述该行需要的每一个键,而不是只写改动的那个。
- 用户可以在自己 profile 的 `cordis.patch.yml` 中覆盖你的行,无需改动你的包,所以优先给出用户大概率会保留的配置默认值,其余交给 schema 承担。
内置组合包名称始终从 dsh 安装目录本身解析pnpm 只管理树外的包,所以你的组合包可以放心依赖 `@deepseek-ai/dsh-base` 存在且与安装保持一致。
## 从 GitHub 安装:构建脚本这道坎
发布到注册表不是必须的——用户可以直接从 git 托管安装:
```sh
dsh plugin --profile demo add github:you/hello-plugin
```
但 git 安装拉取的是**源码,不是构建产物**:没有任何环节运行你的 `build` 脚本,因此 TypeScript 包到手时没有 `lib/` 输出,加载会失败。必须两边各做一件事:
- **作者**提供一个 `prepare` 脚本——pnpm 在 git 安装后运行它——从源码构建出发布入口,且必须自包含:不能假设仅开发环境才有的上下文,例如旁边有一份 monorepo checkout。[turtle-ui](https://github.com/deepseek-harness/turtle-ui) 是一个可用的例子:它的 `prepare` 运行一份专用的 tsdown 配置,直接转译 `src/`,不用项目引用,也不做类型检查。
- **用户**为构建授权。pnpm ≥10 在得到显式允许之前拒绝运行 git 依赖的 `prepare` 脚本,所以第一次 `add` 会失败;`dsh` 会指出修法——把 pnpm 打印的确切包键复制进该 profile 的 `pnpm-workspace.yaml`
```yaml
allowBuilds:
dsh-hello-plugin: true
```
然后重新执行 `add`。
请如实看待这项授权:**允许该包的代码在安装时于你的机器上执行**,且不在 agent 运行的任何沙箱之内。只对源码可信的包授权,并锁定 commit`github:you/hello-plugin#<sha>`),让后续推送无法悄悄改变实际运行的内容。
如果不想让用户做这项授权,就改为分发构建产物——以下两种形式都不需要任何构建权限:
- **发布到 npm**,在 `pnpm publish` 时构建好 `lib/``dsh plugin add your-package` 安装的就是预构建代码。
- **交付 tarball**:用 `pnpm pack` 打包;用户执行 `dsh plugin add ./hello-plugin-0.1.0.tgz`。
## 下一步
- [插件与生命周期](../framework/) — 插件的完整生命周期
- [CLI 行为参考](../../../../apps/cli/reference/README.md) — 确切的层优先级、flag 与 profile 机制

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write docs/user/develop/basic/tool.md
tool.md: 93a1a96feba814a564f8800c8e7b865fe9c0cb73
tool.zh.md: 18e6b9b5d9c17b00c26aa7b98e6ac4531315dc5e
tool.md: 8505bdaf6fcece3235b0302d54e82ee8aed3cbab
tool.zh.md: 1831afa9be74756cb9bb1e96515fefd3685ee4c2

View File

@@ -40,7 +40,7 @@ export function apply(ctx: Context) {
Restart the development command if it is not running:
```sh
pnpm run dsh web --config ./scratch-plugin/cordis.yml
pnpm run dsh web --patch ./scratch-plugin/cordis.yml
```
Open `http://127.0.0.1:3080` and ask: `Use the greet tool to greet Ada.` The model can call `greet` and receives `Hello, Ada!` as the tool result.

View File

@@ -40,7 +40,7 @@ export function apply(ctx: Context) {
如果开发命令未在运行,请重新启动:
```sh
pnpm run dsh web --config ./scratch-plugin/cordis.yml
pnpm run dsh web --patch ./scratch-plugin/cordis.yml
```
打开 `http://127.0.0.1:3080`,然后输入:`Use the greet tool to greet Ada.` 模型可以调用 `greet`,并收到 `Hello, Ada!` 这一工具结果。

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write docs/user/guide/config.md
config.md: ddf4df264e5534fc3b74991941c2f3f82376d53f
config.zh.md: 56ac0146ddae83dbfc86f479030efdb5772a3aaf
config.md: 0f1a99ed0afdab13d052ae2714fc2e1718d3d85e
config.zh.md: 74e14e4e6e1fbb38a7a8d5167a4747080a662128

View File

@@ -8,8 +8,8 @@ Harness uses `cordis.yml` to describe which plugins an agent loads and the confi
The repository examples are runnable configurations and the most reliable starting points for a new project:
- [the shared `dsh` base](../../../apps/cli/config/base.cordis.yml) provides the common model, tools, persistence, policy, and telemetry rows; raw `dsh --config <path>` requires a patch list that selects deployment-specific agents and front doors.
- [the Web overlay](../../../apps/cli/config/web.cordis.yml) adds the browser host, Workspace management, browser interaction, and client plugins.
- [the `dsh-base` bundle patch](../../../packages/bundle/base/cordis.patch.yml) provides the common model, tools, persistence, policy, and telemetry rows every profile starts from.
- [the `dsh-web-app` bundle patch](../../../packages/bundle/web-app/cordis.patch.yml) adds the browser host, Workspace management, browser interaction, and client plugins.
- [headless-agent](../../../examples/headless-agent/cordis.yml) exposes the coding composition as a one-shot task.
- [acp-agent](../../../examples/acp-agent/cordis.yml) exposes fresh sessions to programmatic ACP clients.
@@ -49,9 +49,9 @@ A minimal configuration is a list of plugin entries:
Cordis starts sibling entries concurrently. A plugin declares required services through `inject`; Cordis waits for those services before applying the plugin, so file order does not establish dependency readiness. Missing models, tools, and plugins fail as early as possible instead of being silently ignored.
## CLI overlays
## CLI patch layers
Raw `dsh --config <path>` requires a patch list and applies it directly over `base.cordis.yml`. It does not add a surface overlay or `~/.dsh/config.yaml`, and the named file is not a complete replacement tree. `dsh web` composes `base.cordis.yml` and `web.cordis.yml`, then applies `~/.dsh/config.yaml`; `dsh web --config <path>` replaces that personal layer with the named overlay. Web profile and CLI-flag patches follow the user layer.
`dsh --profile <name>` composes the profile's bundle patch layers (its manifest's `dsh.profile.bundles` list, in order) over an empty root, then the profile's own `~/.dsh/profiles/<name>/cordis.patch.yml`, then each `--patch <path>` overlay, then CLI-flag patches. Later layers win per row.
A patch replaces a row's entire `config` value; it does not deep-merge keys. For example, patching `llm-deepseek` with only `config: { thinking: disabled }` also removes that row's configured `apiKey` and `baseURL`, so restate every key the row must retain.

View File

@@ -8,8 +8,8 @@ Harness 使用 `cordis.yml` 描述 agent智能体加载哪些插件以及
仓库中的示例就是可以运行的配置,也是新项目最可靠的起点:
- [共享的 `dsh` base](../../../apps/cli/config/base.cordis.yml) 提供通用的模型、工具、持久化、策略与遥测配置项;原始 `dsh --config <path>` 要求传入一份 patch 列表,用于选择部署特定的 agent 和前端入口
- [Web overlay](../../../apps/cli/config/web.cordis.yml) 添加浏览器宿主、Workspace 管理、浏览器交互与客户端插件。
- [`dsh-base` 组合包补丁](../../../packages/bundle/base/cordis.patch.yml) 提供通用的模型、工具、持久化、策略与遥测配置项,每个 profile 都以此为起点
- [`dsh-web-app` 组合包补丁](../../../packages/bundle/web-app/cordis.patch.yml) 添加浏览器宿主、Workspace 管理、浏览器交互与客户端插件。
- [headless-agent](../../../examples/headless-agent/cordis.yml) 以单次任务形式暴露 coding 组装。
- [acp-agent](../../../examples/acp-agent/cordis.yml) 向程序化 ACPAgent Client Protocol客户端提供全新会话。
@@ -49,9 +49,9 @@ Harness 使用 `cordis.yml` 描述 agent智能体加载哪些插件以及
Cordis 会并发启动同级配置项。插件通过 `inject` 声明必需服务Cordis 会等到这些服务就绪后再应用该插件,因此文件顺序不能保证依赖已就绪。引用不存在的模型、工具或插件会尽早报错,而不是被静默忽略。
## CLI 覆盖
## CLI 补丁
原始 `dsh --config <path>` 要求传入一份 patch 列表,并将其直接应用在 `base.cordis.yml` 之上。它不会添加 surface overlay 或 `~/.dsh/config.yaml`,指定文件也不是完整替换树。`dsh web` 先组合 `base.cordis.yml``web.cordis.yml`,再应用 `~/.dsh/config.yaml``dsh web --config <path>` 会以指定 overlay 替代该个人层。Web profile 与 CLI命令行界面标志 patch 位于用户层之后
`dsh --profile <name>` 按该 profile 的 manifest元数据清单`dsh.profile.bundles` 列表的顺序,在空根之上组合各组合包补丁层,随后依次应用该 profile 自己的 `~/.dsh/profiles/<name>/cordis.patch.yml`、每个 `--patch <path>` overlay,最后是 CLI命令行界面标志补丁。同一行以较后的层为准
补丁会替换目标行的整个 `config` 值,而不是深度合并各个键。例如,只用 `config: { thinking: disabled }` 修补 `llm-deepseek`,也会移除该行原有的 `apiKey``baseURL`;因此必须重新写出该行需要保留的全部键。

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write docs/user/guide/quickstart.md
quickstart.md: 199b3f092159fa6fbaf3ae298151487c924ac6f1
quickstart.zh.md: 9327ed646ba211bcce6426beb6bf76fca50acbf6
quickstart.md: 4b43291342f80ff9c6dcb844fdc505ef797d1f6c
quickstart.zh.md: 13294c50c2d7d4005c0fd090cc2eca3c4780d0a6

View File

@@ -53,7 +53,7 @@ Open `http://127.0.0.1:3080`. The agent can read and write files, run commands,
## What happened
headless-agent uses the `@deepseek-ai/dsh-cli-demo` app. `dsh web` instead composes [`apps/cli/config/base.cordis.yml`](../../../apps/cli/config/base.cordis.yml) with [`apps/cli/config/web.cordis.yml`](../../../apps/cli/config/web.cordis.yml) and no app bundle. Both select the DeepSeek model and capability plugins appropriate to their entry mode.
headless-agent uses the `@deepseek-ai/dsh-cli-demo` app. `dsh web` instead boots the `web` profile: the [`dsh-base`](../../../packages/bundle/base/cordis.patch.yml) and [`dsh-web-app`](../../../packages/bundle/web-app/cordis.patch.yml) bundle patch layers composed over an empty root. Both select the DeepSeek model and capability plugins appropriate to their entry mode.
## Next steps

View File

@@ -53,7 +53,7 @@ pnpm run dsh web
## 回头看
headless-agent 使用 `@deepseek-ai/dsh-cli-demo` app。`dsh web`组合 [`apps/cli/config/base.cordis.yml`](../../../apps/cli/config/base.cordis.yml) 与 [`apps/cli/config/web.cordis.yml`](../../../apps/cli/config/web.cordis.yml),不使用 app 组合包。二者都会根据各自入口模式选择 DeepSeek 模型和能力插件。
headless-agent 使用 `@deepseek-ai/dsh-cli-demo` app。`dsh web`启动 `web` profile由 [`dsh-base`](../../../packages/bundle/base/cordis.patch.yml) 与 [`dsh-web-app`](../../../packages/bundle/web-app/cordis.patch.yml) 两个组合包的 patch 层在空根之上组合而成。二者都会根据各自入口模式选择 DeepSeek 模型和能力插件。
## 下一步