dsh-code 0.9.1 → 1.0.1
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 +278 -249
- package/README.md +131 -102
- package/bin/deepseek.mjs +100 -6
- package/cordis.patch.yml +36 -1
- package/lib/index.mjs +3055 -819
- package/lib/startup.mjs +21 -11
- package/lib/{theme-BEi4i_aN.mjs → theme-DCT8Y2xf.mjs} +13 -9
- package/lib/types/app.d.ts +84 -16
- package/lib/types/attachments.d.ts +20 -0
- package/lib/types/authorization-panel.d.ts +22 -0
- package/lib/types/authorization.d.ts +36 -0
- package/lib/types/editor.d.ts +6 -0
- package/lib/types/fork.d.ts +8 -0
- package/lib/types/git-workflow.d.ts +23 -0
- package/lib/types/index.d.ts +6 -0
- package/lib/types/kernel-panels.d.ts +39 -0
- package/lib/types/keyboard.d.ts +41 -0
- package/lib/types/mentions.d.ts +30 -38
- package/lib/types/models.d.ts +3 -1
- package/lib/types/permissions.d.ts +4 -14
- package/lib/types/presets.d.ts +5 -20
- package/lib/types/provider-settings.d.ts +16 -0
- package/lib/types/render/animations.d.ts +10 -39
- package/lib/types/render/editor.d.ts +137 -0
- package/lib/types/render/export.d.ts +1 -1
- package/lib/types/render/lines.d.ts +6 -2
- package/lib/types/render/markdown.d.ts +3 -1
- package/lib/types/render/projection.d.ts +29 -3
- package/lib/types/render/status.d.ts +6 -13
- package/lib/types/session-directory.d.ts +1 -3
- package/lib/types/startup.d.ts +14 -11
- package/lib/types/store.d.ts +11 -9
- package/lib/types/subagents.d.ts +3 -3
- package/lib/types/theme.d.ts +14 -1
- package/lib/types/version.d.ts +15 -2
- package/package.json +159 -141
- package/src/app.ts +1490 -663
- package/src/attachments.ts +128 -0
- package/src/authorization-panel.ts +285 -0
- package/src/authorization.ts +147 -0
- package/src/editor.ts +51 -0
- package/src/fork.ts +31 -0
- package/src/git-workflow.ts +87 -0
- package/src/index.ts +1523 -1374
- package/src/internals.ts +14 -1
- package/src/kernel-panels.ts +914 -798
- package/src/keyboard.ts +126 -0
- package/src/mentions.ts +78 -117
- package/src/models.ts +20 -14
- package/src/permissions.ts +5 -13
- package/src/presets.ts +6 -22
- package/src/provider-settings.ts +95 -1
- package/src/render/animations.ts +420 -450
- package/src/render/editor.ts +398 -0
- package/src/render/export.ts +79 -79
- package/src/render/lines.ts +342 -236
- package/src/render/markdown.ts +99 -26
- package/src/render/projection.ts +106 -19
- package/src/render/status.ts +713 -650
- package/src/render/text.ts +150 -150
- package/src/render/tool-detail.ts +3 -1
- package/src/session-directory.ts +4 -4
- package/src/startup.ts +136 -119
- package/src/store.ts +23 -11
- package/src/subagents.ts +13 -5
- package/src/theme.ts +214 -206
- package/src/version.ts +58 -1
package/README.md
CHANGED
|
@@ -2,163 +2,192 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.en.md) | 中文
|
|
4
4
|
|
|
5
|
-
<p align="center"><img src="docs/pictures/1.png" width="95%" alt="
|
|
5
|
+
<p align="center"><img src="docs/pictures/dsh-1.png" width="95%" alt="DSH-Code 欢迎界面与模型状态"></p>
|
|
6
6
|
|
|
7
7
|
<p align="center"><img alt="Typing SVG" src="https://readme-typing-svg.herokuapp.com?font=JetBrains+Mono&weight=500&size=22&duration=4000&pause=700&color=4176E6&center=true&vCenter=true&width=680&lines=DeepSeek+Harness+Code;DSH+%E5%86%85%E6%A0%B8%E7%9A%84%E7%BB%88%E7%AB%AF%E7%BC%96%E7%A0%81%E7%95%8C%E9%9D%A2"></p>
|
|
8
8
|
<p align="center">
|
|
9
9
|
<a href="https://github.com/deepseek-ai/deepseek-harness"><img alt="DeepSeek Harness" src="https://img.shields.io/badge/DeepSeek-Harness-4176E6?style=for-the-badge&logo=deepseek&logoColor=white&labelColor=1c1917"></a>
|
|
10
|
+
<a href="https://www.npmjs.com/package/@deepseek-ai/dsh"><img alt="dsh version" src="https://img.shields.io/badge/dsh-0.1.1--rc.2-4176E6?style=for-the-badge&logo=deepseek&logoColor=white&labelColor=1c1917"></a>
|
|
10
11
|
<a href="https://github.com/UNLINEARITY/dsh-code/stargazers"><img alt="GitHub stars" src="https://img.shields.io/github/stars/UNLINEARITY/dsh-code?label=Stars&style=for-the-badge&logo=github&logoColor=white&color=4176E6&labelColor=1c1917"></a>
|
|
11
12
|
<a href="https://www.npmjs.com/package/dsh-code"><img alt="npm version" src="https://img.shields.io/npm/v/dsh-code?label=npm&style=for-the-badge&logo=npm&color=cb3837&labelColor=1c1917"></a>
|
|
12
13
|
<a href="https://github.com/UNLINEARITY/dsh-code/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/github/license/UNLINEARITY/dsh-code?label=License&style=for-the-badge&logo=opensourceinitiative&color=4176E6&labelColor=1c1917"></a>
|
|
13
14
|
</p>
|
|
14
15
|
|
|
15
|
-
**DSH-Code 是 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(`dsh`)的终端编码界面。** 它以树外 bundle 的形式组合在官方 `@deepseek-ai/dsh-base` 之上,与 Harness Web UI 使用同一套 Agent、Session、工具、命令、技能、权限、sandbox、上下文压缩与插件服务。
|
|
16
|
-
|
|
17
|
-
DSH-Code 没有另外实现一套 Agent loop,而是在 DSH 运行时上增加面向编码工作的 TUI。会话处理参考 [Codex CLI](https://github.com/openai/codex),终端交互参考 [Claude Code](https://code.claude.com/docs/en/overview)。
|
|
18
|
-
|
|
19
16
|
---
|
|
20
17
|
|
|
21
18
|
## 一、项目概览
|
|
22
19
|
|
|
23
|
-
DeepSeek Harness
|
|
20
|
+
**DSH-Code 是 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(`dsh`)的终端编码界面。** 它以树外 bundle 的形式组合在官方 `@deepseek-ai/dsh-base` 之上,与 Harness Web UI 使用同一套 Agent、Session、工具、命令、技能、权限、sandbox、上下文压缩与插件服务。
|
|
24
21
|
|
|
25
|
-
DSH-Code
|
|
22
|
+
DeepSeek Harness 将模型、工具、存储、策略和界面作为插件,通过 Cordis 注册。持久化会话事件记录恢复对话与运行状态所需的信息。DSH-Code 保留这套结构,并补充适合编码任务的终端工作流。界面采用开发者熟悉的终端操作方式,运行行为仍由 DSH 服务和配置决定。
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
| --- | --- |
|
|
29
|
-
| **DeepSeek Harness** | 插件组合、作用域服务、Agent Preset、持久会话、工具、技能、策略、sandbox 与委派 |
|
|
30
|
-
| **Codex CLI** | 会话导航、有界浮层、历史检查、稳定底部布局与缩放处理 |
|
|
31
|
-
| **Claude Code** | 斜杠命令发现、思考折叠、审批、提问与 turn steering |
|
|
24
|
+
## 二、快速开始
|
|
32
25
|
|
|
33
|
-
|
|
26
|
+
需要 Node `^22.19 || >=24` 和预览版 `dsh` CLI(当前版本线:`@deepseek-ai/dsh@0.1.1-rc.2`)。未配置模型时仍可进入 TUI、查看会话和使用非模型功能;在 `/model` 中按 `a` 可管理 API key、OAuth 与设备码登录。
|
|
34
27
|
|
|
35
|
-
|
|
28
|
+
### 1. 安装与更新
|
|
36
29
|
|
|
37
|
-
|
|
30
|
+
初次安装和更新使用同一组指令:
|
|
38
31
|
|
|
39
32
|
```sh
|
|
40
|
-
npm install -g @deepseek-ai/dsh dsh-code
|
|
33
|
+
npm install -g @deepseek-ai/dsh@0.1.1-rc.2 dsh-code@1.0.1
|
|
41
34
|
npm install -g pnpm
|
|
42
|
-
dsh plugin --profile cli add dsh-code@0.
|
|
35
|
+
dsh plugin --profile cli add dsh-code@1.0.1
|
|
43
36
|
```
|
|
44
37
|
|
|
45
|
-
> 提示:pnpm 会忽略发布不足 24 小时的包,因此发布首日请使用精确版本 `dsh-code@0.
|
|
38
|
+
> 提示:pnpm 会忽略发布不足 24 小时的包,因此发布首日请使用精确版本 `dsh-code@1.0.1`;24 小时后可省略版本号。npm 安装不受此限制。
|
|
39
|
+
>
|
|
40
|
+
> 版本对齐:dsh-code 1.0.1 面向 dsh `0.1.1-rc.2` 构建,全部 Harness 依赖均精确锁定为 `0.1.1-rc.2`。请保持全局 dsh 与 dsh-code 同步,避免宿主与插件混用候选版本。rc.2 已删除旧的 DeepSeek 配置项 `maxRequestImageBytes`。
|
|
46
41
|
|
|
47
|
-
###
|
|
48
|
-
|
|
49
|
-
```sh
|
|
50
|
-
npm install -g dsh-code@0.9.1
|
|
51
|
-
dsh plugin --profile cli add dsh-code@0.9.1
|
|
52
|
-
```
|
|
42
|
+
### 2. 启动指令
|
|
53
43
|
|
|
54
44
|
可用的启动指令:
|
|
55
45
|
```sh
|
|
56
|
-
deepseek
|
|
57
46
|
dsh --profile cli
|
|
47
|
+
deepseek
|
|
58
48
|
dsh-code
|
|
59
49
|
```
|
|
60
50
|
|
|
61
51
|
`dsh --profile cli`、`deepseek` 与 `dsh-code` 是并列的启动命令。`deepseek` 与 `dsh-code` 都是 `dsh --profile cli` 的全局别名,后续参数会原样转发,例如 `deepseek --resume abc123`。
|
|
62
52
|
|
|
53
|
+
|
|
63
54
|
> DeepSeek Harness 目前仍处于 developer preview,可能出现破坏兼容性的变化;DSH-Code 会持续跟随其插件接口演进。
|
|
64
55
|
|
|
65
56
|
安装、原生模块和插件加载问题,请查看[常见问题与排障](docs/problems.md)。
|
|
66
57
|
|
|
67
|
-
##
|
|
58
|
+
## 三、核心功能与使用方式
|
|
59
|
+
|
|
60
|
+
DSH-Code 的重点是让 DSH 的 Agent、模型、工具和持久会话可以直接在终端中使用,并覆盖从编写代码到审查修改的完整工作流。
|
|
68
61
|
|
|
69
|
-
###
|
|
62
|
+
### 1. 会话管理
|
|
70
63
|
|
|
71
|
-
|
|
64
|
+
- 使用 `/new` 新建会话,或通过 `/resume`、`--continue` 恢复已有会话
|
|
65
|
+
- 使用 `/fork` 从历史节点创建新的工作分支,同时保留原会话
|
|
66
|
+
- 按当前目录、更新时间和会话范围搜索历史记录
|
|
67
|
+
- 使用 Up/Down 召回输入历史,或通过 `/history` 搜索过去的提示词
|
|
68
|
+
- 支持持久标题、Markdown 导出、上下文占用、token、缓存、TTFT 和耗时统计
|
|
69
|
+
- 恢复会话时同步恢复该会话使用的 Agent Preset 和模型选择
|
|
72
70
|
|
|
73
|
-
|
|
71
|
+
<p align="center"><img src="docs/pictures/dsh-3.png" width="95%" alt="可搜索的会话恢复选择器"></p>
|
|
74
72
|
|
|
75
|
-
|
|
73
|
+
<p align="center"><img src="docs/pictures/dsh-4.png" width="95%" alt="可搜索的提示词历史选择器"></p>
|
|
76
74
|
|
|
77
|
-
|
|
75
|
+
### 2. Agent、模型与扩展
|
|
78
76
|
|
|
79
|
-
|
|
77
|
+
- 每个会话可以选择独立的 Agent Preset,用于组合工具、提示词、技能、上下文压缩、plan mode 和 subagent 能力
|
|
78
|
+
- 使用 `/mode` 选择 `standard`、`code`、`minimal`、`cordis` 或用户自定义 Preset
|
|
79
|
+
- 使用 `/model` 切换模型,管理 provider、API key、OAuth/设备码登录、endpoint、可用模型和上下文窗口
|
|
80
|
+
- 在 `/model` 的 provider 列表中,Enter 管理手动 API key,`l` 发起登录,`o` 经确认后退出登录
|
|
81
|
+
- 自动加载 DSH 中可用的命令与技能;使用 `/help` 查看入口,使用 `/plugin` 检查扩展状态
|
|
82
|
+
- 支持 plan、goal、todo、权限、sandbox、subagent 和运行中的补充指令
|
|
80
83
|
|
|
81
|
-
<p align="center"><img src="docs/pictures/
|
|
84
|
+
<p align="center"><img src="docs/pictures/dsh-2.png" width="95%" alt="每会话 Agent Preset 选择器"></p>
|
|
82
85
|
|
|
83
|
-
###
|
|
86
|
+
### 3. 模型切换动画
|
|
87
|
+
|
|
88
|
+
模型或 reasoning effort 发生以下变化时,输入框会播放 Wave、Aurora 或 Pulse:
|
|
89
|
+
|
|
90
|
+
| 使用场景 | 触发条件 | 动画文字 | 效果档位 |
|
|
91
|
+
| --- | --- | --- | --- |
|
|
92
|
+
| 官方 DeepSeek 模型 | 切换到该模型,或修改该模型的 reasoning effort | `deepseek` | Flash 使用单波段档位,其他 DeepSeek 模型使用多波段档位 |
|
|
93
|
+
| 其他模型 | 切换模型或 reasoning effort 后,实际生效的强度严格高于 `high` | `Into the Unknown` | 使用与非 Flash DeepSeek 模型相同的多波段档位 |
|
|
94
|
+
|
|
95
|
+
高于 `high` 的等级包括 `xhigh`、`x-high`、`very-high`、`max`、`maximum` 和 `ultra`;`high`、`medium`、`low` 与 `off` 不会为非 DeepSeek 模型触发动画。
|
|
96
|
+
|
|
97
|
+
| 样式 | Flash | 其他 DeepSeek / `Into the Unknown` |
|
|
98
|
+
| --- | --- | --- |
|
|
99
|
+
| Wave | 一个蓝色波峰从左向右扫过,约 1.2 秒 | 两个错开的蓝色波峰依次扫过,并带有 `· ✦ ✧` 尾部星光,约 1.5 秒 |
|
|
100
|
+
| Aurora | 两条蓝色光带交错漂移,约 1.5 秒 | 三条不同色调的光带交错漂移,约 1.8 秒 |
|
|
101
|
+
| Pulse | 一个圆环从输入框中心向外扩散,约 1.1 秒 | 两个圆环先后向外扩散,约 1.45 秒 |
|
|
102
|
+
|
|
103
|
+
### 4. 编码工作流
|
|
104
|
+
|
|
105
|
+
- 使用 `@` 引用工作区文件或已有会话;选择 PNG、JPEG、WebP、GIF 时会自动作为真实图片附件
|
|
106
|
+
- 支持启动 prompt、多个 `--image` 参数,以及从终端拖入一张或多张图片
|
|
107
|
+
- 使用 `/diff` 按文件检查改动,使用 `/review` 发起只读代码审查
|
|
108
|
+
- 使用 `/copy` 复制最近一条完整回复,使用 Ctrl+O 查看完整历史和工具详情
|
|
109
|
+
- 支持工具审批、结构化提问、plan review、多选和自定义答案
|
|
110
|
+
- 使用权限 Preset 和 sandbox 控制 Agent 可以执行的操作;任务运行中仍可补充指令或中断
|
|
111
|
+
|
|
112
|
+
### 5. 命令与快捷键
|
|
113
|
+
|
|
114
|
+
启动 TUI:
|
|
84
115
|
|
|
85
116
|
```sh
|
|
86
117
|
dsh --profile cli # 新建 standard 会话
|
|
87
|
-
dsh --profile cli --mode code #
|
|
118
|
+
dsh --profile cli --mode code # 使用指定 Agent Preset 启动
|
|
88
119
|
dsh --profile cli --continue # 恢复当前目录最新会话
|
|
89
|
-
dsh --profile cli --resume abc123 # 按 id
|
|
120
|
+
dsh --profile cli --resume abc123 # 按 id 或唯一前缀恢复会话
|
|
90
121
|
dsh --profile cli --session my-id # 使用指定 id 新建会话
|
|
91
122
|
```
|
|
92
123
|
|
|
93
|
-
进入 TUI
|
|
124
|
+
进入 TUI 后,可以使用以下内置命令。当前 profile 提供的其他 Harness 命令和用户技能会随安装内容变化,完整列表以 `/help` 显示为准。
|
|
94
125
|
|
|
95
|
-
|
|
126
|
+
#### 会话与记录
|
|
127
|
+
|
|
128
|
+
| 命令 | 用途 |
|
|
96
129
|
| --- | --- |
|
|
97
|
-
| `/new [preset]` |
|
|
98
|
-
| `/resume [id\|前缀]` |
|
|
99
|
-
| `/
|
|
100
|
-
| `/
|
|
101
|
-
| `/
|
|
102
|
-
| `/
|
|
103
|
-
| `/
|
|
104
|
-
| `
|
|
105
|
-
| `
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
- 从共享 Harness 注册表实时发现斜杠命令和用户技能
|
|
117
|
-
- 通过 `/plugin` 只读诊断 Cordis loader
|
|
118
|
-
- 从实时 LLM 注册表路由模型,并按持久会话恢复选择;`/model` 可添加或轮换 key、移除可写 key,以及删除用户添加的 provider profile
|
|
119
|
-
- 支持 plan、goal、todo、权限、sandbox、subagent 与运行中 steering
|
|
120
|
-
|
|
121
|
-
### 2. 会话与上下文
|
|
122
|
-
|
|
123
|
-
- `/new`、`/resume`、`--continue` 与显式 session id,且无需重新挂载 Ink
|
|
124
|
-
- Codex 风格可搜索恢复面板,支持根/全部对话、cwd、排序和密度筛选
|
|
125
|
-
- 裸启动延迟到首次真实输入才创建会话,未输入即退出零残留
|
|
126
|
-
- 全局输入历史:Up/Down 跨会话召回,`/history` 搜索面板回填输入框
|
|
127
|
-
- 标题快照按需折叠,完整转录仅在显式请求时加载并支持全量滚动
|
|
128
|
-
- subagent 对话只读检查,以及通过 `@` 注入有界会话引用
|
|
129
|
-
- Markdown 导出、持久标题、上下文占用、缓存、token、TTFT 与耗时指标
|
|
130
|
-
|
|
131
|
-
### 3. 审批与交互
|
|
132
|
-
|
|
133
|
-
- sandbox 升级与 hook `ask` 决策的一次性工具审批条
|
|
134
|
-
- 结构化 `ask_user_question` 与 plan review 菜单,支持多选和自定义答案
|
|
135
|
-
- 在下一个 step 边界进行 turn steering,并提供明确的中断语义
|
|
136
|
-
- Agent mode、plan、权限 preset、goal 与 sandbox 状态相互独立
|
|
137
|
-
|
|
138
|
-
### 4. 终端渲染
|
|
139
|
-
|
|
140
|
-
- 已落定历史只追加,流式可变区域严格有界
|
|
141
|
-
- 思考折叠、终端 Markdown、紧凑工具摘要与完整结构化详情
|
|
142
|
-
- 双行状态栏:mode 与 context 在第二行,context 为蓝色进度条,全蓝强调
|
|
143
|
-
- 运行中提交即时显示为普通提示词行,Delete 取消排队消息,busy 使用 web StateDot 八点追逐动画
|
|
144
|
-
- 回复与输入框光标对齐,欢迎头显示已安装版本与双语 slogan“Into the Unknown 探索未至之境”
|
|
145
|
-
- Ctrl+O 独占历史检查,支持切换条目与完整纵向滚动
|
|
146
|
-
- CJK/控制字符宽度安全、短终端主动降级、缩放防抖重放
|
|
147
|
-
- 固定底部顺序:内容或面板 → notice → 输入框 → 状态栏
|
|
148
|
-
|
|
149
|
-
#### DeepSeek 模型切换动画
|
|
150
|
-
|
|
151
|
-
切换到 DeepSeek 路由,或在同一路由切换 reasoning effort 时,输入框会随机播放 Wave、Aurora 或 Pulse;相邻两次不会重复同一种样式。Flash 模型使用单波段档位,其他 DeepSeek 模型使用更丰富的多波段档位。
|
|
152
|
-
|
|
153
|
-
| 样式 | Flash | DeepSeek |
|
|
154
|
-
| --- | --- | --- |
|
|
155
|
-
| Wave | 单个蓝色波峰从左向右扫过,1.2s | 两个错开的波峰,1.5s |
|
|
156
|
-
| Aurora | 两条蓝色光带正弦漂移,1.5s | 三条不同色调光带,1.8s |
|
|
157
|
-
| Pulse | 一个圆环从输入框中心扩散,1.1s | 两个先后扩散的圆环,1.45s |
|
|
130
|
+
| `/new [preset]` | 创建新会话,可同时指定 Agent Preset |
|
|
131
|
+
| `/resume [id\|前缀]` | 搜索或恢复已有会话 |
|
|
132
|
+
| `/resume cancel` | 取消正在等待的会话切换 |
|
|
133
|
+
| `/fork [event-seq]` | 从最近完成的 turn 或指定事件位置创建分支会话 |
|
|
134
|
+
| `/delete [id\|前缀]` | 删除指定会话及其 subagent 会话 |
|
|
135
|
+
| `/title <text>` | 修改当前会话标题 |
|
|
136
|
+
| `/export [path]` | 将当前会话导出为 Markdown |
|
|
137
|
+
| `/history` | 搜索并复用过去提交的提示词 |
|
|
138
|
+
| `/clear` | 清空当前终端显示,不删除持久会话 |
|
|
139
|
+
|
|
140
|
+
#### Agent、模型与权限
|
|
141
|
+
|
|
142
|
+
| 命令 | 用途 |
|
|
143
|
+
| --- | --- |
|
|
144
|
+
| `/mode [preset]` | 查看或选择当前会话的 Agent Preset |
|
|
145
|
+
| `/model` | 切换模型,管理 provider、API key、网页登录、endpoint 和可用模型 |
|
|
146
|
+
| `/effort` | 调整当前模型的 reasoning effort |
|
|
147
|
+
| `/permission [preset]` | 查看或切换权限 Preset |
|
|
148
|
+
| `/subagent` | 选择 subagent 执行任务时使用的模型 |
|
|
158
149
|
|
|
159
|
-
|
|
150
|
+
#### 编码、任务与后台工作
|
|
160
151
|
|
|
161
|
-
|
|
152
|
+
| 命令 | 用途 |
|
|
153
|
+
| --- | --- |
|
|
154
|
+
| `/diff [--staged\|ref]` | 按文件查看工作区、暂存区或指定 ref 的 Git diff |
|
|
155
|
+
| `/review [--staged\|ref]` | 使用只读权限审查 Git 改动 |
|
|
156
|
+
| `/todos` | 查看当前会话的完整 todo 列表 |
|
|
157
|
+
| `/agents` | 查看当前会话创建的 subagent 会话 |
|
|
158
|
+
| `/jobs` | 查看后台任务及其运行状态 |
|
|
159
|
+
| `/copy` | 复制最近一条完整助手回复 |
|
|
160
|
+
|
|
161
|
+
#### 扩展、显示与退出
|
|
162
|
+
|
|
163
|
+
| 命令 | 用途 |
|
|
164
|
+
| --- | --- |
|
|
165
|
+
| `/plugin [query]` | 查看已加载扩展及其状态 |
|
|
166
|
+
| `/statusline` | 选择状态栏显示的项目 |
|
|
167
|
+
| `/theme` | 切换终端配色主题 |
|
|
168
|
+
| `/help` | 查看快捷键、内置命令、Harness 命令和用户技能 |
|
|
169
|
+
| `/quit` | 退出 DSH-Code |
|
|
170
|
+
|
|
171
|
+
#### 输入与快捷键
|
|
172
|
+
|
|
173
|
+
| 操作 | 用途 |
|
|
174
|
+
| --- | --- |
|
|
175
|
+
| `Enter` | 提交当前输入 |
|
|
176
|
+
| `Up` / `Down` | 召回上一条或下一条输入记录 |
|
|
177
|
+
| `Tab` | 补全命令、技能或 `@` 引用 |
|
|
178
|
+
| `@` | 引用工作区文件或已有会话;图片文件自动作为附件发送 |
|
|
179
|
+
| `Ctrl+O` | 查看完整历史与工具详情 |
|
|
180
|
+
| `Ctrl+R` | 折叠或展开思考过程 |
|
|
181
|
+
| `Shift+Tab` | 循环切换权限 Preset |
|
|
182
|
+
| `Delete` | 输入框为空时,取消最新一条排队消息 |
|
|
183
|
+
| `Ctrl+K` | 删除光标到行尾的内容 |
|
|
184
|
+
| `Ctrl+U` | 清空当前输入行 |
|
|
185
|
+
| `Ctrl+A` / `Ctrl+E` | 移动到当前行开头或结尾 |
|
|
186
|
+
| `Esc` | 关闭当前菜单或中断正在运行的 turn |
|
|
187
|
+
| `Ctrl+C` | 依次用于取消任务、清空输入或退出 |
|
|
188
|
+
| `Ctrl+D` | 退出 DSH-Code |
|
|
189
|
+
|
|
190
|
+
## 四、DSH-Code 如何接入 DSH
|
|
162
191
|
|
|
163
192
|
### 1. 运行时组合
|
|
164
193
|
|
|
@@ -194,7 +223,7 @@ dsh profile
|
|
|
194
223
|
└→ 有界面板 → 输入框 → 状态栏
|
|
195
224
|
```
|
|
196
225
|
|
|
197
|
-
##
|
|
226
|
+
## 五、开发
|
|
198
227
|
|
|
199
228
|
```sh
|
|
200
229
|
pnpm install
|
package/bin/deepseek.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { spawn } from 'node:child_process'
|
|
3
|
+
import { spawn, spawnSync } from 'node:child_process'
|
|
4
4
|
import { existsSync, readFileSync, realpathSync } from 'node:fs'
|
|
5
5
|
import { createRequire } from 'node:module'
|
|
6
6
|
import { homedir } from 'node:os'
|
|
@@ -8,10 +8,23 @@ import { join, resolve } from 'node:path'
|
|
|
8
8
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
9
9
|
|
|
10
10
|
const packageRequire = createRequire(import.meta.url)
|
|
11
|
+
const packageVersion = packageRequire('../package.json').version
|
|
11
12
|
|
|
12
13
|
/** Arguments required to boot DSH-Code's conventional profile. */
|
|
13
14
|
export const profileArgs = (args = []) => ['--profile', 'cli', ...args]
|
|
14
15
|
|
|
16
|
+
export const OPERATION_COMMANDS = ['setup', 'doctor', 'completion', 'update']
|
|
17
|
+
|
|
18
|
+
/** Exact first-day package spec used by setup (pnpm delays an unpinned release). */
|
|
19
|
+
export const setupBundle = (args = []) => args.includes('--local')
|
|
20
|
+
? fileURLToPath(new URL('..', import.meta.url))
|
|
21
|
+
: `dsh-code@${packageVersion}`
|
|
22
|
+
|
|
23
|
+
/** Wrapper-owned operation, or undefined when arguments belong to the TUI. */
|
|
24
|
+
export function operationName(args = process.argv.slice(2)) {
|
|
25
|
+
return OPERATION_COMMANDS.includes(args[0]) ? args[0] : undefined
|
|
26
|
+
}
|
|
27
|
+
|
|
15
28
|
/** The conventional cli profile directory under the DSH home. */
|
|
16
29
|
export function cliProfileDir(home = homedir()) {
|
|
17
30
|
return join(home, '.dsh', 'profiles', 'cli')
|
|
@@ -46,20 +59,20 @@ export function globalDshRoots() {
|
|
|
46
59
|
}
|
|
47
60
|
|
|
48
61
|
/** Resolve the DSH entrypoint without passing user arguments through a Windows shell. */
|
|
49
|
-
export function
|
|
62
|
+
export function rawDshCommand(args, {
|
|
50
63
|
platform = process.platform,
|
|
51
64
|
moduleUrl = import.meta.url,
|
|
52
65
|
fileExists = existsSync,
|
|
53
66
|
roots = globalDshRoots(),
|
|
54
67
|
resolvePackage = packageRequire.resolve,
|
|
55
68
|
} = {}) {
|
|
56
|
-
if (platform !== 'win32') return { command: 'dsh', args
|
|
69
|
+
if (platform !== 'win32') return { command: 'dsh', args }
|
|
57
70
|
const adjacentEntrypoint = fileURLToPath(new URL('../../@deepseek-ai/dsh/lib/bin.js', moduleUrl))
|
|
58
|
-
if (fileExists(adjacentEntrypoint)) return { command: process.execPath, args: [adjacentEntrypoint, ...
|
|
71
|
+
if (fileExists(adjacentEntrypoint)) return { command: process.execPath, args: [adjacentEntrypoint, ...args] }
|
|
59
72
|
for (const root of roots) {
|
|
60
73
|
try {
|
|
61
74
|
const entrypoint = resolvePackage('@deepseek-ai/dsh/lib/bin.js', { paths: [root] })
|
|
62
|
-
return { command: process.execPath, args: [entrypoint, ...
|
|
75
|
+
return { command: process.execPath, args: [entrypoint, ...args] }
|
|
63
76
|
} catch {
|
|
64
77
|
// The next configured global prefix may own DSH instead.
|
|
65
78
|
}
|
|
@@ -67,6 +80,86 @@ export function dshCommand(args, {
|
|
|
67
80
|
return undefined
|
|
68
81
|
}
|
|
69
82
|
|
|
83
|
+
/** Resolve the normal TUI boot command. */
|
|
84
|
+
export function dshCommand(args, options = {}) {
|
|
85
|
+
return rawDshCommand(profileArgs(args), options)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Static shell completion for wrapper commands and the TUI's local flags. */
|
|
89
|
+
export function completionScript(shell) {
|
|
90
|
+
const words = 'setup doctor completion update --help --version --resume --continue --session --mode --theme --image'
|
|
91
|
+
if (shell === 'bash') return `_deepseek_complete() { COMPREPLY=( $(compgen -W "${words}" -- "\${COMP_WORDS[COMP_CWORD]}") ); }\ncomplete -F _deepseek_complete deepseek dsh-code`
|
|
92
|
+
if (shell === 'zsh') return `#compdef deepseek dsh-code\n_arguments '1:command:(${words})'`
|
|
93
|
+
if (shell === 'powershell' || shell === 'pwsh') return `Register-ArgumentCompleter -Native -CommandName deepseek,dsh-code -ScriptBlock { param($wordToComplete) '${words}'.Split(' ') | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) } }`
|
|
94
|
+
throw new Error('completion needs one shell: bash, zsh, or powershell')
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function printDoctor(resolveCommand = rawDshCommand, spawnCommand = spawnSync) {
|
|
98
|
+
const checks = []
|
|
99
|
+
const [major, minor] = process.versions.node.split('.').map(Number)
|
|
100
|
+
checks.push({ ok: major > 22 || (major === 22 && minor >= 19), label: `Node ${process.versions.node}`, detail: 'requires ^22.19 or >=24' })
|
|
101
|
+
const command = resolveCommand(['--profile', 'cli', '--dump-config'])
|
|
102
|
+
checks.push({ ok: command !== undefined, label: '@deepseek-ai/dsh', detail: command === undefined ? 'not found beside dsh-code' : 'entrypoint resolved' })
|
|
103
|
+
checks.push({ ok: profileHasDshCode(), label: 'cli profile', detail: cliProfileDir() })
|
|
104
|
+
if (command !== undefined && profileHasDshCode()) {
|
|
105
|
+
const probe = spawnCommand(command.command, command.args, { encoding: 'utf8', windowsHide: true })
|
|
106
|
+
const output = String(probe.stdout ?? '')
|
|
107
|
+
checks.push({ ok: probe.status === 0 && output.includes('dsh-code'), label: 'composition', detail: probe.status === 0 ? 'dump-config contains dsh-code' : String(probe.stderr ?? '').trim() })
|
|
108
|
+
}
|
|
109
|
+
for (const check of checks) console.log(`${check.ok ? 'ok ' : 'fail'} ${check.label} - ${check.detail}`)
|
|
110
|
+
process.exitCode = checks.every(check => check.ok) ? 0 : 1
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function launchChild(command, args) {
|
|
114
|
+
const child = spawn(command, args, { stdio: 'inherit' })
|
|
115
|
+
child.once('error', error => {
|
|
116
|
+
console.error(`dsh-code: command failed: ${error.message}`)
|
|
117
|
+
process.exitCode = 1
|
|
118
|
+
})
|
|
119
|
+
child.once('exit', (code, signal) => { process.exitCode = code ?? (signal === null ? 0 : 1) })
|
|
120
|
+
return child
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Run one wrapper-owned operational command. */
|
|
124
|
+
export function launchOperation(args = process.argv.slice(2)) {
|
|
125
|
+
const operation = operationName(args)
|
|
126
|
+
if (operation === undefined) return undefined
|
|
127
|
+
if (operation === 'completion') {
|
|
128
|
+
try {
|
|
129
|
+
console.log(completionScript(args[1]))
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error(`dsh-code: ${error.message}`)
|
|
132
|
+
process.exitCode = 1
|
|
133
|
+
}
|
|
134
|
+
return true
|
|
135
|
+
}
|
|
136
|
+
if (operation === 'doctor') {
|
|
137
|
+
printDoctor()
|
|
138
|
+
return true
|
|
139
|
+
}
|
|
140
|
+
if (operation === 'setup') {
|
|
141
|
+
// pnpm deliberately delays unpinned packages during their first 24 hours.
|
|
142
|
+
// Setup must mount the exact globally installed release on launch day.
|
|
143
|
+
const command = rawDshCommand(['plugin', '--profile', 'cli', 'add', setupBundle(args)])
|
|
144
|
+
if (command === undefined) {
|
|
145
|
+
console.error('dsh-code: @deepseek-ai/dsh is not installed; run: npm install -g @deepseek-ai/dsh dsh-code')
|
|
146
|
+
process.exitCode = 1
|
|
147
|
+
return true
|
|
148
|
+
}
|
|
149
|
+
return launchChild(command.command, command.args)
|
|
150
|
+
}
|
|
151
|
+
if (args.includes('--apply')) {
|
|
152
|
+
return launchChild(process.platform === 'win32' ? 'npm.cmd' : 'npm', ['install', '-g', '@deepseek-ai/dsh', 'dsh-code'])
|
|
153
|
+
}
|
|
154
|
+
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm'
|
|
155
|
+
for (const name of ['@deepseek-ai/dsh', 'dsh-code']) {
|
|
156
|
+
const result = spawnSync(npm, ['view', name, 'version'], { encoding: 'utf8', windowsHide: true })
|
|
157
|
+
console.log(`${name}: ${result.status === 0 ? String(result.stdout).trim() : 'version check failed'}`)
|
|
158
|
+
}
|
|
159
|
+
console.log('Run `deepseek update --apply` to install the latest versions.')
|
|
160
|
+
return true
|
|
161
|
+
}
|
|
162
|
+
|
|
70
163
|
/** Launch the installed DSH CLI while preserving its exit status and stdio. */
|
|
71
164
|
export function launchDsh(
|
|
72
165
|
args = process.argv.slice(2),
|
|
@@ -101,5 +194,6 @@ export function launchDsh(
|
|
|
101
194
|
|
|
102
195
|
const entrypoint = process.argv[1]
|
|
103
196
|
if (entrypoint !== undefined && pathToFileURL(realpathSync(resolve(entrypoint))).href === import.meta.url) {
|
|
104
|
-
launchDsh()
|
|
197
|
+
if (operationName() === undefined) launchDsh()
|
|
198
|
+
else launchOperation()
|
|
105
199
|
}
|
package/cordis.patch.yml
CHANGED
|
@@ -69,7 +69,14 @@
|
|
|
69
69
|
- id: tool-todo
|
|
70
70
|
disabled: true
|
|
71
71
|
- id: tool-web
|
|
72
|
-
|
|
72
|
+
config:
|
|
73
|
+
# web_fetch is a core TUI capability, not an opt-in: the fetch provider
|
|
74
|
+
# (web-fetch-http below) needs no API key. The per-preset tool-web rows
|
|
75
|
+
# keep `fetch: false` on the agent plane; through the scope-layered tool
|
|
76
|
+
# registry the preset's web_search shadows the host's same-name tool while
|
|
77
|
+
# the host's web_fetch stays visible, so every model still sees both.
|
|
78
|
+
fetch: true
|
|
79
|
+
searchTimeoutMs: 60000
|
|
73
80
|
|
|
74
81
|
- insert:
|
|
75
82
|
# Code Mode is a core execution capability, not a Web component.
|
|
@@ -82,6 +89,13 @@
|
|
|
82
89
|
- id: session-reference
|
|
83
90
|
name: '@deepseek-ai/dsh-session-reference'
|
|
84
91
|
|
|
92
|
+
# Workspace @file mention discovery: a bounded per-agent fuzzy index over
|
|
93
|
+
# the session cwd (directory listing, symlink guards, tool/result
|
|
94
|
+
# invalidation). The TUI's @ completion consumes ctx.fileReferences
|
|
95
|
+
# instead of running its own workspace scan.
|
|
96
|
+
- id: file-reference-local
|
|
97
|
+
name: '@deepseek-ai/dsh-file-reference-local'
|
|
98
|
+
|
|
85
99
|
# The launcher supplies the shipped preset root beside its own config and
|
|
86
100
|
# the service also discovers the user's local preset root.
|
|
87
101
|
- id: agent-presets
|
|
@@ -89,6 +103,27 @@
|
|
|
89
103
|
config:
|
|
90
104
|
default: standard
|
|
91
105
|
|
|
106
|
+
# Cordis self-inspection (the shipped `cordis` agent preset's toolset):
|
|
107
|
+
# the host runner publishes the `dynamicCordisRunner`/`cordisInspect`
|
|
108
|
+
# services `tool-cordis` injects. Without this host row the preset mount
|
|
109
|
+
# fails ("1 row(s) did not activate: tool-cordis"), because models write
|
|
110
|
+
# composition through the agent plane but the runner is a host singleton.
|
|
111
|
+
- id: cordis-host-runner
|
|
112
|
+
name: '@deepseek-ai/dsh-cordis-host-runner'
|
|
113
|
+
|
|
114
|
+
# Anonymous public HTTP(S) fetch provider for web_fetch (no key): the web
|
|
115
|
+
# service and its search provider stay on the host plane (dsh-base), and
|
|
116
|
+
# this row is what makes fetching real URLs work out of the box.
|
|
117
|
+
- id: web-fetch-http
|
|
118
|
+
name: '@deepseek-ai/dsh-web-fetch-http'
|
|
119
|
+
|
|
120
|
+
# Interactive provider authorization. The base bundle supplies the
|
|
121
|
+
# credential store; mounting the neutral authorization seam wakes the
|
|
122
|
+
# login flows already registered by llm-pi-ai without coupling the TUI to
|
|
123
|
+
# any provider's OAuth or device-code protocol.
|
|
124
|
+
- id: authorization
|
|
125
|
+
name: '@deepseek-ai/dsh-authorization'
|
|
126
|
+
|
|
92
127
|
- id: tui-startup
|
|
93
128
|
name: 'dsh-code/startup'
|
|
94
129
|
|