# Install / 安装 Two modes, same feature. **A** is permanent, **B** is session-local. 两种模式,同一功能:**A** 永久生效,**B** 仅当前会话。 --- ## A · Profile bundle (permanent) / 永久安装 ```sh dsh plugin --profile add github:ruazero/dsh-task-chime ``` `` is your profile — `web` for the DSH Desktop / `dsh web` GUI. `` 是你的 profile,DSH Desktop 与 `dsh web` 图形界面用的是 `web`。 Then **restart the Harness**: quit and reopen DSH Desktop, or restart your `dsh web` process. A composed plugin row is read at boot, so nothing changes until the Host restarts. 然后**重启 Harness**:退出并重开 DSH Desktop,或重启 `dsh web` 进程。组合插件行只在启动时读取,Host 不重启就不会生效。 ### Why no composition editing is needed / 为什么不用改 composition `package.json` declares: ```json "dsh": { "bundle": { "patch": "./cordis.patch.yml" } } ``` so installing the package makes DSH apply the bundle's own `cordis.patch.yml` layer, which inserts the row: ```yaml - insert: - id: task-chime name: dsh-task-chime config: { ... } ``` Later layers still win by id, so your profile's own `cordis.patch.yml` can override any field without forking the package. ### Verify before restarting / 重启前校验 ```sh dsh --profile web --dump-config ``` `--dump-config` applies every bundle patch offline and prints the composed entry list. Find `id: task-chime` in the output and the row is wired; nothing was started to check it. `--dump-config` 会离线套用所有 bundle 补丁并打印最终条目列表。在输出里找到 `id: task-chime` 就说明接线成功,而且这个检查不启动任何东西。 ### Configure / 配置 Edit the `task-chime` section of `settings.yaml` (durable, watched live — no restart needed) or override the row in your profile's `cordis.patch.yml`. Field reference: [README.md](README.md#configuration). 改 `settings.yaml` 的 `task-chime` 段(持久化、实时监听,无需重启),或在 profile 的 `cordis.patch.yml` 里按 id 覆盖。字段说明见 [README.zh.md](README.zh.md#配置)。 ### Remove / 卸载 ```sh dsh plugin --profile web remove dsh-task-chime ``` --- ## B · Dynamic plugin (this session only) / 动态插件 Open a DSH session whose preset exposes the Cordis tools (`cordis_define`, `cordis_run`, `cordis_inspect_*` — the shipped `cordis` preset does), then paste: 打开一个带 Cordis 工具的 DSH 会话(自带的 `cordis` preset 即可),粘贴: ```text Read src/host.js and src/client.js from . Call cordis_define with: plugin: { kind: "new", idPrefix: "chime" } name: "任务完成提示音提醒" code.host = the complete contents of src/host.js code.client = the complete contents of src/client.js Then activate it with cordis_run in "run" mode. ``` When the approval card appears, click allow: - **single check** — authorizes exactly this version - **double check** — also authorizes future versions of the same plugin 出现授权卡片时点允许:**单勾**仅授权当前版本,**双勾**同时授权该插件的后续版本。 Both `src/*.js` files are the plain-JavaScript **function body** the dynamic evaluator expects — each ends with `return { apply(ctx) { … } }`. Do not wrap them in a module and do not add `import`/`require`. Contract of the two halves: | | | |---|---| | Host services | `shell`, `agents`, `sandboxPolicy` (all optional-checked) | | Host events | `agent/status` | | Client services | `slots` | | Client slots | `settings.section` (id `task-chime`), `tool.view.cordis` (key `self`) | | Private RPC | `state`, `patch`, `test` | | Tools | `task_chime` | ### Verify / 验证 Ask the agent to call `task_chime` (say "ring me" / "响一下"). A healthy run returns: ```json { "ok": true, "level": 2, "sound": "通知 · notify.wav", "error": "" } ``` Then let the turn end — the real completion path fires on `agent/status: idle`. ### Uninstall / 卸载 - `cordis_stop` — turn the effects off, keep every version and grant - `cordis_undefine` — remove the plugin and all of its packages permanently --- ## Troubleshooting / 排错 | Symptom / 现象 | Check / 检查 | |---|---| | Mode A: nothing rings after restart | Run `dsh --profile web --dump-config` and confirm `id: task-chime` is present; check the Host log for `task-chime:` warnings | | Mode A: row missing from the dump | The package is not installed in that profile, or you dumped a different `--profile` | | No sound at all, `ok: true` | System volume / output device; try level 3, which prefixes `[console]::Beep` | | `the composition provides no shell service` | That composition mounts no `ctx.shell` implementation (`dsh-pwsh-local` / `dsh-pwsh-sandbox` on Windows) | | `sound is "custom" but customPath is empty or invalid` | `customPath` must be an absolute path with no newlines or tabs | | `unknown sound id "…"` | Check the id against the catalog in README; ids are shared across platforms but each platform maps its own files | | `the player exited with code 1` | The audio file does not exist or is not readable | | Rings for subagents too | Set `scope: roots` (the default) | | Rings when a session is merely opened | Should be impossible — a ring requires an observed `running` first. Please open an issue with the Host log | | Mode B: everything gone after restart | Expected. Install mode A for permanence | | Mode B: client panel missing | The Client half was never approved, or the page needs a refresh; re-run `cordis_run` | For mode B, read exact diagnostics with `cordis_inspect_self(pluginId, packageId)`: a healthy Host half reports `handlers: ["state","patch","test"]` and both halves report `status: "running"`. 方式 B 可用 `cordis_inspect_self(pluginId, packageId)` 读取确切诊断:健康时 Host 半会报 `handlers: ["state","patch","test"]`,两个半边的 `status` 均为 `running`。