relay-dsh-plugin-claude 0.1.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.md +202 -0
- package/README.zh.md +191 -0
- package/cordis.patch.yml +3 -0
- package/docs/images/dsh-new-session-backends.jpg +0 -0
- package/lib/client.js +177 -0
- package/lib/client.js.map +1 -0
- package/lib/host-plugin.js +2262 -0
- package/lib/host-plugin.js.map +1 -0
- package/lib/typert.host.js +16 -0
- package/lib/typert.host.js.map +1 -0
- package/package.json +42 -0
- package/presets/relay-claude/.relay-managed +1 -0
- package/presets/relay-claude/agent.cordis.yml +4 -0
- package/presets/relay-claude/preset.yml +3 -0
package/README.md
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# Claude Code Conversations for DeepSeek Harness
|
|
2
|
+
|
|
3
|
+
English | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
`relay-dsh-plugin-claude` adds **Claude Code as a conversation backend** to the
|
|
6
|
+
official [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)
|
|
7
|
+
(DSH) Web UI. After installation, **Claude Code** appears in DSH's New Session
|
|
8
|
+
mode menu. One DSH Session is bound to one Claude Agent SDK session.
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
The screenshot was captured from official DSH `0.1.1-rc.2` with the Codex and
|
|
13
|
+
Claude plugins installed. If you install only this plugin, only **Claude Code**
|
|
14
|
+
is added.
|
|
15
|
+
|
|
16
|
+
## Do I Need This Plugin?
|
|
17
|
+
|
|
18
|
+
Install it when you want to:
|
|
19
|
+
|
|
20
|
+
- use Claude Code inside DSH instead of switching to a separate Claude Code
|
|
21
|
+
interface;
|
|
22
|
+
- keep DSH's native conversation history, composer, approvals, questions, and
|
|
23
|
+
tool presentation;
|
|
24
|
+
- let one DSH Session continue the same Claude Agent SDK session across turns;
|
|
25
|
+
- use Claude models, reasoning, interruption, and DSH-contributed tools in the
|
|
26
|
+
same conversation.
|
|
27
|
+
|
|
28
|
+
You do not need it to use DSH's standard agents. It also does not add Relay
|
|
29
|
+
Events, file browsing, or a terminal panel. Those are separate optional plugins.
|
|
30
|
+
|
|
31
|
+
## Quick Start With Official DSH
|
|
32
|
+
|
|
33
|
+
The steps below were validated with:
|
|
34
|
+
|
|
35
|
+
- DeepSeek Harness `0.1.1-rc.2`, commit
|
|
36
|
+
[`b150a551`](https://github.com/deepseek-ai/deepseek-harness/commit/b150a551b8d465e31e418e1b2eaf5e79bbb7d28e)
|
|
37
|
+
- Node.js 22.13 or newer
|
|
38
|
+
- `pnpm` available on `PATH`
|
|
39
|
+
|
|
40
|
+
DSH is currently a developer preview and may introduce compatibility-breaking
|
|
41
|
+
changes. This repository tracks official releases and records its tested version
|
|
42
|
+
here.
|
|
43
|
+
|
|
44
|
+
### 1. Prepare Claude Code authentication
|
|
45
|
+
|
|
46
|
+
The Claude Agent SDK is installed as a normal dependency of this plugin. Before
|
|
47
|
+
starting your first DSH Claude session, complete normal local Claude Code setup
|
|
48
|
+
and authentication for the user that will run DSH.
|
|
49
|
+
|
|
50
|
+
Follow the official [Claude Code setup documentation](https://code.claude.com/docs/en/setup),
|
|
51
|
+
then start Claude Code once to verify that authentication succeeds:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
claude
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Credentials stay under Claude Code's normal local authentication mechanism; this
|
|
58
|
+
plugin does not collect them.
|
|
59
|
+
|
|
60
|
+
### 2. Install from npm
|
|
61
|
+
|
|
62
|
+
Stop a running DSH Web process before changing Profile bundles. Then run:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npx @deepseek-ai/dsh@0.1.1-rc.2 plugin --profile web add relay-dsh-plugin-claude
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The official DSH CLI initializes the `web` Profile if it does not exist, asks
|
|
69
|
+
`pnpm` to install the npm package and Claude Agent SDK dependencies, and adds the
|
|
70
|
+
plugin's bundle layer. No Relay checkout is required. The current npm release is
|
|
71
|
+
`0.1.0`. The first installation can
|
|
72
|
+
take longer while platform-specific Claude Agent SDK packages are downloaded;
|
|
73
|
+
wait for pnpm's final `Done` message or an explicit error.
|
|
74
|
+
|
|
75
|
+
If you already installed the `dsh` command, the shorter equivalent is:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
dsh plugin --profile web add relay-dsh-plugin-claude
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
To test an unreleased commit instead, replace the package name with
|
|
82
|
+
`github:yangbobo2021/relay-dsh-plugin-claude`.
|
|
83
|
+
|
|
84
|
+
### 3. Start or restart DSH Web
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npx @deepseek-ai/dsh@0.1.1-rc.2 web
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
If you use an installed command, run `dsh web` instead. Bundle membership is read
|
|
91
|
+
at startup, so restarting after installation, update, or removal is required.
|
|
92
|
+
|
|
93
|
+
### 4. Start a Claude Code conversation
|
|
94
|
+
|
|
95
|
+
1. Open the DSH URL printed in the terminal. The default is
|
|
96
|
+
`http://127.0.0.1:3080`.
|
|
97
|
+
2. On first launch, read the DSH testing notice and select **Continue**.
|
|
98
|
+
3. Select **Add workspace** in the left sidebar and choose the project directory
|
|
99
|
+
Claude may work in.
|
|
100
|
+
4. Select **New Session**.
|
|
101
|
+
5. Open the mode menu labeled **Standard mode** and choose **Claude Code**.
|
|
102
|
+
6. Enter a message and send it. Choose the backend before the first message;
|
|
103
|
+
existing sessions keep the backend with which they were created.
|
|
104
|
+
|
|
105
|
+
There is no separate activation command. A successful install plus a DSH restart
|
|
106
|
+
activates the bundle and registers the managed **Claude Code** mode automatically.
|
|
107
|
+
|
|
108
|
+
## What Works
|
|
109
|
+
|
|
110
|
+
- One persistent Claude Agent SDK session per DSH Session
|
|
111
|
+
- Model and reasoning selection
|
|
112
|
+
- Streaming answers and tool activity in the native DSH conversation
|
|
113
|
+
- DSH approval and user-question flows
|
|
114
|
+
- Interruption and session continuation
|
|
115
|
+
- Generic DSH tools exposed through an in-process Claude SDK MCP server
|
|
116
|
+
|
|
117
|
+
Tools execute through the owning Agent's DSH tool runtime and remain subject to
|
|
118
|
+
DSH permissions and Claude approval behavior. The tool bridge requires the
|
|
119
|
+
default SDK backend. If a developer explicitly selects the CLI fallback, the
|
|
120
|
+
plugin refuses contributed DSH tools instead of silently dropping them.
|
|
121
|
+
|
|
122
|
+
## Plugin Boundary and Relay
|
|
123
|
+
|
|
124
|
+
This repository was designed and compatibility-tested in
|
|
125
|
+
[Relay](https://github.com/yangbobo2021/Relay), an open-source project for
|
|
126
|
+
long-running agent work, external-event delivery, reusable DSH workbench views,
|
|
127
|
+
and multiple conversation backends.
|
|
128
|
+
|
|
129
|
+
The plugin is independently installable. It has no runtime dependency on the
|
|
130
|
+
Relay application, Relay Events, or another Relay plugin. It does not replace the
|
|
131
|
+
official DSH layout or install Files and Terminal views. This separation lets a
|
|
132
|
+
user install only Claude while the broader Relay project can compose Codex,
|
|
133
|
+
Claude, events, waits, monitors, and workbench extensions when those capabilities
|
|
134
|
+
are needed.
|
|
135
|
+
|
|
136
|
+
Explore or star Relay to follow that broader work:
|
|
137
|
+
<https://github.com/yangbobo2021/Relay>.
|
|
138
|
+
|
|
139
|
+
## Update, Inspect, or Remove
|
|
140
|
+
|
|
141
|
+
Stop DSH Web before changing the bundle, then restart it afterward.
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
# Show why the plugin is installed
|
|
145
|
+
dsh plugin --profile web why relay-dsh-plugin-claude
|
|
146
|
+
|
|
147
|
+
# Update the npm dependency
|
|
148
|
+
dsh plugin --profile web update relay-dsh-plugin-claude
|
|
149
|
+
|
|
150
|
+
# Remove it
|
|
151
|
+
dsh plugin --profile web remove relay-dsh-plugin-claude
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Use the `npx @deepseek-ai/dsh@0.1.1-rc.2` prefix instead of `dsh` when you do not
|
|
155
|
+
have a persistent DSH command.
|
|
156
|
+
|
|
157
|
+
## Troubleshooting
|
|
158
|
+
|
|
159
|
+
### Claude Code is missing from the mode menu
|
|
160
|
+
|
|
161
|
+
Restart DSH Web. Then run `dsh plugin --profile web why
|
|
162
|
+
relay-dsh-plugin-claude`. If pnpm cannot find the package, repeat the npm
|
|
163
|
+
installation command and read its final error.
|
|
164
|
+
|
|
165
|
+
### The first message reports an authentication error
|
|
166
|
+
|
|
167
|
+
Start `claude` in the same user environment that starts DSH and complete normal
|
|
168
|
+
Claude Code authentication. Restart DSH afterward.
|
|
169
|
+
|
|
170
|
+
### The composer is disabled
|
|
171
|
+
|
|
172
|
+
DSH requires a workspace before starting a coding conversation. Select **Add
|
|
173
|
+
workspace**, choose a directory, and return to **New Session**.
|
|
174
|
+
|
|
175
|
+
### Installation says pnpm is missing
|
|
176
|
+
|
|
177
|
+
Install pnpm using its [official installation guide](https://pnpm.io/installation)
|
|
178
|
+
and confirm `pnpm --version` works in the same terminal.
|
|
179
|
+
|
|
180
|
+
### DSH changed and the plugin no longer starts
|
|
181
|
+
|
|
182
|
+
DSH is a developer preview. Include the output of `dsh --version`, the plugin
|
|
183
|
+
source revision, and the startup error in a
|
|
184
|
+
[GitHub issue](https://github.com/yangbobo2021/relay-dsh-plugin-claude/issues).
|
|
185
|
+
|
|
186
|
+
## Development
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
git clone https://github.com/yangbobo2021/relay-dsh-plugin-claude.git
|
|
190
|
+
cd relay-dsh-plugin-claude
|
|
191
|
+
npm install
|
|
192
|
+
DSH_ROOT=/path/to/deepseek-harness npm run verify
|
|
193
|
+
npm pack
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
`npm run verify` runs type checking, tests, and the production build. Boundary
|
|
197
|
+
tests reject accidental runtime dependencies on Relay or another feature plugin.
|
|
198
|
+
|
|
199
|
+
## Feedback
|
|
200
|
+
|
|
201
|
+
Report bugs and feature requests in this repository's
|
|
202
|
+
[issue tracker](https://github.com/yangbobo2021/relay-dsh-plugin-claude/issues).
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# 在 DeepSeek Harness 中使用 Claude Code 对话
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
`relay-dsh-plugin-claude` 为官方
|
|
6
|
+
[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)Web
|
|
7
|
+
界面增加 **Claude Code 对话后端**。安装后,DSH 的新建会话模式菜单中会出现
|
|
8
|
+
**Claude Code**。每个 DSH Session 会绑定一个 Claude Agent SDK Session。
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
上图来自安装了 Codex 和 Claude 插件的官方 DSH `0.1.1-rc.2`。如果只安装
|
|
13
|
+
本插件,菜单中只会新增 **Claude Code**。
|
|
14
|
+
|
|
15
|
+
## 什么情况下需要这个插件?
|
|
16
|
+
|
|
17
|
+
以下情况适合安装:
|
|
18
|
+
|
|
19
|
+
- 希望直接在 DSH 中使用 Claude Code,而不必切换到单独的 Claude Code
|
|
20
|
+
界面;
|
|
21
|
+
- 希望保留 DSH 原生的对话历史、输入框、审批、提问和工具展示;
|
|
22
|
+
- 希望一个 DSH Session 在多轮对话中持续使用同一个 Claude Agent SDK
|
|
23
|
+
Session;
|
|
24
|
+
- 希望在同一对话中使用 Claude 模型、reasoning、中断以及 DSH 插件贡献的
|
|
25
|
+
工具。
|
|
26
|
+
|
|
27
|
+
使用 DSH 标准 Agent 不需要安装本插件。本插件也不提供 Relay Events、文件
|
|
28
|
+
浏览和终端面板,这些能力由其他可选插件提供。
|
|
29
|
+
|
|
30
|
+
## 基于官方 DSH 的快速安装
|
|
31
|
+
|
|
32
|
+
以下步骤已经在这些版本上实际验证:
|
|
33
|
+
|
|
34
|
+
- DeepSeek Harness `0.1.1-rc.2`,commit
|
|
35
|
+
[`b150a551`](https://github.com/deepseek-ai/deepseek-harness/commit/b150a551b8d465e31e418e1b2eaf5e79bbb7d28e)
|
|
36
|
+
- Node.js 22.13 或更高版本
|
|
37
|
+
- `pnpm` 已加入 `PATH`
|
|
38
|
+
|
|
39
|
+
DSH 当前仍是开发者预览版本,可能发生不兼容修改。本仓库会跟进官方版本,
|
|
40
|
+
并在这里记录已经验证的版本。
|
|
41
|
+
|
|
42
|
+
### 1. 准备 Claude Code 认证
|
|
43
|
+
|
|
44
|
+
Claude Agent SDK 会作为本插件的普通依赖一起安装。首次创建 DSH Claude
|
|
45
|
+
会话前,请为运行 DSH 的用户完成 Claude Code 的本地配置和认证。
|
|
46
|
+
|
|
47
|
+
按照官方 [Claude Code 安装说明](https://code.claude.com/docs/en/setup)完成
|
|
48
|
+
设置,然后启动一次 Claude Code,确认认证成功:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
claude
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
认证信息仍由 Claude Code 原有的本地机制管理,本插件不会收集认证信息。
|
|
55
|
+
|
|
56
|
+
### 2. 从 npm 安装
|
|
57
|
+
|
|
58
|
+
修改 Profile 插件前,请先停止正在运行的 DSH Web,然后执行:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npx @deepseek-ai/dsh@0.1.1-rc.2 plugin --profile web add relay-dsh-plugin-claude
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
官方 DSH CLI 会在需要时初始化 `web` Profile,通过 `pnpm` 安装 npm 包和
|
|
65
|
+
Claude Agent SDK 依赖,并将插件加入 Bundle 配置。用户不需要下载 Relay
|
|
66
|
+
仓库。当前 npm 版本为 `0.1.0`。首次安装还会下载 Claude Agent SDK 的平台相关软件包,可能需要
|
|
67
|
+
更长时间;请等待 pnpm 最终显示 `Done` 或明确的错误信息。
|
|
68
|
+
|
|
69
|
+
如果已经安装了持久可用的 `dsh` 命令,也可以使用:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
dsh plugin --profile web add relay-dsh-plugin-claude
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
如需测试尚未发布的提交,可将包名替换为
|
|
76
|
+
`github:yangbobo2021/relay-dsh-plugin-claude`。
|
|
77
|
+
|
|
78
|
+
### 3. 启动或重启 DSH Web
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npx @deepseek-ai/dsh@0.1.1-rc.2 web
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
如果使用已经安装的命令,则执行 `dsh web`。DSH 只在启动时读取 Bundle
|
|
85
|
+
成员,因此安装、更新或删除插件后必须重启。
|
|
86
|
+
|
|
87
|
+
### 4. 新建 Claude Code 对话
|
|
88
|
+
|
|
89
|
+
1. 打开终端中显示的 DSH 地址,默认是 `http://127.0.0.1:3080`。
|
|
90
|
+
2. 首次启动时阅读 DSH 测试提示,然后点击 **Continue**。
|
|
91
|
+
3. 点击左侧栏的 **Add workspace**,选择允许 Claude 操作的项目目录。
|
|
92
|
+
4. 点击 **New Session**。
|
|
93
|
+
5. 打开当前显示为 **Standard mode** 的模式菜单,选择 **Claude Code**。
|
|
94
|
+
6. 输入消息并发送。请在发送第一条消息前选择后端;已有会话会继续使用创建
|
|
95
|
+
时选择的后端。
|
|
96
|
+
|
|
97
|
+
插件不需要单独的激活命令。安装成功并重启 DSH 后,Bundle 会自动激活,
|
|
98
|
+
并注册由插件管理的 **Claude Code** 模式。
|
|
99
|
+
|
|
100
|
+
## 支持的能力
|
|
101
|
+
|
|
102
|
+
- 每个 DSH Session 持续绑定一个 Claude Agent SDK Session
|
|
103
|
+
- 模型和 reasoning 选择
|
|
104
|
+
- 在 DSH 原生对话中流式显示回答和工具活动
|
|
105
|
+
- DSH 原生审批和用户提问流程
|
|
106
|
+
- 中断和会话延续
|
|
107
|
+
- 通过进程内 Claude SDK MCP Server 提供通用 DSH 工具
|
|
108
|
+
|
|
109
|
+
工具通过当前 Agent 的 DSH 工具运行时执行,并继续受到 DSH 权限和 Claude
|
|
110
|
+
审批机制约束。工具桥接依赖默认 SDK 后端。如果开发者明确选择 CLI fallback,
|
|
111
|
+
插件会拒绝 DSH 贡献工具,而不是静默丢弃工具。
|
|
112
|
+
|
|
113
|
+
## 插件边界及与 Relay 的关系
|
|
114
|
+
|
|
115
|
+
本仓库在 [Relay](https://github.com/yangbobo2021/Relay) 项目中完成设计与
|
|
116
|
+
兼容性验证。Relay 是面向长时间运行 Agent、外部事件投递、可复用 DSH
|
|
117
|
+
工作台视图和多种对话后端的开源项目。
|
|
118
|
+
|
|
119
|
+
本插件可以独立安装。运行时不依赖 Relay 应用、Relay Events 或其他 Relay
|
|
120
|
+
插件,也不会替换 DSH 官方布局或安装 Files、Terminal 视图。用户可以只安装
|
|
121
|
+
Claude;需要时,Relay 项目则可以进一步组合 Codex、Claude、事件、Wait、
|
|
122
|
+
Monitor 和工作台扩展。
|
|
123
|
+
|
|
124
|
+
可以访问或 Star Relay 仓库,关注这些更完整的工作:
|
|
125
|
+
<https://github.com/yangbobo2021/Relay>。
|
|
126
|
+
|
|
127
|
+
## 更新、检查或删除
|
|
128
|
+
|
|
129
|
+
修改 Bundle 前先停止 DSH Web,完成后重新启动。
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# 检查插件为何被安装
|
|
133
|
+
dsh plugin --profile web why relay-dsh-plugin-claude
|
|
134
|
+
|
|
135
|
+
# 更新 npm 依赖
|
|
136
|
+
dsh plugin --profile web update relay-dsh-plugin-claude
|
|
137
|
+
|
|
138
|
+
# 删除插件
|
|
139
|
+
dsh plugin --profile web remove relay-dsh-plugin-claude
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
如果没有持久安装 `dsh` 命令,请将命令开头的 `dsh` 替换为
|
|
143
|
+
`npx @deepseek-ai/dsh@0.1.1-rc.2`。
|
|
144
|
+
|
|
145
|
+
## 常见问题
|
|
146
|
+
|
|
147
|
+
### 模式菜单中没有 Claude Code
|
|
148
|
+
|
|
149
|
+
先重启 DSH Web,再执行 `dsh plugin --profile web why
|
|
150
|
+
relay-dsh-plugin-claude`。如果 pnpm 找不到插件,请重新执行 npm 安装命令,
|
|
151
|
+
并查看最后显示的错误。
|
|
152
|
+
|
|
153
|
+
### 第一条消息提示认证失败
|
|
154
|
+
|
|
155
|
+
在启动 DSH 的同一用户环境中运行 `claude`,完成正常的 Claude Code 认证,
|
|
156
|
+
然后重启 DSH。
|
|
157
|
+
|
|
158
|
+
### 输入框不可用
|
|
159
|
+
|
|
160
|
+
DSH 在开始编码对话前必须选择工作区。点击 **Add workspace**,选择一个目录,
|
|
161
|
+
然后返回 **New Session**。
|
|
162
|
+
|
|
163
|
+
### 安装时提示找不到 pnpm
|
|
164
|
+
|
|
165
|
+
按照 pnpm 的[官方安装说明](https://pnpm.io/installation)安装,并在同一个
|
|
166
|
+
终端中确认 `pnpm --version` 可以执行。
|
|
167
|
+
|
|
168
|
+
### DSH 更新后插件无法启动
|
|
169
|
+
|
|
170
|
+
DSH 仍是开发者预览版本。请在
|
|
171
|
+
[GitHub Issue](https://github.com/yangbobo2021/relay-dsh-plugin-claude/issues)
|
|
172
|
+
中附上 `dsh --version` 输出、插件源码版本和启动错误。
|
|
173
|
+
|
|
174
|
+
## 开发验证
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
git clone https://github.com/yangbobo2021/relay-dsh-plugin-claude.git
|
|
178
|
+
cd relay-dsh-plugin-claude
|
|
179
|
+
npm install
|
|
180
|
+
DSH_ROOT=/path/to/deepseek-harness npm run verify
|
|
181
|
+
npm pack
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
`npm run verify` 会执行类型检查、测试和生产构建。边界测试会阻止插件意外
|
|
185
|
+
增加对 Relay 或其他功能插件的运行时依赖。
|
|
186
|
+
|
|
187
|
+
## 反馈
|
|
188
|
+
|
|
189
|
+
请通过本仓库的
|
|
190
|
+
[Issue Tracker](https://github.com/yangbobo2021/relay-dsh-plugin-claude/issues)
|
|
191
|
+
报告错误或提出功能建议。
|
package/cordis.patch.yml
ADDED
|
Binary file
|
package/lib/client.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "relay-dsh-plugin-claude",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
let react = require("react");
|
|
8
|
+
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
9
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
10
|
+
//#region \0relay-css-module:./src/client/ClaudeActivityView.module.css.mjs
|
|
11
|
+
const css = ".ts8jCW_activity{width:min(100%,960px);color:var(--dsw-alias-label-secondary)}.ts8jCW_summary{min-width:0;color:var(--dsw-alias-label-tertiary);flex:1;align-items:center;gap:8px;font-size:13px;display:flex}.ts8jCW_summary :first-child{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.ts8jCW_detail{border-left:1px solid var(--dsw-alias-border-l2);margin:4px 0 8px 28px;padding-left:12px;overflow:hidden}.ts8jCW_detail pre{max-height:320px;color:var(--dsw-alias-label-secondary);font:var(--dsw-font-markdown-code-block-small);white-space:pre-wrap;word-break:break-word;margin:0 0 8px;overflow:auto}.ts8jCW_provenance{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;margin-bottom:8px;font-size:12px;line-height:18px;overflow:hidden}";
|
|
12
|
+
const tagId = "relay-dsh-plugin-claude/ClaudeActivityView.module.css";
|
|
13
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
14
|
+
const tag = document.createElement("style");
|
|
15
|
+
tag.dataset.plugin = "relay-dsh-plugin-claude";
|
|
16
|
+
tag.dataset.pluginCss = tagId;
|
|
17
|
+
tag.textContent = css;
|
|
18
|
+
document.head.appendChild(tag);
|
|
19
|
+
}
|
|
20
|
+
var ClaudeActivityView_module_css_default = {
|
|
21
|
+
"activity": "ts8jCW_activity",
|
|
22
|
+
"detail": "ts8jCW_detail",
|
|
23
|
+
"provenance": "ts8jCW_provenance",
|
|
24
|
+
"summary": "ts8jCW_summary"
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/client/ClaudeActivityView.tsx
|
|
28
|
+
function dotState(status) {
|
|
29
|
+
if (status === "running") return "ongoing";
|
|
30
|
+
if (status === "error") return "error";
|
|
31
|
+
return "done";
|
|
32
|
+
}
|
|
33
|
+
const ClaudeActivityView = (0, react.memo)(function ClaudeActivityView({ node }) {
|
|
34
|
+
const activity = node.data;
|
|
35
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
36
|
+
const expandable = activity.input !== void 0 || activity.output !== void 0 || activity.provenance !== void 0;
|
|
37
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
38
|
+
className: ClaudeActivityView_module_css_default.activity,
|
|
39
|
+
"data-claude-activity": activity.type,
|
|
40
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.DisclosureRow, {
|
|
41
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCodeOutline16, {}),
|
|
42
|
+
title: activity.title,
|
|
43
|
+
open,
|
|
44
|
+
expandable,
|
|
45
|
+
onToggle: () => {
|
|
46
|
+
setOpen((value) => !value);
|
|
47
|
+
},
|
|
48
|
+
expandOnRowClick: true,
|
|
49
|
+
collapsedContent: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
50
|
+
className: ClaudeActivityView_module_css_default.summary,
|
|
51
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: activity.summary }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.StateDot, {
|
|
52
|
+
state: dotState(activity.status),
|
|
53
|
+
size: 8
|
|
54
|
+
})]
|
|
55
|
+
}),
|
|
56
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
57
|
+
className: ClaudeActivityView_module_css_default.detail,
|
|
58
|
+
children: [
|
|
59
|
+
activity.provenance !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
60
|
+
className: ClaudeActivityView_module_css_default.provenance,
|
|
61
|
+
title: `Claude Code · Session ${activity.provenance.claudeSessionId} · Turn ${activity.provenance.turnId}`,
|
|
62
|
+
children: [
|
|
63
|
+
"Claude Code · Session ",
|
|
64
|
+
shortId(activity.provenance.claudeSessionId),
|
|
65
|
+
" · Turn ",
|
|
66
|
+
shortId(activity.provenance.turnId)
|
|
67
|
+
]
|
|
68
|
+
}) : null,
|
|
69
|
+
activity.input !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: activity.input }) : null,
|
|
70
|
+
activity.output !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: activity.output }) : null
|
|
71
|
+
]
|
|
72
|
+
})
|
|
73
|
+
})
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
function shortId(value) {
|
|
77
|
+
return value.length > 15 ? `${value.slice(0, 8)}...${value.slice(-4)}` : value;
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
//#region src/client/claude-activity.ts
|
|
81
|
+
const claudeActivityDefinition = {
|
|
82
|
+
kind: "relay-claude-activity",
|
|
83
|
+
target: "chat",
|
|
84
|
+
match: (event) => event.type === "relay-claude/activity" ? {
|
|
85
|
+
id: event.data.itemId,
|
|
86
|
+
role: event.data.phase === "started" ? "start" : "update"
|
|
87
|
+
} : null,
|
|
88
|
+
start: (_context, match) => {
|
|
89
|
+
if (match.event.type !== "relay-claude/activity") throw new Error("Claude activity start requires relay-claude/activity");
|
|
90
|
+
return {
|
|
91
|
+
...match.event.data.activity,
|
|
92
|
+
provenance: {
|
|
93
|
+
claudeSessionId: match.event.data.claudeSessionId,
|
|
94
|
+
turnId: match.event.data.turnId
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
update: (context, match) => match.event.type === "relay-claude/activity" ? {
|
|
99
|
+
...match.event.data.activity,
|
|
100
|
+
provenance: {
|
|
101
|
+
claudeSessionId: match.event.data.claudeSessionId,
|
|
102
|
+
turnId: match.event.data.turnId
|
|
103
|
+
}
|
|
104
|
+
} : context.state,
|
|
105
|
+
buildViewNode: (context) => {
|
|
106
|
+
if (context.start === void 0 || context.state === void 0) return null;
|
|
107
|
+
return {
|
|
108
|
+
key: context.key,
|
|
109
|
+
kind: "relay-claude-activity",
|
|
110
|
+
id: context.id,
|
|
111
|
+
target: "chat",
|
|
112
|
+
anchorSeq: context.start.event.seq,
|
|
113
|
+
location: context.start.location,
|
|
114
|
+
visibility: "visible",
|
|
115
|
+
data: context.state
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
//#endregion
|
|
120
|
+
//#region src/client/index.ts
|
|
121
|
+
const inject = [
|
|
122
|
+
"slots",
|
|
123
|
+
"theme",
|
|
124
|
+
"locale",
|
|
125
|
+
"remote",
|
|
126
|
+
"sessions",
|
|
127
|
+
"connection",
|
|
128
|
+
"conversationEvents"
|
|
129
|
+
];
|
|
130
|
+
async function apply(ctx) {
|
|
131
|
+
ctx.conversationEvents.register(claudeActivityDefinition);
|
|
132
|
+
ctx.slots.inject("conversation.chat.node", () => ctx.slots.register({
|
|
133
|
+
name: "conversation.chat.node",
|
|
134
|
+
key: "relay-claude-activity"
|
|
135
|
+
}, ClaudeActivityView));
|
|
136
|
+
const unsubscribe = installModelSelection(ctx);
|
|
137
|
+
return async () => {
|
|
138
|
+
unsubscribe();
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function installModelSelection(ctx) {
|
|
142
|
+
const connection = ctx.get("connection");
|
|
143
|
+
const selecting = /* @__PURE__ */ new Set();
|
|
144
|
+
const sync = () => {
|
|
145
|
+
const list = ctx.sessions.list.getSnapshot();
|
|
146
|
+
const id = list.current;
|
|
147
|
+
if (id === void 0 || list.byId[id]?.blank !== true || selecting.has(id)) return;
|
|
148
|
+
const preset = list.byId[id]?.agentPreset;
|
|
149
|
+
if (preset === "relay-codex") return;
|
|
150
|
+
selecting.add(id);
|
|
151
|
+
connection.api.sessions.models({ sessionId: id }).then(async (response) => {
|
|
152
|
+
const { result } = response;
|
|
153
|
+
if (!result.ok) return;
|
|
154
|
+
const target = preset === "relay-claude" ? result.value.groups.find((group) => group.id === "relay-claude") : result.value.current.provider === "relay-claude" ? result.value.groups.find((group) => group.id !== "relay-claude" && group.id !== "relay-codex") : void 0;
|
|
155
|
+
const model = target?.models[0];
|
|
156
|
+
if (target && model) await connection.api.sessions.selectModel({
|
|
157
|
+
sessionId: id,
|
|
158
|
+
provider: target.id,
|
|
159
|
+
model: model.id,
|
|
160
|
+
...model.reasoning?.defaultEffort ? { reasoningEffort: model.reasoning.defaultEffort } : {}
|
|
161
|
+
});
|
|
162
|
+
}).catch(() => {}).finally(() => {
|
|
163
|
+
selecting.delete(id);
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
const off = ctx.sessions.list.subscribe(sync);
|
|
167
|
+
sync();
|
|
168
|
+
return off;
|
|
169
|
+
}
|
|
170
|
+
//#endregion
|
|
171
|
+
exports.apply = apply;
|
|
172
|
+
exports.inject = inject;
|
|
173
|
+
return module.exports;
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","names":["css","DisclosureRow","IconCodeOutline16","StateDot"],"sources":["../src/client/ClaudeActivityView.tsx","../src/client/claude-activity.ts","../src/client/index.ts"],"sourcesContent":["import { memo, useState } from 'react'\nimport {\n DisclosureRow,\n IconCodeOutline16,\n StateDot,\n type StateDotState,\n} from '@deepseek-ai/dsh-client-ui-primitives'\nimport type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { ClaudeActivityData } from './claude-activity.ts'\nimport css from './ClaudeActivityView.module.css'\n\ntype ClaudeActivityViewProps = PropsRuntime<'conversation.chat.node', 'relay-claude-activity'>\n\nfunction dotState(status: ClaudeActivityData['status']): StateDotState {\n if (status === 'running') return 'ongoing'\n if (status === 'error') return 'error'\n return 'done'\n}\n\nexport const ClaudeActivityView = memo(function ClaudeActivityView({ node }: ClaudeActivityViewProps) {\n const activity = node.data as ClaudeActivityData\n const [open, setOpen] = useState(false)\n const expandable = activity.input !== undefined || activity.output !== undefined || activity.provenance !== undefined\n return (\n <div className={css.activity} data-claude-activity={activity.type}>\n <DisclosureRow\n icon={<IconCodeOutline16 />}\n title={activity.title}\n open={open}\n expandable={expandable}\n onToggle={() => { setOpen(value => !value) }}\n expandOnRowClick\n collapsedContent={(\n <span className={css.summary}>\n <span>{activity.summary}</span>\n <StateDot state={dotState(activity.status)} size={8} />\n </span>\n )}\n >\n <div className={css.detail}>\n {activity.provenance !== undefined ? (\n <div\n className={css.provenance}\n title={`Claude Code · Session ${activity.provenance.claudeSessionId} · Turn ${activity.provenance.turnId}`}\n >\n Claude Code · Session {shortId(activity.provenance.claudeSessionId)} · Turn {shortId(activity.provenance.turnId)}\n </div>\n ) : null}\n {activity.input !== undefined ? <pre>{activity.input}</pre> : null}\n {activity.output !== undefined ? <pre>{activity.output}</pre> : null}\n </div>\n </DisclosureRow>\n </div>\n )\n})\n\nfunction shortId(value: string): string {\n return value.length > 15 ? `${value.slice(0, 8)}...${value.slice(-4)}` : value\n}\n","import type { ChatConversationViewNode, ConversationNodeDefinition } from '@deepseek-ai/dsh-client-runtime/client'\n\nexport type ClaudeActivityStatus = 'running' | 'completed' | 'error'\n\nexport interface ClaudeActivityData {\n readonly type: string\n readonly status: ClaudeActivityStatus\n readonly title: string\n readonly summary?: string\n readonly input?: string\n readonly output?: string\n readonly provenance?: {\n readonly claudeSessionId: string\n readonly turnId: string\n }\n}\n\nexport interface ClaudeActivityEventData {\n readonly version: 1\n readonly claudeSessionId: string\n readonly turnId: string\n readonly itemId: string\n readonly phase: 'started' | 'completed'\n readonly activity: ClaudeActivityData\n}\n\ndeclare module '@deepseek-ai/dsh-session/types' {\n interface SessionEventMap {\n 'relay-claude/activity': ClaudeActivityEventData\n }\n}\n\ndeclare module '@deepseek-ai/dsh-client-ui-conversation/client' {\n interface ChatNodeDataMap {\n 'relay-claude-activity': ClaudeActivityData\n }\n}\n\nexport const claudeActivityDefinition: ConversationNodeDefinition<ClaudeActivityData> = {\n kind: 'relay-claude-activity',\n target: 'chat',\n match: event => event.type === 'relay-claude/activity'\n ? { id: event.data.itemId, role: event.data.phase === 'started' ? 'start' : 'update' }\n : null,\n start: (_context, match) => {\n if (match.event.type !== 'relay-claude/activity') {\n throw new Error('Claude activity start requires relay-claude/activity')\n }\n return {\n ...match.event.data.activity,\n provenance: {\n claudeSessionId: match.event.data.claudeSessionId,\n turnId: match.event.data.turnId,\n },\n }\n },\n update: (context, match) => match.event.type === 'relay-claude/activity'\n ? {\n ...match.event.data.activity,\n provenance: {\n claudeSessionId: match.event.data.claudeSessionId,\n turnId: match.event.data.turnId,\n },\n }\n : context.state,\n buildViewNode: (context): ChatConversationViewNode | null => {\n if (context.start === undefined || context.state === undefined) return null\n return {\n key: context.key,\n kind: 'relay-claude-activity',\n id: context.id,\n target: 'chat',\n anchorSeq: context.start.event.seq,\n location: context.start.location,\n visibility: 'visible',\n data: context.state,\n }\n },\n}\n","import type { IApiClient } from '@deepseek-ai/dsh-api-remotes/client'\nimport type { ClientContext, SessionId } from '@deepseek-ai/dsh-client-runtime/client'\nimport type {} from '@deepseek-ai/dsh-client-ui-conversation/client'\nimport { ClaudeActivityView } from './ClaudeActivityView.tsx'\nimport { claudeActivityDefinition } from './claude-activity.ts'\n\ninterface ConnectionFace { api: { sessions: Pick<IApiClient['sessions'], 'models' | 'selectModel'> } }\ninterface ModelGroup { readonly id: string; readonly models: readonly { readonly id: string; readonly reasoning?: { readonly defaultEffort?: string } }[] }\n\nexport const inject = ['slots', 'theme', 'locale', 'remote', 'sessions', 'connection', 'conversationEvents']\n\nexport async function apply(ctx: ClientContext): Promise<() => Promise<void>> {\n ctx.conversationEvents.register(claudeActivityDefinition)\n ctx.slots.inject('conversation.chat.node', () => ctx.slots.register({\n name: 'conversation.chat.node', key: 'relay-claude-activity',\n }, ClaudeActivityView))\n const unsubscribe = installModelSelection(ctx)\n return async () => { unsubscribe() }\n}\n\nfunction installModelSelection(ctx: ClientContext): () => void {\n const connection = ctx.get('connection' as never) as unknown as ConnectionFace\n const selecting = new Set<string>()\n const sync = (): void => {\n const list = ctx.sessions.list.getSnapshot()\n const id = list.current\n if (id === undefined || list.byId[id]?.blank !== true || selecting.has(id)) return\n const preset = list.byId[id]?.agentPreset\n if (preset === 'relay-codex') return\n selecting.add(id)\n void connection.api.sessions.models({ sessionId: id }).then(async (response: Awaited<ReturnType<ConnectionFace['api']['sessions']['models']>>) => {\n const { result } = response\n if (!result.ok) return\n const target = preset === 'relay-claude'\n ? (result.value.groups as readonly ModelGroup[]).find(group => group.id === 'relay-claude')\n : result.value.current.provider === 'relay-claude'\n ? (result.value.groups as readonly ModelGroup[]).find(group => group.id !== 'relay-claude' && group.id !== 'relay-codex')\n : undefined\n const model = target?.models[0]\n if (target && model) await connection.api.sessions.selectModel({ sessionId: id as SessionId, provider: target.id, model: model.id, ...(model.reasoning?.defaultEffort ? { reasoningEffort: model.reasoning.defaultEffort } : {}) })\n }).catch(() => {}).finally(() => { selecting.delete(id) })\n }\n const off = ctx.sessions.list.subscribe(sync); sync(); return off\n}\n"],"mappings":"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"}
|