@heybox/hb-sdk 0.8.5 → 0.9.0-alpha.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 (28) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/cli-chunks/{build-zYnPSPFa.cjs → build-Dv5vWsBh.cjs} +5 -5
  3. package/dist/cli-chunks/{context-DWoKsM_O.cjs → context-B15FzPf9.cjs} +2 -2
  4. package/dist/cli-chunks/{create-C9FcEn9Y.cjs → create-BtZUsxJd.cjs} +1 -1
  5. package/dist/cli-chunks/{dev-VxeEocjt.cjs → dev-tAThflC6.cjs} +114 -40
  6. package/dist/cli-chunks/{doctor-6Cf9o1hD.cjs → doctor-PE_MhGBX.cjs} +1 -1
  7. package/dist/cli-chunks/{index-BpLYUwNe.cjs → index-CeA8xI0T.cjs} +2 -2
  8. package/dist/cli-chunks/{index-Brq_-WV3.cjs → index-Dd_eGaDz.cjs} +15 -15
  9. package/dist/cli-chunks/{index.esm-DMvmTtIS.cjs → index.esm-Bw3R5BAL.cjs} +7 -7
  10. package/dist/cli-chunks/{login-DeZpNrkY.cjs → login-5FPaFRi0.cjs} +2 -2
  11. package/dist/cli-chunks/{project-vite-TFEwLzYM.cjs → project-vite-ckDtbYtt.cjs} +1 -1
  12. package/dist/cli-chunks/{remote-DOU11SNj.cjs → remote-DCHqFvmB.cjs} +7 -7
  13. package/dist/cli-chunks/{runtime-gate-DikSEEtm.cjs → runtime-gate-DkTbgx4d.cjs} +1 -1
  14. package/dist/cli-chunks/{runtime-permission-env-Bs_JqpTM.cjs → runtime-permission-env-DR89buKQ.cjs} +1 -1
  15. package/dist/cli-chunks/{session-CbisOcE4.cjs → session-BiT-5VHK.cjs} +1 -1
  16. package/dist/cli-chunks/{skill-B82gXQhX.cjs → skill-C5EoUf2T.cjs} +2 -2
  17. package/dist/cli-chunks/{version-UEmqQ6A-.cjs → version-CJ7rfbl-.cjs} +1 -1
  18. package/dist/cli.cjs +1 -1
  19. package/dist/devtools/browser-dev-host/assets/{browser-dev-host-MOwoKrAP.js → browser-dev-host-Cu0OUKXf.js} +1 -1
  20. package/dist/devtools/browser-dev-host/assets/{desktop-app-launch-BcQjavzW.js → desktop-app-launch-2BQ4uwPZ.js} +1 -1
  21. package/dist/devtools/browser-dev-host/assets/{index-CS-AbGTE.js → index-B1ZPOArZ.js} +3 -3
  22. package/dist/devtools/browser-dev-host/index.html +2 -2
  23. package/dist/index.cjs.js +1 -1
  24. package/dist/index.esm.js +1 -1
  25. package/dist/vite.cjs.js +1 -1
  26. package/dist/vite.esm.js +1 -1
  27. package/package.json +6 -6
  28. package/skill/skill.json +4 -4
package/CHANGELOG.md CHANGED
@@ -2,6 +2,23 @@
2
2
 
3
3
  本文件随 `@heybox/hb-sdk` npm 包公开分发,只记录外部小程序开发者可观察到的变化。
4
4
 
5
+ ## 0.9.0-alpha.0 - 2026-10-06
6
+
7
+ > 影响级别:常规
8
+ > 开发者动作:升级至 `0.9.0-alpha.0` 并重新运行 `hb-sdk dev`;运行期间在后台调整权限后,请重启 CLI 同步。
9
+ > 兼容范围:公开 SDK API 不变;调整本地真实客户端调试的详情读取与启动票可用条件。
10
+
11
+ ### 行为调整
12
+
13
+ - `hb-sdk dev` 只在启动、绑定或权限声明变化时读取远端详情;手机重连复用成功快照,票据续签不再触发详情轮询。
14
+ - 权限校验期间或失败后,真实客户端启动票暂停提供;更新声明并校验成功或重启 CLI 后恢复。
15
+
16
+ ### 问题修复
17
+
18
+ - 修复仅修改小程序绑定时未触发详情校验的问题。
19
+ - 修复声明连续变化时,旧详情、产物摘要或启动票覆盖最新调试状态的问题。
20
+ - 修复详情校验失败后仍能通过本地启动入口获取续签票据的问题。
21
+
5
22
  ## 0.8.5 - 2026-10-02
6
23
 
7
24
  > 影响级别:必须操作
@@ -3,13 +3,13 @@
3
3
  var fs$1 = require('node:fs');
4
4
  var fs = require('node:fs/promises');
5
5
  var path = require('node:path');
6
- var runtimePermissionEnv = require('./runtime-permission-env-Bs_JqpTM.cjs');
6
+ var runtimePermissionEnv = require('./runtime-permission-env-DR89buKQ.cjs');
7
7
  require('node:crypto');
8
8
  require('node:zlib');
9
- var runtimeGate = require('./runtime-gate-DikSEEtm.cjs');
10
- var index = require('./index-Brq_-WV3.cjs');
11
- var projectVite = require('./project-vite-TFEwLzYM.cjs');
12
- require('./version-UEmqQ6A-.cjs');
9
+ var runtimeGate = require('./runtime-gate-DkTbgx4d.cjs');
10
+ var index = require('./index-Dd_eGaDz.cjs');
11
+ var projectVite = require('./project-vite-ckDtbYtt.cjs');
12
+ require('./version-CJ7rfbl-.cjs');
13
13
  require('node:async_hooks');
14
14
  require('node:module');
15
15
  require('path');
@@ -3,10 +3,10 @@
3
3
  var node_crypto = require('node:crypto');
4
4
  var fs = require('node:fs/promises');
5
5
  var path = require('node:path');
6
- var runtimePermissionEnv = require('./runtime-permission-env-Bs_JqpTM.cjs');
6
+ var runtimePermissionEnv = require('./runtime-permission-env-DR89buKQ.cjs');
7
7
  var fs$1 = require('node:fs');
8
8
  var sharp = require('sharp');
9
- var session = require('./session-CbisOcE4.cjs');
9
+ var session = require('./session-BiT-5VHK.cjs');
10
10
 
11
11
  async function inspectBasicInfoImage(bytes, sourcePath, kind) {
12
12
  const inspected = await inspectDecodedBasicInfoImage(bytes, kind);
@@ -5,7 +5,7 @@ var fs = require('node:fs/promises');
5
5
  var path = require('node:path');
6
6
  var require$$0 = require('fs');
7
7
  var require$$1 = require('path');
8
- var index = require('./index-Brq_-WV3.cjs');
8
+ var index = require('./index-Dd_eGaDz.cjs');
9
9
  require('node:module');
10
10
  require('os');
11
11
  require('node:crypto');
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var context = require('./context-DWoKsM_O.cjs');
3
+ var context = require('./context-B15FzPf9.cjs');
4
4
  var node_crypto = require('node:crypto');
5
5
  var fs = require('node:fs');
6
- var runtimePermissionEnv = require('./runtime-permission-env-Bs_JqpTM.cjs');
6
+ var runtimePermissionEnv = require('./runtime-permission-env-DR89buKQ.cjs');
7
7
  var os = require('node:os');
8
8
  var path = require('node:path');
9
9
  var net = require('node:net');
@@ -12,13 +12,13 @@ var node_http = require('node:http');
12
12
  var node_module = require('node:module');
13
13
  var undici = require('undici');
14
14
  var fs$1 = require('node:fs/promises');
15
- var index = require('./index-Brq_-WV3.cjs');
15
+ var index = require('./index-Dd_eGaDz.cjs');
16
16
  var require$$0$1 = require('crypto');
17
17
  var require$$0 = require('buffer');
18
- var session = require('./session-CbisOcE4.cjs');
18
+ var session = require('./session-BiT-5VHK.cjs');
19
19
  var browser = require('./browser-RAy8e8cV.cjs');
20
- var projectVite = require('./project-vite-TFEwLzYM.cjs');
21
- var version = require('./version-UEmqQ6A-.cjs');
20
+ var projectVite = require('./project-vite-ckDtbYtt.cjs');
21
+ var version = require('./version-CJ7rfbl-.cjs');
22
22
  require('node:zlib');
23
23
 
24
24
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
@@ -1992,8 +1992,8 @@ const DEFAULT_CHANNEL_TRANSPORT = {
1992
1992
  };
1993
1993
  const IPV4_LOOPBACK_ADDRESSES = new net.BlockList();
1994
1994
  IPV4_LOOPBACK_ADDRESSES.addSubnet('127.0.0.0', 8, 'ipv4');
1995
- const { WebSocket, WebSocketServer } = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/dev-VxeEocjt.cjs', document.baseURI).href)))('ws');
1996
- const { parse: parseHtml } = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/dev-VxeEocjt.cjs', document.baseURI).href)))('parse5');
1995
+ const { WebSocket, WebSocketServer } = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/dev-tAThflC6.cjs', document.baseURI).href)))('ws');
1996
+ const { parse: parseHtml } = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/dev-tAThflC6.cjs', document.baseURI).href)))('parse5');
1997
1997
  const BROWSER_DEV_HOST_ROOT_CANDIDATES = [
1998
1998
  path.resolve(__dirname, 'devtools/browser-dev-host'),
1999
1999
  path.resolve(__dirname, '../devtools/browser-dev-host'),
@@ -11092,7 +11092,7 @@ function assertNodeRuntimeCapabilities(ctx, settings) {
11092
11092
  function createNodeRealtimeDriverRegistry() {
11093
11093
  const registry = createRuntimeRealtimeDriverRegistry();
11094
11094
  registry.registerLazy('node-websocket', async () => {
11095
- const mod = await Promise.resolve().then(function () { return require('./index.esm-DMvmTtIS.cjs'); });
11095
+ const mod = await Promise.resolve().then(function () { return require('./index.esm-Bw3R5BAL.cjs'); });
11096
11096
  return mod.createNodeWebSocketRuntimeDriver();
11097
11097
  });
11098
11098
  return registry;
@@ -15218,7 +15218,7 @@ const COMPANION_ARTIFACT_ACCESS_TOKEN_ENV = 'HB_SDK_COMPANION_ARTIFACT_ACCESS_TO
15218
15218
  // 本地 PC 调试 manifest 的专用令牌:开窗时扩展还没拿到 LocalDevelopmentBinding,只能靠启动 URI 带来。
15219
15219
  const MINI_PROGRAM_MANIFEST_ACCESS_TOKEN_ENV = 'HB_SDK_MINI_PROGRAM_MANIFEST_ACCESS_TOKEN';
15220
15220
  const COMPANION_ARTIFACT_ACCESS_TOKEN_HEADER = 'x-hb-sdk-companion-dev-token';
15221
- /** Dev Context 结果缓存 TTL 默认值;手机端重连不再 1:1 产生远端请求。 */
15221
+ /** 失败上下文的缓存窗口;成功上下文复用到绑定或声明变化。 */
15222
15222
  const DEFAULT_DEV_CONTEXT_CACHE_TTL_MS = 30_000;
15223
15223
  /** 覆盖 Dev Context 缓存 TTL(毫秒);设为 0 关闭缓存。 */
15224
15224
  const DEV_CONTEXT_CACHE_TTL_ENV = 'HB_SDK_DEV_CONTEXT_TTL_MS';
@@ -15244,7 +15244,10 @@ const DEV_CONTEXT_RATE_LIMIT_CACHE_MAX_MS = 300_000;
15244
15244
  * `hb-sdk dev` 启动拖住几分钟却依然恢复不了。
15245
15245
  */
15246
15246
  const DEV_CONTEXT_STARTUP_RATE_LIMIT_WAIT_MAX_MS = 30_000;
15247
- /** 读取 Dev Context 缓存 TTL;非法值回落到默认 30s,0 表示关闭缓存。 */
15247
+ /** 新声明已替代在途请求;旧结果不应用,也不作为远端失败提示。 */
15248
+ class DevContextSupersededError extends Error {
15249
+ }
15250
+ /** 读取 Dev Context 缓存 TTL;非法值回落到默认 30 秒,0 表示关闭缓存。 */
15248
15251
  function resolveDevContextCacheTtlMs(env = process.env) {
15249
15252
  const raw = env[DEV_CONTEXT_CACHE_TTL_ENV];
15250
15253
  if (raw === undefined || raw.trim() === '')
@@ -15394,12 +15397,16 @@ async function runDevCommand(options, runtime = {}) {
15394
15397
  * 读取 Dev Context。
15395
15398
  *
15396
15399
  * key 里带上当前 `package.json` 绑定的 miniProgramId:项目绑定变更会直接换成另一个缓存 key,
15397
- * 立即重新请求远端,而不是等 30s TTL(限流时 300s)过期后才发现换了小程序。
15400
+ * 立即重新请求远端,而不是等缓存过期后才发现换了小程序。
15398
15401
  * 读绑定是本地文件读取,不打远端,符合「只读本地快照」的高频读范式。
15399
15402
  */
15400
- const readDevLaunchContext = async () => {
15403
+ const readDevLaunchContext = async (reuseSnapshot = false) => {
15401
15404
  const boundMiniProgramId = await context.readBoundMiniProgramId(projectRoot).catch(() => undefined);
15402
- return devContextCache.read(`${projectRoot}\0${boundMiniProgramId ?? ''}`);
15405
+ const key = `${projectRoot}\0${boundMiniProgramId ?? ''}`;
15406
+ const snapshot = reuseSnapshot ? devContextCache.peek(key) : undefined;
15407
+ if (snapshot?.context.source === 'remote' && !snapshot.context.rateLimit?.limited)
15408
+ return snapshot;
15409
+ return devContextCache.read(key);
15403
15410
  };
15404
15411
  let { context: devLaunchContext, miniProgram } = await readDevLaunchContext();
15405
15412
  let lastRateLimitHint = '';
@@ -15435,6 +15442,7 @@ async function runDevCommand(options, runtime = {}) {
15435
15442
  }
15436
15443
  }
15437
15444
  let currentDevContext = devLaunchContext;
15445
+ let devContextGeneration = 0;
15438
15446
  let contextRevision = 1;
15439
15447
  let launchRuntimePermissions = context.createMobileDevSessionRuntimePermissions(devLaunchContext);
15440
15448
  const mobileDevContextUrlsByOrigin = new Map();
@@ -15569,7 +15577,10 @@ async function runDevCommand(options, runtime = {}) {
15569
15577
  },
15570
15578
  readMobileDevSessionContext: async () => {
15571
15579
  if (currentDevContext.source === 'remote') {
15572
- const refreshed = await readDevLaunchContext();
15580
+ const generation = devContextGeneration;
15581
+ const refreshed = await readDevLaunchContext(true);
15582
+ if (generation !== devContextGeneration)
15583
+ return currentDevContext;
15573
15584
  if (refreshed.context.rateLimit?.limited) {
15574
15585
  // 被限流时不再替换上下文,只透出限流状态;手机端据此停止重连。
15575
15586
  applyRateLimitState(refreshed.context.rateLimit);
@@ -15613,7 +15624,10 @@ async function runDevCommand(options, runtime = {}) {
15613
15624
  companionDeclared: currentDevContext.declaredPermissions?.companion?.enabled === true && runtimePermissionEnv.hasMiniappDesktopPlatform(currentDevContext.platforms),
15614
15625
  miniProgramId: devLaunchContext.miniProgramId,
15615
15626
  refreshPermissions: async () => {
15627
+ const generation = devContextGeneration;
15616
15628
  const refreshed = await readDevLaunchContext();
15629
+ if (generation !== devContextGeneration)
15630
+ throw new DevContextSupersededError();
15617
15631
  // 限流必须原样抛出,才能走 30s 起、上限 300s 的退避与「请勿反复重启」提示。
15618
15632
  if (refreshed.context.rateLimit?.limited) {
15619
15633
  throw index.createCliRateLimitedErrorFromState(refreshed.context.rateLimit);
@@ -15644,7 +15658,10 @@ async function runDevCommand(options, runtime = {}) {
15644
15658
  },
15645
15659
  onReadiness: devReadiness => browserDevHost.updateBootstrap({ devReadiness }),
15646
15660
  // 主动失效:项目绑定变更或开发者点重试后立即重新请求(key 会带上新绑定,这里清空全部)。
15647
- onInvalidate: () => devContextCache.invalidate(),
15661
+ onInvalidate: () => {
15662
+ devContextGeneration += 1;
15663
+ devContextCache.invalidate();
15664
+ },
15648
15665
  // 限流状态与恢复都要透出给调试页与宿主页。
15649
15666
  onRateLimit: state => applyRateLimitState(state),
15650
15667
  projectRoot,
@@ -15674,10 +15691,11 @@ async function runDevCommand(options, runtime = {}) {
15674
15691
  * `refresh()` 会清空缓存并立刻打一次远端 `detail`(密集写入可达数十次/分钟)。
15675
15692
  */
15676
15693
  let lastDeclarationFingerprint;
15694
+ const readBindingFingerprint = () => context.readBoundMiniProgramIdFromPackageJson(JSON.parse(fs.readFileSync(packagePath, 'utf8')));
15677
15695
  const readDeclarationFingerprint = () => JSON.stringify([
15678
15696
  runtimePermissionEnv.readMiniappPermissionsFromPackageJson(projectRoot, runtimePermissionEnv.resolveMiniappSdkVersion()).permissions ?? null,
15679
15697
  runtimePermissionEnv.readMiniappPlatformsFromPackageJson(projectRoot),
15680
- context.readBoundMiniProgramId(projectRoot),
15698
+ readBindingFingerprint(),
15681
15699
  ]);
15682
15700
  // 先记录启动时已生效的声明,这样与调试声明无关的写入(版本号、依赖等)不会触发远端刷新。
15683
15701
  try {
@@ -15692,7 +15710,7 @@ async function runDevCommand(options, runtime = {}) {
15692
15710
  const local = runtimePermissionEnv.readMiniappPermissionsFromPackageJson(projectRoot, runtimePermissionEnv.resolveMiniappSdkVersion());
15693
15711
  const platforms = runtimePermissionEnv.readMiniappPlatformsFromPackageJson(projectRoot);
15694
15712
  // 与调试声明无关的写入(版本号、依赖等)不触发远端刷新。
15695
- const fingerprint = JSON.stringify([local.permissions ?? null, platforms, context.readBoundMiniProgramId(projectRoot)]);
15713
+ const fingerprint = JSON.stringify([local.permissions ?? null, platforms, readBindingFingerprint()]);
15696
15714
  if (fingerprint === lastDeclarationFingerprint)
15697
15715
  return;
15698
15716
  lastDeclarationFingerprint = fingerprint;
@@ -16093,14 +16111,17 @@ function startLocalDevLaunchTokenSession(options) {
16093
16111
  let hasReportedTokenFailure = false;
16094
16112
  let refreshTimer;
16095
16113
  let companionDeclared = options.companionDeclared;
16096
- let permissionsRefreshAt = Date.now() + 30_000;
16114
+ let permissionsRefreshPending = false;
16115
+ let permissionsRefreshFailure;
16116
+ let permissionsGeneration = 0;
16117
+ let validatedPermissionsGeneration = 0;
16097
16118
  let publishedToken;
16098
16119
  let publishedDigest;
16099
16120
  let ticket;
16100
16121
  let pending;
16101
16122
  let refreshing = false;
16102
16123
  let consecutiveFailures = 0;
16103
- const getTicket = async (companionManifestSha256) => {
16124
+ const acquireTicket = async (companionManifestSha256) => {
16104
16125
  if (closed)
16105
16126
  return undefined;
16106
16127
  if (ticket && (companionManifestSha256 === undefined || ticket.companionManifestSha256 === companionManifestSha256) && ticket.refreshAt > Date.now())
@@ -16110,11 +16131,14 @@ function startLocalDevLaunchTokenSession(options) {
16110
16131
  const issueTicket = (companionManifestSha256) => {
16111
16132
  if (pending && pending.digest === companionManifestSha256)
16112
16133
  return pending.promise;
16134
+ const generation = permissionsGeneration;
16113
16135
  const promise = issueLocalDevLaunchToken({
16114
16136
  ...options,
16115
16137
  ...(companionManifestSha256 ? { companionManifestSha256 } : {}),
16116
16138
  })
16117
16139
  .then(issued => {
16140
+ if (closed || generation !== permissionsGeneration)
16141
+ throw new DevContextSupersededError();
16118
16142
  ticket = issued;
16119
16143
  return issued;
16120
16144
  }).finally(() => { if (pending?.promise === promise)
@@ -16122,16 +16146,50 @@ function startLocalDevLaunchTokenSession(options) {
16122
16146
  pending = { digest: companionManifestSha256, promise };
16123
16147
  return promise;
16124
16148
  };
16149
+ const getTicket = async (companionManifestSha256) => {
16150
+ if (closed)
16151
+ return undefined;
16152
+ const generation = permissionsGeneration;
16153
+ const assertPermissionsReady = () => {
16154
+ if (generation !== permissionsGeneration)
16155
+ throw new DevContextSupersededError();
16156
+ if (permissionsRefreshFailure)
16157
+ throw permissionsRefreshFailure.error;
16158
+ if (validatedPermissionsGeneration !== permissionsGeneration)
16159
+ throw new Error('远端上下文正在刷新,请稍后再试');
16160
+ };
16161
+ assertPermissionsReady();
16162
+ const issued = await acquireTicket(companionManifestSha256);
16163
+ if (closed)
16164
+ return undefined;
16165
+ assertPermissionsReady();
16166
+ return issued;
16167
+ };
16125
16168
  const refresh = async () => {
16126
16169
  if (refreshing || closed)
16127
16170
  return;
16128
16171
  refreshing = true;
16172
+ const generation = permissionsGeneration;
16129
16173
  try {
16130
- if (options.refreshPermissions && Date.now() >= permissionsRefreshAt) {
16131
- // A-3:无论成败都推进,否则权限刷新失败后每一轮重试都会再打一次远端 detail。
16132
- permissionsRefreshAt = Date.now() + 30_000;
16133
- companionDeclared = await options.refreshPermissions();
16174
+ if (options.refreshPermissions && permissionsRefreshPending) {
16175
+ permissionsRefreshPending = false;
16176
+ try {
16177
+ const nextCompanionDeclared = await options.refreshPermissions();
16178
+ if (generation !== permissionsGeneration || closed)
16179
+ return;
16180
+ companionDeclared = nextCompanionDeclared;
16181
+ permissionsRefreshFailure = undefined;
16182
+ validatedPermissionsGeneration = generation;
16183
+ }
16184
+ catch (error) {
16185
+ if (generation !== permissionsGeneration || error instanceof DevContextSupersededError)
16186
+ return;
16187
+ permissionsRefreshFailure = { error };
16188
+ throw error;
16189
+ }
16134
16190
  }
16191
+ if (!options.refreshPermissions)
16192
+ validatedPermissionsGeneration = generation;
16135
16193
  let manifest;
16136
16194
  let snapshotError;
16137
16195
  try {
@@ -16144,44 +16202,51 @@ function startLocalDevLaunchTokenSession(options) {
16144
16202
  catch (error) {
16145
16203
  snapshotError = error;
16146
16204
  }
16205
+ if (closed || generation !== permissionsGeneration)
16206
+ return;
16147
16207
  const digest = manifest?.artifacts.length ? manifest.digest : undefined;
16148
- const issued = await getTicket(digest);
16208
+ const issued = await acquireTicket(digest);
16149
16209
  if (!issued)
16150
16210
  return;
16151
- if (closed)
16211
+ if (closed || generation !== permissionsGeneration)
16152
16212
  return;
16153
- if (publishedToken !== issued.token || publishedDigest !== digest) {
16213
+ if (!permissionsRefreshFailure && (publishedToken !== issued.token || publishedDigest !== digest)) {
16154
16214
  publishedToken = issued.token;
16155
16215
  publishedDigest = digest;
16156
16216
  options.onToken(issued.token, digest, issued.expiresAt);
16157
16217
  }
16158
16218
  options.onReadiness({
16159
16219
  browser: { state: 'ready' },
16160
- mobile: { state: 'ready' },
16161
- companion: snapshotError
16162
- ? { state: snapshotError instanceof Error && snapshotError.message.includes('artifact-updating') ? 'pending' : 'blocked', reason: safeCompanionFailureReason(snapshotError) }
16163
- : manifest?.artifacts.length
16164
- ? companionDeclared
16165
- ? { state: 'ready', digest, artifacts: manifest.artifacts, reason: '本地产物和启动票已就绪,PC 授权将在打开后验证' }
16166
- : { state: 'blocked', reason: 'Companion 本地权限或桌面平台声明未开启' }
16167
- : { state: 'not-configured', reason: '未配置本地 Companion 产物' },
16220
+ mobile: permissionsRefreshFailure
16221
+ ? { state: 'blocked', reason: '远端上下文刷新失败,请更新声明或重新启动调试' }
16222
+ : { state: 'ready' },
16223
+ companion: permissionsRefreshFailure
16224
+ ? { state: 'blocked', reason: '远端上下文刷新失败,请更新声明或重新启动调试' }
16225
+ : snapshotError
16226
+ ? { state: snapshotError instanceof Error && snapshotError.message.includes('artifact-updating') ? 'pending' : 'blocked', reason: safeCompanionFailureReason(snapshotError) }
16227
+ : manifest?.artifacts.length
16228
+ ? companionDeclared
16229
+ ? { state: 'ready', digest, artifacts: manifest.artifacts, reason: '本地产物和启动票已就绪,PC 授权将在打开后验证' }
16230
+ : { state: 'blocked', reason: 'Companion 本地权限或桌面平台声明未开启' }
16231
+ : { state: 'not-configured', reason: '未配置本地 Companion 产物' },
16168
16232
  });
16169
16233
  if (snapshotError)
16170
16234
  options.logger.debug(`PC Companion 快照校验失败:${index.readRedactedErrorMessage(snapshotError, { verbose: true })}`);
16171
16235
  const ttl = Math.max(0, issued.expiresAt - Date.now());
16172
- scheduleExpiration(ttl);
16236
+ if (!permissionsRefreshFailure)
16237
+ scheduleExpiration(ttl);
16173
16238
  schedule(Math.min(2_000, Math.max(1_000, Math.floor(ttl * 0.8))));
16174
- if (hasReportedTokenFailure) {
16239
+ if (hasReportedTokenFailure && !permissionsRefreshFailure) {
16175
16240
  hasReportedTokenFailure = false;
16176
16241
  options.logger.success('本地调试凭证已恢复');
16177
16242
  }
16178
- if (consecutiveFailures > 0) {
16243
+ if (consecutiveFailures > 0 && !permissionsRefreshFailure) {
16179
16244
  consecutiveFailures = 0;
16180
16245
  options.onRateLimit?.(null);
16181
16246
  }
16182
16247
  }
16183
16248
  catch (error) {
16184
- if (closed)
16249
+ if (closed || generation !== permissionsGeneration || error instanceof DevContextSupersededError)
16185
16250
  return;
16186
16251
  // A2 + A3:限流类错误走 30s 起、上限 300s 的退避,并明确提示不要反复重启。
16187
16252
  const rateLimitState = index.readCliRateLimitState(error);
@@ -16207,6 +16272,12 @@ function startLocalDevLaunchTokenSession(options) {
16207
16272
  }
16208
16273
  finally {
16209
16274
  refreshing = false;
16275
+ // 请求期间有新声明时立即处理最新一代,避免被并发保护丢掉刷新事件。
16276
+ if (permissionsRefreshPending && !closed) {
16277
+ if (refreshTimer)
16278
+ clearTimeout(refreshTimer);
16279
+ schedule(0);
16280
+ }
16210
16281
  }
16211
16282
  };
16212
16283
  const schedule = (delayMs) => {
@@ -16235,7 +16306,10 @@ function startLocalDevLaunchTokenSession(options) {
16235
16306
  refresh: () => {
16236
16307
  // 项目绑定变更或开发者主动重试:主动失效 Dev Context 缓存后立即重新请求。
16237
16308
  options.onInvalidate?.();
16238
- permissionsRefreshAt = 0;
16309
+ permissionsGeneration += 1;
16310
+ permissionsRefreshPending = true;
16311
+ ticket = undefined;
16312
+ pending = undefined;
16239
16313
  publishedDigest = undefined;
16240
16314
  if (refreshTimer)
16241
16315
  clearTimeout(refreshTimer);
@@ -3,7 +3,7 @@
3
3
  var fs = require('node:fs/promises');
4
4
  var os = require('node:os');
5
5
  var path = require('node:path');
6
- var index = require('./index-Brq_-WV3.cjs');
6
+ var index = require('./index-Dd_eGaDz.cjs');
7
7
  require('node:module');
8
8
  require('node:fs');
9
9
  require('path');
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var index$2 = require('./index-Brq_-WV3.cjs');
3
+ var index$2 = require('./index-Dd_eGaDz.cjs');
4
4
  var require$$0$3 = require('fs');
5
5
  var require$$0$2 = require('crypto');
6
6
  var require$$1$2 = require('path');
7
7
  var require$$0$5 = require('assert');
8
8
  var require$$0$4 = require('events');
9
9
  var require$$1$1 = require('util');
10
- var runtimePermissionEnv = require('./runtime-permission-env-Bs_JqpTM.cjs');
10
+ var runtimePermissionEnv = require('./runtime-permission-env-DR89buKQ.cjs');
11
11
  var require$$0$7 = require('net');
12
12
  var require$$0$6 = require('url');
13
13
  var require$$2$1 = require('http');
@@ -235,19 +235,19 @@ function requireArgument () {
235
235
 
236
236
  var command = {};
237
237
 
238
- const require$5 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-Brq_-WV3.cjs', document.baseURI).href)));
238
+ const require$5 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-Dd_eGaDz.cjs', document.baseURI).href)));
239
239
  function __require$4() { return require$5("node:events"); }
240
240
 
241
- const require$4 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-Brq_-WV3.cjs', document.baseURI).href)));
241
+ const require$4 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-Dd_eGaDz.cjs', document.baseURI).href)));
242
242
  function __require$3() { return require$4("node:child_process"); }
243
243
 
244
- const require$3 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-Brq_-WV3.cjs', document.baseURI).href)));
244
+ const require$3 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-Dd_eGaDz.cjs', document.baseURI).href)));
245
245
  function __require$2() { return require$3("node:path"); }
246
246
 
247
- const require$2 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-Brq_-WV3.cjs', document.baseURI).href)));
247
+ const require$2 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-Dd_eGaDz.cjs', document.baseURI).href)));
248
248
  function __require$1() { return require$2("node:fs"); }
249
249
 
250
- const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-Brq_-WV3.cjs', document.baseURI).href)));
250
+ const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli-chunks/index-Dd_eGaDz.cjs', document.baseURI).href)));
251
251
  function __require() { return require$1("node:process"); }
252
252
 
253
253
  var help = {};
@@ -13554,7 +13554,7 @@ function getPathname(pathWithQuery) {
13554
13554
  }
13555
13555
 
13556
13556
  const CLI_VERSION_PLACEHOLDER = ['__HB', 'SDK', 'CLI', 'VERSION__'].join('_');
13557
- const BUILT_CLI_VERSION = '0.8.5';
13557
+ const BUILT_CLI_VERSION = '0.9.0-alpha.0';
13558
13558
  const PACKAGE_JSON_CANDIDATES = [
13559
13559
  path.resolve(__dirname, '..', '..', 'package.json'),
13560
13560
  path.resolve(__dirname, '..', 'package.json'),
@@ -13913,39 +13913,39 @@ function createCommandLoggerResolver(options) {
13913
13913
  };
13914
13914
  }
13915
13915
  const defaultClearLoginStatus = async (...args) => {
13916
- const { clearLoginStatus } = await Promise.resolve().then(function () { return require('./login-DeZpNrkY.cjs'); });
13916
+ const { clearLoginStatus } = await Promise.resolve().then(function () { return require('./login-5FPaFRi0.cjs'); });
13917
13917
  return clearLoginStatus(...args);
13918
13918
  };
13919
13919
  const defaultLoginToHeybox = async (...args) => {
13920
- const { loginToHeybox } = await Promise.resolve().then(function () { return require('./login-DeZpNrkY.cjs'); });
13920
+ const { loginToHeybox } = await Promise.resolve().then(function () { return require('./login-5FPaFRi0.cjs'); });
13921
13921
  return loginToHeybox(...args);
13922
13922
  };
13923
13923
  const defaultPrintLoginStatus = async (...args) => {
13924
- const { printLoginStatus } = await Promise.resolve().then(function () { return require('./login-DeZpNrkY.cjs'); });
13924
+ const { printLoginStatus } = await Promise.resolve().then(function () { return require('./login-5FPaFRi0.cjs'); });
13925
13925
  return printLoginStatus(...args);
13926
13926
  };
13927
13927
  const defaultRunBuildCommand = async (...args) => {
13928
- const { runBuildCommand } = await Promise.resolve().then(function () { return require('./build-zYnPSPFa.cjs'); });
13928
+ const { runBuildCommand } = await Promise.resolve().then(function () { return require('./build-Dv5vWsBh.cjs'); });
13929
13929
  return runBuildCommand(...args);
13930
13930
  };
13931
13931
  const defaultRunCreateCommand = async (...args) => {
13932
- const { runCreateCommand } = await Promise.resolve().then(function () { return require('./create-C9FcEn9Y.cjs'); });
13932
+ const { runCreateCommand } = await Promise.resolve().then(function () { return require('./create-BtZUsxJd.cjs'); });
13933
13933
  return runCreateCommand(...args);
13934
13934
  };
13935
13935
  const defaultRunDevCommand = async (...args) => {
13936
- const { runDevCommand } = await Promise.resolve().then(function () { return require('./dev-VxeEocjt.cjs'); }).then(function (n) { return n.dev; });
13936
+ const { runDevCommand } = await Promise.resolve().then(function () { return require('./dev-tAThflC6.cjs'); }).then(function (n) { return n.dev; });
13937
13937
  return runDevCommand(...args);
13938
13938
  };
13939
13939
  const defaultRunDoctorCommand = async (...args) => {
13940
- const { runDoctorCommand } = await Promise.resolve().then(function () { return require('./doctor-6Cf9o1hD.cjs'); });
13940
+ const { runDoctorCommand } = await Promise.resolve().then(function () { return require('./doctor-PE_MhGBX.cjs'); });
13941
13941
  return runDoctorCommand(...args);
13942
13942
  };
13943
13943
  const defaultRunSkillInstallCommand = async (...args) => {
13944
- const { runSkillInstallCommand } = await Promise.resolve().then(function () { return require('./skill-B82gXQhX.cjs'); });
13944
+ const { runSkillInstallCommand } = await Promise.resolve().then(function () { return require('./skill-C5EoUf2T.cjs'); });
13945
13945
  return runSkillInstallCommand(...args);
13946
13946
  };
13947
13947
  const defaultRunRemoteCommand = async (...args) => {
13948
- const { runRemoteCommand } = await Promise.resolve().then(function () { return require('./remote-DOU11SNj.cjs'); });
13948
+ const { runRemoteCommand } = await Promise.resolve().then(function () { return require('./remote-DCHqFvmB.cjs'); });
13949
13949
  return runRemoteCommand(...args);
13950
13950
  };
13951
13951
  function resolveStandaloneLogger(options, verbose) {
@@ -11,8 +11,8 @@ var require$$0$4 = require('url');
11
11
  var require$$0 = require('zlib');
12
12
  var require$$0$1 = require('buffer');
13
13
  var require$$1 = require('util');
14
- var index = require('./index-Brq_-WV3.cjs');
15
- var dev = require('./dev-VxeEocjt.cjs');
14
+ var index = require('./index-Dd_eGaDz.cjs');
15
+ var dev = require('./dev-tAThflC6.cjs');
16
16
  require('node:module');
17
17
  require('node:fs');
18
18
  require('node:fs/promises');
@@ -23,12 +23,12 @@ require('node:crypto');
23
23
  require('readline');
24
24
  require('tty');
25
25
  require('assert');
26
- require('./context-DWoKsM_O.cjs');
27
- require('./runtime-permission-env-Bs_JqpTM.cjs');
28
- require('./version-UEmqQ6A-.cjs');
26
+ require('./context-B15FzPf9.cjs');
27
+ require('./runtime-permission-env-DR89buKQ.cjs');
28
+ require('./version-CJ7rfbl-.cjs');
29
29
  require('node:async_hooks');
30
30
  require('sharp');
31
- require('./session-CbisOcE4.cjs');
31
+ require('./session-BiT-5VHK.cjs');
32
32
  require('fs');
33
33
  require('constants');
34
34
  require('node:os');
@@ -42,7 +42,7 @@ require('node:buffer');
42
42
  require('node:url');
43
43
  require('node:util');
44
44
  require('node:child_process');
45
- require('./project-vite-TFEwLzYM.cjs');
45
+ require('./project-vite-ckDtbYtt.cjs');
46
46
  require('node:zlib');
47
47
 
48
48
  var bufferUtil = {exports: {}};
@@ -3,9 +3,9 @@
3
3
  var promises = require('node:readline/promises');
4
4
  var node_crypto = require('node:crypto');
5
5
  var node_http = require('node:http');
6
- var session = require('./session-CbisOcE4.cjs');
6
+ var session = require('./session-BiT-5VHK.cjs');
7
7
  var browser = require('./browser-RAy8e8cV.cjs');
8
- var index = require('./index-Brq_-WV3.cjs');
8
+ var index = require('./index-Dd_eGaDz.cjs');
9
9
  require('node:path');
10
10
  require('fs');
11
11
  require('constants');
@@ -5,7 +5,7 @@ var fs$1 = require('node:fs/promises');
5
5
  var node_module = require('node:module');
6
6
  var path = require('node:path');
7
7
  var node_url = require('node:url');
8
- var index = require('./index-Brq_-WV3.cjs');
8
+ var index = require('./index-Dd_eGaDz.cjs');
9
9
 
10
10
  function findProjectRoot(startDir) {
11
11
  let current = path.resolve(startDir);
@@ -1,18 +1,18 @@
1
1
  'use strict';
2
2
 
3
- var runtimePermissionEnv = require('./runtime-permission-env-Bs_JqpTM.cjs');
4
- var context = require('./context-DWoKsM_O.cjs');
3
+ var runtimePermissionEnv = require('./runtime-permission-env-DR89buKQ.cjs');
4
+ var context = require('./context-B15FzPf9.cjs');
5
5
  var promises = require('node:readline/promises');
6
- var index = require('./index-Brq_-WV3.cjs');
7
- var session = require('./session-CbisOcE4.cjs');
6
+ var index = require('./index-Dd_eGaDz.cjs');
7
+ var session = require('./session-BiT-5VHK.cjs');
8
8
  var childProcess = require('node:child_process');
9
9
  var fs = require('node:fs');
10
10
  var fs$1 = require('node:fs/promises');
11
11
  var path = require('node:path');
12
12
  var node_crypto = require('node:crypto');
13
13
  require('node:zlib');
14
- var runtimeGate = require('./runtime-gate-DikSEEtm.cjs');
15
- require('./version-UEmqQ6A-.cjs');
14
+ var runtimeGate = require('./runtime-gate-DkTbgx4d.cjs');
15
+ require('./version-CJ7rfbl-.cjs');
16
16
  require('node:async_hooks');
17
17
  require('sharp');
18
18
  require('node:module');
@@ -274,7 +274,7 @@ function createDefaultCosClient(uploadToken, COS) {
274
274
  };
275
275
  }
276
276
  async function loadCosConstructor() {
277
- const cosModule = await Promise.resolve().then(function () { return require('./index-BpLYUwNe.cjs'); }).then(function (n) { return n.index; });
277
+ const cosModule = await Promise.resolve().then(function () { return require('./index-CeA8xI0T.cjs'); }).then(function (n) { return n.index; });
278
278
  return cosModule.default;
279
279
  }
280
280
  function formatSize(bytes) {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var runtimePermissionEnv = require('./runtime-permission-env-Bs_JqpTM.cjs');
3
+ var runtimePermissionEnv = require('./runtime-permission-env-DR89buKQ.cjs');
4
4
 
5
5
  // Shorthands
6
6
  /**
@@ -2,7 +2,7 @@
2
2
 
3
3
  var fs = require('node:fs');
4
4
  var path = require('node:path');
5
- var version = require('./version-UEmqQ6A-.cjs');
5
+ var version = require('./version-CJ7rfbl-.cjs');
6
6
  require('node:crypto');
7
7
  var node_async_hooks = require('node:async_hooks');
8
8