@heybox/hb-sdk 0.9.2-alpha.7 → 0.9.2-alpha.8

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 (36) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +2 -0
  3. package/dist/cli-chunks/{build-Do22AWbq.cjs → build-BinntZJf.cjs} +5 -5
  4. package/dist/cli-chunks/{context-DQhjWa7X.cjs → context-BI3QMxw2.cjs} +2 -2
  5. package/dist/cli-chunks/{create-QuI_mw8x.cjs → create-BK028Mlk.cjs} +1 -1
  6. package/dist/cli-chunks/deploy-lock-pKDDxTKm.cjs +148 -0
  7. package/dist/cli-chunks/{dev-KAhj5UTy.cjs → dev-DeNzUY6g.cjs} +8 -8
  8. package/dist/cli-chunks/{doctor-DNoQWBpo.cjs → doctor-BOfbKnN2.cjs} +1 -1
  9. package/dist/cli-chunks/games-yqu20laX.cjs +140 -0
  10. package/dist/cli-chunks/{index-DZUYwb3h.cjs → index-C7nrP0tt.cjs} +1 -1
  11. package/dist/cli-chunks/{index-bZIxID9N.cjs → index-CY67PpQk.cjs} +35 -16
  12. package/dist/cli-chunks/{index.esm-EWleN3S5.cjs → index.esm-DQdwzMhB.cjs} +6 -6
  13. package/dist/cli-chunks/{login-BYM3Nwau.cjs → login-PJdMmFoB.cjs} +1 -1
  14. package/dist/cli-chunks/{project-vite-6eLmb4Em.cjs → project-vite-Dm128JTE.cjs} +1 -1
  15. package/dist/cli-chunks/{remote-dvOjaxJu.cjs → remote-CZuy1lmn.cjs} +33 -146
  16. package/dist/cli-chunks/{runtime-gate-BKc2zPV-.cjs → runtime-gate-g3afiufR.cjs} +2 -2
  17. package/dist/cli-chunks/{runtime-permission-env-B9SqoP85.cjs → runtime-permission-env-CDx5qO-T.cjs} +2 -2
  18. package/dist/cli-chunks/{skill-DFXZ0SK_.cjs → skill-Bdy5Ehue.cjs} +2 -2
  19. package/dist/cli-chunks/{version-CwEOrhL1.cjs → version-D40WHkF9.cjs} +1 -1
  20. package/dist/cli.cjs +1 -1
  21. package/dist/devtools/browser-dev-host/assets/{browser-dev-host-BitDUIsy.js → browser-dev-host-BW7iWnpt.js} +1 -1
  22. package/dist/devtools/browser-dev-host/assets/{desktop-app-launch-B0yrI7xe.js → desktop-app-launch-lmlBUG16.js} +1 -1
  23. package/dist/devtools/browser-dev-host/assets/{index-D_mC4Hvt.js → index-D7F2y1lF.js} +3 -3
  24. package/dist/devtools/browser-dev-host/index.html +2 -2
  25. package/dist/index.cjs.js +1 -1
  26. package/dist/index.esm.js +1 -1
  27. package/dist/miniapp-publish.cjs.js +22 -0
  28. package/dist/miniapp-publish.esm.js +22 -1
  29. package/dist/templates/vanilla-vite-js/README.md.ejs +4 -0
  30. package/dist/vite.cjs.js +46 -3
  31. package/dist/vite.esm.js +46 -3
  32. package/package.json +5 -5
  33. package/skill/SKILL.md +9 -0
  34. package/skill/skill.json +5 -5
  35. package/types/miniapp-publish/index.d.ts +15 -2
  36. package/types/vite/index.d.ts +7 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  本文件随 `@heybox/hb-sdk` npm 包公开分发,只记录外部小程序开发者可观察到的变化。
4
4
 
5
+ ## 0.9.2-alpha.8 - 2026-10-20
6
+
7
+ ### 新增能力
8
+
9
+ - 新增 `hb-sdk remote games search "游戏名" --json`,查询平台游戏 appid、中英文名称和分页结果,无需先绑定小程序项目。
10
+ - CLI 游戏搜索增加请求频率保护,操作过于频繁时提示稍后重试。
11
+
12
+ ### 行为调整
13
+
14
+ - 开发启动、构建和部署时,对简介缺失、工具类未关联游戏给出非阻断提醒;部署不重复输出内部构建的资料提示。
15
+ - Agent Skill 主动检查小程序分类、简介和游戏绑定,保留已有内容,通用工具可保持不关联游戏。
16
+
17
+ ### 问题修复
18
+
19
+ - 修复 Vite 5/6 开发服务在输出资料或旧模板平台提醒时无法启动的问题。
20
+
5
21
  ## 0.9.2-alpha.7 - 2026-10-20
6
22
 
7
23
  ### 行为调整
package/README.md CHANGED
@@ -124,6 +124,8 @@ async function revokeAuthorizationFromUserAction() {
124
124
 
125
125
  小程序类别需在 `package.json#heybox.category` 声明为 `tool`、`game` 或 `other`,构建后写入 Manifest,CLI/Open 提审自动采用,发布后生效。开发者提审页不展示或提供手动选择类别;新上传版本(含已有小程序更新)必须声明,缺少类别的项目须补配置后重新构建上传,详见 [小程序类别](https://docs.xiaoheihe.cn/hb_sdk/guide/cli#小程序类别)。
126
126
 
127
+ 使用 `hb-sdk remote games search "游戏名" --json` 查询平台游戏候选,无需先绑定项目;核对后将返回的字符串 `appid` 填入 `heybox.bindAppIds`,能否绑定以部署预检为准。简介缺失、工具类未关联游戏时,开发启动、构建和部署会给出非阻断提醒;具体流程见 [CLI 指南](https://docs.xiaoheihe.cn/hb_sdk/guide/cli)。
128
+
127
129
  `bindAppIds` 只接受规范十进制字符串(形如 `/^[1-9]\d*$/`,拒绝前导零、空串与非数字),每项必须是正 int32(最大 `2147483647`),数组内不允许重复,最多 20 项,并按数值升序写入 Manifest。它不是权限,构建不联网;游戏真实性在远端预检和提审时校验。字段缺失或 `[]` 都表示清空绑定。PC 展示仍受 `platforms` 过滤。
128
130
 
129
131
  再启用构建插件:
@@ -1,14 +1,14 @@
1
1
  'use strict';
2
2
 
3
- var runtimeGate = require('./runtime-gate-BKc2zPV-.cjs');
3
+ var runtimeGate = require('./runtime-gate-g3afiufR.cjs');
4
4
  var fs$1 = require('node:fs');
5
5
  var fs = require('node:fs/promises');
6
6
  var path = require('node:path');
7
- var runtimePermissionEnv = require('./runtime-permission-env-B9SqoP85.cjs');
8
- var index = require('./index-bZIxID9N.cjs');
7
+ var runtimePermissionEnv = require('./runtime-permission-env-CDx5qO-T.cjs');
8
+ var index = require('./index-CY67PpQk.cjs');
9
9
  require('node:crypto');
10
10
  require('node:zlib');
11
- var projectVite = require('./project-vite-6eLmb4Em.cjs');
11
+ var projectVite = require('./project-vite-Dm128JTE.cjs');
12
12
  require('node:module');
13
13
  require('node:url');
14
14
  require('./_commonjs-dynamic-modules-DUamuDzp.cjs');
@@ -16,7 +16,7 @@ require('fs');
16
16
  require('path');
17
17
  require('os');
18
18
  require('inspector');
19
- require('./version-CwEOrhL1.cjs');
19
+ require('./version-D40WHkF9.cjs');
20
20
  require('node:async_hooks');
21
21
  require('readline');
22
22
  require('tty');
@@ -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-B9SqoP85.cjs');
6
+ var runtimePermissionEnv = require('./runtime-permission-env-CDx5qO-T.cjs');
7
7
  var fs$1 = require('node:fs');
8
8
  var sharp = require('sharp');
9
- var index = require('./index-bZIxID9N.cjs');
9
+ var index = require('./index-CY67PpQk.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-bZIxID9N.cjs');
8
+ var index = require('./index-CY67PpQk.cjs');
9
9
  require('node:module');
10
10
  require('readline');
11
11
  require('os');
@@ -0,0 +1,148 @@
1
+ 'use strict';
2
+
3
+ var node_crypto = require('node:crypto');
4
+ var fs = require('node:fs/promises');
5
+ var path = require('node:path');
6
+ var index = require('./index-CY67PpQk.cjs');
7
+
8
+ const DEPLOY_LOCKED_MESSAGE = '当前设备已有同版本产物正在上传,请等待完成后重试';
9
+ const DEPLOY_LOCK_DIRECTORY_NAME = 'deploy-locks';
10
+ const DEPLOY_LOCK_OWNER_FILE = 'owner.json';
11
+ const INCOMPLETE_LOCK_GRACE_MS = 30_000;
12
+ const defaultPaths = index.envPaths('hb-sdk', { suffix: '' });
13
+ class DeployLockConflictError extends Error {
14
+ }
15
+ async function withDeployLock(scope, operation, options = {}) {
16
+ let lock;
17
+ try {
18
+ lock = await acquireDeployLock(scope, options);
19
+ }
20
+ catch (error) {
21
+ if (error instanceof DeployLockConflictError) {
22
+ throw error;
23
+ }
24
+ // 本地文件锁只减少重复操作,文件系统异常不阻断服务端上传流程。
25
+ return operation();
26
+ }
27
+ try {
28
+ return await operation();
29
+ }
30
+ finally {
31
+ await lock.release().catch(() => undefined);
32
+ }
33
+ }
34
+ async function acquireDeployLock(scope, options = {}) {
35
+ const lockDirectory = getDeployLockDirectory(scope, options.cacheRoot);
36
+ const ownerFile = path.join(lockDirectory, DEPLOY_LOCK_OWNER_FILE);
37
+ const owner = {
38
+ version: 1,
39
+ pid: options.pid ?? process.pid,
40
+ token: options.token ?? node_crypto.randomBytes(16).toString('hex'),
41
+ };
42
+ await fs.mkdir(path.dirname(lockDirectory), { recursive: true, mode: 0o700 });
43
+ for (let attempt = 0; attempt < 2; attempt += 1) {
44
+ let created = false;
45
+ try {
46
+ await fs.mkdir(lockDirectory, { mode: 0o700 });
47
+ created = true;
48
+ await fs.writeFile(ownerFile, `${JSON.stringify(owner)}\n`, { encoding: 'utf8', mode: 0o600 });
49
+ return createDeployLock(lockDirectory, ownerFile, owner.token);
50
+ }
51
+ catch (error) {
52
+ if (created) {
53
+ await fs.rm(lockDirectory, { force: true, recursive: true });
54
+ throw error;
55
+ }
56
+ if (!isNodeError(error) || error.code !== 'EEXIST') {
57
+ throw error;
58
+ }
59
+ if (!(await canReclaimDeployLock(lockDirectory, ownerFile, options))) {
60
+ throw new DeployLockConflictError(DEPLOY_LOCKED_MESSAGE);
61
+ }
62
+ await reclaimDeployLock(lockDirectory, owner.token);
63
+ }
64
+ }
65
+ throw new DeployLockConflictError(DEPLOY_LOCKED_MESSAGE);
66
+ }
67
+ function getDeployLockDirectory(scope, cacheRoot = defaultPaths.cache) {
68
+ const scopeHash = node_crypto.createHash('sha256').update(`${scope.apiBaseUrl}\0${scope.miniProgramId}\0${scope.version}`).digest('hex');
69
+ return path.join(cacheRoot, DEPLOY_LOCK_DIRECTORY_NAME, scopeHash);
70
+ }
71
+ function createDeployLock(lockDirectory, ownerFile, token) {
72
+ let released = false;
73
+ return {
74
+ async release() {
75
+ if (released)
76
+ return;
77
+ released = true;
78
+ await removeOwnedLock(lockDirectory, ownerFile, token);
79
+ },
80
+ };
81
+ }
82
+ async function canReclaimDeployLock(lockDirectory, ownerFile, options) {
83
+ const owner = await readDeployLockOwner(ownerFile);
84
+ if (owner) {
85
+ return !(options.isProcessRunning ?? isProcessRunning)(owner.pid);
86
+ }
87
+ try {
88
+ const lockStat = await fs.stat(lockDirectory);
89
+ return (options.now ?? Date.now)() - lockStat.mtimeMs >= INCOMPLETE_LOCK_GRACE_MS;
90
+ }
91
+ catch (error) {
92
+ return isNodeError(error) && error.code === 'ENOENT';
93
+ }
94
+ }
95
+ async function removeOwnedLock(lockDirectory, ownerFile, token) {
96
+ const owner = await readDeployLockOwner(ownerFile);
97
+ if (owner?.token === token) {
98
+ await fs.rm(lockDirectory, { force: true, recursive: true });
99
+ }
100
+ }
101
+ async function reclaimDeployLock(lockDirectory, token) {
102
+ const reclaimDirectory = `${lockDirectory}.reclaim-${node_crypto.createHash('sha256').update(token).digest('hex')}`;
103
+ try {
104
+ await fs.rename(lockDirectory, reclaimDirectory);
105
+ }
106
+ catch (error) {
107
+ if (isNodeError(error) && error.code === 'ENOENT')
108
+ return;
109
+ throw error;
110
+ }
111
+ await fs.rm(reclaimDirectory, { force: true, recursive: true });
112
+ }
113
+ async function readDeployLockOwner(ownerFile) {
114
+ try {
115
+ const value = JSON.parse(await fs.readFile(ownerFile, 'utf8'));
116
+ return isDeployLockOwner(value) ? value : null;
117
+ }
118
+ catch (error) {
119
+ if (isNodeError(error) && error.code === 'ENOENT')
120
+ return null;
121
+ if (error instanceof SyntaxError)
122
+ return null;
123
+ throw error;
124
+ }
125
+ }
126
+ function isDeployLockOwner(value) {
127
+ return (typeof value === 'object' &&
128
+ value !== null &&
129
+ value.version === 1 &&
130
+ Number.isInteger(value.pid) &&
131
+ typeof value.token === 'string');
132
+ }
133
+ function isProcessRunning(pid) {
134
+ try {
135
+ process.kill(pid, 0);
136
+ return true;
137
+ }
138
+ catch (error) {
139
+ return !isNodeError(error) || error.code !== 'ESRCH';
140
+ }
141
+ }
142
+ function isNodeError(error) {
143
+ return error instanceof Error && 'code' in error;
144
+ }
145
+
146
+ exports.DEPLOY_LOCKED_MESSAGE = DEPLOY_LOCKED_MESSAGE;
147
+ exports.acquireDeployLock = acquireDeployLock;
148
+ exports.withDeployLock = withDeployLock;
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-bZIxID9N.cjs');
4
- var context = require('./context-DQhjWa7X.cjs');
3
+ var index = require('./index-CY67PpQk.cjs');
4
+ var context = require('./context-BI3QMxw2.cjs');
5
5
  var node_crypto = require('node:crypto');
6
6
  var fs = require('node:fs');
7
- var runtimePermissionEnv = require('./runtime-permission-env-B9SqoP85.cjs');
7
+ var runtimePermissionEnv = require('./runtime-permission-env-CDx5qO-T.cjs');
8
8
  var os = require('node:os');
9
9
  var path = require('node:path');
10
10
  var net = require('node:net');
@@ -16,8 +16,8 @@ var fs$1 = require('node:fs/promises');
16
16
  var require$$0$1 = require('crypto');
17
17
  var require$$0 = require('buffer');
18
18
  var browser = require('./browser-RAy8e8cV.cjs');
19
- var projectVite = require('./project-vite-6eLmb4Em.cjs');
20
- var version = require('./version-CwEOrhL1.cjs');
19
+ var projectVite = require('./project-vite-Dm128JTE.cjs');
20
+ var version = require('./version-D40WHkF9.cjs');
21
21
  require('node:zlib');
22
22
 
23
23
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
@@ -1995,8 +1995,8 @@ const DEFAULT_CHANNEL_TRANSPORT = {
1995
1995
  };
1996
1996
  const IPV4_LOOPBACK_ADDRESSES = new net.BlockList();
1997
1997
  IPV4_LOOPBACK_ADDRESSES.addSubnet('127.0.0.0', 8, 'ipv4');
1998
- 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-KAhj5UTy.cjs', document.baseURI).href)))('ws');
1999
- 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-KAhj5UTy.cjs', document.baseURI).href)))('parse5');
1998
+ 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-DeNzUY6g.cjs', document.baseURI).href)))('ws');
1999
+ 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-DeNzUY6g.cjs', document.baseURI).href)))('parse5');
2000
2000
  const BROWSER_DEV_HOST_ROOT_CANDIDATES = [
2001
2001
  path.resolve(__dirname, 'devtools/browser-dev-host'),
2002
2002
  path.resolve(__dirname, '../devtools/browser-dev-host'),
@@ -11100,7 +11100,7 @@ function assertNodeRuntimeCapabilities(ctx, settings) {
11100
11100
  function createNodeRealtimeDriverRegistry() {
11101
11101
  const registry = createRuntimeRealtimeDriverRegistry();
11102
11102
  registry.registerLazy('node-websocket', async () => {
11103
- const mod = await Promise.resolve().then(function () { return require('./index.esm-EWleN3S5.cjs'); });
11103
+ const mod = await Promise.resolve().then(function () { return require('./index.esm-DQdwzMhB.cjs'); });
11104
11104
  return mod.createNodeWebSocketRuntimeDriver();
11105
11105
  });
11106
11106
  return registry;
@@ -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-bZIxID9N.cjs');
6
+ var index = require('./index-CY67PpQk.cjs');
7
7
  require('node:module');
8
8
  require('readline');
9
9
  require('os');
@@ -0,0 +1,140 @@
1
+ 'use strict';
2
+
3
+ var node_crypto = require('node:crypto');
4
+ var fs = require('node:fs/promises');
5
+ var path = require('node:path');
6
+ var index = require('./index-CY67PpQk.cjs');
7
+ var deployLock = require('./deploy-lock-pKDDxTKm.cjs');
8
+ require('node:module');
9
+ require('readline');
10
+ require('os');
11
+ require('tty');
12
+ require('assert');
13
+ require('events');
14
+ require('stream');
15
+ require('buffer');
16
+ require('util');
17
+ require('path');
18
+ require('fs');
19
+ require('constants');
20
+ require('node:fs');
21
+ require('node:zlib');
22
+
23
+ const WINDOW_MS = 30 * 60 * 1000;
24
+ const MAX_REQUESTS = 50;
25
+ const INTERVAL_MS = 1000;
26
+ /** 仅限制当前设备 CLI 的出站搜索,账号隔离并跨进程、跨项目持久保存。 */
27
+ async function reserveGameSearchRequest(account, apiBaseUrl, options = {}) {
28
+ const cacheRoot = options.cacheRoot ?? index.envPaths('hb-sdk', { suffix: '' }).cache;
29
+ const scope = node_crypto.createHash('sha256').update(`${apiBaseUrl}\0${account}`).digest('hex');
30
+ let lock;
31
+ try {
32
+ lock = await deployLock.acquireDeployLock({ apiBaseUrl, miniProgramId: `game-search:${scope}`, version: 'rate-limit-v1' }, { cacheRoot });
33
+ }
34
+ catch (error) {
35
+ if (error instanceof Error && error.message === deployLock.DEPLOY_LOCKED_MESSAGE) {
36
+ throw new Error('游戏搜索请求正在处理中,请稍后重试');
37
+ }
38
+ throw error;
39
+ }
40
+ const directory = path.join(cacheRoot, 'game-search-limits');
41
+ const file = path.join(directory, `${scope}.json`);
42
+ const temp = `${file}.${node_crypto.randomUUID()}.tmp`;
43
+ try {
44
+ const now = (options.now ?? Date.now)();
45
+ let timestamps = [];
46
+ try {
47
+ const raw = await fs.readFile(file, 'utf8');
48
+ let stored;
49
+ try {
50
+ stored = JSON.parse(raw);
51
+ }
52
+ catch (error) {
53
+ if (!(error instanceof SyntaxError))
54
+ throw error;
55
+ }
56
+ if (Array.isArray(stored) && stored.length <= MAX_REQUESTS && stored.every((value) => Number.isSafeInteger(value) && value >= 0)) {
57
+ timestamps = stored.filter((value) => value > now - WINDOW_MS).sort((a, b) => a - b);
58
+ }
59
+ else {
60
+ // 在账号锁内清除损坏的辅助缓存,本次按新记录继续,避免永久阻断搜索。
61
+ await fs.rm(file, { force: true });
62
+ }
63
+ }
64
+ catch (error) {
65
+ if (error.code !== 'ENOENT')
66
+ throw error;
67
+ }
68
+ const last = timestamps.at(-1);
69
+ const intervalWait = last === undefined ? 0 : last + INTERVAL_MS - now;
70
+ const windowWait = timestamps.length < MAX_REQUESTS ? 0 : timestamps[0] + WINDOW_MS - now;
71
+ const wait = Math.max(intervalWait, windowWait);
72
+ if (wait > 0) {
73
+ throw new Error(`游戏搜索过于频繁,请 ${Math.ceil(wait / 1000)} 秒后重试`);
74
+ }
75
+ timestamps.push(now);
76
+ await fs.mkdir(directory, { recursive: true, mode: 0o700 });
77
+ await fs.writeFile(temp, JSON.stringify(timestamps), { mode: 0o600, flag: 'wx' });
78
+ await fs.rename(temp, file);
79
+ }
80
+ finally {
81
+ await fs.rm(temp, { force: true }).finally(() => lock.release());
82
+ }
83
+ }
84
+
85
+ const GAME_SEARCH_API_PATH = '/bbs/app/topic/search_game';
86
+ /** 查询平台游戏候选,不依赖项目绑定,也不写入本地配置或远端状态。 */
87
+ async function runGameSearchCommand(query, options = {}, runtime = {}) {
88
+ const q = query.trim();
89
+ if (!q || Array.from(q).length > 100)
90
+ throw new Error('游戏搜索关键词须为 1–100 个字符');
91
+ const offset = parsePagination(options.offset ?? '0', 'offset', 0, 10_000);
92
+ const limit = parsePagination(options.limit ?? '10', 'limit', 1, 20);
93
+ const session = runtime.session ?? (await (runtime.requireAuthSession ?? index.requireHeyboxAuthSession)());
94
+ const context = index.createHeyboxOpenPlatformRequestContext(session, GAME_SEARCH_API_PATH);
95
+ await reserveGameSearchRequest(session.heyboxId, context.baseUrl, runtime.rateLimit);
96
+ const response = await (runtime.fetchImpl ?? fetch)(index.createHeyboxApiUrl(context.baseUrl, GAME_SEARCH_API_PATH, { ...context.platformParams, q, offset, limit: limit + 1 }), { headers: context.headers, redirect: 'error', signal: AbortSignal.timeout(15_000) });
97
+ const result = await index.readHeyboxApiEnvelope(response, { pathWithQuery: GAME_SEARCH_API_PATH, requireResult: true });
98
+ if (!Array.isArray(result?.games))
99
+ throw new Error('游戏搜索返回格式异常:缺少 games 数组');
100
+ const games = result.games.slice(0, limit).map(normalizeGame);
101
+ const output = {
102
+ games,
103
+ has_more: result.games.length > limit,
104
+ next_offset: offset + games.length,
105
+ };
106
+ const message = options.json
107
+ ? JSON.stringify(output, null, 2)
108
+ : [
109
+ ...(games.length ? games.map((game) => `${game.appid}\t${game.name}${game.name_en ? `(${game.name_en})` : ''}`) : ['未找到匹配游戏,请尝试中文名或英文名。']),
110
+ '搜索结果为游戏候选,请核对具体游戏及平台;能否绑定以部署预检为准。',
111
+ ...(output.has_more ? [`更多结果:--offset ${output.next_offset} --limit ${limit}`] : []),
112
+ ].join('\n');
113
+ (runtime.write ?? ((text) => process.stdout.write(`${text}\n`)))(message);
114
+ return output;
115
+ }
116
+ function parsePagination(value, name, min, max) {
117
+ if (!/^(0|[1-9]\d*)$/.test(value))
118
+ throw new Error(`--${name} 必须为 ${min}–${max} 的整数`);
119
+ const parsed = Number(value);
120
+ if (!Number.isSafeInteger(parsed) || parsed < min || parsed > max)
121
+ throw new Error(`--${name} 必须为 ${min}–${max} 的整数`);
122
+ return parsed;
123
+ }
124
+ function normalizeGame(value) {
125
+ if (!value || typeof value !== 'object')
126
+ throw new Error('游戏搜索返回格式异常');
127
+ const game = value;
128
+ const appid = typeof game.appid === 'number' || typeof game.appid === 'string' ? String(game.appid) : '';
129
+ if (!/^[1-9]\d*$/.test(appid) ||
130
+ !Number.isSafeInteger(Number(appid)) ||
131
+ Number(appid) > 2_147_483_647 ||
132
+ typeof game.name !== 'string' ||
133
+ !game.name.trim()) {
134
+ throw new Error('游戏搜索返回无效 appid 或名称');
135
+ }
136
+ const icon = typeof game.vertical_image === 'string' && game.vertical_image ? game.vertical_image : game.image;
137
+ return { appid, name: game.name, ...(typeof game.name_en === 'string' && game.name_en.trim() ? { name_en: game.name_en } : {}), ...(typeof icon === 'string' && icon ? { icon_url: icon } : {}) };
138
+ }
139
+
140
+ exports.runGameSearchCommand = runGameSearchCommand;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index$2 = require('./index-bZIxID9N.cjs');
3
+ var index$2 = require('./index-CY67PpQk.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');
@@ -238,19 +238,19 @@ function requireArgument () {
238
238
 
239
239
  var command = {};
240
240
 
241
- 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-bZIxID9N.cjs', document.baseURI).href)));
241
+ 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-CY67PpQk.cjs', document.baseURI).href)));
242
242
  function __require$4() { return require$5("node:events"); }
243
243
 
244
- 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-bZIxID9N.cjs', document.baseURI).href)));
244
+ 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-CY67PpQk.cjs', document.baseURI).href)));
245
245
  function __require$3() { return require$4("node:child_process"); }
246
246
 
247
- 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-bZIxID9N.cjs', document.baseURI).href)));
247
+ 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-CY67PpQk.cjs', document.baseURI).href)));
248
248
  function __require$2() { return require$3("node:path"); }
249
249
 
250
- 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-bZIxID9N.cjs', document.baseURI).href)));
250
+ 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-CY67PpQk.cjs', document.baseURI).href)));
251
251
  function __require$1() { return require$2("node:fs"); }
252
252
 
253
- 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-bZIxID9N.cjs', document.baseURI).href)));
253
+ 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-CY67PpQk.cjs', document.baseURI).href)));
254
254
  function __require() { return require$1("node:process"); }
255
255
 
256
256
  var help = {};
@@ -17249,7 +17249,7 @@ async function inspectFeedbackLog(file, size) {
17249
17249
  return { mimeType: 'text/plain', width: 0, height: 0 };
17250
17250
  }
17251
17251
  async function createFeedbackCosClient(getToken) {
17252
- const { default: COS } = await Promise.resolve().then(function () { return require('./index-DZUYwb3h.cjs'); }).then(function (n) { return n.index; });
17252
+ const { default: COS } = await Promise.resolve().then(function () { return require('./index-C7nrP0tt.cjs'); }).then(function (n) { return n.index; });
17253
17253
  const cos = new COS({
17254
17254
  getAuthorization(_options, callback) {
17255
17255
  void getToken().then((token) => callback({
@@ -20900,7 +20900,7 @@ function readEnvNameArgFromArgv(argv) {
20900
20900
  }
20901
20901
 
20902
20902
  const CLI_VERSION_PLACEHOLDER = ['__HB', 'SDK', 'CLI', 'VERSION__'].join('_');
20903
- const BUILT_CLI_VERSION = '0.9.2-alpha.7';
20903
+ const BUILT_CLI_VERSION = '0.9.2-alpha.8';
20904
20904
  const PACKAGE_JSON_CANDIDATES = [
20905
20905
  path.resolve(__dirname, '..', '..', 'package.json'),
20906
20906
  path.resolve(__dirname, '..', 'package.json'),
@@ -20966,6 +20966,7 @@ function createCliProgram(overrides = {}) {
20966
20966
  runDevCommand: defaultRunDevCommand,
20967
20967
  runDoctorCommand: defaultRunDoctorCommand,
20968
20968
  runRemoteCommand: defaultRunRemoteCommand,
20969
+ runGameSearchCommand: defaultRunGameSearchCommand,
20969
20970
  runSkillInstallCommand: defaultRunSkillInstallCommand,
20970
20971
  ...overrides,
20971
20972
  };
@@ -21070,6 +21071,20 @@ function addRemotePublicOptions(command) {
21070
21071
  }
21071
21072
  function installRemoteCommands(program, handlers, resolveLogger) {
21072
21073
  const remote = addRemotePublicOptions(program.command('remote').description('管理当前项目绑定的远程 Heybox 工坊小程序'));
21074
+ const games = addVerboseOption(remote.command('games').description('查询平台游戏信息'));
21075
+ addVerboseOption(games.command('search').description('按名称查找游戏 appid,不修改绑定')
21076
+ .argument('<query>', '中文或英文游戏名')
21077
+ .option('--offset <offset>', '结果偏移量,0–10000', '0')
21078
+ .option('--limit <limit>', '每页数量,1–20', '10')
21079
+ .option('--json', '输出 JSON'))
21080
+ .action(async (query, _options, command) => {
21081
+ const options = readCommandOptionsWithAncestors(command);
21082
+ await handlers.runGameSearchCommand(query, {
21083
+ offset: readStringOption(options.offset),
21084
+ limit: readStringOption(options.limit),
21085
+ json: Boolean(options.json),
21086
+ });
21087
+ });
21073
21088
  addRemotePublicOptions(remote.command('access').description('查看当前账号的小程序工坊访问权限')).action(createRemoteAction(handlers, resolveLogger, 'access'));
21074
21089
  const entity = addRemotePublicOptions(remote.command('entity').description('查看和切换当前开发者主体'));
21075
21090
  addRemotePublicOptions(entity.command('list').description('列出当前账号可切换的开发者主体')).action(createRemoteAction(handlers, resolveLogger, 'entity:list'));
@@ -21269,39 +21284,39 @@ function createCommandLoggerResolver(options) {
21269
21284
  };
21270
21285
  }
21271
21286
  const defaultClearLoginStatus = async (...args) => {
21272
- const { clearLoginStatus } = await Promise.resolve().then(function () { return require('./login-BYM3Nwau.cjs'); });
21287
+ const { clearLoginStatus } = await Promise.resolve().then(function () { return require('./login-PJdMmFoB.cjs'); });
21273
21288
  return clearLoginStatus(...args);
21274
21289
  };
21275
21290
  const defaultLoginToHeybox = async (...args) => {
21276
- const { loginToHeybox } = await Promise.resolve().then(function () { return require('./login-BYM3Nwau.cjs'); });
21291
+ const { loginToHeybox } = await Promise.resolve().then(function () { return require('./login-PJdMmFoB.cjs'); });
21277
21292
  return loginToHeybox(...args);
21278
21293
  };
21279
21294
  const defaultPrintLoginStatus = async (...args) => {
21280
- const { printLoginStatus } = await Promise.resolve().then(function () { return require('./login-BYM3Nwau.cjs'); });
21295
+ const { printLoginStatus } = await Promise.resolve().then(function () { return require('./login-PJdMmFoB.cjs'); });
21281
21296
  return printLoginStatus(...args);
21282
21297
  };
21283
21298
  const defaultRunBuildCommand = async (...args) => {
21284
- const { runBuildCommand } = await Promise.resolve().then(function () { return require('./build-Do22AWbq.cjs'); });
21299
+ const { runBuildCommand } = await Promise.resolve().then(function () { return require('./build-BinntZJf.cjs'); });
21285
21300
  return runBuildCommand(...args);
21286
21301
  };
21287
21302
  const defaultRunCreateCommand = async (...args) => {
21288
- const { runCreateCommand } = await Promise.resolve().then(function () { return require('./create-QuI_mw8x.cjs'); });
21303
+ const { runCreateCommand } = await Promise.resolve().then(function () { return require('./create-BK028Mlk.cjs'); });
21289
21304
  return runCreateCommand(...args);
21290
21305
  };
21291
21306
  const defaultRunDevCommand = async (...args) => {
21292
- const { runDevCommand } = await Promise.resolve().then(function () { return require('./dev-KAhj5UTy.cjs'); }).then(function (n) { return n.dev; });
21307
+ const { runDevCommand } = await Promise.resolve().then(function () { return require('./dev-DeNzUY6g.cjs'); }).then(function (n) { return n.dev; });
21293
21308
  return runDevCommand(...args);
21294
21309
  };
21295
21310
  const defaultRunDoctorCommand = async (...args) => {
21296
- const { runDoctorCommand } = await Promise.resolve().then(function () { return require('./doctor-DNoQWBpo.cjs'); });
21311
+ const { runDoctorCommand } = await Promise.resolve().then(function () { return require('./doctor-BOfbKnN2.cjs'); });
21297
21312
  return runDoctorCommand(...args);
21298
21313
  };
21299
21314
  const defaultRunSkillInstallCommand = async (...args) => {
21300
- const { runSkillInstallCommand } = await Promise.resolve().then(function () { return require('./skill-DFXZ0SK_.cjs'); });
21315
+ const { runSkillInstallCommand } = await Promise.resolve().then(function () { return require('./skill-Bdy5Ehue.cjs'); });
21301
21316
  return runSkillInstallCommand(...args);
21302
21317
  };
21303
21318
  const defaultRunRemoteCommand = async (...args) => {
21304
- const { runRemoteCommand } = await Promise.resolve().then(function () { return require('./remote-dvOjaxJu.cjs'); });
21319
+ const { runRemoteCommand } = await Promise.resolve().then(function () { return require('./remote-CZuy1lmn.cjs'); });
21305
21320
  return runRemoteCommand(...args);
21306
21321
  };
21307
21322
  function resolveStandaloneLogger(options, verbose) {
@@ -21392,6 +21407,10 @@ function parseNonNegativeInteger(value) {
21392
21407
  }
21393
21408
  return parsed;
21394
21409
  }
21410
+ const defaultRunGameSearchCommand = async (...args) => {
21411
+ const { runGameSearchCommand } = await Promise.resolve().then(function () { return require('./games-yqu20laX.cjs'); });
21412
+ return runGameSearchCommand(...args);
21413
+ };
21395
21414
 
21396
21415
  exports.CliError = CliError;
21397
21416
  exports.HB_SDK_PACKAGE_NAME = HB_SDK_PACKAGE_NAME;
@@ -11,8 +11,8 @@ var require$$0$3 = require('url');
11
11
  var require$$5 = require('zlib');
12
12
  var require$$0 = require('buffer');
13
13
  var require$$1 = require('util');
14
- var index = require('./index-bZIxID9N.cjs');
15
- var dev = require('./dev-KAhj5UTy.cjs');
14
+ var index = require('./index-CY67PpQk.cjs');
15
+ var dev = require('./dev-DeNzUY6g.cjs');
16
16
  require('node:module');
17
17
  require('readline');
18
18
  require('os');
@@ -26,9 +26,9 @@ require('constants');
26
26
  require('node:fs');
27
27
  require('node:fs/promises');
28
28
  require('node:zlib');
29
- require('./context-DQhjWa7X.cjs');
30
- require('./runtime-permission-env-B9SqoP85.cjs');
31
- require('./version-CwEOrhL1.cjs');
29
+ require('./context-BI3QMxw2.cjs');
30
+ require('./runtime-permission-env-CDx5qO-T.cjs');
31
+ require('./version-D40WHkF9.cjs');
32
32
  require('node:async_hooks');
33
33
  require('sharp');
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-6eLmb4Em.cjs');
45
+ require('./project-vite-Dm128JTE.cjs');
46
46
 
47
47
  var bufferUtil = {exports: {}};
48
48
 
@@ -3,7 +3,7 @@
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 index = require('./index-bZIxID9N.cjs');
6
+ var index = require('./index-CY67PpQk.cjs');
7
7
  var browser = require('./browser-RAy8e8cV.cjs');
8
8
  require('node:module');
9
9
  require('readline');
@@ -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-bZIxID9N.cjs');
8
+ var index = require('./index-CY67PpQk.cjs');
9
9
 
10
10
  function findProjectRoot(startDir) {
11
11
  let current = path.resolve(startDir);