u1s1-cli-cn 1.18.0 → 1.20.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.
Files changed (43) hide show
  1. package/dist/agents/agent-config.d.ts +1 -1
  2. package/dist/agents/agent-config.js +1 -1
  3. package/dist/agents/claude.d.ts +4 -1
  4. package/dist/agents/claude.js +6 -3
  5. package/dist/agents/codex.d.ts +4 -1
  6. package/dist/agents/codex.js +6 -3
  7. package/dist/agents/custom-models.d.ts +61 -0
  8. package/dist/agents/custom-models.js +175 -0
  9. package/dist/agents/dsh.d.ts +90 -0
  10. package/dist/agents/dsh.js +243 -0
  11. package/dist/agents/launch.d.ts +24 -2
  12. package/dist/agents/launch.js +115 -15
  13. package/dist/agents/models-list.d.ts +65 -0
  14. package/dist/agents/models-list.js +297 -0
  15. package/dist/agents/node-runtime.d.ts +91 -0
  16. package/dist/agents/node-runtime.js +223 -0
  17. package/dist/agents/runtime.d.ts +26 -3
  18. package/dist/agents/runtime.js +50 -14
  19. package/dist/agents/status.d.ts +4 -0
  20. package/dist/agents/status.js +32 -7
  21. package/dist/api.d.ts +2 -0
  22. package/dist/chat-protocol/anthropic.d.ts +29 -0
  23. package/dist/chat-protocol/anthropic.js +484 -0
  24. package/dist/chat-protocol/json.d.ts +20 -0
  25. package/dist/chat-protocol/json.js +22 -0
  26. package/dist/chat-protocol/responses.d.ts +97 -0
  27. package/dist/chat-protocol/responses.js +1076 -0
  28. package/dist/chat-protocol/sse.d.ts +19 -0
  29. package/dist/chat-protocol/sse.js +67 -0
  30. package/dist/chat-protocol/thinking.d.ts +22 -0
  31. package/dist/chat-protocol/thinking.js +58 -0
  32. package/dist/config-command.d.ts +1 -1
  33. package/dist/config-command.js +20 -10
  34. package/dist/config.d.ts +23 -1
  35. package/dist/config.js +52 -1
  36. package/dist/custom-endpoint-proxy.d.ts +92 -0
  37. package/dist/custom-endpoint-proxy.js +461 -0
  38. package/dist/device-auth.d.ts +14 -3
  39. package/dist/device-auth.js +36 -2
  40. package/dist/index.js +12 -3
  41. package/dist/launcher.d.ts +5 -1
  42. package/dist/launcher.js +35 -11
  43. package/package.json +1 -1
@@ -32,7 +32,7 @@ export declare const allowedByBrake: (v: string, brake: RuntimeBrake) => boolean
32
32
  * latest 超过 max_tested 时自然退到 max_tested(它是测过的版本,必然已发布)。
33
33
  */
34
34
  export declare function bestInstallTarget(candidates: Array<string | undefined>, brake: RuntimeBrake): string | undefined;
35
- export type ManagedAgent = "claude" | "codex";
35
+ export type ManagedAgent = "claude" | "codex" | "dsh";
36
36
  export declare const MANAGED_AGENTS: readonly ManagedAgent[];
37
37
  export declare function isManagedAgent(value: unknown): value is ManagedAgent;
38
38
  /** 平台二进制所在的 npm 包:装进 node_modules 的目录名,以及它在 npm 源上的名字和版本。 */
@@ -60,6 +60,16 @@ export interface AgentRuntimeSpec {
60
60
  platformPackage: (version: string, platform: NodeJS.Platform, arch: string, musl: boolean) => PlatformPackageRef | undefined;
61
61
  /** 可执行文件在 node_modules 下的相对路径(posix 写法);不支持的系统/架构返回 undefined */
62
62
  binInNodeModules: (platform: NodeJS.Platform, arch: string, musl: boolean) => string | undefined;
63
+ /**
64
+ * 入口是 JS 文件、要用不低于这个版本的 Node 运行(dsh:engines.node >=24.9.0)。探测版本、npm 的
65
+ * postinstall 和启动都用调用方给的那个 node(EnsureRuntimeOptions.node);没给就当跑不起来。
66
+ */
67
+ minNode?: string;
68
+ /** 没有单独的平台包、npm 元数据量不出整棵依赖树时,首次下载前提示的大致大小(字节) */
69
+ sizeHint?: {
70
+ downloadBytes: number;
71
+ unpackedBytes: number;
72
+ };
63
73
  }
64
74
  /**
65
75
  * 官方包的 bin 就是 `bin/claude.exe`(各平台同名):postinstall 把对应平台的原生二进制
@@ -74,6 +84,15 @@ export declare const CLAUDE_RUNTIME: AgentRuntimeSpec;
74
84
  * 让它提示用 npm 升级;更新由启动器管,不需要)。原生二进制按自己所在目录找 rg 等附带文件。
75
85
  */
76
86
  export declare const CODEX_RUNTIME: AgentRuntimeSpec;
87
+ /** dsh 实测过的版本;网关刹车没给 max_tested_version(老网关、老缓存)时也不越过它(dsh.ts)。 */
88
+ export declare const DSH_TESTED_VERSION = "0.2.2-rc.1";
89
+ /**
90
+ * DeepSeek Harness:`@deepseek-ai/dsh`(MIT)是纯 JS 包,bin 是 `lib/bin.js`,依赖树里的原生模块
91
+ * (node-pty 等)带各平台预编译文件,由 npm 的 postinstall 处理。没有单独的平台包,校验时
92
+ * 主包同时充当「平台包」。engines.node >=24.9.0:便携包自带的 Node 22 跑不了,由 node-runtime.ts
93
+ * 找/下载 Node 24。0.2.2-rc.1 实测:下载约 290 MB,装好约 920 MB。
94
+ */
95
+ export declare const DSH_RUNTIME: AgentRuntimeSpec;
77
96
  export declare function runtimeSpec(agent: ManagedAgent): AgentRuntimeSpec;
78
97
  export interface RuntimePaths {
79
98
  /** ~/.u1s1/agents/<agent> */
@@ -121,7 +140,7 @@ export declare function findOnPath(command: string, opts: {
121
140
  * 跑 `<bin> --version` 取版本。环境里去掉密钥、关掉自动更新;配置目录(CLAUDE_CONFIG_DIR /
122
141
  * CODEX_HOME)指到启动器自己的目录,免得探测用户自己装的客户端时碰到用户的 ~/.claude、~/.codex。
123
142
  */
124
- export declare function probeVersion(bin: string, configDir?: string, spec?: AgentRuntimeSpec): string | undefined;
143
+ export declare function probeVersion(bin: string, configDir?: string, spec?: AgentRuntimeSpec, node?: string): string | undefined;
125
144
  /** 版本高于 max_tested、这次没用上的那份客户端(给用户解释为什么换版本 / 另装一份)。 */
126
145
  export interface SkippedRuntime extends FoundRuntime {
127
146
  maxTestedVersion: string;
@@ -274,6 +293,8 @@ export interface InstallOptions {
274
293
  retryDelayMs?: number;
275
294
  /** 校验时跑 --version 用的隔离配置目录(CLAUDE_CONFIG_DIR / CODEX_HOME) */
276
295
  probeConfigDir?: string;
296
+ /** spec.minNode 时运行入口、npm 及其 postinstall 用的 Node */
297
+ node?: string;
277
298
  }
278
299
  /**
279
300
  * 装一个确切版本:npm install 到暂存目录 → 校验(锁文件里的 integrity 与 registry 元数据一致、
@@ -329,6 +350,8 @@ export interface EnsureRuntimeOptions {
329
350
  install?: (opts: InstallOptions) => Promise<FoundRuntime>;
330
351
  /** 见 PlanInput.autoUpdate;缺省开 */
331
352
  autoUpdate?: boolean;
353
+ /** spec.minNode 的客户端(dsh)用来探测、安装的 Node(node-runtime.ts 找好的) */
354
+ node?: string;
332
355
  }
333
356
  export interface EnsuredRuntime extends FoundRuntime {
334
357
  /** pin 的版本被刹车挡住、已忽略 */
@@ -347,7 +370,7 @@ export declare class RuntimePlanError extends Error {
347
370
  }>);
348
371
  }
349
372
  /**
350
- * 找到(必要时下载或更新)可用的客户端运行时。CLI(`u1s1 claude` / `u1s1 codex`)与桌面端共用。
373
+ * 找到(必要时下载或更新)可用的客户端运行时。CLI(`u1s1 claude` / `u1s1 codex` / `u1s1 dsh`)与桌面端共用。
351
374
  * 失败抛 RuntimePlanError(刹车/版本问题)或 RuntimeInstallError(下载问题)。
352
375
  */
353
376
  export declare function ensureAgentRuntime(agent: ManagedAgent, opts: EnsureRuntimeOptions): Promise<EnsuredRuntime>;
@@ -5,7 +5,8 @@
5
5
  * 用户确认后才下载;不打进我们的包、不改二进制、不动它自带的登录方式。
6
6
  * 安装交给 npm(`npm install --prefix`),上游调整包结构(平台二进制、postinstall)由 npm 处理。
7
7
  *
8
- * 目录布局(以 claude 为例;codex 同理,可执行文件在平台包里,见 CODEX_RUNTIME):
8
+ * 目录布局(以 claude 为例;codex 同理,可执行文件在平台包里,见 CODEX_RUNTIME;dsh 的入口是 JS 文件,
9
+ * 由 Node ≥24.9 运行,见 DSH_RUNTIME 与 node-runtime.ts):
9
10
  * ~/.u1s1/agents/claude/runtime/<版本>/node_modules/@anthropic-ai/claude-code/bin/claude.exe
10
11
  * ~/.u1s1/agents/claude/state.json 当前版本、pin、每日检查时间、待更新版本
11
12
  * ~/.u1s1/agents/claude/config/ CLAUDE_CONFIG_DIR(见 claude.ts;codex 是 home/,见 codex.ts)
@@ -128,9 +129,9 @@ export function bestInstallTarget(candidates, brake) {
128
129
  }
129
130
  return best;
130
131
  }
131
- export const MANAGED_AGENTS = ["claude", "codex"];
132
+ export const MANAGED_AGENTS = ["claude", "codex", "dsh"];
132
133
  export function isManagedAgent(value) {
133
- return value === "claude" || value === "codex";
134
+ return value === "claude" || value === "codex" || value === "dsh";
134
135
  }
135
136
  function npmOs(platform) {
136
137
  return platform === "win32" ? "win32" : platform === "darwin" ? "darwin" : platform === "linux" ? "linux" : undefined;
@@ -192,11 +193,37 @@ export const CODEX_RUNTIME = {
192
193
  return `@openai/codex-${os}-${arch}/vendor/${triple}/bin/${os === "win32" ? "codex.exe" : "codex"}`;
193
194
  },
194
195
  };
196
+ /** dsh 实测过的版本;网关刹车没给 max_tested_version(老网关、老缓存)时也不越过它(dsh.ts)。 */
197
+ export const DSH_TESTED_VERSION = "0.2.2-rc.1";
198
+ /**
199
+ * DeepSeek Harness:`@deepseek-ai/dsh`(MIT)是纯 JS 包,bin 是 `lib/bin.js`,依赖树里的原生模块
200
+ * (node-pty 等)带各平台预编译文件,由 npm 的 postinstall 处理。没有单独的平台包,校验时
201
+ * 主包同时充当「平台包」。engines.node >=24.9.0:便携包自带的 Node 22 跑不了,由 node-runtime.ts
202
+ * 找/下载 Node 24。0.2.2-rc.1 实测:下载约 290 MB,装好约 920 MB。
203
+ */
204
+ export const DSH_RUNTIME = {
205
+ agent: "dsh",
206
+ npmPackage: "@deepseek-ai/dsh",
207
+ command: "dsh",
208
+ binEnv: "U1S1_DSH_BIN",
209
+ configDirEnv: "DSH_HOME",
210
+ probeEnv: { DSH_TELEMETRY_DISABLED: "1" },
211
+ platformPackage: (version, platform, arch) => {
212
+ if (!npmOs(platform) || (arch !== "x64" && arch !== "arm64"))
213
+ return undefined;
214
+ return { dir: "@deepseek-ai/dsh", name: "@deepseek-ai/dsh", version };
215
+ },
216
+ binInNodeModules: (platform, arch) => npmOs(platform) && (arch === "x64" || arch === "arm64") ? "@deepseek-ai/dsh/lib/bin.js" : undefined,
217
+ minNode: "24.9.0",
218
+ sizeHint: { downloadBytes: 290 * 1024 * 1024, unpackedBytes: 920 * 1024 * 1024 },
219
+ };
195
220
  export function runtimeSpec(agent) {
196
221
  if (agent === "claude")
197
222
  return CLAUDE_RUNTIME;
198
223
  if (agent === "codex")
199
224
  return CODEX_RUNTIME;
225
+ if (agent === "dsh")
226
+ return DSH_RUNTIME;
200
227
  throw new Error(`unknown agent runtime: ${String(agent)}`);
201
228
  }
202
229
  export function runtimePaths(agentsRoot, agent) {
@@ -296,7 +323,7 @@ function isFile(p) {
296
323
  * 跑 `<bin> --version` 取版本。环境里去掉密钥、关掉自动更新;配置目录(CLAUDE_CONFIG_DIR /
297
324
  * CODEX_HOME)指到启动器自己的目录,免得探测用户自己装的客户端时碰到用户的 ~/.claude、~/.codex。
298
325
  */
299
- export function probeVersion(bin, configDir, spec = CLAUDE_RUNTIME) {
326
+ export function probeVersion(bin, configDir, spec = CLAUDE_RUNTIME, node) {
300
327
  const env = stripSecretEnv(process.env);
301
328
  for (const [key, value] of Object.entries(spec.probeEnv))
302
329
  env[key] = value;
@@ -304,8 +331,12 @@ export function probeVersion(bin, configDir, spec = CLAUDE_RUNTIME) {
304
331
  env[spec.configDirEnv] = configDir;
305
332
  else
306
333
  delete env[spec.configDirEnv];
334
+ // JS 入口(dsh):用调用方给的 Node 跑;没给就不试(系统 node 可能太旧,报出来的错不是版本号)
335
+ if (spec.minNode && !node)
336
+ return undefined;
337
+ const [command, args] = spec.minNode ? [node, [bin, "--version"]] : [bin, ["--version"]];
307
338
  try {
308
- const r = spawnSync(bin, ["--version"], { env, encoding: "utf8", timeout: 20_000, windowsHide: true });
339
+ const r = spawnSync(command, args, { env, encoding: "utf8", timeout: 20_000, windowsHide: true });
309
340
  if (r.status !== 0)
310
341
  return undefined;
311
342
  return versionFromOutput(`${r.stdout ?? ""}`);
@@ -548,7 +579,7 @@ export async function installRuntime(opts) {
548
579
  fetchPackageMeta(registry, spec.npmPackage, version),
549
580
  fetchPackageMeta(registry, plat.name, plat.version),
550
581
  ]);
551
- const downloadBytes = await downloadSize(platMeta?.tarball);
582
+ const downloadBytes = spec.sizeHint?.downloadBytes ?? await downloadSize(platMeta?.tarball);
552
583
  if (opts.needsConsent) {
553
584
  const ok = hooks.consent
554
585
  ? await hooks.consent({
@@ -557,17 +588,20 @@ export async function installRuntime(opts) {
557
588
  version,
558
589
  registry,
559
590
  downloadBytes,
560
- unpackedBytes: platMeta?.unpackedSize !== undefined
591
+ unpackedBytes: spec.sizeHint?.unpackedBytes ?? (platMeta?.unpackedSize !== undefined
561
592
  ? platMeta.unpackedSize + (mainMeta?.unpackedSize ?? 0)
562
- : undefined,
593
+ : undefined),
563
594
  })
564
595
  : false;
565
596
  if (!ok)
566
597
  throw new RuntimeInstallError("declined", hooks.text.declined());
567
598
  }
568
- const npm = opts.npm ?? findNpm({ execPath: process.execPath, platform: process.platform, env: process.env });
569
- if (!npm)
599
+ const found = opts.npm ?? findNpm({ execPath: process.execPath, platform: process.platform, env: process.env });
600
+ if (!found)
570
601
  throw new RuntimeInstallError("no_npm", hooks.text.noNpm());
602
+ // JS 入口的客户端:npm 本身和 postinstall 都用那个够新的 Node 跑(npm 按运行它的 Node 核对 engines)
603
+ const scriptNode = spec.minNode ? opts.node : undefined;
604
+ const npm = scriptNode && found.command === process.execPath ? { ...found, command: scriptNode } : found;
571
605
  mkdirSync(paths.runtimeDir, { recursive: true, mode: 0o700 });
572
606
  const maxAttempts = opts.maxAttempts ?? 3;
573
607
  const retryDelayMs = opts.retryDelayMs ?? 3_000;
@@ -584,6 +618,7 @@ export async function installRuntime(opts) {
584
618
  registry,
585
619
  progress: hooks.progress,
586
620
  totalBytes: downloadBytes,
621
+ node: scriptNode,
587
622
  });
588
623
  lastOutput = result.output;
589
624
  if (result.code !== 0) {
@@ -604,7 +639,7 @@ export async function installRuntime(opts) {
604
639
  platVersion: plat.version,
605
640
  mainMeta,
606
641
  platMeta,
607
- probe: (bin) => probeVersion(bin, opts.probeConfigDir, spec),
642
+ probe: (bin) => probeVersion(bin, opts.probeConfigDir, spec, opts.node),
608
643
  });
609
644
  if (problem) {
610
645
  rmSync(staging, { recursive: true, force: true });
@@ -724,7 +759,7 @@ export function npmEnv(base, execPath, platform = process.platform) {
724
759
  function runNpmInstall(npm, o) {
725
760
  return new Promise((resolve) => {
726
761
  const child = spawn(npm.command, [...npm.prefixArgs, ...npmInstallArgs(o)], {
727
- env: npmEnv(process.env, process.execPath),
762
+ env: npmEnv(process.env, o.node ?? process.execPath),
728
763
  stdio: ["ignore", "pipe", "pipe"],
729
764
  windowsHide: true,
730
765
  });
@@ -813,7 +848,7 @@ export class RuntimePlanError extends Error {
813
848
  }
814
849
  }
815
850
  /**
816
- * 找到(必要时下载或更新)可用的客户端运行时。CLI(`u1s1 claude` / `u1s1 codex`)与桌面端共用。
851
+ * 找到(必要时下载或更新)可用的客户端运行时。CLI(`u1s1 claude` / `u1s1 codex` / `u1s1 dsh`)与桌面端共用。
817
852
  * 失败抛 RuntimePlanError(刹车/版本问题)或 RuntimeInstallError(下载问题)。
818
853
  */
819
854
  export async function ensureAgentRuntime(agent, opts) {
@@ -821,7 +856,7 @@ export async function ensureAgentRuntime(agent, opts) {
821
856
  const paths = runtimePaths(opts.agentsRoot, agent);
822
857
  const env = opts.env ?? process.env;
823
858
  const registry = npmRegistryFor(opts.site, env);
824
- const probe = (bin) => probeVersion(bin, opts.probeConfigDir, spec);
859
+ const probe = (bin) => probeVersion(bin, opts.probeConfigDir, spec, opts.node);
825
860
  const state = readRuntimeState(paths);
826
861
  let latestMemo;
827
862
  const plan = await planRuntime({
@@ -867,6 +902,7 @@ export async function ensureAgentRuntime(agent, opts) {
867
902
  needsConsent: plan.needsConsent,
868
903
  hooks: opts.hooks,
869
904
  probeConfigDir: opts.probeConfigDir,
905
+ node: opts.node,
870
906
  });
871
907
  return { ...installed, ...extra };
872
908
  }
@@ -10,6 +10,10 @@ export interface InstallCommandDeps {
10
10
  fetchPublicRuntime?: (url: URL) => Promise<Response>;
11
11
  ensure?: typeof ensureAgentRuntime;
12
12
  checkLatest?: typeof dailyUpdateCheck;
13
+ /** dsh 的 Node;测试注入 */
14
+ ensureNode?: () => Promise<{
15
+ bin: string;
16
+ } | undefined>;
13
17
  }
14
18
  /**
15
19
  * `u1s1 agents install claude|codex`:找到或下载原版,不启动。与 `u1s1 claude` / `u1s1 codex` 走同一套
@@ -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) {
package/dist/api.d.ts CHANGED
@@ -91,6 +91,8 @@ export interface ApiEndpoint {
91
91
  vision?: boolean;
92
92
  context_window?: number;
93
93
  max_tokens?: number;
94
+ /** 推理参数格式(openai | deepseek);老服务端不下发,按 openai。见 config.ts CUSTOM_THINKING_FORMATS。 */
95
+ thinking_format?: string;
94
96
  }[];
95
97
  }
96
98
  /**
@@ -0,0 +1,29 @@
1
+ import { type JsonRecord } from "./json.ts";
2
+ import { type ReasoningFields } from "./thinking.ts";
3
+ export declare const MESSAGES_PATH = "/v1/messages";
4
+ /** Chat usage (any OpenAI-compatible shape) → Anthropic usage. */
5
+ export type AnthropicUsage = (usage: unknown) => JsonRecord;
6
+ /**
7
+ * Plain Chat Completions usage → Anthropic usage: cache reads
8
+ * (`prompt_tokens_details.cached_tokens`, or DeepSeek's
9
+ * `prompt_cache_hit_tokens`) are reported beside `input_tokens`, not in it.
10
+ */
11
+ export declare function chatUsageToAnthropic(value: unknown): JsonRecord;
12
+ /** Anthropic error body: `{type: "error", error: {type, message}}`. */
13
+ export declare function anthropicErrorBody(status: number, message: string): JsonRecord;
14
+ /**
15
+ * Anthropic Messages request → Chat Completions body. `thinking` and
16
+ * `output_config.effort` become whatever `reasoningFields` returns for the
17
+ * requested level (thinking.ts); `metadata` is dropped on purpose.
18
+ */
19
+ export declare function anthropicRequestToChat(body: JsonRecord, reasoningFields: ReasoningFields): JsonRecord;
20
+ export declare function chatCompletionToAnthropic(value: unknown, requestedModel: string, usage?: AnthropicUsage): JsonRecord;
21
+ /** OpenAI chat.completion.chunk SSE → Anthropic Messages SSE event sequence. */
22
+ export declare function chatSseToAnthropic(requestedModel: string, usage?: AnthropicUsage): TransformStream<Uint8Array, Uint8Array>;
23
+ export declare function anthropicErrorType(status: number): string;
24
+ /**
25
+ * Anthropic SDKs retry 408/409/429/5xx unless the server sends
26
+ * `x-should-retry: false`. Quota and policy refusals are final: without the
27
+ * header the client would hammer the gateway with retries.
28
+ */
29
+ export declare function anthropicShouldRetry(status: number, code: unknown): boolean;