u1s1-cli 1.14.6 → 1.15.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.
Files changed (44) hide show
  1. package/dist/agent-setup.d.ts +7 -0
  2. package/dist/agent-setup.js +14 -0
  3. package/dist/agents/agent-config.d.ts +83 -0
  4. package/dist/agents/agent-config.js +154 -0
  5. package/dist/agents/claude.d.ts +113 -0
  6. package/dist/agents/claude.js +411 -0
  7. package/dist/agents/codex.d.ts +111 -0
  8. package/dist/agents/codex.js +392 -0
  9. package/dist/agents/launch.d.ts +109 -0
  10. package/dist/agents/launch.js +444 -0
  11. package/dist/agents/pi.d.ts +9 -0
  12. package/dist/agents/pi.js +562 -0
  13. package/dist/agents/prefs.d.ts +35 -0
  14. package/dist/agents/prefs.js +96 -0
  15. package/dist/agents/runtime.d.ts +354 -0
  16. package/dist/agents/runtime.js +884 -0
  17. package/dist/agents/status.d.ts +20 -0
  18. package/dist/agents/status.js +241 -0
  19. package/dist/config-command.d.ts +18 -0
  20. package/dist/config-command.js +335 -0
  21. package/dist/config.d.ts +17 -0
  22. package/dist/config.js +35 -1
  23. package/dist/device-auth.d.ts +37 -1
  24. package/dist/device-auth.js +43 -8
  25. package/dist/embed.d.ts +13 -0
  26. package/dist/embed.js +15 -0
  27. package/dist/index.js +22 -556
  28. package/dist/launcher.d.ts +48 -0
  29. package/dist/launcher.js +235 -0
  30. package/dist/mcp-server.d.ts +105 -0
  31. package/dist/mcp-server.js +449 -0
  32. package/dist/pi-ui-text.d.ts +57 -0
  33. package/dist/pi-ui-text.js +148 -0
  34. package/dist/usage.js +2 -2
  35. package/package.json +1 -1
  36. package/scripts/p0-claude-code/README.md +39 -0
  37. package/scripts/p0-claude-code/launch-claude.ts +94 -0
  38. package/scripts/p0-claude-code/replay.ts +74 -0
  39. package/scripts/p0-claude-code/seed-local.mjs +145 -0
  40. package/scripts/p0-claude-code/tap.mjs +105 -0
  41. package/scripts/patch-pi.js +76 -55
  42. package/scripts/pi-patch-report.mjs +224 -0
  43. package/scripts/pi-upgrade.mjs +829 -0
  44. package/scripts/render-regression.mjs +67 -5
@@ -0,0 +1,96 @@
1
+ /**
2
+ * 用户给官方原版客户端(claude / codex)定的偏好,存在 ~/.u1s1/config.json:
3
+ *
4
+ * "agents": {
5
+ * "claude": { "model": "<模型 id>", "autoUpdate": false },
6
+ * "codex": { "model": "<模型 id>" }
7
+ * }
8
+ *
9
+ * model 默认模型。启动时还在网关下发的阵容里就用它,不在了退回网关默认并提示一次
10
+ * (提示过的 id 记在 modelNotice,同一个 id 不重复提示)。缺省 = 跟随网关默认。
11
+ * autoUpdate 每天查一次新版、下次启动前更新。缺省 = 开。关掉后版本刹车照样生效
12
+ * (见 runtime.ts planRuntime 的 update_required)。
13
+ *
14
+ * 由 `u1s1 config` 改(config-command.ts),启动流程(launch.ts)读。只改这几个键,config.json
15
+ * 其余内容原样保留。
16
+ */
17
+ import { readRawConfigFile, updateRawConfigFile } from "../config.js";
18
+ function isRecord(v) {
19
+ return typeof v === "object" && v !== null && !Array.isArray(v);
20
+ }
21
+ const MODEL_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._:/@+-]{0,199}$/;
22
+ /** 用户能填的模型 id:不带空白、引号等(会原样写进 TOML / JSON)。 */
23
+ export function isModelId(value) {
24
+ return typeof value === "string" && MODEL_ID_RE.test(value);
25
+ }
26
+ export function readAgentPrefs(agent, raw = readRawConfigFile()) {
27
+ const all = raw?.["agents"];
28
+ const own = isRecord(all) ? all[agent] : undefined;
29
+ if (!isRecord(own))
30
+ return { autoUpdate: true };
31
+ return {
32
+ ...(isModelId(own["model"]) ? { model: own["model"] } : {}),
33
+ autoUpdate: own["autoUpdate"] !== false,
34
+ ...(isModelId(own["modelNotice"]) ? { modelNotice: own["modelNotice"] } : {}),
35
+ };
36
+ }
37
+ export function saveAgentPrefs(agent, patch) {
38
+ updateRawConfigFile((file) => {
39
+ const all = isRecord(file["agents"]) ? { ...file["agents"] } : {};
40
+ const own = isRecord(all[agent]) ? { ...all[agent] } : {};
41
+ for (const [key, value] of Object.entries(patch)) {
42
+ if (value === undefined)
43
+ continue;
44
+ if (value === null)
45
+ delete own[key];
46
+ else
47
+ own[key] = value;
48
+ }
49
+ // 自动更新开着是默认,不必写出来
50
+ if (own["autoUpdate"] === true)
51
+ delete own["autoUpdate"];
52
+ // 用户换了模型或清掉了偏好:旧的提示记录没用了
53
+ if (patch.model !== undefined && patch.modelNotice === undefined)
54
+ delete own["modelNotice"];
55
+ if (Object.keys(own).length)
56
+ all[agent] = own;
57
+ else
58
+ delete all[agent];
59
+ if (Object.keys(all).length)
60
+ file["agents"] = all;
61
+ else
62
+ delete file["agents"];
63
+ });
64
+ }
65
+ /** 纯函数:用户偏好在阵容里就用它,否则网关默认。 */
66
+ export function chooseAgentModel(config, preferred) {
67
+ if (preferred && config.models.some((m) => m.id === preferred))
68
+ return { model: preferred };
69
+ return { model: config.defaultModel, ...(preferred ? { missing: preferred } : {}) };
70
+ }
71
+ /**
72
+ * 启动时选模型。用户选的模型不在阵容里时退回网关默认,同一个 id 只提示一次;
73
+ * 它回到阵容后清掉提示记录(再消失时会再提示)。偏好本身不删:模型可能只是暂时下架。
74
+ */
75
+ export function resolveLaunchModel(agent, config, deps = {}) {
76
+ const prefs = deps.prefs ?? readAgentPrefs(agent);
77
+ const choice = chooseAgentModel(config, prefs.model);
78
+ const save = deps.save ?? ((patch) => {
79
+ try {
80
+ saveAgentPrefs(agent, patch);
81
+ }
82
+ catch {
83
+ // config.json 写不进去不挡启动,最多下次再提示一次
84
+ }
85
+ });
86
+ if (choice.missing) {
87
+ if (prefs.modelNotice !== choice.missing) {
88
+ deps.notify?.(choice.missing, choice.model);
89
+ save({ modelNotice: choice.missing });
90
+ }
91
+ }
92
+ else if (prefs.modelNotice) {
93
+ save({ modelNotice: null });
94
+ }
95
+ return choice.model;
96
+ }
@@ -0,0 +1,354 @@
1
+ import { existsSync } from "node:fs";
2
+ import type { SiteId } from "../site.js";
3
+ interface ParsedVersion {
4
+ nums: [number, number, number];
5
+ pre?: string;
6
+ }
7
+ export declare function parseVersion(value: string | undefined | null): ParsedVersion | undefined;
8
+ export declare function isVersion(value: unknown): value is string;
9
+ /** 规范化:去掉前导 v、首尾空白;不是版本号返回 undefined。 */
10
+ export declare function normalizeVersion(value: unknown): string | undefined;
11
+ /** semver 比较(预发布段按标识符逐段比,数字段小于字母段;够用,不处理 build metadata)。 */
12
+ export declare function compareVersions(a: string, b: string): number;
13
+ /** `claude --version` 之类的输出 → 版本号(取第一个形如 x.y.z 的片段)。 */
14
+ export declare function versionFromOutput(output: string): string | undefined;
15
+ export interface RuntimeBrake {
16
+ minVersion?: string;
17
+ maxTestedVersion?: string;
18
+ blockedVersions: string[];
19
+ }
20
+ export declare const NO_BRAKE: RuntimeBrake;
21
+ /** 网关 runtime 字段 → RuntimeBrake;非法值按「没设」处理(blocked 里的非法项丢弃)。 */
22
+ export declare function brakeFromApi(runtime: unknown): RuntimeBrake;
23
+ export type BrakeVerdict = "ok" | "blocked" | "below_min" | "above_max_tested";
24
+ /**
25
+ * 安装与运行用同一套规则:blocked 不装不用、低于 min 不装不用、高于 max_tested 不装不用。
26
+ * 后台把 max_tested 调低,已装的更高版本下次启动时就会被换下来(见 planRuntime)。
27
+ */
28
+ export declare function checkBrake(version: string, brake: RuntimeBrake): BrakeVerdict;
29
+ export declare const allowedByBrake: (v: string, brake: RuntimeBrake) => boolean;
30
+ /**
31
+ * 自动更新 / 首次安装的目标:候选(官方 latest、网关的 max_tested 等)里刹车允许安装的最高版本。
32
+ * latest 超过 max_tested 时自然退到 max_tested(它是测过的版本,必然已发布)。
33
+ */
34
+ export declare function bestInstallTarget(candidates: Array<string | undefined>, brake: RuntimeBrake): string | undefined;
35
+ export type ManagedAgent = "claude" | "codex";
36
+ export declare const MANAGED_AGENTS: readonly ManagedAgent[];
37
+ export declare function isManagedAgent(value: unknown): value is ManagedAgent;
38
+ /** 平台二进制所在的 npm 包:装进 node_modules 的目录名,以及它在 npm 源上的名字和版本。 */
39
+ export interface PlatformPackageRef {
40
+ /** node_modules 下的目录名(lockfile 的键) */
41
+ dir: string;
42
+ /** npm 源上的包名(npm 别名时与 dir 不同) */
43
+ name: string;
44
+ /** npm 源上的版本 */
45
+ version: string;
46
+ }
47
+ export interface AgentRuntimeSpec {
48
+ agent: ManagedAgent;
49
+ /** 官方 npm 包 */
50
+ npmPackage: string;
51
+ /** 用户机器上可能已有的同名命令 */
52
+ command: string;
53
+ /** 指定可执行文件路径的环境变量(最高优先级) */
54
+ binEnv: string;
55
+ /** 探测版本时指向启动器自己目录的环境变量,免得碰到用户自己的配置目录 */
56
+ configDirEnv: string;
57
+ /** 探测版本时额外设的环境(关掉自动更新之类) */
58
+ probeEnv: Readonly<Record<string, string>>;
59
+ /** 平台二进制包;不支持的系统/架构返回 undefined */
60
+ platformPackage: (version: string, platform: NodeJS.Platform, arch: string, musl: boolean) => PlatformPackageRef | undefined;
61
+ /** 可执行文件在 node_modules 下的相对路径(posix 写法);不支持的系统/架构返回 undefined */
62
+ binInNodeModules: (platform: NodeJS.Platform, arch: string, musl: boolean) => string | undefined;
63
+ }
64
+ /**
65
+ * 官方包的 bin 就是 `bin/claude.exe`(各平台同名):postinstall 把对应平台的原生二进制
66
+ * 复制到这里。直接起这个文件,不经 node_modules/.bin 的 shell 包装(Windows 上是 .cmd)。
67
+ * 平台包名与官方 install.cjs 的 PLATFORMS 表一致。
68
+ */
69
+ export declare const CLAUDE_RUNTIME: AgentRuntimeSpec;
70
+ /**
71
+ * Codex:主包 `@openai/codex` 只有一个 JS 入口 `bin/codex.js`,平台二进制在 optionalDependencies 里,
72
+ * 以 npm 别名装进来(`@openai/codex-darwin-arm64` → `npm:@openai/codex@<版本>-darwin-arm64`)。
73
+ * 直接起平台包里的原生二进制,不经 codex.js(那层只是找二进制、设几个「由 npm 管理」的环境变量,
74
+ * 让它提示用 npm 升级;更新由启动器管,不需要)。原生二进制按自己所在目录找 rg 等附带文件。
75
+ */
76
+ export declare const CODEX_RUNTIME: AgentRuntimeSpec;
77
+ export declare function runtimeSpec(agent: ManagedAgent): AgentRuntimeSpec;
78
+ export interface RuntimePaths {
79
+ /** ~/.u1s1/agents/<agent> */
80
+ root: string;
81
+ runtimeDir: string;
82
+ stateFile: string;
83
+ npmCache: string;
84
+ }
85
+ export declare function runtimePaths(agentsRoot: string, agent: ManagedAgent): RuntimePaths;
86
+ export declare function versionDir(paths: RuntimePaths, version: string): string;
87
+ export declare function managedBinPath(paths: RuntimePaths, spec: AgentRuntimeSpec, version: string): string;
88
+ export interface RuntimeState {
89
+ /** 启动器管理的、当前使用的版本(runtime/<版本> 已装好且验证过) */
90
+ current?: string;
91
+ /** `u1s1 agents pin` 锁定的版本 */
92
+ pinned?: string;
93
+ /** 上次查官方最新版的时间(ms) */
94
+ lastCheckAt?: number;
95
+ /** 上次查到的官方 latest */
96
+ latest?: string;
97
+ /** 每日检查算出的待更新版本:下次启动前安装 */
98
+ pending?: string;
99
+ }
100
+ export declare function readRuntimeState(paths: RuntimePaths): RuntimeState;
101
+ export declare function writeRuntimeState(paths: RuntimePaths, state: RuntimeState): void;
102
+ export declare function updateRuntimeState(paths: RuntimePaths, patch: Partial<RuntimeState>): RuntimeState;
103
+ /** runtime/ 下已装好的版本(目录名是版本号、可执行文件存在),从新到旧。 */
104
+ export declare function installedVersions(paths: RuntimePaths, spec: AgentRuntimeSpec, exists?: typeof existsSync): string[];
105
+ export type RuntimeSource = "env" | "managed" | "path";
106
+ export interface FoundRuntime {
107
+ source: RuntimeSource;
108
+ bin: string;
109
+ version: string;
110
+ }
111
+ /**
112
+ * PATH 里找命令。Windows 只认 .exe:npm 全局装出来的 claude.cmd 要经 shell 才能起,
113
+ * 参数转义有坑(CVE-2024-27980 之后 Node 也不再直接 spawn .cmd),不值得冒险。
114
+ */
115
+ export declare function findOnPath(command: string, opts: {
116
+ env: NodeJS.ProcessEnv;
117
+ platform: NodeJS.Platform;
118
+ exists?: (p: string) => boolean;
119
+ }): string | undefined;
120
+ /**
121
+ * 跑 `<bin> --version` 取版本。环境里去掉密钥、关掉自动更新;配置目录(CLAUDE_CONFIG_DIR /
122
+ * CODEX_HOME)指到启动器自己的目录,免得探测用户自己装的客户端时碰到用户的 ~/.claude、~/.codex。
123
+ */
124
+ export declare function probeVersion(bin: string, configDir?: string, spec?: AgentRuntimeSpec): string | undefined;
125
+ /** 版本高于 max_tested、这次没用上的那份客户端(给用户解释为什么换版本 / 另装一份)。 */
126
+ export interface SkippedRuntime extends FoundRuntime {
127
+ maxTestedVersion: string;
128
+ }
129
+ export type RuntimePlan = {
130
+ action: "use";
131
+ runtime: FoundRuntime;
132
+ pinIgnored?: string;
133
+ skipped?: SkippedRuntime[];
134
+ } | {
135
+ action: "install";
136
+ version: string;
137
+ reason: "first" | "update" | "pin" | "blocked" | "below_min" | "above_max_tested";
138
+ /** 安装失败时可以退回的版本(没有 = 必须装成功才能启动) */
139
+ fallback?: FoundRuntime;
140
+ /** 第一次从官方下载:要先征得用户同意 */
141
+ needsConsent: boolean;
142
+ pinIgnored?: string;
143
+ skipped?: SkippedRuntime[];
144
+ } | {
145
+ action: "error";
146
+ /** update_required:自动更新关着,托管的当前版本过不了刹车,要用户自己更新(u1s1 agents install) */
147
+ code: "env_bin_unusable" | "env_bin_brake" | "no_version" | "update_required";
148
+ verdict?: BrakeVerdict;
149
+ bin?: string;
150
+ version?: string;
151
+ };
152
+ export interface PlanInput {
153
+ brake: RuntimeBrake;
154
+ state: RuntimeState;
155
+ /** 环境变量指定的可执行文件;version 为 undefined 表示跑不起来 */
156
+ envBin?: () => Promise<{
157
+ bin: string;
158
+ version?: string;
159
+ } | undefined>;
160
+ /** 启动器管理的当前版本(state.current 且可执行文件在) */
161
+ managed: () => Promise<FoundRuntime | undefined>;
162
+ /** 已装好的托管版本列表 */
163
+ installed: () => string[];
164
+ /** 用户机器上已有的命令 */
165
+ onPath: () => Promise<FoundRuntime | undefined>;
166
+ /** 官方 latest(只在需要时才查) */
167
+ latest: () => Promise<string | undefined>;
168
+ /**
169
+ * 自动更新(`u1s1 config set <客户端>.auto-update off` 关掉;缺省开)。关着时不装每日检查记下的
170
+ * 新版;托管的当前版本过不了刹车(停用、低于最低版本、高于已验证的最高版本)也不替用户换,
171
+ * 返回 update_required。pin、首次下载、`u1s1 agents install` 都是用户自己的动作,不受影响。
172
+ */
173
+ autoUpdate?: boolean;
174
+ }
175
+ /**
176
+ * 查找顺序:环境变量 → ~/.u1s1/agents/<客户端>(pin 优先) → PATH 里已有的同名命令 → 下载。
177
+ * 只做决定、不做 I/O 副作用;所有探测都是惰性的,用不到的不跑。
178
+ *
179
+ * 高于 max_tested 的版本一律不用:u1s1 自己装的换成不超过上限的版本(装不上不退回,没有
180
+ * fallback);环境变量指定的和 PATH 里的不替用户动,接着往下找 / 另装一份,并在 skipped 里说明。
181
+ */
182
+ export declare function planRuntime(input: PlanInput): Promise<RuntimePlan>;
183
+ export interface NpmCommand {
184
+ command: string;
185
+ /** 放在 npm 参数前面(用 node 直接跑 npm-cli.js 时是脚本路径) */
186
+ prefixArgs: string[];
187
+ source: "bundled" | "path";
188
+ }
189
+ /**
190
+ * npm 查找顺序:
191
+ * 1. 随运行本 CLI 的 Node 一起的 npm(官方 Node 发行包的布局):
192
+ * Linux/macOS: <node 所在目录>/../lib/node_modules/npm/bin/npm-cli.js
193
+ * Windows: <node.exe 所在目录>/node_modules/npm/bin/npm-cli.js
194
+ * 便携包里 node 在 ~/.u1s1/node/bin/node(Windows ~/.u1s1/node/node.exe),所以打包时
195
+ * npm 放到 ~/.u1s1/node/lib/node_modules/npm(Windows ~/.u1s1/node/node_modules/npm)。
196
+ * 用当前 Node(process.execPath)直接跑 npm-cli.js,不依赖 PATH、不经 shell。
197
+ * 2. PATH 里的 npm。Windows 上 npm.cmd 旁边的 node_modules/npm/bin/npm-cli.js,
198
+ * 同样用 node 直接跑(不 spawn .cmd)。
199
+ */
200
+ export declare function findNpm(opts: {
201
+ execPath: string;
202
+ platform: NodeJS.Platform;
203
+ env: NodeJS.ProcessEnv;
204
+ exists?: (p: string) => boolean;
205
+ }): NpmCommand | undefined;
206
+ /** 中国站走国内 npm 镜像(同一份包,带完整性校验);U1S1_NPM_REGISTRY 可覆盖。 */
207
+ export declare function npmRegistryFor(site: SiteId, env?: NodeJS.ProcessEnv): string;
208
+ /** npm 的平台二进制子包在 node_modules 下的目录名。 */
209
+ export declare function platformPackage(spec: AgentRuntimeSpec, platform?: NodeJS.Platform, arch?: string, musl?: boolean): string | undefined;
210
+ /** 某个版本的平台二进制子包(目录名 + npm 源上的名字与版本)。 */
211
+ export declare function platformPackageRef(spec: AgentRuntimeSpec, version: string, platform?: NodeJS.Platform, arch?: string, musl?: boolean): PlatformPackageRef | undefined;
212
+ export interface PackageMeta {
213
+ version: string;
214
+ integrity?: string;
215
+ tarball?: string;
216
+ unpackedSize?: number;
217
+ }
218
+ export declare function fetchPackageMeta(registry: string, pkg: string, tag: string, fetchImpl?: typeof fetch): Promise<PackageMeta | undefined>;
219
+ export declare function fetchLatestVersion(registry: string, pkg: string, fetchImpl?: typeof fetch): Promise<string | undefined>;
220
+ /**
221
+ * 压缩包大小。npm 源对 HEAD 不一定给 content-length(registry.npmjs.org 就不给),
222
+ * 用只取 1 字节的 Range 请求读 content-range 里的总长;国内镜像会 302 到 CDN,fetch 自动跟随。
223
+ */
224
+ export declare function downloadSize(url: string | undefined, fetchImpl?: typeof fetch): Promise<number | undefined>;
225
+ export interface DownloadInfo {
226
+ agent: ManagedAgent;
227
+ npmPackage: string;
228
+ version: string;
229
+ registry: string;
230
+ /** 压缩包下载量(字节),拿不到为 undefined */
231
+ downloadBytes?: number;
232
+ /** 解压后占用(字节) */
233
+ unpackedBytes?: number;
234
+ }
235
+ export declare class RuntimeInstallError extends Error {
236
+ readonly code: "declined" | "no_npm" | "npm_failed" | "verify_failed" | "unsupported_platform";
237
+ readonly detail?: string | undefined;
238
+ /** 这次安装本来是要换下这些超出 max_tested 的版本(ensureAgentRuntime 填,给调用方说明后果) */
239
+ skipped?: SkippedRuntime[];
240
+ constructor(code: "declined" | "no_npm" | "npm_failed" | "verify_failed" | "unsupported_platform", message: string, detail?: string | undefined);
241
+ }
242
+ export interface InstallHooks {
243
+ /** 首次下载前征得同意;返回 false = 用户拒绝 */
244
+ consent?: (info: DownloadInfo) => Promise<boolean>;
245
+ /** 进度与阶段提示(写 stderr) */
246
+ log: (line: string) => void;
247
+ /** 进度行(同一行刷新;非 TTY 时可不实现) */
248
+ progress?: (downloadedBytes: number, totalBytes: number | undefined) => void;
249
+ /** 文案(i18n 在调用方) */
250
+ text: InstallText;
251
+ }
252
+ export interface InstallText {
253
+ noNpm: () => string;
254
+ npmFailed: (attempt: number, max: number) => string;
255
+ retrying: (seconds: number) => string;
256
+ verifyFailed: (detail: string) => string;
257
+ declined: () => string;
258
+ unsupported: () => string;
259
+ installing: (version: string) => string;
260
+ installed: (version: string) => string;
261
+ /** 已有的某份客户端高于 max_tested、这次不用它时的说明;不给就不说明(桌面端自己处理 skipped) */
262
+ overMaxTested?: (skipped: SkippedRuntime) => string;
263
+ }
264
+ export interface InstallOptions {
265
+ spec: AgentRuntimeSpec;
266
+ paths: RuntimePaths;
267
+ version: string;
268
+ registry: string;
269
+ needsConsent: boolean;
270
+ hooks: InstallHooks;
271
+ /** 测试注入 */
272
+ npm?: NpmCommand;
273
+ maxAttempts?: number;
274
+ retryDelayMs?: number;
275
+ /** 校验时跑 --version 用的隔离配置目录(CLAUDE_CONFIG_DIR / CODEX_HOME) */
276
+ probeConfigDir?: string;
277
+ }
278
+ /**
279
+ * 装一个确切版本:npm install 到暂存目录 → 校验(锁文件里的 integrity 与 registry 元数据一致、
280
+ * 可执行文件报出的版本号就是目标版本)→ 整目录改名成 runtime/<版本>。中途失败不影响已装的版本。
281
+ */
282
+ export declare function installRuntime(opts: InstallOptions): Promise<FoundRuntime>;
283
+ /**
284
+ * 完整性校验。npm 自己已按 registry 元数据里的 integrity 校验过每个压缩包;这里再确认
285
+ * 装进来的正是我们要的那两个包、那个版本(锁文件条目与刚取的元数据一致),
286
+ * 且可执行文件能跑、报出的就是目标版本(postinstall 没装上平台二进制时这里会失败)。
287
+ */
288
+ export declare function verifyStaging(input: {
289
+ spec: AgentRuntimeSpec;
290
+ staging: string;
291
+ version: string;
292
+ platPkg: string;
293
+ /** 平台包在 npm 源上的版本(npm 别名时带平台后缀,如 0.167.2-darwin-arm64);默认同 version */
294
+ platVersion?: string;
295
+ mainMeta?: PackageMeta;
296
+ platMeta?: PackageMeta;
297
+ probe?: (bin: string) => string | undefined;
298
+ }): string | undefined;
299
+ export declare function npmInstallArgs(o: {
300
+ staging: string;
301
+ cache: string;
302
+ spec: string;
303
+ registry: string;
304
+ }): string[];
305
+ /** npm 的子进程环境:去掉密钥;当前 Node 所在目录放到 PATH 最前,postinstall 的 `node install.cjs` 用的就是它。 */
306
+ export declare function npmEnv(base: NodeJS.ProcessEnv, execPath: string, platform?: NodeJS.Platform): NodeJS.ProcessEnv;
307
+ export declare const UPDATE_CHECK_INTERVAL_MS: number;
308
+ /**
309
+ * 每天最多查一次官方最新版;算出刹车允许的目标版本高于当前托管版本时记为 pending,
310
+ * 下次启动前安装(planRuntime 的 update 分支)。pin 了就不记 pending。
311
+ */
312
+ export declare function dailyUpdateCheck(input: {
313
+ paths: RuntimePaths;
314
+ brake: RuntimeBrake;
315
+ now: number;
316
+ latest: () => Promise<string | undefined>;
317
+ force?: boolean;
318
+ }): Promise<RuntimeState>;
319
+ export interface EnsureRuntimeOptions {
320
+ brake: RuntimeBrake;
321
+ site: SiteId;
322
+ /** ~/.u1s1/agents;测试与桌面端可覆盖 */
323
+ agentsRoot: string;
324
+ hooks: InstallHooks;
325
+ /** 探测版本时给子进程的 CLAUDE_CONFIG_DIR / CODEX_HOME 隔离目录(须已存在) */
326
+ probeConfigDir?: string;
327
+ env?: NodeJS.ProcessEnv;
328
+ /** 测试注入:替换真正的下载安装 */
329
+ install?: (opts: InstallOptions) => Promise<FoundRuntime>;
330
+ /** 见 PlanInput.autoUpdate;缺省开 */
331
+ autoUpdate?: boolean;
332
+ }
333
+ export interface EnsuredRuntime extends FoundRuntime {
334
+ /** pin 的版本被刹车挡住、已忽略 */
335
+ pinIgnored?: string;
336
+ /** 高于 max_tested、这次没用上的客户端 */
337
+ skipped?: SkippedRuntime[];
338
+ /** 安装失败、退回到旧版本时的错误 */
339
+ installError?: RuntimeInstallError;
340
+ }
341
+ export declare class RuntimePlanError extends Error {
342
+ readonly plan: Extract<RuntimePlan, {
343
+ action: "error";
344
+ }>;
345
+ constructor(plan: Extract<RuntimePlan, {
346
+ action: "error";
347
+ }>);
348
+ }
349
+ /**
350
+ * 找到(必要时下载或更新)可用的客户端运行时。CLI(`u1s1 claude` / `u1s1 codex`)与桌面端共用。
351
+ * 失败抛 RuntimePlanError(刹车/版本问题)或 RuntimeInstallError(下载问题)。
352
+ */
353
+ export declare function ensureAgentRuntime(agent: ManagedAgent, opts: EnsureRuntimeOptions): Promise<EnsuredRuntime>;
354
+ export {};