@xmanrui/dsh-im 4.8.0 → 4.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +8 -79
- package/README.md +8 -79
- package/lib/client.js +4 -3
- package/lib/index.js +224 -220
- package/package.json +1 -1
- package/plugin-src/client/styles.js +3 -2
- package/src/channels/dingtalk/dingtalk-bridge.mjs +1 -0
- package/src/channels/feishu/bridge.mjs +174 -20
- package/src/channels/feishu/feishu-cards.mjs +69 -0
- package/src/channels/feishu/feishu-runtime.mjs +5 -0
- package/src/channels/feishu/slash-command-registry.mjs +3 -0
- package/src/channels/qq/qq-bridge.mjs +1 -0
- package/src/channels/shared/harness-approval.mjs +24 -1
- package/src/channels/shared/harness-client.mjs +45 -16
- package/src/channels/shared/i18n-en/feishu.mjs +11 -0
- package/src/channels/shared/i18n-en/shared-a.mjs +1 -0
- package/src/channels/shared/semantic/reply-reference.mjs +5 -11
- package/src/channels/shared/text-harness-bridge.mjs +1 -0
- package/src/channels/shared/workspace-command.mjs +2 -2
- package/src/channels/telegram/telegram-runtime.mjs +6 -9
- package/src/channels/wecom/wecom-bridge.mjs +1 -0
- package/src/channels/weixin/weixin-bridge.mjs +1 -0
package/README.en.md
CHANGED
|
@@ -42,7 +42,7 @@ Connect IM bots to DeepSeek Harness by scanning a QR code, using an App Manifest
|
|
|
42
42
|
|
|
43
43
|

|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
<img src="docs/images/Context_enhancement_en.png" alt="Context enhancement page" width="49%"> <img src="docs/images/access_mode_en.png" alt="Access modes page" width="49%">
|
|
46
46
|
|
|
47
47
|
## Built-in channels
|
|
48
48
|
|
|
@@ -82,13 +82,7 @@ After the model calls the file-return tool, the plugin hands the specified file
|
|
|
82
82
|
|
|
83
83
|
## AI Office Connector
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
The current protocol is `office-harness.v1`. The connector authenticates and advertises capabilities with `POST /api/harness/connector/heartbeat`, then opens the downstream event plane with `GET /api/harness/connector/stream` over SSE. The settings page derives every fixed hook from the Office Base URL and reconnects with backoff after a disconnect.
|
|
88
|
-
|
|
89
|
-
A `job.available` event makes the local connector fetch the payload, validate Workspace/Preset aliases, claim a 90-second lease, and renew it every 30 seconds. It creates an isolated Harness Session, reports safe status/tool/text progress, and writes a terminal result exactly once. Tool approvals and follow-up questions surface in Office; approve, reject, and text answers return over SSE to the original Session. Heartbeats and leases recover from dropped connections.
|
|
90
|
-
|
|
91
|
-
A successful heartbeat response must be JSON: `{"ok":true,"protocolVersion":"office-harness.v1"}`. This makes a successful connection test proof of a compatible Office Connector instead of any URL that happens to return 200.
|
|
85
|
+
[Read the AI Office Connector guide](docs/AI-Office-Connector.en.md)
|
|
92
86
|
|
|
93
87
|
## Installation
|
|
94
88
|
|
|
@@ -140,41 +134,15 @@ See the [Proactive Delivery Guide](PROACTIVE_DELIVERY.en.md) ([简体中文](PRO
|
|
|
140
134
|
|
|
141
135
|
### Context enhancement
|
|
142
136
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
When enabled, ordinary user messages receive the current scope's `<dsh_im_source>` prefix. Nonempty guidance for that scope is automatically wrapped in `<dsh_im_source_guidance>` tags. Both guidance fields start empty and have their own instructions, example, **Use example**, and **Clear** actions. No fields selected in the current scope means no source block. Commands, approvals and question answers keep their existing control paths.
|
|
146
|
-
|
|
147
|
-
Existing shared fields and guidance are automatically copied into both group and direct configurations during upgrade, while their original enable switches remain independent. The first read does not rewrite the settings file; the new structure is persisted through the existing mechanism on the next successful bot-settings write, with no manual migration required.
|
|
148
|
-
|
|
149
|
-
When the current conversation scope is off, text, images, files and Session behavior are unchanged, without enhancement assembly or extra network queries. Unsaved or cancelled drafts have no effect. Saving does not reconnect bots or recreate Sessions; messages already received retain their original configuration snapshot.
|
|
150
|
-
|
|
151
|
-
These blocks are **user-message content**, not changes to Harness, system prompts or permissions. Identifiers may contain platform user IDs or phone-number-like values and are sent to the current model and stored in Session history. Turning the feature off stops future additions; it does not erase existing history.
|
|
137
|
+
[Read the context enhancement guide](docs/context-enhancement.md)
|
|
152
138
|
|
|
153
139
|
### Access modes
|
|
154
140
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
Each WhatsApp bot also has its own access mode. Existing bots migrate to **Only me**, which is also the default for newly linked bots and accepts only self-chat messages from the linked account. **Selected contacts** additionally accepts direct messages from allowlisted phone numbers and ignores groups. Enter one number with its country or region code per line; a leading `+` is optional. **Open responses** accepts all direct messages, group messages sent by the linked account, and mentions of or replies to that account from other group members; this also lets an owner-only group act as a separate conversation. Switching modes retains the allowlist. An empty Selected contacts allowlist behaves like Only me, and rejected messages are ignored silently.
|
|
141
|
+
[Read the access modes guide](docs/access-modes.md)
|
|
158
142
|
|
|
159
143
|
## Checking and installing updates
|
|
160
144
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
After installation, the backend still requires a manual restart, and the panel reports **Installed; restart manually** based on the Host's status. The updater does not request a restart, hot reload, or page refresh. The host's existing module watcher may refresh the plugin interface, but an interface change does not mean the new backend version is running; the Host-reported running version is authoritative. Update when bots are idle, then restart the current Harness / Desktop yourself. Closing the settings page does not cancel a submitted installation.
|
|
164
|
-
|
|
165
|
-
If the existing page still shows a restart notice after you restart manually, click **Refresh status** in the dialog or reopen **Restart needed**. This reads the current Host status without checking npm or refreshing the page.
|
|
166
|
-
|
|
167
|
-
The button reuses Desktop's package-management service or the current Harness CLI for an exact-version install equivalent to the following (replace the example profile and version with the confirmed values):
|
|
168
|
-
|
|
169
|
-
```sh
|
|
170
|
-
dsh plugin --profile web add -w --save-exact @xmanrui/dsh-im@3.1.0 --registry=https://registry.npmjs.org/
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
The **Manual update** section at the bottom of the dialog generates a short command for the current profile, such as `dsh plugin --profile web add -w @xmanrui/dsh-im@3.1.1`. Click the copy icon at the far right of the command, then run it in a terminal. It requests a known target version; otherwise, `@latest` resolves the version from npm when executed. The manual command uses your local npm registry configuration without fetching GitHub; the install button still forces the official registry and saves an exact version. If clipboard access fails, select and copy the command manually. For Desktop, use the current Desktop's built-in terminal. For Web, use the environment that started the current Harness and preserve the same `DSH_HOME`. If a restart is already pending, restarting is usually enough without another installation. No potentially destructive command is generated for source links or profiles that cannot be safely identified.
|
|
174
|
-
|
|
175
|
-
Source `link:`, `file:`, Git, and unrecognized installations can check versions but are never replaced automatically. Confirm the intended profile before manually migrating to npm. Conflicting scoped registries, incompatible Node versions, and unavailable Host executors disable installation with an explanation. Standard Windows CLI installations currently require a manual update; Desktop uses its existing executor.
|
|
176
|
-
|
|
177
|
-
Do not modify the same profile through a terminal or plugin market during installation. A failed command may leave partial dependency changes; it is not an automatic rollback. Inspect the installation, reinstall the previous exact version if needed, and restart manually. The updater keeps only the profile's latest job and manifest backup under the current `DSH_HOME/updates/dsh-im`, without copying bot credentials. Resolve uncertain remaining installers or locks before retrying; do not blindly delete a lock.
|
|
145
|
+
[Read the update-checking and installation guide](docs/checking-and-installing-updates.md)
|
|
178
146
|
|
|
179
147
|
## Bot commands
|
|
180
148
|
|
|
@@ -202,8 +170,8 @@ Do not modify the same profile through a terminal or plugin market during instal
|
|
|
202
170
|
| `/cancel` | Cancel batch input and discard its collected messages. |
|
|
203
171
|
| `/repair` | In a Feishu direct chat, incrementally repair the card callback and permissions required for media and the native Slash Command panel. |
|
|
204
172
|
| `/compact` | Immediately compact older context in the Session bound to the current chat. |
|
|
205
|
-
| `/workspace <workspace index or absolute path>` | Switch the current bot's Harness workspace by `/workspacelist` index or absolute path. |
|
|
206
|
-
| `/workspacelist` | List workspace absolute paths that still exist on the current Harness Host. |
|
|
173
|
+
| `/workspace <workspace index or absolute path>`, `/ws <workspace index or absolute path>` | Switch the current bot's Harness workspace by `/workspacelist` index or absolute path. |
|
|
174
|
+
| `/workspacelist`, `/workspaces`, `/wsl` | List workspace absolute paths that still exist on the current Harness Host. |
|
|
207
175
|
| `/sessionlist [workspace number or absolute path]`, `/sessions [...]` | Equivalent aliases that list every registered session ID and title in the selected workspace; omit the argument to use the current workspace. |
|
|
208
176
|
| `/sessionlist --limit N`, `/sessions --limit N` | List the first N sessions in the current workspace's existing order; N must be a positive integer. |
|
|
209
177
|
| `/session <Session ID>` | Bind the current chat to an existing Harness session. |
|
|
@@ -211,48 +179,9 @@ Do not modify the same profile through a terminal or plugin market during instal
|
|
|
211
179
|
| Interactive question | Reply with an option number, option label, or custom text; separate multiple choices with commas. |
|
|
212
180
|
| Remote approval | Reply with `批准` / `拒绝` / `同意` / `不同意` / `yes` / `no`. |
|
|
213
181
|
|
|
214
|
-
Example: send `/models`, then `/model 2` to switch to the second model in the list; send `/reasoninglist`, then `/reasoning 2` to switch to the current model's second reasoning effort; send `/presetlist`, then `/preset 2` to select the second Agent Preset for this bot. Other examples: `/help`, `/new`, `/status`, `/version`, `/model deepseek-official/deepseek-v4-pro max`, `/reasoning --default`, `/preset marketing-jeep`, `/preset --default`, `/steer inspect only the configuration file`, `/stop`, `/compact`, `/workspace /Users/alice/projects/my-app`, `/sessionlist 2`, `/sessionlist /Users/alice/projects/my-app`, `/session session-id`, `/history`, or `/history 5`
|
|
215
|
-
|
|
216
|
-
If the Slack desktop app has no native Slash Command registered with the same name, it intercepts messages that begin directly with `/`. Send the command with one leading space instead, for example ` /presetlist`, ` /preset 2`, ` /history`, or ` /history 10`; the plugin command layer trims surrounding whitespace, so it executes exactly like the unspaced form.
|
|
217
|
-
|
|
218
|
-
**Feishu `/` command panel**: On startup the Feishu bot registers its common commands (`menu`, `new`, `help`, `status`, `compact`, `sessionlist`, `workspacelist`, `watch`, `unwatch`, `watchlist`, `archived`) as native Slash Commands through the `app_slash_commands` OpenAPI, so typing `/` in a Feishu direct-message input box pops the command panel and tapping a command triggers it. The command list is owned and pushed by dsh-im; it does not depend on the dsh/Harness backend. Apps created through the built-in QR flow request `application:app_slash_command:read` and `application:app_slash_command:write` by default; existing apps can add them incrementally through **Complete permissions** or `/repair`, followed by any publishing steps Feishu requires. The Feishu client also caches the list for a few minutes. This is best-effort and never blocks message delivery.
|
|
219
|
-
|
|
220
182
|
### Command details
|
|
221
183
|
|
|
222
|
-
|
|
223
|
-
- `/status` takes no arguments, never prompts the model, and does not change the Session binding. It confirms that the current bot can reach DeepSeek Harness.
|
|
224
|
-
- `/version` takes no arguments and never contacts Harness, creates a Session, or prompts the model. It returns the version of the running dsh-im plugin.
|
|
225
|
-
- `/new` only removes the current chat's saved dsh-im Session binding; it never deletes, empties, or archives the old Session. The next ordinary message creates and binds a new Session in the current workspace. If a task is running or waiting for a question or approval, finish the interaction or use `/stop` before `/new`.
|
|
226
|
-
- `/models` takes no arguments and never creates a Session. It assigns a number to every currently configured Harness model and also shows its stable, copyable `provider/model-id`. If one provider fails, models from the remaining providers are still shown.
|
|
227
|
-
- Bare `/model` shows the current Session model and reasoning effort. With arguments, it accepts a number from `/models` or an exact full model ID, followed optionally by an exact reasoning effort ID published in that target model's metadata, for example `/model 2 max`. When the effort is omitted, Harness resolves the target model's current default. If the chat has no Session yet, a valid switch creates and binds a blank Session without prompting the model.
|
|
228
|
-
- `/reasoninglist` and `/reasonings` are equivalent. They list the efforts from the current model's metadata and mark the current and default values. `/reasoning` shows the current value; `/reasoning <number or effort ID>` accepts a listed number or an exact metadata ID; `/reasoning --default` lets Harness resolve the current model's default again. Every `/reasoning...` command requires an existing Session and never creates one or prompts the model.
|
|
229
|
-
- The model or reasoning effort cannot be changed while a task is running or waiting for an approval or question answer. Wait for it to finish or use `/stop` first. A change takes effect on the next model request and keeps Harness's default-saving semantics: Harness attempts to save the accepted model and effort as the default selection for future Sessions, while other existing Sessions remain unchanged. A Session containing images cannot switch to a model that does not accept image input.
|
|
230
|
-
- `/presetlist` and `/presets` are equivalent. They take no arguments and never create a Session. Each reads the Host's currently available Agent Presets, showing their names, stable IDs, the Host default, and this bot's selection. A selected Preset that has been deleted or become broken is retained and marked unavailable instead of being cleared automatically. Only safe names and IDs are shown; paths, errors, and other Host internals are never exposed.
|
|
231
|
-
- Bare `/preset` shows this bot's setting for future new Sessions; it does not inspect or change the current Session. With an argument, it accepts a number from the most recent `/presetlist` in this chat or an exact ID; use `/preset id:<ID>` for a numeric ID. A numbered selection resolves the ID from that displayed list and then validates it against the latest Host catalog, asking for a fresh list if it has changed.
|
|
232
|
-
- `/preset --default` clears this bot's explicit override so future Sessions resolve the Host default when they are created. Explicitly selecting an ID that currently matches the Host default pins that ID instead. Following the Host default remains available even while the catalog cannot be read.
|
|
233
|
-
- An Agent Preset change is bot-wide: it affects future new Sessions in every chat for this bot, but never modifies, stops, unbinds, or rebuilds an existing Session and never runs `/new` automatically. If this chat already has a Session, ordinary messages keep using it; the first ordinary message after `/new` creates a Session with the new setting. Presets can still be queried or changed while a task is running or awaiting interaction because the command does not touch that Session.
|
|
234
|
-
- `/stop` and `/steer` control only a running task started by this chat. Even when multiple chats bind the same Session, they do not intentionally control another chat's task. `/stop` does not delete the Session or its history, preserves queued work that has not started, and is safe to repeat.
|
|
235
|
-
- `/steer` accepts text only, including multiple lines. It neither creates another Session nor starts a second task. Send an ordinary message when no task is running; while an approval or question is pending, answer it first or use `/stop`.
|
|
236
|
-
- `/batch`, `/send`, and `/cancel` are available only in a direct chat with the bot. After `/batch`, subsequent text-only messages are held temporarily, up to 10 messages. The tenth is collected and prompts you to submit; later messages are rejected and the batch is never submitted automatically. `/send` processes the collected messages in their original order as one input, while `/cancel` discards them. Images, files, and other commands are not collected. An unsubmitted batch is lost if the bot restarts. Ordinary chat behavior is unchanged when batch input is not active.
|
|
237
|
-
- Feishu `/repair` is available only in a direct chat and follows the current bot's channel access policy just like every other command; the plugin defines no separate administrator role. It incrementally adds the currently missing `card.action.trigger`, `im:message:readonly`, `im:resource`, `application:app_slash_command:read`, and `application:app_slash_command:write`, while the confirmation page shows only items the app is currently missing. The authorization page must be opened by an account that can access the target app in Feishu Open Platform. Bare `/repair` starts repair; if an older attempt is still awaiting authorization, it invalidates that one-time link before generating a new one. Use `/repair qr` for the current link's QR code, `/repair status` to inspect the attempt, `/repair verify` to refresh verification, and `/repair cancel` to cancel it; none of these four supplemental commands starts another authorization. Once Feishu has accepted the update and the bot is waiting for the test-button callback, a second repair is not started concurrently.
|
|
238
|
-
- `/compact` acts only on the Harness Session already bound to the current chat and is never sent to the model. The bot reports the applicable status when the chat has no Session yet, the Session is generating a reply, or there is no compactable history.
|
|
239
|
-
- The path must be an existing absolute directory. The bot returns an actionable error and the correct usage when validation fails.
|
|
240
|
-
- `/workspacelist` takes no arguments. It combines the Harness global registry with the current bot's path. When that current path still exists and is safe to display, it appears first and is marked as current. `/workspace N` switches using the freshly resolved list order at execution time; absolute paths remain supported.
|
|
241
|
-
- `/sessionlist` and `/sessions` are equivalent. A numeric argument uses the same freshly resolved order as `/workspacelist` at command execution time. An absolute path can also select a workspace directly, and the result echoes the resolved path.
|
|
242
|
-
- `/sessionlist --limit N` and `/sessions --limit N` limit only that command's response. They do not change any global or bot setting, and omitting `--limit` still lists every session.
|
|
243
|
-
- Both session-list aliases include every session registered to the selected workspace. Archived sessions are marked as archived; blank and subagent sessions are included when they belong to that workspace; sessions without a title are shown as `No title yet`. Any listed ID can be passed directly to `/session Session ID`.
|
|
244
|
-
- `/session` accepts exactly one Session ID obtained from `/sessionlist`. It neither creates a session nor immediately prompts the model; later messages in the current chat continue the bound session. Regular archived sessions can be bound without being unarchived, while subagent sessions cannot be bound.
|
|
245
|
-
- `/history` works identically in direct chats on all nine channels. It only reads the Session already bound to this chat: it never creates a Session, prompts the model, or interrupts running tasks or pending interactions. It returns the latest 3 messages by default. `/history N` accepts a positive integer, caps values above 5 at 5, and returns fewer when fewer are available. Zero, negative, fractional, nonnumeric, and multiple arguments show usage; commands with images or files are rejected. While collecting batch input, use `/send` or `/cancel` first.
|
|
246
|
-
- A user message or a final assistant reply counts as one history item, not one turn or day. The latest N items are displayed oldest first. Tool events, reasoning, injected content, and unfinished assistant output are omitted; old attachments are not downloaded or resent. Long text is marked as truncated, with at most 3 text segments per reply and no automatic pagination. After binding a Session, send `/history` manually; binding never replays history automatically. Message text may still contain sensitive information from the original conversation, so expose the bot only to trusted users.
|
|
247
|
-
- `/session` locates the session's unique workspace automatically. Binding inside the current workspace replaces only this chat's mapping. A cross-workspace binding switches the bot workspace, clears the old session mappings for all of that bot's chats, and then binds this chat, so it affects the bot's other chats. A reply already being generated may still finish.
|
|
248
|
-
- Workspace switches and session bindings only clear or replace dsh-im chat mappings. They never delete, empty, or archive old Session contents; an old Session can still be listed and bound again.
|
|
249
|
-
- Any user admitted by the current channel access policy can run these commands; there is no separate administrator role. Telegram Compatible mode follows the original DM and group mention/reply rules, while Safe mode admits only allowlisted private users. WhatsApp Only me accepts self-chat only, Selected contacts accepts self-chat plus allowlisted direct messages, and Open responses accepts every direct message, group messages from the linked account, and mentions or replies from other group members.
|
|
250
|
-
- Agent Preset names and IDs come from the same Harness Host, and any command-authorized user can change the Preset used by all future new Sessions across this bot's chats. Expose `/presetlist` and `/preset` only to trusted users.
|
|
251
|
-
- The list comes from the Harness Host's global registry and can include local absolute paths for other bots, other channels, or non-IM projects. Restrict the bot's visibility to trusted users.
|
|
252
|
-
- Session results also come from the global Harness Host. Session IDs and titles can belong to other bots, other channels, or non-IM projects, and may contain sensitive metadata. Enable these commands only when every user in the bot's visibility scope is trusted.
|
|
253
|
-
- Any user who can run `/session` can continue the selected session and use later messages to write to it or invoke its available tools. Expose the bot and session list only to trusted users.
|
|
254
|
-
- A successful switch clears only the current bot's old Harness session mappings and does not affect other bots.
|
|
255
|
-
- The new workspace applies to subsequent messages; a reply that has already started generating is allowed to finish.
|
|
184
|
+
[Read the command details](docs/bot-commands.md)
|
|
256
185
|
|
|
257
186
|
## Other features
|
|
258
187
|
|
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ Connect IM bots to DeepSeek Harness by scanning a QR code, using an App Manifest
|
|
|
45
45
|
|
|
46
46
|

|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
<img src="docs/images/Context_enhancement.png" alt="上下文增强页面" width="49%"> <img src="docs/images/access_mode.png" alt="访问模式页面" width="49%">
|
|
49
49
|
|
|
50
50
|
## 当前内置渠道
|
|
51
51
|
|
|
@@ -85,13 +85,7 @@ Connect IM bots to DeepSeek Harness by scanning a QR code, using an App Manifest
|
|
|
85
85
|
|
|
86
86
|
## AI Office Connector
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
当前协议版本为 `office-harness.v1`。连接器使用 `POST /api/harness/connector/heartbeat` 完成鉴权和能力握手,再以 `GET /api/harness/connector/stream` 建立 SSE 下行;设置页会从 Office Base URL 自动展示全部固定 Hook,并在断线后按退避策略自动重连。
|
|
91
|
-
|
|
92
|
-
Office 的 `job.available` 会触发本机拉取任务、校验 Workspace/Preset alias、领取 90 秒租约并每 30 秒续租。连接器创建独立 Harness Session,把状态、工具名和增量文字安全回传 Office,终态只允许写入一次。Harness 发起的工具审批或补充问题会进入 Office 人工面板;批准、拒绝或文字答案再经 SSE 回到原 Session,断线时由租约与 Heartbeat 恢复。
|
|
93
|
-
|
|
94
|
-
Heartbeat 成功响应必须是 JSON:`{"ok":true,"protocolVersion":"office-harness.v1"}`。这使「连接测试通过」代表命中了兼容的 Office Connector,而不只是某个碰巧返回 200 的网址。
|
|
88
|
+
[查看 AI Office Connector 说明](docs/AI-Office-Connector.md)
|
|
95
89
|
|
|
96
90
|
## 安装
|
|
97
91
|
|
|
@@ -143,41 +137,15 @@ dsh web
|
|
|
143
137
|
|
|
144
138
|
### 上下文增强
|
|
145
139
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
开启后,插件在普通用户消息前附加当前场景的 `<dsh_im_source>` 来源块;当前场景非空的增强提示词自动包裹为 `<dsh_im_source_guidance>`。两个场景的提示词默认留空,并分别提供说明、示例、「填入示例」和「清空」;当前场景字段全部取消时不生成来源块。命令、审批和问题回答继续走原有控制链路。
|
|
149
|
-
|
|
150
|
-
升级前已经保存的共用字段与增强提示词会自动复制到群聊、私聊两份配置,原有两个开关也分别保留。升级后的首次读取不会改写配置文件;之后任意一次机器人设置成功保存时,会随现有设置写入机制自动落盘为新结构,无需手工迁移。
|
|
151
|
-
|
|
152
|
-
当前会话类型未开启时,原有文字、图片、文件和会话处理保持不变,不组装增强内容,也不新增网络查询。草稿、清空后取消等操作不改变运行配置;保存不重连机器人、不重建会话,已经接收的消息仍使用接收时的配置。
|
|
153
|
-
|
|
154
|
-
来源与提示词都属于**用户消息内容**,不修改 Harness、系统提示词或权限。来源标识可能包含平台用户 ID 或电话号码形式的信息,并随消息交给当前模型、留在会话历史中;关闭只停止后续附加,不删除已经写入的历史。
|
|
140
|
+
[查看上下文增强说明](docs/上下文增强.md)
|
|
155
141
|
|
|
156
142
|
### 访问模式
|
|
157
143
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
每个 WhatsApp 机器人也有独立的访问模式。旧机器人升级后和新接入机器人都默认使用**仅自己模式**,只响应已绑定账号的自聊消息。**指定联系人模式**额外接受白名单电话号码的私聊并忽略群聊;号码需包含国家或地区代码,每行一个,可带开头的 `+`。**开放响应模式**响应所有私聊、已绑定账号自己发出的群聊消息,以及其他群成员对该账号的提及或回复;因此也可以把“仅自己”的群当作独立会话使用。切换模式会保留白名单;指定联系人模式的空白名单等同于仅自己模式。未授权消息会被静默忽略。
|
|
144
|
+
[查看访问模式说明](docs/访问模式.md)
|
|
161
145
|
|
|
162
146
|
## 检查与安装更新
|
|
163
147
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
安装完成后,后台仍需手动重启,页面根据 Host 状态显示「已安装,待手动重启」。更新功能不会主动重启、执行热更新或刷新页面。宿主自带的模块监视机制可能自行刷新插件界面,但界面变化不代表后台版本已生效,运行版本以 Host 报告为准。请在机器人任务空闲时更新,并自行重启当前 Harness / Desktop。关闭设置页不会取消已提交的安装任务。
|
|
167
|
-
|
|
168
|
-
手动重启后,如果原页面仍显示待重启,点击窗口中的「刷新状态」,或重新打开「待手动重启」窗口。该操作只重新读取当前 Host 状态,不查询 npm,也不刷新页面。
|
|
169
|
-
|
|
170
|
-
按钮复用 Desktop 内置包管理服务或标准 Harness 的 CLI,执行相当于以下命令的精确版本安装(将示例 profile、版本替换为确认值):
|
|
171
|
-
|
|
172
|
-
```sh
|
|
173
|
-
dsh plugin --profile web add -w --save-exact @xmanrui/dsh-im@3.1.0 --registry=https://registry.npmjs.org/
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
更新窗口下方的「手工更新」会按当前 profile 生成精简命令,例如 `dsh plugin --profile web add -w @xmanrui/dsh-im@3.1.1`,点击命令最右侧的复制图标后可在终端执行。已知目标版本时指定该版本;尚未查到版本时使用 `@latest`,以执行时 npm 返回的版本为准。手工命令沿用本机 npm 源配置,不拉取 GitHub;按钮安装仍固定使用官方源并保存精确版本。浏览器无法复制时可选中文本手动复制。Desktop 请使用当前 Desktop 的内置终端;Web 请使用启动当前 Harness 的环境并保持相同 `DSH_HOME`。如果已经提示「待手动重启」,通常只需重启,无需再次安装。源码链接或无法安全确认的 profile 不生成可能覆盖安装的命令。
|
|
177
|
-
|
|
178
|
-
源码 `link:`、`file:`、Git 来源或无法确认归属的安装只提供版本检查,不会替换开发链接;如需迁移为 npm 安装,请自行确认对应 profile。作用域 registry 冲突、Node 版本不满足要求或缺少当前 Host 的执行器时,按钮会说明原因。标准 Windows CLI 暂需手动更新;Desktop 使用其原有执行器。
|
|
179
|
-
|
|
180
|
-
安装期间不要同时在终端或插件市场修改该 profile。失败可能已经改变部分依赖,不能视为自动回滚;先检查安装状态,必要时按上述命令重装原精确版本,再手动重启。更新器只在当前 `DSH_HOME/updates/dsh-im` 下保存该 profile 最近一次任务与清单备份,不复制机器人凭据;残留安装进程或锁状态不明确时,请先人工确认,不要盲目重试或删除锁。
|
|
148
|
+
[查看检查与安装更新说明](docs/检查与安装更新.md)
|
|
181
149
|
|
|
182
150
|
## 机器人命令
|
|
183
151
|
|
|
@@ -205,8 +173,8 @@ dsh plugin --profile web add -w --save-exact @xmanrui/dsh-im@3.1.0 --registry=ht
|
|
|
205
173
|
| `/cancel` | 取消批量输入并丢弃已收集的消息。 |
|
|
206
174
|
| `/repair` | 在飞书私聊中增量修复卡片回调,并补全媒体与原生 Slash Command 面板所需的权限。 |
|
|
207
175
|
| `/compact` | 立即压缩当前聊天绑定会话的较早上下文。 |
|
|
208
|
-
| `/workspace <工作区序号或绝对路径>` | 按 `/workspacelist` 序号或绝对路径切换当前机器人的 Harness 工作区。 |
|
|
209
|
-
| `/workspacelist` | 列出当前 Harness Host 上仍然存在的工作区绝对路径。 |
|
|
176
|
+
| `/workspace <工作区序号或绝对路径>`、`/ws <工作区序号或绝对路径>` | 按 `/workspacelist` 序号或绝对路径切换当前机器人的 Harness 工作区。 |
|
|
177
|
+
| `/workspacelist`、`/workspaces`、`/wsl` | 列出当前 Harness Host 上仍然存在的工作区绝对路径。 |
|
|
210
178
|
| `/sessionlist [工作区序号或绝对路径]`、`/sessions [...]` | 两个等价命令;列出指定工作区登记的所有会话 ID 和标题,省略参数时使用当前工作区。 |
|
|
211
179
|
| `/sessionlist --limit N`、`/sessions --limit N` | 列出当前工作区现有顺序中的前 N 个会话;N 必须是正整数。 |
|
|
212
180
|
| `/session <Session ID>` | 将当前聊天绑定到指定的已有 Harness 会话。 |
|
|
@@ -214,48 +182,9 @@ dsh plugin --profile web add -w --save-exact @xmanrui/dsh-im@3.1.0 --registry=ht
|
|
|
214
182
|
| 交互式提问 | 回复选项序号、选项文字或自定义文字;多选时用逗号分隔。 |
|
|
215
183
|
| 远程审批 | 回复 `批准` / `拒绝` / `同意` / `不同意` / `yes` / `no`。 |
|
|
216
184
|
|
|
217
|
-
示例:先发送 `/models`,再发送 `/model 2` 切换到列表中的第 2 个模型;先发送 `/reasoninglist`,再发送 `/reasoning 2` 切换到当前模型的第 2 个推理等级;先发送 `/presetlist`,再发送 `/preset 2` 为当前机器人选择第 2 个 Agent Preset。其他命令示例:`/help`、`/new`、`/status`、`/version`、`/model deepseek-official/deepseek-v4-pro max`、`/reasoning --default`、`/preset marketing-jeep`、`/preset --default`、`/steer 只检查配置文件`、`/stop`、`/compact`、`/workspace /Users/alice/projects/my-app`、`/sessionlist 2`、`/sessionlist /Users/alice/projects/my-app`、`/session session-id`、`/history` 或 `/history 5`
|
|
218
|
-
|
|
219
|
-
Slack 桌面端若未注册同名的原生 Slash Command,会拦截直接以 `/` 开头的消息。此时请加一个前导空格发送,例如 ` /presetlist`、` /preset 2`、` /history` 或 ` /history 10`;插件命令层会去除首尾空白,执行效果与无空格命令相同。
|
|
220
|
-
|
|
221
|
-
**飞书输入框的 `/` 命令面板**:机器人启动时,dsh-im 会调用飞书 `app_slash_commands` OpenAPI,把常用命令(`menu`、`new`、`help`、`status`、`compact`、`sessionlist`、`workspacelist`、`watch`、`unwatch`、`watchlist`、`archived`)注册成原生 Slash Command,这样在飞书单聊输入框输入 `/` 会弹出命令面板,点选即触发。命令列表由 dsh-im 自己持有并推送注册,不依赖 dsh/Harness 后端。扫码新建的应用会默认申请 `application:app_slash_command:read` 和 `application:app_slash_command:write`;已有应用可通过“补全权限”或私聊 `/repair` 增量补全并按飞书提示发布。注册后飞书客户端约有几分钟缓存延迟。该能力是尽力而为的,注册失败不会影响机器人消息收发。
|
|
222
|
-
|
|
223
185
|
### 命令说明
|
|
224
186
|
|
|
225
|
-
|
|
226
|
-
- `/status` 不需要参数,也不会向模型发送消息或改变会话绑定;它用于确认当前机器人能够连接 DeepSeek Harness。
|
|
227
|
-
- `/version` 不需要参数,也不会访问 Harness、创建会话或调用模型;它返回当前运行的 dsh-im 插件版本。
|
|
228
|
-
- `/new` 只解除当前聊天在 dsh-im 中保存的会话绑定,不会删除、清空或归档旧 Session。下一条普通消息会在当前工作区创建并绑定一个新 Session。任务正在运行或等待问题、审批时,应先完成交互或使用 `/stop`,再使用 `/new`。
|
|
229
|
-
- `/models` 不需要参数,也不会创建会话。它为 Harness 当前配置的全部可用模型分配序号,同时显示可稳定复制的 `Provider/模型ID`;某个 Provider 查询失败时,其他 Provider 的结果仍会显示。
|
|
230
|
-
- `/model` 不带参数时查看当前会话的模型和推理等级;带参数时接受 `/models` 列出的序号或精确完整模型 ID,并可追加目标模型元数据公布的精确推理等级 ID,例如 `/model 2 max`。省略推理等级时,由 Harness 解析目标模型的当前默认值。聊天尚无会话时,有效的切换命令会创建并绑定一个空白会话,但不会触发模型回复。
|
|
231
|
-
- `/reasoninglist` 和 `/reasonings` 完全等价,按当前模型的元数据列出可选推理等级并标记当前值和默认值。`/reasoning` 查看当前值;`/reasoning <序号或等级ID>` 接受列表序号或元数据中的精确 ID;`/reasoning --default` 让 Harness 重新采用当前模型的默认推理等级。所有 `/reasoning...` 命令都要求当前聊天已有 Session,不会自行创建 Session 或触发模型回复。
|
|
232
|
-
- 正在运行任务或等待审批、问题回答时不能修改模型或推理等级;请等待完成,或先使用 `/stop`。修改从下一次模型请求起生效,并沿用 Harness 的默认保存语义:Harness 会尝试把已接受的模型和推理等级保存为以后新会话的默认选择,已有其他会话不受影响。含图片的会话无法切换到不支持图片输入的模型。
|
|
233
|
-
- `/presetlist` 和 `/presets` 完全等价,不需要参数,也不会创建会话。它们每次都读取 Host 当前可用的 Agent Preset,显示名称、稳定 ID、Host 默认项和当前机器人的选择;已删除或损坏的当前选择会保留并标记为“已不可用”,不会被自动清除。列表只公开安全的名称和 ID,不公开 Preset 路径、错误或其他 Host 内部字段。
|
|
234
|
-
- `/preset` 不带参数时查看当前机器人的“新会话设置”,不是查看或修改当前 Session。带参数时接受最近一次 `/presetlist` 在当前聊天中显示的序号或完整 ID;纯数字 ID 使用 `/preset id:<ID>`。选择序号时会先按该次列表解析 ID,再用 Host 最新目录复验,目录已经变化时会要求重新列出。
|
|
235
|
-
- `/preset --default` 清除当前机器人的显式覆盖值,让以后新建的 Session 在创建时跟随 Host 当前默认;显式选择一个恰好等于 Host 默认的 ID 则会固定该 ID。目录暂时不可读时仍可恢复为跟随 Host 默认。
|
|
236
|
-
- Agent Preset 修改是机器人级配置,会影响该机器人所有聊天以后创建的新 Session,但不会修改、停止、解绑或重建已有 Session,也不会自动执行 `/new`。若当前聊天已有会话,继续发送消息仍使用原 Session;发送 `/new` 后的下一条普通消息才会按新设置创建 Session。任务正在运行或等待交互时也可查询或修改 Preset,因为命令不会触碰当前 Session。
|
|
237
|
-
- `/stop` 和 `/steer` 只控制当前聊天自己发起的运行任务,即使多个聊天绑定同一个 Session,也不会有意控制其他聊天的任务。`/stop` 不删除会话或历史,并保留尚未开始的排队消息;重复发送是安全的。
|
|
238
|
-
- `/steer` 只接受文字,可包含多行;它不会创建新会话或第二个任务。没有运行任务时请直接发送普通消息;等待审批或问题回答时请先处理交互,或使用 `/stop`。
|
|
239
|
-
- `/batch`、`/send` 和 `/cancel` 仅在与机器人的私聊中可用。发送 `/batch` 后,接下来的纯文字消息会暂存,最多 10 条;第 10 条仍会收录并提示提交,之后的消息不会收录,也不会自动提交。发送 `/send` 后,机器人会按原顺序将整批内容作为一次输入处理;发送 `/cancel` 会直接丢弃当前批次。图片、文件和其他命令不会被收录。机器人重启会丢失尚未提交的批次。未进入批量输入模式时,普通聊天流程不变。
|
|
240
|
-
- 飞书 `/repair` 仅在私聊中可用,并与其他命令一样只服从当前飞书机器人的渠道访问策略;插件不另行区分管理员和普通用户。它增量补全当前缺少的 `card.action.trigger`、`im:message:readonly`、`im:resource`、`application:app_slash_command:read` 和 `application:app_slash_command:write`,确认页只显示当前应用缺少的项。授权页必须由在飞书开放平台中有权访问目标应用的账号打开。普通 `/repair` 会启动修复;若旧任务仍在等待授权,会先作废旧的一次性链接再生成新链接。发送 `/repair qr` 获取当前链接的二维码,`/repair status` 查询当前任务,`/repair verify` 重新查询验证状态,`/repair cancel` 取消任务;这四个补充命令均不会另起授权。平台已接受更新、正在等待测试按钮回调时,不会并发启动第二次修复。
|
|
241
|
-
- `/compact` 只作用于当前聊天已经绑定的 Harness 会话,不会把命令发送给模型。当前聊天尚未创建会话、会话正在生成回复或没有可压缩历史时,机器人会直接返回对应状态。
|
|
242
|
-
- 只接受已经存在的绝对目录;路径无效时机器人会返回具体提示和正确用法。
|
|
243
|
-
- `/workspacelist` 不需要参数。它合并 Harness 全局登记项与当前机器人的路径;当前路径仍存在且可安全显示时会排在首位并标记为“当前”。`/workspace N` 会在执行时按最新列表顺序切换,也可继续使用绝对路径。
|
|
244
|
-
- `/sessionlist` 和 `/sessions` 完全等价。数字参数按命令执行时与 `/workspacelist` 相同的最新顺序解析;也可使用绝对路径直接指定工作区。结果会回显最终选中的路径。
|
|
245
|
-
- `/sessionlist --limit N` 和 `/sessions --limit N` 只限制本次命令的返回条数,不改变任何全局或机器人配置。未指定 `--limit` 时仍列出全部会话。
|
|
246
|
-
- 两个会话列表命令都会列出该工作区登记的所有会话。已归档会话会标记为“已归档”;空白会话和子代理会话在它们归属该工作区时也会列出;没有标题的会话显示为“暂无标题”。结果中的 ID 可直接用于 `/session Session ID`。
|
|
247
|
-
- `/session` 只接受一个由 `/sessionlist` 获得的 Session ID。它不会新建会话或立即向模型发送消息;绑定成功后,当前聊天的后续消息会继续该会话。普通归档会话可以绑定但不会自动取消归档,子代理会话不能绑定。
|
|
248
|
-
- `/history` 在九个渠道的私聊中统一可用,只读取当前聊天已经绑定的会话,不新建会话、不调用模型,也不影响正在运行的任务或待处理交互。默认返回最近 3 条;`/history N` 接受正整数,超过 5 自动按 5 条处理,数量不足时返回实际条数。零、负数、小数、非数字和多个参数会提示用法,附带图片或文件时会拒绝处理;批量输入收集中请先 `/send` 或 `/cancel`。
|
|
249
|
-
- 历史预览中,一条用户消息或一条助手最终回复各算一条,不按轮次或天数计数。先取最新 N 条,再按从旧到新的顺序显示;不展示工具、推理、注入内容或尚未完成的助手片段,不下载或重发历史附件。长正文会截断并注明,全部结果最多发送 3 段文字,不自动翻页。绑定会话后可手动发送 `/history`,不会自动重发历史。正文仍可能包含会话原有的敏感信息,请只向可信用户开放机器人。
|
|
250
|
-
- `/session` 会自动定位会话唯一所属的工作区。同工作区绑定只替换当前聊天的映射;跨工作区绑定会切换该机器人的工作区、清除该机器人所有聊天的旧会话映射,再绑定当前聊天,因此会影响该机器人的其他聊天。已经开始生成的回复仍可完成。
|
|
251
|
-
- 工作区切换和会话绑定只会清除或替换 dsh-im 的聊天映射,不会删除、清空或归档任何旧 Session 内容;旧 Session 仍可再次列出和绑定。
|
|
252
|
-
- 任何通过当前渠道访问策略的用户都可以执行这些命令,不另行区分管理员和普通用户。Telegram 兼容模式遵循原有私聊及群聊提及/回复规则;安全模式只允许当前机器人白名单中的私聊用户执行。WhatsApp 仅自己模式只接受自聊,指定联系人模式接受自聊和白名单私聊,开放响应模式接受所有私聊、已绑定账号自己发出的群聊消息,以及其他群成员的提及或回复。
|
|
253
|
-
- Agent Preset 名称和 ID 来自同一个 Harness Host,且任何有命令权限的用户都能修改该机器人所有聊天未来新 Session 的 Preset;请只向可信用户开放 `/presetlist` 和 `/preset`。
|
|
254
|
-
- 工作区列表来自 Harness Host 的全局登记信息,可能包含其他机器人、其他渠道或非 IM 项目的本机绝对路径。请将机器人可见范围限制给可信用户。
|
|
255
|
-
- 会话列表同样来自该全局 Harness Host;会话 ID 和标题可能属于其他机器人、其他渠道或非 IM 项目,并可能包含敏感元数据。开放命令前请确保所有可见用户都可信。
|
|
256
|
-
- 任何能执行 `/session` 的用户都能接续所选会话,并通过后续消息写入会话或触发其可用工具。请只向可信用户开放机器人及其会话列表。
|
|
257
|
-
- 切换成功后只清除当前机器人的旧 Harness 会话映射,不影响其他机器人。
|
|
258
|
-
- 新工作区对后续消息生效;已经开始生成的回复会继续完成。
|
|
187
|
+
[查看命令说明](docs/机器人命令.md)
|
|
259
188
|
|
|
260
189
|
## 其它功能
|
|
261
190
|
|
package/lib/client.js
CHANGED
|
@@ -571,7 +571,7 @@ var React23 = __toESM(require("react"), 1);
|
|
|
571
571
|
// package.json
|
|
572
572
|
var package_default = {
|
|
573
573
|
name: "@xmanrui/dsh-im",
|
|
574
|
-
version: "4.
|
|
574
|
+
version: "4.9.0",
|
|
575
575
|
description: "\u628A\u4E5D\u79CD IM \u673A\u5668\u4EBA\u548C\u516C\u7F51 AI Office \u63A5\u5165\u672C\u673A DeepSeek Harness\u3002 Connect nine IM channels and a public AI Office to a local DeepSeek Harness.",
|
|
576
576
|
keywords: [
|
|
577
577
|
"deepseek-harness",
|
|
@@ -13278,14 +13278,15 @@ var CSS11 = String.raw`
|
|
|
13278
13278
|
.dim-contextSwitch:checked { border-color: var(--dsw-alias-state-business-primary, #3370ff); background: var(--dsw-alias-state-business-primary, #3370ff); }
|
|
13279
13279
|
.dim-contextSwitch:checked::before { transform: translateX(13px); background: #fff; }
|
|
13280
13280
|
.dim-contextFields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 3px 12px; }
|
|
13281
|
-
.dim-contextField { min-width: 0; min-height: 30px; display: flex; align-items: center; gap: 6px; }
|
|
13281
|
+
.dim-contextField { position: relative; min-width: 0; min-height: 30px; display: flex; align-items: center; gap: 6px; }
|
|
13282
13282
|
.dim-contextField input { flex: none; width: 14px; height: 14px; margin: 0; accent-color: var(--dsw-alias-state-business-primary, #3370ff); }
|
|
13283
13283
|
.dim-contextFieldText { min-width: 0; display: grid; grid-template-columns: max-content max-content; align-items: center; column-gap: 5px; overflow-wrap: anywhere; }
|
|
13284
13284
|
.dim-contextFieldName { min-width: 0; line-height: 17px; cursor: pointer; }
|
|
13285
13285
|
.dim-contextFieldKey { min-width: 0; grid-column: 1 / -1; color: var(--dsw-alias-label-tertiary, #8f959e); font: 10px/14px ui-monospace, SFMono-Regular, Menlo, monospace; overflow-wrap: anywhere; cursor: pointer; }
|
|
13286
|
-
.dim-contextFieldHelp { position:
|
|
13286
|
+
.dim-contextFieldHelp { position: static; }
|
|
13287
13287
|
.dim-contextFieldHelpButton { width: 16px; height: 16px; font-size: 10px; }
|
|
13288
13288
|
.dim-contextTooltip.dim-contextFieldTooltip { top: calc(100% + 6px); right: 0; left: auto; width: min(280px, calc(100vw - 72px)); }
|
|
13289
|
+
.dim-contextField:nth-child(odd) .dim-contextFieldTooltip { right: auto; left: 0; }
|
|
13289
13290
|
.dim-contextEditorHeader { position: relative; flex-wrap: wrap; }
|
|
13290
13291
|
.dim-contextEditorTitle { min-width: 0; display: inline-flex; align-items: center; gap: 6px; }
|
|
13291
13292
|
.dim-contextEditorTitle > label { font-weight: 500; }
|