u1s1-cli-cn 1.19.0 → 1.20.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.
@@ -12,10 +12,14 @@ import { siteOf } from "../site.js";
12
12
  import { loadPublicAgentRuntime, parseAgentConfig, readConfigCache } from "./agent-config.js";
13
13
  import { claudePaths } from "./claude.js";
14
14
  import { codexPaths } from "./codex.js";
15
- import { AGENT_PROFILES, agentsRoot, cliInstallHooks, notOpenText, printRuntimeFailure, printRuntimeNotes, } from "./launch.js";
15
+ import { dshPaths } from "./dsh.js";
16
+ import { AGENT_PROFILES, agentsRoot, cliInstallHooks, effectiveBrake, ensureDshNode, notOpenText, printRuntimeFailure, printRuntimeNotes, } from "./launch.js";
17
+ import { findNode } from "./node-runtime.js";
16
18
  import { readAgentPrefs } from "./prefs.js";
17
- import { bestInstallTarget, checkBrake, compareVersions, dailyUpdateCheck, ensureAgentRuntime, fetchLatestVersion, findOnPath, installedVersions, MANAGED_AGENTS, NO_BRAKE, normalizeVersion, npmRegistryFor, probeVersion, readRuntimeState, runtimeSpec, updateRuntimeState, } from "./runtime.js";
19
+ import { bestInstallTarget, checkBrake, compareVersions, DSH_TESTED_VERSION, dailyUpdateCheck, ensureAgentRuntime, fetchLatestVersion, findOnPath, installedVersions, MANAGED_AGENTS, NO_BRAKE, normalizeVersion, npmRegistryFor, probeVersion, readRuntimeState, runtimeSpec, updateRuntimeState, } from "./runtime.js";
18
20
  export function launchPaths(agent) {
21
+ if (agent === "dsh")
22
+ return dshPaths();
19
23
  return agent === "codex" ? codexPaths() : claudePaths();
20
24
  }
21
25
  function cachedConfig(agent) {
@@ -24,7 +28,18 @@ function cachedConfig(agent) {
24
28
  return cached ? parseAgentConfig(cached.body, AGENT_PROFILES[agent].gatewayAgent) : undefined;
25
29
  }
26
30
  function cachedBrake(agent) {
27
- return cachedConfig(agent)?.runtime ?? NO_BRAKE;
31
+ return effectiveBrake(agent, cachedConfig(agent)?.runtime ?? NO_BRAKE);
32
+ }
33
+ /** 探测 dsh 这类 JS 入口的客户端时用的 Node:只找、不下载;找不到就不探测。 */
34
+ function probeNode(agent) {
35
+ if (!runtimeSpec(agent).minNode)
36
+ return undefined;
37
+ try {
38
+ return findNode(agentsRoot())?.bin;
39
+ }
40
+ catch {
41
+ return undefined;
42
+ }
28
43
  }
29
44
  function verdictText(v, brake) {
30
45
  if (v === "blocked")
@@ -49,7 +64,8 @@ async function managedAgentLines(agent) {
49
64
  const site = siteOf(cfg);
50
65
  const spec = runtimeSpec(agent);
51
66
  const cached = cachedConfig(agent);
52
- const brake = cached?.runtime ?? NO_BRAKE;
67
+ const brake = effectiveBrake(agent, cached?.runtime ?? NO_BRAKE);
68
+ const node = probeNode(agent);
53
69
  const paths = launchPaths(agent);
54
70
  const state = readRuntimeState(paths);
55
71
  const installed = installedVersions(paths, spec);
@@ -59,7 +75,7 @@ async function managedAgentLines(agent) {
59
75
  // 探测用户自己的命令时把配置目录指到启动器自己的目录(CODEX_HOME 指向不存在的目录时 Codex 会报错)
60
76
  if (envBin || pathBin)
61
77
  mkdirSync(paths.configDir, { recursive: true, mode: 0o700 });
62
- const pathVersion = pathBin ? probeVersion(pathBin, paths.configDir, spec) : undefined;
78
+ const pathVersion = pathBin ? probeVersion(pathBin, paths.configDir, spec, node) : undefined;
63
79
  const latest = await fetchLatestVersion(npmRegistryFor(site.id), spec.npmPackage);
64
80
  const autoUpdate = readAgentPrefs(agent).autoUpdate;
65
81
  const lines = [];
@@ -67,7 +83,7 @@ async function managedAgentLines(agent) {
67
83
  lines.push(tr(`暂不可用:${cached.disabledReason ?? notOpenText()}`, `Not available: ${cached.disabledReason ?? notOpenText()}`));
68
84
  }
69
85
  if (envBin) {
70
- const v = probeVersion(envBin, paths.configDir, spec);
86
+ const v = probeVersion(envBin, paths.configDir, spec, node);
71
87
  lines.push(tr(`使用 ${spec.binEnv} 指定的 ${envBin}(${v ?? "无法运行"})`, `Using ${envBin} from ${spec.binEnv} (${v ?? "doesn't run"})`));
72
88
  if (v && checkBrake(v, brake) === "above_max_tested") {
73
89
  lines.push(tr(`它${verdictText("above_max_tested", brake)},运行时改用 u1s1 管理的版本`, `It's ${verdictText("above_max_tested", brake)}; u1s1 ${agent} uses a u1s1-managed copy instead`));
@@ -116,7 +132,7 @@ async function managedAgentLines(agent) {
116
132
  }
117
133
  return lines;
118
134
  }
119
- const PIN_EXAMPLE = { claude: "2.1.322", codex: "0.167.2" };
135
+ const PIN_EXAMPLE = { claude: "2.1.322", codex: "0.167.2", dsh: DSH_TESTED_VERSION };
120
136
  export async function pinCommand(raw, agent = "claude") {
121
137
  const version = normalizeVersion(raw);
122
138
  if (!version) {
@@ -196,6 +212,7 @@ export async function installCommand(deps = {}, agent = "claude") {
196
212
  return got;
197
213
  brake = got;
198
214
  }
215
+ brake = effectiveBrake(agent, brake);
199
216
  const paths = launchPaths(agent);
200
217
  const spec = runtimeSpec(agent);
201
218
  mkdirSync(paths.configDir, { recursive: true, mode: 0o700 });
@@ -210,6 +227,13 @@ export async function installCommand(deps = {}, agent = "claude") {
210
227
  force: true,
211
228
  }).catch(() => undefined);
212
229
  }
230
+ // dsh:先准备够新的 Node(没有就征得同意后下载)
231
+ let node;
232
+ if (spec.minNode) {
233
+ node = (deps.ensureNode ? await deps.ensureNode() : await ensureDshNode(site.id))?.bin;
234
+ if (!node)
235
+ return 1;
236
+ }
213
237
  let runtime;
214
238
  try {
215
239
  runtime = await (deps.ensure ?? ensureAgentRuntime)(agent, {
@@ -218,6 +242,7 @@ export async function installCommand(deps = {}, agent = "claude") {
218
242
  agentsRoot: agentsRoot(),
219
243
  hooks: cliInstallHooks(agent),
220
244
  probeConfigDir: paths.configDir,
245
+ node,
221
246
  });
222
247
  }
223
248
  catch (e) {
@@ -1,4 +1,4 @@
1
- declare const CLIENTS: readonly ["claude", "codex"];
1
+ declare const CLIENTS: readonly ["claude", "codex", "dsh"];
2
2
  type Client = (typeof CLIENTS)[number];
3
3
  export type ConfigKey = "default-client" | "pi.model" | `${Client}.model` | `${Client}.auto-update` | `${Client}.pin`;
4
4
  export declare const CONFIG_KEYS: readonly ConfigKey[];
@@ -9,14 +9,16 @@
9
9
  * u1s1 config unset <键> 恢复默认
10
10
  *
11
11
  * 键:
12
- * default-client pi | claude | codex 同 u1s1 use
12
+ * default-client pi | claude | codex | dsh 同 u1s1 use
13
13
  * pi.model 模型 id 或别名 同 u1s1 model <模型>
14
14
  * claude.model 模型 id u1s1 claude 的默认模型(--settings 的 model)
15
15
  * codex.model 模型 id u1s1 codex 的默认模型(config.toml 的 model)
16
+ * dsh.model 模型 id u1s1 dsh 的默认模型(--patch 里 agent-default-model)
16
17
  * claude.auto-update on | off 每天查新、下次启动前更新;缺省 on
17
18
  * codex.auto-update on | off
18
19
  * claude.pin 版本号 同 u1s1 agents pin / unpin
19
20
  * codex.pin 版本号
21
+ * dsh.auto-update / dsh.pin 同上
20
22
  *
21
23
  * 客户端的模型只按网关上次下发的阵容(启动配置缓存)核对:还没启动过、没有缓存时照收,启动时再核对,
22
24
  * 不在阵容里就退回默认模型并提示一次(prefs.ts)。
@@ -25,23 +27,26 @@ import { existsSync } from "node:fs";
25
27
  import { createInterface } from "node:readline/promises";
26
28
  import { agentSettingsFile, isDefaultAgent, loadConfig, readRawConfigFile, saveDefaultAgent, } from "./config.js";
27
29
  import { tr } from "./i18n.js";
28
- const CLIENTS = ["claude", "codex"];
30
+ const CLIENTS = ["claude", "codex", "dsh"];
29
31
  export const CONFIG_KEYS = [
30
32
  "default-client",
31
33
  "pi.model",
32
34
  "claude.model",
33
35
  "codex.model",
36
+ "dsh.model",
34
37
  "claude.auto-update",
35
38
  "codex.auto-update",
39
+ "dsh.auto-update",
36
40
  "claude.pin",
37
41
  "codex.pin",
42
+ "dsh.pin",
38
43
  ];
39
44
  export function isConfigKey(value) {
40
45
  return typeof value === "string" && CONFIG_KEYS.includes(value);
41
46
  }
42
47
  function clientOf(key) {
43
48
  const prefix = key.split(".")[0];
44
- return prefix === "claude" || prefix === "codex" ? prefix : undefined;
49
+ return CLIENTS.includes(prefix ?? "") ? prefix : undefined;
45
50
  }
46
51
  function describe(key) {
47
52
  const client = clientOf(key);
@@ -100,7 +105,8 @@ async function cachedLineup(client) {
100
105
  // 自定义端点的模型(ep…/<模型>)也能选:按上次拉到的端点缓存核对,不联网
101
106
  const { agentCustomModels } = await import("./agents/custom-models.js");
102
107
  const { loadEndpointsCache } = await import("./config.js");
103
- const custom = agentCustomModels(loadEndpointsCache()).map((c) => c.id);
108
+ // dsh 走 /v1/chat/completions,本地路由只转 /v1/messages、/v1/responses:不列自定义模型
109
+ const custom = client === "dsh" ? [] : agentCustomModels(loadEndpointsCache()).map((c) => c.id);
104
110
  return { ids: [...config.models.map((m) => m.id), ...custom], defaultModel: config.defaultModel };
105
111
  }
106
112
  function parseSwitch(value) {
@@ -121,7 +127,7 @@ export async function writeConfigValue(key, value) {
121
127
  return 0;
122
128
  }
123
129
  if (!isDefaultAgent(value)) {
124
- console.error(tr("default-client 只能是 pi、claude 或 codex。", "default-client must be pi, claude or codex."));
130
+ console.error(tr("default-client 只能是 pi、claude、codex 或 dsh。", "default-client must be pi, claude, codex or dsh."));
125
131
  return 1;
126
132
  }
127
133
  saveDefaultAgent(value);
@@ -196,11 +202,11 @@ export function configHelpLines() {
196
202
  ["u1s1 config unset <键>", tr("恢复默认", "Restore the default")],
197
203
  ];
198
204
  const keyRows = [
199
- ["default-client", "pi | claude | codex"],
205
+ ["default-client", "pi | claude | codex | dsh"],
200
206
  ["pi.model", tr("模型 id 或别名", "model id or alias")],
201
- ["claude.model, codex.model", tr("模型 id;default = 跟随网关默认", "model id; default = gateway default")],
202
- ["claude.auto-update, codex.auto-update", "on | off"],
203
- ["claude.pin, codex.pin", tr("版本号", "version")],
207
+ ["claude.model, codex.model, dsh.model", tr("模型 id;default = 跟随网关默认", "model id; default = gateway default")],
208
+ ["<client>.auto-update", "on | off (claude / codex / dsh)"],
209
+ ["<client>.pin", tr("版本号(claude / codex / dsh)", "version (claude / codex / dsh)")],
204
210
  ];
205
211
  const usage = rows.map(([a, b]) => ` ${tr(a, a.replace("<键>", "<key>").replace("<值>", "<value>")).padEnd(30)}${b}`);
206
212
  return [
@@ -269,7 +275,7 @@ function padDisplay(text, width) {
269
275
  async function choicesFor(key) {
270
276
  const client = clientOf(key);
271
277
  if (key === "default-client") {
272
- return ["pi", "claude", "codex"].map((a) => ({ label: a, value: a }));
278
+ return ["pi", "claude", "codex", "dsh"].map((a) => ({ label: a, value: a }));
273
279
  }
274
280
  if (key.endsWith(".auto-update")) {
275
281
  return [
package/dist/config.d.ts CHANGED
@@ -211,7 +211,7 @@ export interface CliConfig {
211
211
  /** 默认客户端(`u1s1 use`/首次选择器写入);缺省 = 存量用户,按 Pi 处理(见 launcher.ts)。 */
212
212
  defaultAgent?: DefaultAgent;
213
213
  }
214
- export type DefaultAgent = "pi" | "claude" | "codex";
214
+ export type DefaultAgent = "pi" | "claude" | "codex" | "dsh";
215
215
  export declare function isDefaultAgent(value: unknown): value is DefaultAgent;
216
216
  export declare const u1s1Dir: string;
217
217
  export declare const configFile: string;
package/dist/config.js CHANGED
@@ -322,7 +322,7 @@ export function findModel(query) {
322
322
  return undefined;
323
323
  }
324
324
  export function isDefaultAgent(value) {
325
- return value === "pi" || value === "claude" || value === "codex";
325
+ return value === "pi" || value === "claude" || value === "codex" || value === "dsh";
326
326
  }
327
327
  export const u1s1Dir = join(homedir(), ".u1s1");
328
328
  export const configFile = join(u1s1Dir, "config.json");
@@ -77,7 +77,7 @@ export interface CustomRoutes {
77
77
  * their own: the Gateway still requires the DPoP proof and a valid attestation.
78
78
  */
79
79
  export interface LaunchedAgent {
80
- name: "pi" | "claude-code" | "codex";
80
+ name: "pi" | "claude-code" | "codex" | "dsh";
81
81
  /** The client's own version (e.g. Claude Code `2.1.322`), not the CLI's. */
82
82
  version?: string;
83
83
  }
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ import { printConsoleBanner } from "./brand.js";
11
11
  import { activeSite, loadConfig, pinLegacySiteBaseUrl, readSettings, VERSION } from "./config.js";
12
12
  import { siteLinks, siteOf } from "./site.js";
13
13
  import { isEnglish, tr } from "./i18n.js";
14
- import { isLauncherWord, launcherHelpRow, runLauncher } from "./launcher.js";
14
+ import { dshHelpRow, isLauncherWord, launcherHelpRow, runLauncher } from "./launcher.js";
15
15
  /**
16
16
  * Configure the same undici dispatcher used by the embedded kernel before any
17
17
  * CLI startup request runs. The kernel keeps this helper in an internal file,
@@ -41,6 +41,7 @@ function printHelp() {
41
41
  const rows = [
42
42
  [tr("u1s1 -p \"一句话\"", "u1s1 -p \"prompt\""), tr("不进界面直接回答(脚本里用)", "Answer once without the UI (for scripts)")],
43
43
  launcherHelpRow(),
44
+ dshHelpRow(),
44
45
  ["u1s1 login / logout", tr("登录 / 退出", "Sign in / sign out")],
45
46
  ["u1s1 usage", tr("查看剩余额度", "Show your remaining balance")],
46
47
  ["u1s1 model", tr("查看或切换默认模型", "Show or change the default model")],
@@ -236,7 +237,7 @@ async function run() {
236
237
  await COMMANDS[cmd](rest);
237
238
  return;
238
239
  }
239
- // pi / claude / codex / use / agents / config:启动器的保留字,先于拼错检测
240
+ // pi / claude / codex / dsh / use / agents / config:启动器的保留字,先于拼错检测
240
241
  if (cmd && isLauncherWord(cmd)) {
241
242
  await runLauncher(args);
242
243
  return;
@@ -1,7 +1,7 @@
1
1
  import { type DefaultAgent } from "./config.js";
2
2
  export type AgentChoice = DefaultAgent;
3
3
  /** 启动器的保留字:不会再当 prompt 交给默认客户端。 */
4
- export declare const LAUNCHER_WORDS: readonly ["pi", "claude", "codex", "use", "agents", "config"];
4
+ export declare const LAUNCHER_WORDS: readonly ["pi", "claude", "codex", "dsh", "use", "agents", "config"];
5
5
  export declare function isLauncherWord(word: string): boolean;
6
6
  export type Dispatch = {
7
7
  kind: "agent";
@@ -44,3 +44,7 @@ export declare function runLauncher(args: string[]): Promise<void>;
44
44
  export declare function parseSelection(answer: string): AgentChoice | undefined;
45
45
  /** `u1s1 --help` 里启动器那一行;use / agents / config 只在「其他命令」里报名字,各自 --help 看用法。 */
46
46
  export declare function launcherHelpRow(): [string, string];
47
+ /**
48
+ * `u1s1 --help` 里 dsh 单独一行(它没有终端界面,默认进网页界面)。Hearth 按这一行判断 CLI 支不支持 `u1s1 dsh`。
49
+ */
50
+ export declare function dshHelpRow(): [string, string];
package/dist/launcher.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * 启动器:选择器与分发。一个命令 `u1s1`,可以启动内置的 Pi,也可以启动用户机器上的官方原版客户端。
3
3
  *
4
- * u1s1 pi|claude|codex [参数…] 指定客户端,后面的参数原样传给它
4
+ * u1s1 pi|claude|codex|dsh [参数…] 指定客户端,后面的参数原样传给它(dsh 不带子命令时进网页界面)
5
5
  * u1s1 [参数…] 默认客户端;存量用户(已有配置、没有默认客户端字段)默认 Pi,
6
6
  * 全新用户首次运行出选择器并记住
7
7
  * u1s1 use <客户端> 改默认
@@ -9,7 +9,7 @@
9
9
  * u1s1 agents models [--json] 各客户端可用的模型(带显示名),给 Hearth 等前端用;不登录、秒回
10
10
  * u1s1 config [list|get|set|unset …] 用户可调的设置(默认客户端、各客户端默认模型、自动更新),见 config-command.ts
11
11
  *
12
- * claude / codex 是否可用完全由网关配置(/v1/agents/:agent/config 的 enabled)决定,这里不写死。
12
+ * claude / codex / dsh 是否可用完全由网关配置(/v1/agents/:agent/config 的 enabled)决定,这里不写死。
13
13
  *
14
14
  * 现有子命令(login、usage、model、update、deploy 等)在 index.ts 里先于这里处理,行为不变。
15
15
  */
@@ -18,7 +18,7 @@ import { createInterface } from "node:readline/promises";
18
18
  import { agentSettingsFile, isDefaultAgent, loadConfig, readRawConfigFile, saveDefaultAgent, } from "./config.js";
19
19
  import { tr } from "./i18n.js";
20
20
  /** 启动器的保留字:不会再当 prompt 交给默认客户端。 */
21
- export const LAUNCHER_WORDS = ["pi", "claude", "codex", "use", "agents", "config"];
21
+ export const LAUNCHER_WORDS = ["pi", "claude", "codex", "dsh", "use", "agents", "config"];
22
22
  export function isLauncherWord(word) {
23
23
  return LAUNCHER_WORDS.includes(word);
24
24
  }
@@ -33,6 +33,7 @@ export function resolveDispatch(args, ctx) {
33
33
  case "pi":
34
34
  case "claude":
35
35
  case "codex":
36
+ case "dsh":
36
37
  return { kind: "agent", agent: first, args: rest, via: "explicit" };
37
38
  case "use":
38
39
  return { kind: "use", args: rest };
@@ -104,7 +105,9 @@ async function launch(agent, args) {
104
105
  }
105
106
  const code = agent === "codex"
106
107
  ? await (await import("./agents/codex.js")).runCodex(args)
107
- : await (await import("./agents/claude.js")).runClaude(args);
108
+ : agent === "dsh"
109
+ ? await (await import("./agents/dsh.js")).runDsh(args)
110
+ : await (await import("./agents/claude.js")).runClaude(args);
108
111
  // 签名代理是 unref 的,子进程退出后不必等;直接带着子进程的退出码退出
109
112
  process.exit(code);
110
113
  }
@@ -121,6 +124,10 @@ const OPTIONS = [
121
124
  agent: "codex",
122
125
  line: () => tr("codex 官方 Codex CLI,首次使用时下载", "codex Official Codex CLI, downloaded on first use"),
123
126
  },
127
+ {
128
+ agent: "dsh",
129
+ line: () => tr("dsh DeepSeek Harness(网页界面),首次使用时下载", "dsh DeepSeek Harness (web UI), downloaded on first use"),
130
+ },
124
131
  ];
125
132
  export function parseSelection(answer) {
126
133
  const a = answer.trim().toLowerCase();
@@ -152,7 +159,7 @@ async function selectAgent() {
152
159
  function useCommand(args) {
153
160
  const target = args[0];
154
161
  if (!isDefaultAgent(target)) {
155
- console.error(tr("用法: u1s1 use <pi|claude|codex>", "Usage: u1s1 use <pi|claude|codex>"));
162
+ console.error(tr("用法: u1s1 use <pi|claude|codex|dsh>", "Usage: u1s1 use <pi|claude|codex|dsh>"));
156
163
  process.exitCode = target === undefined || target === "--help" || target === "-h" ? 0 : 1;
157
164
  return;
158
165
  }
@@ -168,10 +175,10 @@ async function agentsCommand(args) {
168
175
  return;
169
176
  }
170
177
  if (sub === "pin" || sub === "unpin") {
171
- if (agent !== "claude" && agent !== "codex") {
178
+ if (agent !== "claude" && agent !== "codex" && agent !== "dsh") {
172
179
  console.error(sub === "pin"
173
- ? tr("用法: u1s1 agents pin <claude|codex> <版本>", "Usage: u1s1 agents pin <claude|codex> <version>")
174
- : tr("用法: u1s1 agents unpin <claude|codex>", "Usage: u1s1 agents unpin <claude|codex>"));
180
+ ? tr("用法: u1s1 agents pin <claude|codex|dsh> <版本>", "Usage: u1s1 agents pin <claude|codex|dsh> <version>")
181
+ : tr("用法: u1s1 agents unpin <claude|codex|dsh>", "Usage: u1s1 agents unpin <claude|codex|dsh>"));
175
182
  process.exitCode = 1;
176
183
  return;
177
184
  }
@@ -190,8 +197,8 @@ async function agentsCommand(args) {
190
197
  console.log(tr("pi 随 u1s1 一起安装,不用单独下载。", "pi ships with u1s1; nothing to download."));
191
198
  return;
192
199
  }
193
- if ((agent !== "claude" && agent !== "codex") || version !== undefined) {
194
- console.error(tr("用法: u1s1 agents install <claude|codex>", "Usage: u1s1 agents install <claude|codex>"));
200
+ if ((agent !== "claude" && agent !== "codex" && agent !== "dsh") || version !== undefined) {
201
+ console.error(tr("用法: u1s1 agents install <claude|codex|dsh>", "Usage: u1s1 agents install <claude|codex|dsh>"));
195
202
  process.exitCode = 1;
196
203
  return;
197
204
  }
@@ -212,7 +219,7 @@ function agentsHelpLines() {
212
219
  return [
213
220
  tr("用法:", "Usage:"),
214
221
  tr(" u1s1 agents 查看各客户端的安装状态、版本、是否有更新", " u1s1 agents Show each client's install status, version and updates"),
215
- tr(" u1s1 agents install <客户端> 下载或更新到可用版本,不启动(claude / codex)", " u1s1 agents install <client> Download or update to a usable version without launching (claude / codex)"),
222
+ tr(" u1s1 agents install <客户端> 下载或更新到可用版本,不启动(claude / codex / dsh)", " u1s1 agents install <client> Download or update to a usable version without launching (claude / codex / dsh)"),
216
223
  tr(" u1s1 agents pin <客户端> <版本> 锁定版本(不超出允许的范围)", " u1s1 agents pin <client> <ver> Pin a version (within the allowed range)"),
217
224
  tr(" u1s1 agents unpin <客户端> 解除锁定,恢复自动更新", " u1s1 agents unpin <client> Remove the pin and resume automatic updates"),
218
225
  tr(" u1s1 agents models [--json] 列出各客户端可用的模型(带显示名);--offline 只读本地缓存", " u1s1 agents models [--json] List each client's models with display names; --offline reads local caches only"),
@@ -223,3 +230,12 @@ function agentsHelpLines() {
223
230
  export function launcherHelpRow() {
224
231
  return ["u1s1 pi|claude|codex", tr("用指定客户端启动,后面的参数原样传入", "Start a specific client; extra args are passed through")];
225
232
  }
233
+ /**
234
+ * `u1s1 --help` 里 dsh 单独一行(它没有终端界面,默认进网页界面)。Hearth 按这一行判断 CLI 支不支持 `u1s1 dsh`。
235
+ */
236
+ export function dshHelpRow() {
237
+ return [
238
+ "u1s1 dsh [web|headless]",
239
+ tr("启动 DeepSeek Harness;不带子命令时打开网页界面,参数原样传入", "Start DeepSeek Harness; opens its web UI by default, extra args are passed through"),
240
+ ];
241
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "u1s1-cli-cn",
3
- "version": "1.19.0",
3
+ "version": "1.20.1",
4
4
  "description": "u1s1 — 有一说一,最省心的 AI 编程搭子。终端里用中文说需求,AI 帮你读文件、改代码、跑命令。",
5
5
  "type": "module",
6
6
  "bin": {