@heybox/hb-sdk 0.8.1-alpha.9 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/CHANGELOG.md +93 -1
  2. package/README.md +64 -18
  3. package/dist/cli-chunks/{build-D8eh0bxZ.cjs → build-DPe1Ycjd.cjs} +21 -7
  4. package/dist/cli-chunks/{context-JfGWhXSD.cjs → context-BSUhAv3Z.cjs} +2 -2
  5. package/dist/cli-chunks/{create-BiqK-4fa.cjs → create-CaiKrGnb.cjs} +2 -1
  6. package/dist/cli-chunks/{dev-u27Q6a-K.cjs → dev-BG1o8Q-0.cjs} +45 -12
  7. package/dist/cli-chunks/doctor-DutO2P5H.cjs +195 -0
  8. package/dist/cli-chunks/{index-CtR3w1bw.cjs → index-Bur0U2z1.cjs} +2 -2
  9. package/dist/cli-chunks/{index-B2eLzOSD.cjs → index-CKIyipP9.cjs} +77 -21
  10. package/dist/cli-chunks/{index.esm-CCDqeyc7.cjs → index.esm-BPlpP-O0.cjs} +8 -8
  11. package/dist/cli-chunks/{login-BSySslS2.cjs → login-C1JlLEza.cjs} +2 -2
  12. package/dist/cli-chunks/{project-vite-C-r7_UvY.cjs → project-vite-Bd0WzAqQ.cjs} +1 -1
  13. package/dist/cli-chunks/{remote-WvNfCBeJ.cjs → remote-DTFEf3Dj.cjs} +74 -10
  14. package/dist/cli-chunks/{runtime-permission-env-g_2W-HqP.cjs → runtime-permission-env-C2S34ldj.cjs} +145 -4
  15. package/dist/cli-chunks/{session-CaNwlovY.cjs → session-zXVkHuhY.cjs} +1 -1
  16. package/dist/cli-chunks/{skill-V_4EkY23.cjs → skill-CCB3DyXk.cjs} +3 -2
  17. package/dist/cli-chunks/{version-Dox07wdq.cjs → version-0qwlEyZC.cjs} +1 -1
  18. package/dist/cli.cjs +2 -1
  19. package/dist/devtools/browser-dev-host/assets/browser-dev-host-pUcws1MK.js +101 -0
  20. package/dist/devtools/browser-dev-host/assets/{desktop-app-launch-BE-Jw0zD.js → desktop-app-launch-DOfl5YvO.js} +3 -3
  21. package/dist/devtools/browser-dev-host/assets/{index-wEzSxtKd.js → index-CFr28-0O.js} +4 -4
  22. package/dist/devtools/browser-dev-host/assets/{index-D-aNERAr.css → index-DXd5IZBz.css} +1 -1
  23. package/dist/devtools/browser-dev-host/index.html +3 -3
  24. package/dist/index.cjs.js +24 -24
  25. package/dist/index.esm.js +24 -24
  26. package/dist/miniapp-publish.cjs.js +121 -3
  27. package/dist/miniapp-publish.esm.js +118 -4
  28. package/dist/protocol.cjs.js +27 -27
  29. package/dist/protocol.esm.js +27 -27
  30. package/dist/vite.cjs.js +179 -17
  31. package/dist/vite.esm.js +179 -18
  32. package/docs/device-logs.md +36 -0
  33. package/docs/runtime-host-migration.md +120 -0
  34. package/package.json +8 -6
  35. package/skill/SKILL.md +25 -20
  36. package/skill/references/api-protocol.md +3 -3
  37. package/skill/references/api-root.md +104 -11
  38. package/skill/references/cli.md +110 -9
  39. package/skill/references/examples.md +2 -2
  40. package/skill/references/recipes.md +25 -10
  41. package/skill/references/safety-boundaries.md +10 -7
  42. package/skill/skill.json +5 -5
  43. package/types/miniapp-manifest/bindings.d.ts +5 -0
  44. package/types/miniapp-manifest/index.d.ts +1 -0
  45. package/types/miniapp-manifest/node.d.ts +9 -1
  46. package/types/miniapp-manifest/schema.d.ts +94 -0
  47. package/types/miniapp-publish/index.d.ts +4 -2
  48. package/types/modules/companion/index.d.ts +68 -0
  49. package/types/modules/files/types.d.ts +10 -11
  50. package/types/modules/network/index.d.ts +3 -3
  51. package/types/skill-metadata.d.ts +16 -0
  52. package/types/vite/index.d.ts +1 -0
  53. package/dist/cli-chunks/doctor-ppQbhj7e.cjs +0 -65
  54. package/dist/devtools/browser-dev-host/assets/browser-dev-host-BYKHn0Ny.js +0 -101
@@ -0,0 +1,195 @@
1
+ 'use strict';
2
+
3
+ var fs = require('node:fs/promises');
4
+ var os = require('node:os');
5
+ var path = require('node:path');
6
+ var index = require('./index-CKIyipP9.cjs');
7
+ require('node:module');
8
+ require('node:fs');
9
+ require('path');
10
+ require('os');
11
+ require('node:crypto');
12
+ require('readline');
13
+ require('tty');
14
+ require('assert');
15
+ require('events');
16
+ require('stream');
17
+ require('buffer');
18
+ require('util');
19
+
20
+ const CANDIDATES = [path.resolve(__dirname, '..', 'package.json'), path.resolve(__dirname, '..', '..', 'package.json'), path.resolve(__dirname, '..', '..', '..', 'package.json')];
21
+ /** 默认探测目标;`agents` 代表通用 `.agents/skills` 目录(项目级优先,其次全局)。 */
22
+ const AGENTS = ['codex', 'claude', 'cursor', 'agents'];
23
+ const AGENTS_TARGET = 'agents';
24
+ const AGENTS_PROJECT_TARGET = 'agents(project)';
25
+ const AGENTS_GLOBAL_TARGET = 'agents(global)';
26
+ const SKILL_MANIFEST_FILE = 'skill.json';
27
+ const INTEGRITY_PATTERN = /^sha256-([0-9a-f]{64})$/;
28
+ async function runDoctorCommand(runtime = {}) {
29
+ const logger = runtime.logger ?? index.createCliLogger();
30
+ const result = await logger.task('正在检查本地 Agent Skill', () => getDoctorResult(runtime), { successText: 'Agent Skill 检查完成' });
31
+ if (runtime.json) {
32
+ logger.raw(JSON.stringify(result));
33
+ }
34
+ else {
35
+ logger.section('Doctor');
36
+ logger.info(`SDK version: ${result.currentSdkVersion}`);
37
+ for (const agent of result.agents) {
38
+ logger.info(`${agent.agent}: ${agent.status}${agent.skillVersion ? ` (${agent.skillVersion})` : ''}${agent.reason ? ` - ${agent.reason}` : ''}`);
39
+ }
40
+ logger.info(`Status: ${result.status}`);
41
+ if (result.status !== 'OK') {
42
+ logger.warn(doctorRemediation(result));
43
+ }
44
+ }
45
+ return result;
46
+ }
47
+ async function getDoctorResult(runtime = {}) {
48
+ const version = await readVersion(runtime.packageJsonFiles);
49
+ const targets = runtime.agentNames ?? AGENTS;
50
+ const agents = await Promise.all(targets.map((agent) => inspectAgent(agent, version, runtime)));
51
+ const status = agents.every((agent) => agent.status === 'OK') ? 'OK' : agents.find((agent) => agent.status !== 'OK').status;
52
+ const primary = agents.find((agent) => agent.agent === 'codex') ?? agents[0];
53
+ return {
54
+ currentSdkVersion: version,
55
+ status,
56
+ agents,
57
+ localSkillJsonPath: primary?.path ?? '',
58
+ localSkillVersion: primary?.skillVersion,
59
+ };
60
+ }
61
+ async function inspectAgent(agent, version, runtime) {
62
+ if (agent === AGENTS_TARGET) {
63
+ return inspectAgentsTarget(version, runtime);
64
+ }
65
+ return inspectSkillJson(agent, resolveAgentSkillJsonPath(agent, runtime), version);
66
+ }
67
+ /**
68
+ * 探测通用 `.agents/skills`:先项目级 `<cwd>/.agents`,再全局 `~/.agents`。
69
+ * 两者都不存在时返回 `SKILL_MISSING`,并在 `reason` 中说明已检查的两个路径。
70
+ */
71
+ async function inspectAgentsTarget(version, runtime) {
72
+ const projectFile = path.join(resolveAgentsProjectRoot(runtime), 'skills', index.HB_SDK_SKILL_NAME, SKILL_MANIFEST_FILE);
73
+ if (await fileExists(projectFile)) {
74
+ return inspectSkillJson(AGENTS_PROJECT_TARGET, projectFile, version);
75
+ }
76
+ const globalFile = path.join(resolveAgentsGlobalRoot(runtime), 'skills', index.HB_SDK_SKILL_NAME, SKILL_MANIFEST_FILE);
77
+ if (await fileExists(globalFile)) {
78
+ return inspectSkillJson(AGENTS_GLOBAL_TARGET, globalFile, version);
79
+ }
80
+ return {
81
+ agent: AGENTS_TARGET,
82
+ path: projectFile,
83
+ status: 'SKILL_MISSING',
84
+ reason: `未找到 .agents/skills/${index.HB_SDK_SKILL_NAME}/${SKILL_MANIFEST_FILE}(已检查项目级 ${projectFile} 与全局 ${globalFile})`,
85
+ };
86
+ }
87
+ async function inspectSkillJson(agent, file, version) {
88
+ let manifest;
89
+ try {
90
+ manifest = JSON.parse(await fs.readFile(file, 'utf8'));
91
+ }
92
+ catch {
93
+ return { agent, path: file, status: 'SKILL_MISSING' };
94
+ }
95
+ const skillVersion = typeof manifest.skillVersion === 'string' ? manifest.skillVersion : undefined;
96
+ const sdk = manifest.sdk;
97
+ const distribution = manifest.distribution;
98
+ const versionAligned = manifest.name === index.HB_SDK_SKILL_NAME &&
99
+ sdk?.package === index.HB_SDK_PACKAGE_NAME &&
100
+ sdk?.version === version &&
101
+ distribution?.type === 'npm' &&
102
+ distribution?.package === index.HB_SDK_PACKAGE_NAME &&
103
+ distribution?.version === version &&
104
+ skillVersion !== undefined &&
105
+ skillVersion.startsWith(`${version}+skill.`);
106
+ if (!versionAligned) {
107
+ return { agent, path: file, status: 'SKILL_OUTDATED', skillVersion, reason: `skill.json 版本或分发字段与当前 SDK ${version} 不一致` };
108
+ }
109
+ const expectedIntegrity = readExpectedIntegrity(manifest);
110
+ if (!expectedIntegrity) {
111
+ return { agent, path: file, status: 'SKILL_TAMPERED', skillVersion, reason: 'skill.json 缺少合法的 integrity 字段,无法校验 Skill 内容' };
112
+ }
113
+ let actualIntegrity;
114
+ try {
115
+ actualIntegrity = index.createSkillContentHash(await readSkillContentEntries(path.dirname(file))).hex;
116
+ }
117
+ catch {
118
+ return { agent, path: file, status: 'SKILL_TAMPERED', skillVersion, reason: 'Skill 内容文件缺失,无法校验内容完整性' };
119
+ }
120
+ if (actualIntegrity !== expectedIntegrity || skillVersion !== `${version}+skill.${expectedIntegrity.slice(0, 12)}`) {
121
+ return { agent, path: file, status: 'SKILL_TAMPERED', skillVersion, reason: 'Skill 内容与 skill.json 的 integrity 不一致,可能被手工修改' };
122
+ }
123
+ return { agent, path: file, status: 'OK', skillVersion };
124
+ }
125
+ /**
126
+ * 读取 Skill 可分发内容:`SKILL.md` 与 `references/` 的直接子文件(不含子目录、不含 skill.json 与 scripts/)。
127
+ * 路径统一使用 `/` 分隔,确保与发布时在 CI 上生成的 integrity 可跨平台比较。
128
+ */
129
+ async function readSkillContentEntries(skillDir) {
130
+ const entries = [{ path: 'SKILL.md', content: await fs.readFile(path.join(skillDir, 'SKILL.md')) }];
131
+ const referencesDir = path.join(skillDir, 'references');
132
+ const references = await fs.readdir(referencesDir, { withFileTypes: true });
133
+ for (const entry of references) {
134
+ if (entry.isDirectory()) {
135
+ continue;
136
+ }
137
+ entries.push({ path: `references/${entry.name}`, content: await fs.readFile(path.join(referencesDir, entry.name)) });
138
+ }
139
+ return entries;
140
+ }
141
+ function readExpectedIntegrity(manifest) {
142
+ if (typeof manifest.integrity !== 'string') {
143
+ return undefined;
144
+ }
145
+ return INTEGRITY_PATTERN.exec(manifest.integrity)?.[1];
146
+ }
147
+ function resolveAgentSkillJsonPath(agent, runtime) {
148
+ const home = runtime.agentRoots?.[agent] ??
149
+ runtime.env?.[`${agent.toUpperCase()}_HOME`] ??
150
+ process.env[`${agent.toUpperCase()}_HOME`] ??
151
+ (agent === 'codex' ? runtime.codexHome : undefined) ??
152
+ path.join(os.homedir(), `.${agent}`);
153
+ return path.join(home, 'skills', index.HB_SDK_SKILL_NAME, SKILL_MANIFEST_FILE);
154
+ }
155
+ function resolveAgentsProjectRoot(runtime) {
156
+ return (runtime.agentsProjectRoot ??
157
+ runtime.agentRoots?.[AGENTS_PROJECT_TARGET] ??
158
+ runtime.agentRoots?.[AGENTS_TARGET] ??
159
+ path.join(runtime.cwd ?? process.cwd(), '.agents'));
160
+ }
161
+ function resolveAgentsGlobalRoot(runtime) {
162
+ return runtime.agentsGlobalRoot ?? runtime.agentRoots?.[AGENTS_GLOBAL_TARGET] ?? path.join(runtime.env?.HOME ?? process.env.HOME ?? os.homedir(), '.agents');
163
+ }
164
+ async function fileExists(file) {
165
+ try {
166
+ await fs.access(file);
167
+ return true;
168
+ }
169
+ catch {
170
+ return false;
171
+ }
172
+ }
173
+ function doctorRemediation(result) {
174
+ if (result.agents.some((agent) => agent.status === 'SKILL_TAMPERED')) {
175
+ return '检测到 Skill 内容被手工修改,请运行 hb-sdk skill install --force 覆盖对应 Skill。';
176
+ }
177
+ return '请运行 hb-sdk skill install 安装或更新对应 Skill。';
178
+ }
179
+ async function readVersion(files = CANDIDATES) {
180
+ for (const file of files) {
181
+ try {
182
+ const manifest = JSON.parse(await fs.readFile(file, 'utf8'));
183
+ if (typeof manifest.version === 'string' && manifest.version) {
184
+ return manifest.version;
185
+ }
186
+ }
187
+ catch {
188
+ /* 继续尝试下一个候选文件 */
189
+ }
190
+ }
191
+ throw new Error(`未能读取 ${index.HB_SDK_PACKAGE_NAME} 当前版本号`);
192
+ }
193
+
194
+ exports.getDoctorResult = getDoctorResult;
195
+ exports.runDoctorCommand = runDoctorCommand;
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var index$2 = require('./index-B2eLzOSD.cjs');
3
+ var index$2 = require('./index-CKIyipP9.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-g_2W-HqP.cjs');
10
+ var runtimePermissionEnv = require('./runtime-permission-env-C2S34ldj.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');
@@ -6,6 +6,7 @@ var fs = require('node:fs/promises');
6
6
  var path = require('node:path');
7
7
  var require$$1$1 = require('path');
8
8
  var require$$1 = require('os');
9
+ var node_crypto = require('node:crypto');
9
10
  var require$$0$5 = require('readline');
10
11
  var require$$1$2 = require('tty');
11
12
  var require$$0$2 = require('assert');
@@ -234,19 +235,19 @@ function requireArgument () {
234
235
 
235
236
  var command = {};
236
237
 
237
- 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-B2eLzOSD.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-CKIyipP9.cjs', document.baseURI).href)));
238
239
  function __require$4() { return require$5("node:events"); }
239
240
 
240
- 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-B2eLzOSD.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-CKIyipP9.cjs', document.baseURI).href)));
241
242
  function __require$3() { return require$4("node:child_process"); }
242
243
 
243
- 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-B2eLzOSD.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-CKIyipP9.cjs', document.baseURI).href)));
244
245
  function __require$2() { return require$3("node:path"); }
245
246
 
246
- 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-B2eLzOSD.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-CKIyipP9.cjs', document.baseURI).href)));
247
248
  function __require$1() { return require$2("node:fs"); }
248
249
 
249
- 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-B2eLzOSD.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-CKIyipP9.cjs', document.baseURI).href)));
250
251
  function __require() { return require$1("node:process"); }
251
252
 
252
253
  var help = {};
@@ -3795,13 +3796,38 @@ const {
3795
3796
  Help,
3796
3797
  } = commander;
3797
3798
 
3799
+ const DEFAULT_BROWSER_DEV_HOST_PORT = 5174;
3800
+ /**
3801
+ * 解析日志类命令要访问的端口:
3802
+ * 1. 子命令显式 `--port` 优先;
3803
+ * 2. 否则跟随父 `dev` 命令的 `--browser-dev-host-port`;
3804
+ * 3. 都没有时回退调试台默认端口 5174。
3805
+ * 这里不能读 `dev --port`:那是小程序开发服务器端口,日志路由只挂在调试台服务上。
3806
+ */
3807
+ function resolveDebugHostPort(command, explicitPort) {
3808
+ if (explicitPort !== undefined)
3809
+ return Number(explicitPort);
3810
+ let current = command.parent;
3811
+ while (current) {
3812
+ const ancestorPort = current.opts().browserDevHostPort;
3813
+ if (ancestorPort !== undefined)
3814
+ return Number(ancestorPort);
3815
+ current = current.parent;
3816
+ }
3817
+ return DEFAULT_BROWSER_DEV_HOST_PORT;
3818
+ }
3798
3819
  /** Agent 输出只使用 stdout JSON/NDJSON,不混入交互提示。 */
3799
3820
  function installDevLogCommands(dev) {
3821
+ // dev 与 logs/devices/sandbox 都声明了 --port。默认的“选项可穿插”解析会把子命令的
3822
+ // --port 归给父 dev 的 --port(小程序开发服务器端口)。commander 要求**父命令链**都开启
3823
+ // 位置化解析,子命令才会优先认自己声明的选项,因此这里同时打开 dev 与其父程序。
3824
+ dev.enablePositionalOptions();
3825
+ dev.parent?.enablePositionalOptions();
3800
3826
  dev.command('sandbox').description('查看设备沙箱').command('list')
3801
3827
  .requiredOption('--device <id>', '设备会话 ID').option('--path <path>', '逻辑目录', '.')
3802
- .option('--port <port>', '调试台端口', '5174').option('--json', 'JSON 输出')
3828
+ .option('--port <port>', '调试台端口,默认跟随 dev --browser-dev-host-port(5174').option('--json', 'JSON 输出')
3803
3829
  .action(async (options, command) => {
3804
- const port = Number(command.parent?.parent?.opts().port ?? options.port);
3830
+ const port = resolveDebugHostPort(command, options.port);
3805
3831
  if (!Number.isInteger(port) || port < 1 || port > 65535)
3806
3832
  throw new Error('端口无效');
3807
3833
  const origin = `http://127.0.0.1:${port}`;
@@ -3815,7 +3841,7 @@ function installDevLogCommands(dev) {
3815
3841
  dev
3816
3842
  .command(kind)
3817
3843
  .description(kind === 'logs' ? '读取多设备调试日志' : '列出调试设备会话')
3818
- .option('--port <port>', '调试台端口', '5174')
3844
+ .option('--port <port>', '调试台端口,默认跟随 dev --browser-dev-host-port(5174')
3819
3845
  .option('--json', '输出机器可读 JSON')
3820
3846
  .option('--device <id>', '设备会话 ID')
3821
3847
  .option('--level <level>', '日志级别')
@@ -3829,7 +3855,7 @@ function installDevLogCommands(dev) {
3829
3855
  .option('--follow', '持续输出 NDJSON')
3830
3856
  .option('--duration <seconds>', '持续读取时长,默认 60 秒', '60')
3831
3857
  .action(async (options, command) => {
3832
- const port = Number(command.parent?.opts().port ?? options.port);
3858
+ const port = resolveDebugHostPort(command, options.port);
3833
3859
  const duration = Number(options.duration);
3834
3860
  if (!Number.isInteger(port) || port < 1 || port > 65535 || !Number.isFinite(duration) || duration <= 0)
3835
3861
  throw new Error('端口或持续时间无效');
@@ -3954,6 +3980,23 @@ var envPaths = /*@__PURE__*/getDefaultExportFromCjs(envPathsExports);
3954
3980
 
3955
3981
  const HB_SDK_PACKAGE_NAME = '@heybox/hb-sdk';
3956
3982
  const HB_SDK_SKILL_NAME = 'hb-sdk';
3983
+ /**
3984
+ * 计算 Skill 可分发内容(`SKILL.md` + `references/*`)的内容哈希。
3985
+ *
3986
+ * 该实现必须与 `scripts/skill/skill-metadata.mjs` 的 `createSkillContentHash` 语义完全一致:
3987
+ * 按 `path` 升序排序后依次写入 `path`、`\0`、`content`、`\0`,最后取 sha256 十六进制摘要。
3988
+ * 发布到 npm 的包内不含 `scripts/`,因此这里保留独立实现,供 CLI 运行期校验已安装 Skill。
3989
+ */
3990
+ function createSkillContentHash(fileEntries) {
3991
+ const hash = node_crypto.createHash('sha256');
3992
+ for (const entry of [...fileEntries].sort((left, right) => left.path.localeCompare(right.path))) {
3993
+ hash.update(entry.path);
3994
+ hash.update('\0');
3995
+ hash.update(entry.content);
3996
+ hash.update('\0');
3997
+ }
3998
+ return { hex: hash.digest('hex') };
3999
+ }
3957
4000
 
3958
4001
  var ora$1 = {exports: {}};
3959
4002
 
@@ -13424,7 +13467,7 @@ function getPathname(pathWithQuery) {
13424
13467
  }
13425
13468
 
13426
13469
  const CLI_VERSION_PLACEHOLDER = ['__HB', 'SDK', 'CLI', 'VERSION__'].join('_');
13427
- const BUILT_CLI_VERSION = '0.8.1-alpha.9';
13470
+ const BUILT_CLI_VERSION = '0.8.1';
13428
13471
  const PACKAGE_JSON_CANDIDATES = [
13429
13472
  path.resolve(__dirname, '..', '..', 'package.json'),
13430
13473
  path.resolve(__dirname, '..', 'package.json'),
@@ -13479,6 +13522,7 @@ async function runCli(options = {}) {
13479
13522
  }
13480
13523
  }
13481
13524
  function createCliProgram(overrides = {}) {
13525
+ const processLike = overrides.process ?? process;
13482
13526
  const handlers = {
13483
13527
  clearLoginStatus: defaultClearLoginStatus,
13484
13528
  loginToHeybox: defaultLoginToHeybox,
@@ -13519,7 +13563,11 @@ function createCliProgram(overrides = {}) {
13519
13563
  await handlers.runDevCommand(options, { logger });
13520
13564
  }, handlers.printUpdateReminder, resolveLogger));
13521
13565
  installDevLogCommands(program.commands.find(command => command.name() === 'dev'));
13522
- addVerboseOption(program.command('build').description('构建当前小程序项目').option('--env <name>', '加载项目根下 .env.<name> 预设并作为 Vite mode')).action(async (...args) => {
13566
+ addVerboseOption(program.command('build').description('构建当前小程序项目')
13567
+ .option('--env <name>', '加载项目根下 .env.<name> 预设并作为 Vite mode')
13568
+ // 根程序开启位置化解析后,子命令必须自己声明同名选项才能拿到它;这里声明但不展示,
13569
+ // 只为让 action 输出“build 不支持 --env-file”的明确报错,而不是 commander 的 unknown option。
13570
+ .addOption(new Option('--env-file <path>', 'build 不支持该选项').hideHelp())).action(async (...args) => {
13523
13571
  const command = readCommandFromActionArgs(args);
13524
13572
  if (!command) {
13525
13573
  throw new Error('无法解析 build 命令上下文');
@@ -13545,6 +13593,10 @@ function createCliProgram(overrides = {}) {
13545
13593
  const command = readCommandFromActionArgs(args);
13546
13594
  const logger = resolveLogger(command);
13547
13595
  const result = await handlers.runDoctorCommand({ logger, json: Boolean(command?.opts().json) });
13596
+ // 与公开文档一致:缺失、过期、版本不匹配或内容被手工修改时返回非零退出码。
13597
+ if (result.status !== 'OK') {
13598
+ processLike.exitCode = 1;
13599
+ }
13548
13600
  if (result.status !== 'SDK_MISMATCH') {
13549
13601
  await handlers.printUpdateReminder({ logger });
13550
13602
  }
@@ -13664,7 +13716,10 @@ function installRemoteCommands(program, handlers, resolveLogger) {
13664
13716
  .description('构建并提交当前小程序版本审核')
13665
13717
  .option('--from-version <version>', '复用指定历史版本产物提交审核')
13666
13718
  .option('--release-note <text>', '发布日志,提交审核必填')
13667
- .option('--auto-publish', '审核通过后自动发布;默认需在 CLI 中手动发布')).action(createRemoteAction(handlers, resolveLogger, 'deploy', (command) => {
13719
+ .option('--auto-publish', '审核通过后自动发布;默认需在 CLI 中手动发布')
13720
+ // 根程序开启位置化解析后,子命令需要自己声明这两个根级选项才能继续支持 deploy --env / --env-file。
13721
+ .option('--env <name>', '加载项目根下 .env.<name> 预设')
13722
+ .option('--env-file <path>', '显式指定 .env 文件路径,优先级高于 --env')).action(createRemoteAction(handlers, resolveLogger, 'deploy', (command) => {
13668
13723
  const options = readCommandOptionsWithAncestors(command);
13669
13724
  return {
13670
13725
  autoPublish: Boolean(options.autoPublish),
@@ -13773,39 +13828,39 @@ function createCommandLoggerResolver(options) {
13773
13828
  };
13774
13829
  }
13775
13830
  const defaultClearLoginStatus = async (...args) => {
13776
- const { clearLoginStatus } = await Promise.resolve().then(function () { return require('./login-BSySslS2.cjs'); });
13831
+ const { clearLoginStatus } = await Promise.resolve().then(function () { return require('./login-C1JlLEza.cjs'); });
13777
13832
  return clearLoginStatus(...args);
13778
13833
  };
13779
13834
  const defaultLoginToHeybox = async (...args) => {
13780
- const { loginToHeybox } = await Promise.resolve().then(function () { return require('./login-BSySslS2.cjs'); });
13835
+ const { loginToHeybox } = await Promise.resolve().then(function () { return require('./login-C1JlLEza.cjs'); });
13781
13836
  return loginToHeybox(...args);
13782
13837
  };
13783
13838
  const defaultPrintLoginStatus = async (...args) => {
13784
- const { printLoginStatus } = await Promise.resolve().then(function () { return require('./login-BSySslS2.cjs'); });
13839
+ const { printLoginStatus } = await Promise.resolve().then(function () { return require('./login-C1JlLEza.cjs'); });
13785
13840
  return printLoginStatus(...args);
13786
13841
  };
13787
13842
  const defaultRunBuildCommand = async (...args) => {
13788
- const { runBuildCommand } = await Promise.resolve().then(function () { return require('./build-D8eh0bxZ.cjs'); });
13843
+ const { runBuildCommand } = await Promise.resolve().then(function () { return require('./build-DPe1Ycjd.cjs'); });
13789
13844
  return runBuildCommand(...args);
13790
13845
  };
13791
13846
  const defaultRunCreateCommand = async (...args) => {
13792
- const { runCreateCommand } = await Promise.resolve().then(function () { return require('./create-BiqK-4fa.cjs'); });
13847
+ const { runCreateCommand } = await Promise.resolve().then(function () { return require('./create-CaiKrGnb.cjs'); });
13793
13848
  return runCreateCommand(...args);
13794
13849
  };
13795
13850
  const defaultRunDevCommand = async (...args) => {
13796
- const { runDevCommand } = await Promise.resolve().then(function () { return require('./dev-u27Q6a-K.cjs'); }).then(function (n) { return n.dev; });
13851
+ const { runDevCommand } = await Promise.resolve().then(function () { return require('./dev-BG1o8Q-0.cjs'); }).then(function (n) { return n.dev; });
13797
13852
  return runDevCommand(...args);
13798
13853
  };
13799
13854
  const defaultRunDoctorCommand = async (...args) => {
13800
- const { runDoctorCommand } = await Promise.resolve().then(function () { return require('./doctor-ppQbhj7e.cjs'); });
13855
+ const { runDoctorCommand } = await Promise.resolve().then(function () { return require('./doctor-DutO2P5H.cjs'); });
13801
13856
  return runDoctorCommand(...args);
13802
13857
  };
13803
13858
  const defaultRunSkillInstallCommand = async (...args) => {
13804
- const { runSkillInstallCommand } = await Promise.resolve().then(function () { return require('./skill-V_4EkY23.cjs'); });
13859
+ const { runSkillInstallCommand } = await Promise.resolve().then(function () { return require('./skill-CCB3DyXk.cjs'); });
13805
13860
  return runSkillInstallCommand(...args);
13806
13861
  };
13807
13862
  const defaultRunRemoteCommand = async (...args) => {
13808
- const { runRemoteCommand } = await Promise.resolve().then(function () { return require('./remote-WvNfCBeJ.cjs'); });
13863
+ const { runRemoteCommand } = await Promise.resolve().then(function () { return require('./remote-DTFEf3Dj.cjs'); });
13809
13864
  return runRemoteCommand(...args);
13810
13865
  };
13811
13866
  function resolveStandaloneLogger(options, verbose) {
@@ -13904,6 +13959,7 @@ exports.applyServiceTagIfNeeded = applyServiceTagIfNeeded;
13904
13959
  exports.commonjsGlobal = commonjsGlobal;
13905
13960
  exports.createCliLogger = createCliLogger;
13906
13961
  exports.createCliProgram = createCliProgram;
13962
+ exports.createSkillContentHash = createSkillContentHash;
13907
13963
  exports.envPaths = envPaths;
13908
13964
  exports.getDefaultExportFromCjs = getDefaultExportFromCjs;
13909
13965
  exports.readErrorMessage = readErrorMessage;
@@ -11,27 +11,27 @@ 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-B2eLzOSD.cjs');
15
- var dev = require('./dev-u27Q6a-K.cjs');
14
+ var index = require('./index-CKIyipP9.cjs');
15
+ var dev = require('./dev-BG1o8Q-0.cjs');
16
16
  require('node:module');
17
17
  require('node:fs');
18
18
  require('node:fs/promises');
19
19
  require('node:path');
20
20
  require('path');
21
21
  require('os');
22
+ require('node:crypto');
22
23
  require('readline');
23
24
  require('tty');
24
25
  require('assert');
25
- require('node:crypto');
26
26
  require('node:os');
27
27
  require('node:net');
28
28
  require('node:dns/promises');
29
29
  require('node:http');
30
- require('./context-JfGWhXSD.cjs');
31
- require('./runtime-permission-env-g_2W-HqP.cjs');
32
- require('./version-Dox07wdq.cjs');
30
+ require('./context-BSUhAv3Z.cjs');
31
+ require('./runtime-permission-env-C2S34ldj.cjs');
32
+ require('./version-0qwlEyZC.cjs');
33
33
  require('node:async_hooks');
34
- require('./session-CaNwlovY.cjs');
34
+ require('./session-zXVkHuhY.cjs');
35
35
  require('fs');
36
36
  require('constants');
37
37
  require('undici');
@@ -41,7 +41,7 @@ require('node:buffer');
41
41
  require('node:url');
42
42
  require('node:util');
43
43
  require('node:child_process');
44
- require('./project-vite-C-r7_UvY.cjs');
44
+ require('./project-vite-Bd0WzAqQ.cjs');
45
45
  require('node:zlib');
46
46
 
47
47
  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-CaNwlovY.cjs');
6
+ var session = require('./session-zXVkHuhY.cjs');
7
7
  var browser = require('./browser-RAy8e8cV.cjs');
8
- var index = require('./index-B2eLzOSD.cjs');
8
+ var index = require('./index-CKIyipP9.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-B2eLzOSD.cjs');
8
+ var index = require('./index-CKIyipP9.cjs');
9
9
 
10
10
  function findProjectRoot(startDir) {
11
11
  let current = path.resolve(startDir);