@heybox/hb-sdk 0.4.4 → 0.4.6

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.
@@ -20,6 +20,8 @@
20
20
  - [Create a mini-program template](#create-a-mini-program-template)
21
21
  - [Local dev and mock runtime](#local-dev-and-mock-runtime)
22
22
  - [Deploy and backend operations](#deploy-and-backend-operations)
23
+ - [Remote entity scope](#remote-entity-scope)
24
+ - [Remote management commands](#remote-management-commands)
23
25
  - [CLI login cache](#cli-login-cache)
24
26
  - [Agent Skill doctor](#agent-skill-doctor)
25
27
  - [Update reminders](#update-reminders)
@@ -27,7 +29,7 @@
27
29
  - [Generated template README](#generated-template-readme)
28
30
  ## When to use the CLI
29
31
 
30
- Use the bundled `hb-sdk` CLI when the task is about creating an external mini-program project, starting local Vite development, debugging SDK calls in a browser mock runtime host, or managing the CLI's own Heybox auth cache.
32
+ Use the bundled `hb-sdk` CLI when the task is about creating an external mini-program project, starting local Vite development, debugging SDK calls in a browser mock runtime host, managing the CLI's own Heybox auth cache, or inspecting/switching the developer platform current entity for remote mini-program management.
31
33
 
32
34
  Do not use the CLI to replace iframe SDK calls. `hb-sdk login` is for CLI commands only and does not change `auth.login()`, `user.getInfo()`, `network.request()`, or mock-host user state.
33
35
 
@@ -35,341 +37,39 @@ The CLI, templates, and mock host are owned by `@heybox/hb-sdk`. Do not create a
35
37
 
36
38
  ## Command surface
37
39
 
38
- ```ts
39
- import { Command, CommanderError, InvalidArgumentError } from 'commander';
40
- import { printUpdateReminder as defaultPrintUpdateReminder } from './update-check';
41
- import { printError as defaultPrintError } from './utils/errors';
42
- import { createCliLogger, type CliLogger } from './utils/logger';
43
- import { getCliVersion } from './version';
44
-
45
- type ClearLoginStatus = typeof import('./commands/login').clearLoginStatus;
46
- type LoginToHeybox = typeof import('./commands/login').loginToHeybox;
47
- type PrintLoginStatus = typeof import('./commands/login').printLoginStatus;
48
- type RunCreateCommand = typeof import('./commands/create').runCreateCommand;
49
- type RunDeployCommand = typeof import('./commands/deploy').runDeployCommand;
50
- type RunDevCommand = typeof import('./commands/dev').runDevCommand;
51
- type RunDoctorCommand = typeof import('./commands/doctor').runDoctorCommand;
52
-
53
- export interface CliCommandHandlers {
54
- clearLoginStatus: ClearLoginStatus;
55
- loginToHeybox: LoginToHeybox;
56
- printLoginStatus: PrintLoginStatus;
57
- printUpdateReminder: typeof defaultPrintUpdateReminder;
58
- runCreateCommand: RunCreateCommand;
59
- runDeployCommand: RunDeployCommand;
60
- runDevCommand: RunDevCommand;
61
- runDoctorCommand: RunDoctorCommand;
62
- }
63
-
64
- export interface CliRuntimeOptions extends Partial<CliCommandHandlers> {
65
- argv?: string[];
66
- createLogger?: (options: { verbose: boolean }) => CliLogger;
67
- logger?: CliLogger;
68
- printError?: typeof defaultPrintError;
69
- process?: Pick<NodeJS.Process, 'exit'>;
70
- }
71
-
72
- export async function runCli(options: CliRuntimeOptions = {}) {
73
- const processLike = options.process ?? process;
74
- const argv = options.argv ?? process.argv;
75
- const verbose = hasVerboseArg(argv);
76
-
77
- try {
78
- await createCliProgram(options).parseAsync(argv);
79
- } catch (error) {
80
- if (error instanceof CommanderError && error.exitCode === 0) {
81
- processLike.exit(0);
82
- return;
83
- }
84
-
85
- if (!(error instanceof CommanderError)) {
86
- (options.printError ?? defaultPrintError)(error, { logger: resolveStandaloneLogger(options, verbose), verbose });
87
- }
88
-
89
- processLike.exit(error instanceof CommanderError ? error.exitCode : 1);
90
- }
91
- }
92
-
93
- export function createCliProgram(overrides: Partial<CliCommandHandlers> & Pick<CliRuntimeOptions, 'createLogger' | 'logger'> = {}) {
94
- const handlers: CliCommandHandlers = {
95
- clearLoginStatus: defaultClearLoginStatus,
96
- loginToHeybox: defaultLoginToHeybox,
97
- printLoginStatus: defaultPrintLoginStatus,
98
- printUpdateReminder: defaultPrintUpdateReminder,
99
- runCreateCommand: defaultRunCreateCommand,
100
- runDeployCommand: defaultRunDeployCommand,
101
- runDevCommand: defaultRunDevCommand,
102
- runDoctorCommand: defaultRunDoctorCommand,
103
- ...overrides,
104
- };
105
- const program = new Command();
106
- const resolveLogger = createCommandLoggerResolver(overrides);
107
-
108
- program
109
- .name('hb-sdk')
110
- .description('hb-sdk developer tools')
111
- .version(getCliVersion())
112
- .option('-v, --verbose', '输出详细调试信息')
113
- .showHelpAfterError()
114
- .exitOverride();
115
- installVersionUpdateReminder(program, handlers.printUpdateReminder, resolveLogger);
116
-
117
- addVerboseOption(
118
- program.command('create').description('创建外部小程序项目开发模板').argument('<project-name>', '项目目录名,例如 my-miniapp'),
119
- ).action(
120
- withUpdateReminder(
121
- async (projectName, _options, command: Command) => {
122
- const logger = resolveLogger(command);
123
- await handlers.runCreateCommand(projectName, { logger });
124
- },
125
- handlers.printUpdateReminder,
126
- resolveLogger,
127
- ),
128
- );
129
-
130
- addVerboseOption(
131
- program
132
- .command('dev')
133
- .description('启动当前小程序项目的 Vite dev server 和浏览器 mock runtime host')
134
- .option('--port <port>', 'App dev server 端口', parsePositivePort)
135
- .option('--mock-port <port>', 'Mock host 端口', parsePositivePort)
136
- .option('--runtime-url <url>', '真实客户端调试时使用的自定义 runtime 地址')
137
- .option('--no-open', '不自动打开浏览器调试页'),
138
- ).action(
139
- withUpdateReminder(
140
- async (options, command: Command) => {
141
- const logger = resolveLogger(command);
142
- await handlers.runDevCommand(options, { logger });
143
- },
144
- handlers.printUpdateReminder,
145
- resolveLogger,
146
- ),
147
- );
148
-
149
- addVerboseOption(
150
- program
151
- .command('deploy')
152
- .description('构建并提交当前小程序版本审核')
153
- .option('--skip-build', '跳过 build,直接读 dist 目录上传并提交审核')
154
- .option('--release-note <text>', '发布日志,提交审核必填')
155
- .option('--auto-publish', '审核通过后自动发布;默认需在开放平台手动发布')
156
- .option('--api-base-url <url>', 'Heybox 后台 API origin,默认读取 HB_SDK_API_BASE_URL 或生产地址')
157
- .option('--allow-unsafe-api-base-url', '允许向非 Heybox HTTPS API origin 发送登录态,仅限本地调试')
158
- .option('--login-base-url <url>', '校验 CLI 登录态使用的登录 origin,默认读取 HB_SDK_LOGIN_BASE_URL 或生产地址'),
159
- ).action(
160
- withUpdateReminder(
161
- async (options, command: Command) => {
162
- const logger = resolveLogger(command);
163
- await handlers.runDeployCommand(
164
- {
165
- allowUnsafeApiBaseUrl: Boolean(options.allowUnsafeApiBaseUrl),
166
- apiBaseUrl: options.apiBaseUrl,
167
- autoPublish: Boolean(options.autoPublish),
168
- loginBaseUrl: options.loginBaseUrl,
169
- releaseNote: options.releaseNote,
170
- skipBuild: Boolean(options.skipBuild),
171
- },
172
- { logger },
173
- );
174
- },
175
- handlers.printUpdateReminder,
176
- resolveLogger,
177
- ),
178
- );
179
-
180
- addVerboseOption(program.command('doctor').description('诊断 hb-sdk 本地环境和 Agent Skill 版本')).action(async (...args: unknown[]) => {
181
- const logger = resolveLogger(readCommandFromActionArgs(args));
182
- const result = await handlers.runDoctorCommand({ logger });
183
-
184
- if (result.status !== 'SDK_MISMATCH') {
185
- await handlers.printUpdateReminder({ logger });
186
- }
187
- });
188
-
189
- const login = addVerboseOption(
190
- program
191
- .command('login')
192
- .description('登录 Heybox 并缓存 CLI 登录态')
193
- .option('--login-base-url <url>', 'Heybox 登录入口 origin,默认读取 HB_SDK_LOGIN_BASE_URL 或生产地址'),
194
- ).action(
195
- withUpdateReminder(
196
- async (options, command: Command) => {
197
- const logger = resolveLogger(command);
198
- await handlers.loginToHeybox({
199
- logger,
200
- loginBaseUrl: options.loginBaseUrl,
201
- });
202
- },
203
- handlers.printUpdateReminder,
204
- resolveLogger,
205
- ),
206
- );
207
-
208
- addVerboseOption(login.command('status').description('查看脱敏后的 Heybox 登录态')).action(
209
- withUpdateReminder(
210
- async (...args: unknown[]) => {
211
- const logger = resolveLogger(readCommandFromActionArgs(args));
212
- await handlers.printLoginStatus({ logger });
213
- },
214
- handlers.printUpdateReminder,
215
- resolveLogger,
216
- ),
217
- );
218
-
219
- addVerboseOption(login.command('clear').description('清理 hb-sdk 命名空间中的 Heybox 登录态')).action(
220
- withUpdateReminder(
221
- async (...args: unknown[]) => {
222
- const logger = resolveLogger(readCommandFromActionArgs(args));
223
- await handlers.clearLoginStatus({ logger });
224
- },
225
- handlers.printUpdateReminder,
226
- resolveLogger,
227
- ),
228
- );
229
-
230
- return program;
231
- }
232
-
233
- function addVerboseOption<T extends Command>(command: T): T {
234
- return command.option('-v, --verbose', '输出详细调试信息') as T;
235
- }
236
-
237
- function hasVerboseArg(argv: string[]) {
238
- return argv.includes('--verbose') || argv.includes('-v');
239
- }
240
-
241
- type ResolveCommandLogger = (commandOrVerbose?: Command | boolean) => CliLogger;
242
-
243
- function createCommandLoggerResolver(options: Pick<CliRuntimeOptions, 'createLogger' | 'logger'>): ResolveCommandLogger {
244
- let defaultLogger: CliLogger | undefined;
245
- let verboseLogger: CliLogger | undefined;
246
-
247
- return (commandOrVerbose?: Command | boolean) => {
248
- if (options.logger) {
249
- return options.logger;
250
- }
251
-
252
- const verbose = typeof commandOrVerbose === 'boolean' ? commandOrVerbose : readCommandVerbose(commandOrVerbose);
253
- if (verbose) {
254
- verboseLogger ??= resolveStandaloneLogger(options, true);
255
- return verboseLogger;
256
- }
257
-
258
- defaultLogger ??= resolveStandaloneLogger(options, false);
259
- return defaultLogger;
260
- };
261
- }
262
-
263
- const defaultClearLoginStatus: ClearLoginStatus = async (...args) => {
264
- const { clearLoginStatus } = await import('./commands/login');
265
- return clearLoginStatus(...args);
266
- };
267
-
268
- const defaultLoginToHeybox: LoginToHeybox = async (...args) => {
269
- const { loginToHeybox } = await import('./commands/login');
270
- return loginToHeybox(...args);
271
- };
272
-
273
- const defaultPrintLoginStatus: PrintLoginStatus = async (...args) => {
274
- const { printLoginStatus } = await import('./commands/login');
275
- return printLoginStatus(...args);
276
- };
277
-
278
- const defaultRunCreateCommand: RunCreateCommand = async (...args) => {
279
- const { runCreateCommand } = await import('./commands/create');
280
- return runCreateCommand(...args);
281
- };
282
-
283
- const defaultRunDeployCommand: RunDeployCommand = async (...args) => {
284
- const { runDeployCommand } = await import('./commands/deploy');
285
- return runDeployCommand(...args);
286
- };
287
-
288
- const defaultRunDevCommand: RunDevCommand = async (...args) => {
289
- const { runDevCommand } = await import('./commands/dev');
290
- return runDevCommand(...args);
291
- };
292
-
293
- const defaultRunDoctorCommand: RunDoctorCommand = async (...args) => {
294
- const { runDoctorCommand } = await import('./commands/doctor');
295
- return runDoctorCommand(...args);
296
- };
297
-
298
- function resolveStandaloneLogger(options: Pick<CliRuntimeOptions, 'createLogger' | 'logger'>, verbose: boolean) {
299
- return options.logger ?? options.createLogger?.({ verbose }) ?? createCliLogger({ verbose });
300
- }
301
-
302
- function readCommandVerbose(command?: Command) {
303
- if (!command) {
304
- return false;
305
- }
306
-
307
- return Boolean(command.optsWithGlobals?.().verbose || command.opts().verbose);
308
- }
309
-
310
- function installVersionUpdateReminder(program: Command, printUpdateReminder: typeof defaultPrintUpdateReminder, resolveLogger: ResolveCommandLogger) {
311
- const parseAsync = program.parseAsync.bind(program);
312
-
313
- program.parseAsync = (async (...args: Parameters<Command['parseAsync']>) => {
314
- const [argv, parseOptions] = args;
315
-
316
- if (isVersionRequest(argv, parseOptions)) {
317
- const logger = resolveLogger(hasVerboseArg(getUserArgs(argv, parseOptions)));
318
- logger.raw(getCliVersion(), { stream: 'stdout' });
319
- await printUpdateReminder({ logger });
320
- throw new CommanderError(0, 'commander.version', 'version displayed');
321
- }
322
-
323
- return parseAsync(...args);
324
- }) as Command['parseAsync'];
325
- }
326
-
327
- function isVersionRequest(argv: readonly string[] | undefined, parseOptions: { from?: string } | undefined) {
328
- const userArgs = getUserArgs(argv, parseOptions).filter((arg) => arg !== '--verbose' && arg !== '-v');
329
-
330
- return userArgs.length === 1 && (userArgs[0] === '--version' || userArgs[0] === '-V');
331
- }
332
-
333
- function getUserArgs(argv: readonly string[] | undefined, parseOptions: { from?: string } | undefined) {
334
- const args = [...(argv ?? process.argv)];
335
-
336
- if (parseOptions?.from === 'user') {
337
- return args;
338
- }
339
-
340
- if (parseOptions?.from === 'electron') {
341
- return args.slice(1);
342
- }
343
-
344
- return args.slice(2);
345
- }
346
-
347
- function withUpdateReminder<Args extends unknown[]>(
348
- action: (...args: Args) => Promise<void>,
349
- printUpdateReminder: typeof defaultPrintUpdateReminder,
350
- resolveLogger: ResolveCommandLogger,
351
- ) {
352
- return async (...args: Args) => {
353
- await action(...args);
354
- await printUpdateReminder({ logger: resolveLogger(readCommandFromActionArgs(args)) });
355
- };
356
- }
357
-
358
- function readCommandFromActionArgs(args: unknown[]) {
359
- const lastArg = args[args.length - 1];
360
- return lastArg instanceof Command ? lastArg : undefined;
361
- }
362
-
363
- function parsePositivePort(value: string) {
364
- const parsed = Number(value);
365
- if (!Number.isInteger(parsed) || parsed <= 0) {
366
- throw new InvalidArgumentError('必须是正整数端口号');
367
- }
368
-
369
- return parsed;
370
- }
40
+ ```text
41
+ hb-sdk create <project-name>
42
+ hb-sdk dev [--port <port>] [--mock-port <port>] [--runtime-url <url>] [--no-open]
43
+ hb-sdk login [--login-base-url <url>] [--no-select-entity]
44
+ hb-sdk login status
45
+ hb-sdk login clear
46
+ hb-sdk doctor
47
+ hb-sdk remote access
48
+ hb-sdk remote entity list
49
+ hb-sdk remote entity current
50
+ hb-sdk remote entity switch <entity-id>
51
+ hb-sdk remote list [--status <status>] [--keyword <text>]
52
+ hb-sdk remote create --name <name> [--preview-image-url <url>] [--yes] [--force-bind]
53
+ hb-sdk remote bind <mini-program-id> [--force]
54
+ hb-sdk remote info
55
+ hb-sdk remote update [--name <name>] [--preview-image-url <url>]
56
+ hb-sdk remote allowlist list
57
+ hb-sdk remote allowlist add <heybox-id...>
58
+ hb-sdk remote allowlist remove <heybox-id...>
59
+ hb-sdk remote allowlist set <heybox-id...>
60
+ hb-sdk remote deploy --release-note <text> [--skip-build] [--auto-publish]
61
+ hb-sdk remote versions
62
+ hb-sdk remote preview <version>
63
+ hb-sdk remote release <version> [--yes]
64
+ hb-sdk remote withdraw <version> [--yes] [--reason <text>]
65
+ hb-sdk remote take-down [--yes]
66
+ hb-sdk remote reopen [--yes]
67
+
68
+ Removed: hb-sdk deploy
371
69
  ```
372
70
 
71
+ Top-level `hb-sdk deploy` has been hard-cut and must not be documented as a valid compatibility alias. Keep `hb-sdk login` top-level because it manages CLI login state, not a specific remote mini-program.
72
+
373
73
  ## Create a mini-program template
374
74
 
375
75
  ## 创建外部小程序模板
@@ -428,24 +128,24 @@ Use `hb-sdk dev` for local browser SDK debugging. Use the Mock runtime host's "
428
128
  ## 部署发布
429
129
 
430
130
  ```bash
431
- hb-sdk deploy --release-note "修复登录状态展示,补充异常提示"
432
- hb-sdk deploy --release-note "审核通过后自动发布" --auto-publish
433
- hb-sdk deploy --skip-build --release-note "复用已有 dist 构建产物"
434
- hb-sdk deploy --api-base-url https://api.test.xiaoheihe.cn --login-base-url https://login.test.xiaoheihe.cn --release-note "测试环境验证"
435
- hb-sdk deploy --verbose --api-base-url https://api.test.xiaoheihe.cn --login-base-url https://login.test.xiaoheihe.cn --release-note "排查预检失败"
436
- HB_SDK_ALLOW_UNSAFE_API_BASE_URL=1 hb-sdk deploy --api-base-url http://127.0.0.1:8080 --release-note "本地后台联调"
131
+ hb-sdk remote deploy --release-note "修复登录状态展示,补充异常提示"
132
+ hb-sdk remote deploy --release-note "审核通过后自动发布" --auto-publish
133
+ hb-sdk remote deploy --skip-build --release-note "复用已有 dist 构建产物"
134
+ hb-sdk remote deploy --api-base-url https://api.test.xiaoheihe.cn --login-base-url https://login.test.xiaoheihe.cn --release-note "测试环境验证"
135
+ hb-sdk remote deploy --verbose --api-base-url https://api.test.xiaoheihe.cn --login-base-url https://login.test.xiaoheihe.cn --release-note "排查预检失败"
136
+ HB_SDK_ALLOW_UNSAFE_API_BASE_URL=1 hb-sdk remote deploy --api-base-url http://127.0.0.1:8080 --release-note "本地后台联调"
437
137
  ```
438
138
 
439
- `hb-sdk deploy` 把预检、构建、上传和提交审核串成一条命令:
139
+ `hb-sdk remote deploy` 把预检、构建、上传和提交审核串成一条命令。顶层 `hb-sdk deploy` 已硬切删除,不再作为兼容别名保留:
440
140
 
441
141
  1. 读取 `package.json.heybox.miniProgramId`,缺失即报错。
442
142
  2. 校验登录态,需先 `hb-sdk login`。
443
143
  3. 如果需要以公司的名义发布小程序,需先找 @秦浩东 申请小程序开发权限。
444
144
  4. 读取并校验 `--release-note`;TTY 环境缺失时会提示输入,CI / 非 TTY 环境缺失时直接失败。建议让 AI 生成 1-5 条简短发布日志。
445
- 5. 普通 deploy 先读取 `package.json.version`,登录后、build 前调用版本预检接口;预检通过后才执行 `<pm> run build`。
145
+ 5. 普通 remote deploy 先读取 `package.json.version`,登录后、build 前调用版本预检接口;预检通过后才执行 `<pm> run build`。
446
146
  6. `--skip-build` 跳过构建,但会先读取已有 `dist/manifest.json.version`,再调用版本预检接口。
447
147
  7. 解析 `dist/manifest.json`,自动剥离 BOM,并校验 `version` 是合法 SemVer:允许 prerelease,例如 `1.2.3-rc.1`;拒绝 build metadata,例如 `1.2.3+build.1`;拒绝 `0.0.0`。
448
- 8. 普通 deploy 的 `dist/manifest.json.version` 必须与预检使用的 `package.json.version` 一致,否则失败且不上传。
148
+ 8. 普通 remote deploy 的 `dist/manifest.json.version` 必须与预检使用的 `package.json.version` 一致,否则失败且不上传。
449
149
  9. 遍历 `dist/` 文件,过滤掉 `manifest.json`、`.DS_Store`、`*.map`;遇到 symbolic link 或 `node_modules` 路径直接报错。
450
150
  10. 4 并发把文件上传到 CDN,默认只展示上传阶段和文件总数;`--verbose` 会展示并发数、bucket / region 和逐文件结果,但不会输出 keys、签名、cookie 或 token。
451
151
  11. 全部上传成功后调用提交审核接口,CLI 输出提交审核成功、发布策略和可用的 preview URL。
@@ -462,22 +162,91 @@ HB_SDK_ALLOW_UNSAFE_API_BASE_URL=1 hb-sdk deploy --api-base-url http://127.0.0.1
462
162
 
463
163
  `manifest.json` 仅作为提交审核接口的 `manifest` 字段提交,不会上传到 CDN。Vite 项目通过 `miniappManifest()` 插件生成;CLI 不会自动注入插件,请在 `vite.config.ts` 中显式挂载。小程序构建产物需要使用相对资源路径;`hb-sdk create` 模板会显式配置 `base: './'`,未配置 `base` 的项目也会由 `miniappManifest()` 在 build 时默认补成 `./`。
464
164
 
465
- 默认发布策略是 `auto_publish=false`:运营审核通过后需在开放平台手动发布。需要审核通过后自动发布并下架旧线上版本时,使用 `--auto-publish`。
165
+ 默认发布策略是 `auto_publish=false`:运营审核通过后使用 `hb-sdk remote versions` 查看版本状态,再用 `hb-sdk remote release <version>` 发布。需要审核通过后自动发布并下架旧线上版本时,使用 `--auto-publish`。如需让指定用户预览未发布候选版本,使用 `hb-sdk remote allowlist add <heybox_id>` 管理预览白名单。
466
166
 
467
- 内部测试或预发环境可通过 `HB_SDK_API_BASE_URL` / `HB_SDK_LOGIN_BASE_URL` 设置默认后台环境,也可以用 `--api-base-url` / `--login-base-url` 覆盖单次命令。自定义地址只接受 origin,不允许包含 path、query 或 hash;API origin 默认还必须是 Heybox 受信 HTTPS 域名,只有本地联调等场景可显式使用 `--allow-unsafe-api-base-url` 或 `HB_SDK_ALLOW_UNSAFE_API_BASE_URL=1` 放开。`apiBaseUrl` 只影响 deploy 里的预检、CDN 上传凭证/回调、提交审核;`loginBaseUrl` 用于 `hb-sdk login` 的登录入口,以及 deploy 前校验当前 CLI 登录态是否属于同一个登录环境。开发环境如需给后台请求带 `x-rylai-service-tag` 和 `special_tag`,可在 `packages/hb-sdk/src/cli/config.ts` 里按 `@heybox/hb-types` 的 `RylaiServiceTagConfig` 配置 `default_tag` 或 path-prefix 级 `special_tag`。日志只输出 origin,不输出带身份和签名参数的完整请求 URL。
167
+ 内部测试或预发环境可通过 `HB_SDK_API_BASE_URL` / `HB_SDK_LOGIN_BASE_URL` 设置默认后台环境,也可以用 `--api-base-url` / `--login-base-url` 覆盖单次命令。自定义地址只接受 origin,不允许包含 path、query 或 hash;API origin 默认还必须是 Heybox 受信 HTTPS 域名,只有本地联调等场景可显式使用 `--allow-unsafe-api-base-url` 或 `HB_SDK_ALLOW_UNSAFE_API_BASE_URL=1` 放开。`apiBaseUrl` 影响 `hb-sdk remote` 里的远端平台后台 API,包括预检、CDN 上传凭证/回调、提交审核、版本、发布、撤回、下架、重新上架、详情、基础信息和白名单等调用;`loginBaseUrl` 用于 `hb-sdk login` 的登录入口,以及 remote 命令前校验当前 CLI 登录态是否属于同一个登录环境。开发环境如需给后台请求带 `x-rylai-service-tag` 和 `special_tag`,可在 `packages/hb-sdk/src/cli/config.ts` 里按 `@heybox/hb-types` 的 `RylaiServiceTagConfig` 配置 `default_tag` 或 path-prefix 级 `special_tag`。日志只输出 origin,不输出带身份和签名参数的完整请求 URL。
468
168
 
469
169
  `hb-sdk doctor`、npm latest 检查、mock host 的 `network.request()` 不受这些配置影响。
470
170
 
171
+ Before precheck, build, upload, or submit audit, `hb-sdk remote deploy` must verify that the current project's bound mini-program belongs to the server-side current entity. If `detail.entity_id` differs from the current entity, the command fails with both entity ids/names and suggests `hb-sdk remote entity switch <entity-id>`. It must not auto-switch entities and must not continue into precheck/build/upload/submit on mismatch.
172
+
471
173
  Agent rules:
472
174
 
473
- - Use `hb-sdk deploy --release-note <text>` for normal build, upload, and submit-audit flows.
474
- - Use `--api-base-url <url>` or `HB_SDK_API_BASE_URL` only for deploy backend APIs.
175
+ - Use `hb-sdk remote deploy --release-note <text>` for normal build, upload, and submit-audit flows.
176
+ - Verify remote deploy guidance says current-entity mismatch fails before precheck/build/upload/submit and never auto-switches the developer entity.
177
+ - Never recommend top-level `hb-sdk deploy`; it has been removed rather than retained as a compatibility alias.
178
+ - After non-auto deploy succeeds, suggest `hb-sdk remote versions` and then `hb-sdk remote release <version>` after approval. Do not send the user to Open for manual publish when the CLI command exists.
179
+ - Use `hb-sdk remote allowlist add <heybox_id>` when preview access needs to be granted.
180
+ - Use `--api-base-url <url>` or `HB_SDK_API_BASE_URL` for remote platform backend APIs.
475
181
  - Use `--allow-unsafe-api-base-url` or `HB_SDK_ALLOW_UNSAFE_API_BASE_URL=1` only for local backend debugging against non-Heybox or non-HTTPS API origins.
476
- - Use `--login-base-url <url>` or `HB_SDK_LOGIN_BASE_URL` for CLI browser login and deploy login-environment validation.
182
+ - Use `--login-base-url <url>` or `HB_SDK_LOGIN_BASE_URL` for CLI browser login and remote command login-environment validation.
477
183
  - Use `packages/hb-sdk/src/cli/config.ts` with `RylaiServiceTagConfig` only when Heybox backend API requests need the development-only `x-rylai-service-tag` header and matching `special_tag` query parameter.
478
184
  - Custom base URLs must be origin-only; API origins must be Heybox trusted HTTPS unless the unsafe debug switch is explicit. Do not include path, query, or hash.
479
185
  - Do not expect custom base URLs to affect `hb-sdk doctor`, npm latest checks, or mock-host `network.request()`.
480
186
 
187
+ ## Remote entity scope
188
+
189
+ Developer entity selection lives under `hb-sdk remote entity`:
190
+
191
+ ```bash
192
+ hb-sdk remote entity list
193
+ hb-sdk remote entity current
194
+ hb-sdk remote entity switch <entity-id>
195
+ ```
196
+
197
+ The authoritative current entity is the developer platform server-side current entity. The CLI auth cache may contain a `selectedEntity` value, but that value is only a hint snapshot for `hb-sdk login status` display and drift troubleshooting. Do not use `selectedEntity` as the source of truth for permissions, ownership, create, bind, deploy, or release decisions.
198
+
199
+ `hb-sdk login` tries to make the server-side current entity explicit after browser login. Zero entities leaves login successful and prints a guidance message. One entity is displayed and, when needed, switched to current. Multiple entities in a TTY prompt for a choice; multiple entities in non-interactive mode do not block login but tell the user to run `hb-sdk remote entity switch <entity-id>`. Passing `--no-select-entity` writes only the login state and does not modify the server-side current entity.
200
+
201
+ Agent rules:
202
+
203
+ - Treat the server-side current entity as the authority for remote create, bind, deploy, list, access, versions, preview, release, withdraw, take-down, and reopen workflows.
204
+ - Treat CLI `selectedEntity` as a display/debug snapshot only; it can drift from the server-side current entity and must not be used as a permission source.
205
+ - Use `hb-sdk remote entity current` when a user needs to confirm which entity create/deploy will use.
206
+ - Use `hb-sdk remote entity switch <entity-id>` to change entity scope. Do not recommend `--entity-id` or an environment variable as a remote command override.
207
+ - `hb-sdk remote list` lists mini-programs in the current entity scope only; do not promise cross-entity aggregation.
208
+
209
+ ## Remote management commands
210
+
211
+ ## 远端管理命令
212
+
213
+ 远端平台操作统一放在 `hb-sdk remote` 命令组下,默认作用于当前项目绑定的小程序,也就是 `package.json.heybox.miniProgramId`。`remote list` 只用于发现可管理的小程序;会改变远端状态的命令仍然只操作当前绑定的小程序,不接受临时 `mini_program_id` 参数。
214
+
215
+ 常用命令:
216
+
217
+ ```bash
218
+ hb-sdk remote access
219
+ hb-sdk remote list
220
+ hb-sdk remote create --name "我的小程序"
221
+ hb-sdk remote bind mp_xxxxxxxx
222
+ hb-sdk remote info
223
+ hb-sdk remote update --name "新名称"
224
+ hb-sdk remote allowlist add 12345678
225
+ hb-sdk remote versions
226
+ hb-sdk remote preview 1.2.3
227
+ hb-sdk remote release 1.2.3
228
+ hb-sdk remote withdraw 1.2.3 --reason "需要修复说明"
229
+ hb-sdk remote take-down
230
+ hb-sdk remote reopen
231
+ ```
232
+
233
+ `hb-sdk remote create` 会创建远端用户小程序并写入当前项目绑定;已有绑定时必须传 `--force-bind` 才能覆盖。`hb-sdk remote bind <mini-program-id>` 会先校验当前 CLI 用户可管理目标小程序,再写入本地配置;`--force` 只允许覆盖本地绑定,不跳过远端校验。
234
+
235
+ `hb-sdk remote release`、`hb-sdk remote withdraw`、`hb-sdk remote take-down` 和 `hb-sdk remote reopen` 会改变审核、发布或用户侧可见状态。交互式终端会展示小程序 id、名称、当前状态、目标版本和操作,再要求确认;非 TTY 环境必须传 `--yes`。
236
+
237
+ 所有 `hb-sdk remote` 子命令都支持 `--json`。开启后 stdout 只输出一个 JSON 对象;进度、警告、版本提醒和 verbose 诊断不能污染 stdout。
238
+
239
+ Agent rules:
240
+
241
+ - Use `hb-sdk remote entity list/current/switch` for developer entity inspection and switching.
242
+ - Use `hb-sdk remote create --name <name>` for create-and-bind and `hb-sdk remote bind <mini-program-id>` for binding an existing manageable remote mini-program.
243
+ - Explain that `remote create` creates under the current entity and that multi-entity non-TTY usage must confirm with `--yes`; `--yes` confirms current-entity usage but does not switch entities.
244
+ - Explain that `remote bind` verifies the mini-program is manageable by the current entity and does not write `package.json.heybox.miniProgramId` on entity mismatch.
245
+ - Use `hb-sdk remote info`, `hb-sdk remote update`, `hb-sdk remote access`, `hb-sdk remote list`, `hb-sdk remote versions`, `hb-sdk remote preview <version>`, and `hb-sdk remote allowlist ...` instead of sending users to Open when a matching CLI command exists.
246
+ - Treat `hb-sdk remote list` as discovery only. Dangerous write commands still target the bound mini-program from `package.json.heybox.miniProgramId`.
247
+ - Require confirmation or `--yes` for `hb-sdk remote release`, `hb-sdk remote withdraw`, `hb-sdk remote take-down`, and `hb-sdk remote reopen`.
248
+ - Use `--json` for script consumption and keep stdout as exactly one JSON object.
249
+
481
250
  ## CLI login cache
482
251
 
483
252
  ## CLI 登录态
@@ -499,6 +268,7 @@ hb-sdk login clear
499
268
  Agent rules:
500
269
 
501
270
  - Keep CLI auth cache separate from iframe SDK login state.
271
+ - Keep `selectedEntity` guidance explicit: it is only a hint snapshot, while every remote command uses the server-side current entity.
502
272
  - It is correct to say status output is redacted.
503
273
  - Do not expose or template pkey, cookie, token, or private credential values.
504
274
  - Use `hb-sdk login clear` only to clear the `hb-sdk` CLI namespace.
@@ -542,7 +312,7 @@ Agent rules:
542
312
 
543
313
  ## 版本提醒
544
314
 
545
- `hb-sdk create`、`hb-sdk dev`、`hb-sdk deploy`、`hb-sdk login`、`hb-sdk login status`、`hb-sdk login clear`、`hb-sdk doctor` 会在命令成功执行后检查 npm registry 上 `@heybox/hb-sdk` 的 `latest` 版本。检查结果会缓存 24 小时;检查失败会静默跳过;`CI=true` 时会跳过检查,避免污染 CI 日志。`hb-sdk doctor` 已经诊断出 `SDK_MISMATCH` 时不会再追加统一提醒,避免同一次输出里重复提示升级 SDK。`hb-sdk --version` / `hb-sdk -V` 也会执行同一套检查,但 stdout 只输出版本号,升级提醒继续按 warn 级别写到 stderr。本地可通过 `HB_SDK_NO_UPDATE_CHECK=1` 禁用检查。
315
+ `hb-sdk create`、`hb-sdk dev`、`hb-sdk remote ...`、`hb-sdk login`、`hb-sdk login status`、`hb-sdk login clear`、`hb-sdk doctor` 会在命令成功执行后检查 npm registry 上 `@heybox/hb-sdk` 的 `latest` 版本。普通命令的检查结果会缓存 24 小时;检查失败会静默跳过;`CI=true` 时会跳过检查,避免污染 CI 日志。`hb-sdk doctor` 已经诊断出 `SDK_MISMATCH` 时不会再追加统一提醒,避免同一次输出里重复提示升级 SDK。`hb-sdk --version` / `hb-sdk -V` 会直接请求 npm registry 获取 latest,不读取本地缓存;stdout 只输出版本号,升级提醒继续按 warn 级别写到 stderr。本地可通过 `HB_SDK_NO_UPDATE_CHECK=1` 禁用检查。
546
316
 
547
317
  ## Repository validation commands
548
318
 
@@ -585,7 +355,7 @@ npm run deploy
585
355
 
586
356
  - `npm run dev`:启动本地 Vite 服务和 `hb-sdk` 内置 mock runtime host,适合本地调试 SDK 能力;调试页内可点击按钮在 Mac 版 APP 中启动同一页面,也可以选择局域网网卡后用手机小黑盒 APP 扫码调试。手机需要与电脑处在同一局域网,并使用支持小程序调试壳的新版小黑盒 APP。Codex、VSCode 等内嵌浏览器可能无法唤起系统 APP,需要时请在系统浏览器中打开同一个调试页后重试。
587
357
  - `npm run build`:先执行 TypeScript 检查,再构建生产产物。
588
- - `npm run deploy -- --release-note "..."`:构建、上传并提交当前小程序版本审核。部署前需要先把 `package.json` 中的 `heybox.miniProgramId` 改成后台分配的真实小程序 id,并执行过 `npx hb-sdk login`;默认审核通过后需在开放平台手动发布,如需审核通过后自动发布可追加 `--auto-publish`。
358
+ - `npm run deploy -- --release-note "..."`:运行 `hb-sdk remote deploy`,构建、上传并提交当前小程序版本审核。部署前需要先执行过 `npx hb-sdk login`;多主体账号还应通过 `npx hb-sdk remote entity current` 确认服务端 current entity。远端小程序可通过 `npx hb-sdk remote create --name "..."` 在 current entity 下创建并绑定,或用 `npx hb-sdk remote bind <mini-program-id>` 绑定 current entity 可管理的已有小程序。`selectedEntity` 只是 CLI 登录缓存中的提示快照,实际 deploy/create/bind 以服务端 current entity 为准。默认审核通过后用 `hb-sdk remote versions` 查看状态,再用 `hb-sdk remote release <version>` 发布,如需审核通过后自动发布可追加 `--auto-publish`。顶层 `hb-sdk deploy` 已删除,不再作为兼容别名保留。
589
359
 
590
360
  ## 更多能力
591
361