@heybox/hb-sdk 0.8.1-alpha.2 → 0.8.1-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +58 -4
  3. package/dist/cli-chunks/{build-FQoALfGC.cjs → build-B0X9pazW.cjs} +16 -10
  4. package/dist/cli-chunks/{context-CA_Q1lyH.cjs → context-DVfWZ6d1.cjs} +8 -3
  5. package/dist/cli-chunks/{create-BjIl4hy4.cjs → create-CyQWVxCA.cjs} +1 -1
  6. package/dist/cli-chunks/{dev-CiPQYsW_.cjs → dev-DP7WtQOo.cjs} +465 -117
  7. package/dist/cli-chunks/{doctor-CS6c3n-W.cjs → doctor-D6l-ONq-.cjs} +1 -1
  8. package/dist/cli-chunks/{index-BEn7WaqA.cjs → index-CDwwaNvP.cjs} +87 -15
  9. package/dist/cli-chunks/{index-CsP_x6y6.cjs → index-DvOPzPxS.cjs} +2 -2
  10. package/dist/cli-chunks/{index.esm-DeEc_-uV.cjs → index.esm-B8pX0BrZ.cjs} +9 -8
  11. package/dist/cli-chunks/{login-BENCVgaQ.cjs → login-Dt-FHzpL.cjs} +2 -2
  12. package/dist/cli-chunks/{project-vite-BO8oOfcs.cjs → project-vite-CE7kyqxl.cjs} +1 -1
  13. package/dist/cli-chunks/{remote-IiVCXcSq.cjs → remote-Be6PeR-n.cjs} +41 -28
  14. package/dist/cli-chunks/{runtime-gate-BMSY22AL.cjs → runtime-gate-BWb8QIcX.cjs} +0 -107
  15. package/dist/cli-chunks/{runtime-permission-env-BPRwn4Yc.cjs → runtime-permission-env-DWSscWBT.cjs} +304 -23
  16. package/dist/cli-chunks/{session-C0eIKZ6V.cjs → session-DZXRQ4Dp.cjs} +1 -1
  17. package/dist/cli-chunks/{skill-DpInwbiA.cjs → skill-B8GWL2KT.cjs} +83 -27
  18. package/dist/cli-chunks/{version-BONZQWPR.cjs → version-D19lZmYN.cjs} +1 -1
  19. package/dist/cli.cjs +1 -1
  20. package/dist/devtools/browser-dev-host/assets/browser-dev-host-Bb43BPMS.js +101 -0
  21. package/dist/devtools/browser-dev-host/assets/desktop-app-launch-DnPRjCa3.js +6 -0
  22. package/dist/devtools/browser-dev-host/assets/index-D-aNERAr.css +1 -0
  23. package/dist/devtools/browser-dev-host/assets/index-Dh5wRj5c.js +567 -0
  24. package/dist/devtools/browser-dev-host/index.html +3 -3
  25. package/dist/index.cjs.js +1893 -1562
  26. package/dist/index.esm.js +1893 -1563
  27. package/dist/miniapp-publish.cjs.js +61 -0
  28. package/dist/miniapp-publish.esm.js +59 -1
  29. package/dist/protocol.cjs.js +64 -13
  30. package/dist/protocol.esm.js +64 -13
  31. package/dist/templates/vanilla-vite-js/README.md.ejs +1 -1
  32. package/dist/templates/vanilla-vite-js/package.json.ejs +1 -0
  33. package/dist/templates/vanilla-vite-js/vite.config.js +1 -1
  34. package/dist/vite.cjs.js +1333 -18
  35. package/dist/vite.esm.js +1334 -20
  36. package/package.json +8 -8
  37. package/skill/SKILL.md +10 -5
  38. package/skill/references/api-protocol.md +3 -3
  39. package/skill/references/api-root.md +225 -210
  40. package/skill/references/cli.md +9 -3
  41. package/skill/references/examples.md +13 -1
  42. package/skill/references/recipes.md +161 -0
  43. package/skill/references/safety-boundaries.md +7 -1
  44. package/skill/skill.json +5 -5
  45. package/types/core/client.d.ts +2 -0
  46. package/types/core/sdk.d.ts +3 -0
  47. package/types/core/singleton.d.ts +3 -0
  48. package/types/devtools/device-logs.d.ts +48 -0
  49. package/types/index.d.ts +3 -1
  50. package/types/miniapp-manifest/companion-directory.d.ts +2 -0
  51. package/types/miniapp-manifest/companion-executable.d.ts +4 -0
  52. package/types/miniapp-manifest/companion-types.d.ts +38 -0
  53. package/types/miniapp-manifest/companions.d.ts +17 -0
  54. package/types/miniapp-manifest/index.d.ts +2 -0
  55. package/types/miniapp-manifest/node.d.ts +9 -0
  56. package/types/miniapp-manifest/permissions.d.ts +1 -1
  57. package/types/miniapp-manifest/schema.d.ts +5 -1
  58. package/types/miniapp-publish/index.d.ts +17 -2
  59. package/types/modules/companion/index.d.ts +57 -0
  60. package/types/protocol/dev-session.d.ts +6 -0
  61. package/types/vite/index.d.ts +11 -4
  62. package/dist/devtools/browser-dev-host/assets/browser-dev-host-DzEst9n7.js +0 -99
  63. package/dist/devtools/browser-dev-host/assets/index-B-NHlLsr.js +0 -567
  64. package/dist/devtools/browser-dev-host/assets/index-P-ra4m1y.css +0 -1
  65. package/dist/devtools/browser-dev-host/assets/workbench-state-BwV7bm4n.js +0 -5
@@ -2,7 +2,8 @@
2
2
 
3
3
  var fs = require('node:fs');
4
4
  var path = require('node:path');
5
- var version = require('./version-BONZQWPR.cjs');
5
+ var version = require('./version-D19lZmYN.cjs');
6
+ require('node:crypto');
6
7
  var node_async_hooks = require('node:async_hooks');
7
8
 
8
9
  var re = {exports: {}};
@@ -2799,6 +2800,7 @@ const MINI_PROGRAM_PERMISSION_KEYS = [
2799
2800
  'clipboard',
2800
2801
  'leaderboard',
2801
2802
  'network',
2803
+ 'companion',
2802
2804
  ];
2803
2805
  const MINI_PROGRAM_PERMISSION_CATALOG = [
2804
2806
  {
@@ -2911,6 +2913,29 @@ const MINI_PROGRAM_PERMISSION_CATALOG = [
2911
2913
  methods: ['network.request', 'network.download'],
2912
2914
  conditions: ['声明后仍需平台批准,并继续执行网络安全策略。'],
2913
2915
  },
2916
+ {
2917
+ key: 'companion',
2918
+ name: '桌面辅助应用',
2919
+ description: '下载、准备并运行随当前小程序版本发布的受管桌面程序。',
2920
+ access: 'platform-approval',
2921
+ risk: 'high',
2922
+ config: {},
2923
+ methods: [
2924
+ 'companion.getInfo',
2925
+ 'companion.getPreparationStatus',
2926
+ 'companion.prepare',
2927
+ 'companion.cancelPreparation',
2928
+ 'companion.getActiveSession',
2929
+ 'companion.launch',
2930
+ 'companion.session.write',
2931
+ 'companion.session.closeStdin',
2932
+ 'companion.session.terminate',
2933
+ 'companion.session.ackOutput',
2934
+ 'companion.openAttachment',
2935
+ 'companion.showNotification',
2936
+ ],
2937
+ conditions: ['声明后仍需平台批准,并继续执行可信用户手势、Host 能力和当前版本 Manifest 校验。'],
2938
+ },
2914
2939
  ];
2915
2940
  new Set(MINI_PROGRAM_PERMISSION_KEYS);
2916
2941
 
@@ -2919,7 +2944,7 @@ function isManagedMiniProgramRuntimePermissionKey(key) {
2919
2944
  return MANAGED_RUNTIME_PERMISSION_KEYS.has(key);
2920
2945
  }
2921
2946
  function parseMiniProgramRuntimePermissions(snapshot) {
2922
- if (!isRecord$2(snapshot) || snapshot.schema_version !== 1 || !Array.isArray(snapshot.entries)) {
2947
+ if (!isRecord$4(snapshot) || snapshot.schema_version !== 1 || !Array.isArray(snapshot.entries)) {
2923
2948
  return { valid: false, permissions: {} };
2924
2949
  }
2925
2950
  if (snapshot.revision !== undefined && (typeof snapshot.revision !== 'number' || !Number.isInteger(snapshot.revision) || snapshot.revision < 0)) {
@@ -2928,7 +2953,7 @@ function parseMiniProgramRuntimePermissions(snapshot) {
2928
2953
  const seenKeys = new Set();
2929
2954
  const permissions = {};
2930
2955
  for (const rawEntry of snapshot.entries) {
2931
- if (!isRecord$2(rawEntry) || typeof rawEntry.key !== 'string' || !rawEntry.key.trim()) {
2956
+ if (!isRecord$4(rawEntry) || typeof rawEntry.key !== 'string' || !rawEntry.key.trim()) {
2932
2957
  return { valid: false, permissions: {} };
2933
2958
  }
2934
2959
  const inputKey = rawEntry.key.trim();
@@ -2938,13 +2963,13 @@ function parseMiniProgramRuntimePermissions(snapshot) {
2938
2963
  }
2939
2964
  seenKeys.add(key);
2940
2965
  if (!isManagedMiniProgramRuntimePermissionKey(key)) {
2941
- if (!isRecord$2(rawEntry.config))
2942
- return { valid: false, permissions: {} };
2966
+ // 未知权限必须忽略,不能让 config:null / 缺字段把已认识的批准一起否掉。
2967
+ // 服务端会对无 config message 字段输出 null(Rylai EmitUnpopulated)。
2943
2968
  continue;
2944
2969
  }
2945
2970
  if (key === 'network') {
2946
2971
  const config = rawEntry.config;
2947
- if (!isRecord$2(config) || typeof config.useOfficialDomain !== 'boolean') {
2972
+ if (!isRecord$4(config) || typeof config.useOfficialDomain !== 'boolean') {
2948
2973
  return { valid: false, permissions: {} };
2949
2974
  }
2950
2975
  permissions[key] = {
@@ -2954,7 +2979,7 @@ function parseMiniProgramRuntimePermissions(snapshot) {
2954
2979
  };
2955
2980
  continue;
2956
2981
  }
2957
- if (rawEntry.config !== null && rawEntry.config !== undefined && (!isRecord$2(rawEntry.config) || Object.keys(rawEntry.config).length > 0)) {
2982
+ if (rawEntry.config !== null && rawEntry.config !== undefined && (!isRecord$4(rawEntry.config) || Object.keys(rawEntry.config).length > 0)) {
2958
2983
  return { valid: false, permissions: {} };
2959
2984
  }
2960
2985
  permissions[key] = {
@@ -2965,7 +2990,7 @@ function parseMiniProgramRuntimePermissions(snapshot) {
2965
2990
  }
2966
2991
  return { valid: true, permissions };
2967
2992
  }
2968
- function isRecord$2(value) {
2993
+ function isRecord$4(value) {
2969
2994
  return typeof value === 'object' && value !== null && !Array.isArray(value);
2970
2995
  }
2971
2996
 
@@ -2978,7 +3003,7 @@ function parseMiniappPermissions(value, options) {
2978
3003
  }
2979
3004
  return { declared: false };
2980
3005
  }
2981
- if (!isRecord$1(value)) {
3006
+ if (!isRecord$3(value)) {
2982
3007
  throw new Error(`${sourceLabel} 必须是 JSON 对象`);
2983
3008
  }
2984
3009
  const knownKeys = new Set(MINIAPP_PERMISSION_KEYS);
@@ -2992,7 +3017,7 @@ function parseMiniappPermissions(value, options) {
2992
3017
  continue;
2993
3018
  const declaration = value[key];
2994
3019
  const itemLabel = `${sourceLabel}.${key}`;
2995
- if (!isRecord$1(declaration))
3020
+ if (!isRecord$3(declaration))
2996
3021
  throw new Error(`${itemLabel} 必须是 JSON 对象`);
2997
3022
  const definition = MINI_PROGRAM_PERMISSION_CATALOG.find((item) => item.key === key);
2998
3023
  if (!definition)
@@ -3028,7 +3053,7 @@ function getMissingPermissionsWarning(sourceLabel = 'package.json#heybox.permiss
3028
3053
  }
3029
3054
  function composeMiniappRuntimePermissions(local, approvals) {
3030
3055
  const parsedApprovals = parseMiniProgramRuntimePermissions(approvals);
3031
- const approvalRevision = isRecord$1(approvals) && Number.isInteger(approvals.revision) ? approvals.revision : undefined;
3056
+ const approvalRevision = isRecord$3(approvals) && Number.isInteger(approvals.revision) ? approvals.revision : undefined;
3032
3057
  const views = [];
3033
3058
  const entries = [];
3034
3059
  for (const definition of MINI_PROGRAM_PERMISSION_CATALOG) {
@@ -3042,9 +3067,22 @@ function composeMiniappRuntimePermissions(local, approvals) {
3042
3067
  }
3043
3068
  const approval = parsedApprovals.valid ? parsedApprovals.permissions[definition.key] : undefined;
3044
3069
  const approved = approval?.status === 'enabled';
3070
+ const effective = declared && approved;
3071
+ if (definition.key !== 'network') {
3072
+ views.push({
3073
+ key: definition.key,
3074
+ access: definition.access,
3075
+ declared,
3076
+ approved,
3077
+ effective,
3078
+ });
3079
+ if (declared) {
3080
+ entries.push({ key: definition.key, status: effective ? 'enabled' : 'disabled', config: {} });
3081
+ }
3082
+ continue;
3083
+ }
3045
3084
  const requestedOfficialDomain = declaration?.enabled === true && 'useOfficialDomain' in declaration && declaration.useOfficialDomain;
3046
3085
  const approvedOfficialDomain = approval?.config.useOfficialDomain === true;
3047
- const effective = declared && approved;
3048
3086
  const effectiveOfficialDomain = effective && (local.declared ? requestedOfficialDomain : true) && approvedOfficialDomain;
3049
3087
  views.push({
3050
3088
  key: definition.key,
@@ -3065,14 +3103,180 @@ function composeMiniappRuntimePermissions(local, approvals) {
3065
3103
  views,
3066
3104
  };
3067
3105
  }
3068
- function isRecord$1(value) {
3106
+ function isRecord$3(value) {
3069
3107
  return typeof value === 'object' && value !== null && !Array.isArray(value);
3070
3108
  }
3071
3109
 
3110
+ const MINIAPP_PLATFORM_VALUES = ['android', 'ios', 'ohos', 'windows', 'macos', 'linux'];
3111
+ function isValidMiniappManifestVersion(version) {
3112
+ return getMiniappManifestVersionError(version) === undefined;
3113
+ }
3114
+ function validateMiniappManifestVersion(version, sourceLabel = 'manifest.version') {
3115
+ const error = getMiniappManifestVersionError(version);
3116
+ if (error) {
3117
+ throw new Error(`${sourceLabel} ${error}`);
3118
+ }
3119
+ return String(version).trim();
3120
+ }
3121
+ function parseMiniappManifestJson(raw, sourceLabel = 'manifest.json') {
3122
+ const hadBom = raw.charCodeAt(0) === 0xfeff;
3123
+ const text = hadBom ? raw.slice(1) : raw;
3124
+ let parsed;
3125
+ try {
3126
+ parsed = JSON.parse(text);
3127
+ }
3128
+ catch (error) {
3129
+ throw new Error(`${sourceLabel} 不是合法 JSON:${formatReason$1(error)}`);
3130
+ }
3131
+ if (!isManifestRecord(parsed)) {
3132
+ throw new Error(`${sourceLabel} 必须是 JSON 对象`);
3133
+ }
3134
+ return {
3135
+ manifest: parsed,
3136
+ hadBom,
3137
+ };
3138
+ }
3139
+ function validateMiniappManifestForDeploy(manifest) {
3140
+ const version = validateMiniappManifestVersion(manifest.version, 'manifest.version');
3141
+ const sdkVersion = validateSdkVersion(manifest.sdkVersion, 'manifest.sdkVersion');
3142
+ const permissions = parseMiniappPermissions(manifest.permissions, {
3143
+ present: Object.prototype.hasOwnProperty.call(manifest, 'permissions'),
3144
+ sdkVersion,
3145
+ sourceLabel: 'manifest.permissions',
3146
+ });
3147
+ const companions = validateGeneratedCompanions(manifest.companions);
3148
+ return {
3149
+ version,
3150
+ sdkVersion,
3151
+ platforms: validateMiniappPlatforms(manifest.platforms, 'manifest.platforms'),
3152
+ ...(permissions.permissions === undefined ? {} : { permissions: permissions.permissions }),
3153
+ ...(companions === undefined ? {} : { companions }),
3154
+ };
3155
+ }
3156
+ function validateGeneratedCompanions(value) {
3157
+ if (value === undefined)
3158
+ return undefined;
3159
+ if (!isRecord$2(value) || Object.keys(value).length === 0)
3160
+ throw new Error('manifest.companions 必须是非空对象');
3161
+ for (const [alias, definition] of Object.entries(value)) {
3162
+ if (!/^[a-z][a-z0-9-]{0,31}$/.test(alias) ||
3163
+ !isRecord$2(definition) ||
3164
+ typeof definition.displayName !== 'string' ||
3165
+ !definition.displayName ||
3166
+ Array.from(definition.displayName).length > 120 ||
3167
+ !Array.isArray(definition.capabilities) ||
3168
+ definition.capabilities.some((capability) => capability !== 'stdio' && capability !== 'attachments' && capability !== 'notifications') ||
3169
+ new Set(definition.capabilities).size !== definition.capabilities.length ||
3170
+ !isRecord$2(definition.targets) ||
3171
+ Object.keys(definition.targets).length === 0)
3172
+ throw new Error(`manifest.companions.${alias} 不合法`);
3173
+ for (const [target, artifact] of Object.entries(definition.targets)) {
3174
+ if (isRecord$2(artifact) && artifact.elevation === 'required') {
3175
+ throw new Error(`manifest.companions.${alias}.targets.${target}.elevation V1 仅支持 none,暂不支持管理员权限启动`);
3176
+ }
3177
+ if ((target !== 'windows-x64' && target !== 'macos-arm64') ||
3178
+ !isRecord$2(artifact) ||
3179
+ artifact.path !== `companions/${alias}/${target}.zip` ||
3180
+ !Number.isSafeInteger(artifact.size) ||
3181
+ Number(artifact.size) <= 0 ||
3182
+ typeof artifact.sha256 !== 'string' ||
3183
+ !/^[a-f0-9]{64}$/.test(artifact.sha256) ||
3184
+ !isRecord$2(artifact.entrypoint) ||
3185
+ (artifact.entrypoint.kind !== 'executable' && artifact.entrypoint.kind !== 'app-bundle') ||
3186
+ typeof artifact.entrypoint.path !== 'string' ||
3187
+ !artifact.entrypoint.path ||
3188
+ artifact.elevation !== 'none' ||
3189
+ !isValidGeneratedCompanionArgs(artifact.args)) {
3190
+ throw new Error(`manifest.companions.${alias}.targets.${target} 不合法`);
3191
+ }
3192
+ }
3193
+ }
3194
+ return value;
3195
+ }
3196
+ function isValidGeneratedCompanionArgs(value) {
3197
+ if (!Array.isArray(value) || value.length > 64)
3198
+ return false;
3199
+ let totalBytes = 0;
3200
+ for (const arg of value) {
3201
+ if (typeof arg !== 'string' || /[\u0000\r\n]/.test(arg))
3202
+ return false;
3203
+ const bytes = Buffer.byteLength(arg, 'utf8');
3204
+ if (bytes > 1024)
3205
+ return false;
3206
+ totalBytes += bytes;
3207
+ }
3208
+ return totalBytes <= 16_384;
3209
+ }
3210
+ function validateMiniappPlatforms(platforms, sourceLabel = 'platforms') {
3211
+ if (!Array.isArray(platforms) || platforms.length === 0) {
3212
+ throw new Error(`${sourceLabel} 必须是非空平台数组`);
3213
+ }
3214
+ const allowedPlatforms = new Set(MINIAPP_PLATFORM_VALUES);
3215
+ const seen = new Set();
3216
+ for (const platform of platforms) {
3217
+ if (typeof platform !== 'string' || !allowedPlatforms.has(platform)) {
3218
+ throw new Error(`${sourceLabel} 包含不支持的平台:${String(platform)}`);
3219
+ }
3220
+ if (seen.has(platform)) {
3221
+ throw new Error(`${sourceLabel} 包含重复平台:${platform}`);
3222
+ }
3223
+ seen.add(platform);
3224
+ }
3225
+ return Object.freeze(MINIAPP_PLATFORM_VALUES.filter((platform) => seen.has(platform)));
3226
+ }
3227
+ function areMiniappPlatformsEqual(left, right) {
3228
+ return left.length === right.length && left.every((platform, index) => platform === right[index]);
3229
+ }
3230
+ function validateSdkVersion(version, sourceLabel = 'sdkVersion') {
3231
+ if (typeof version !== 'string' || version.trim() === '') {
3232
+ throw new Error(`${sourceLabel} 必须是合法 SemVer:${String(version)}`);
3233
+ }
3234
+ const normalized = version.trim();
3235
+ const parsed = semverExports.parse(normalized);
3236
+ if (!parsed || parsed.version !== normalized || parsed.build.length > 0) {
3237
+ throw new Error(`${sourceLabel} 必须是合法 SemVer:${normalized}`);
3238
+ }
3239
+ return normalized;
3240
+ }
3241
+ function isManifestRecord(value) {
3242
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
3243
+ }
3244
+ function isRecord$2(value) {
3245
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
3246
+ }
3247
+ function getMiniappManifestVersionError(version) {
3248
+ if (typeof version !== 'string' || version.trim() === '') {
3249
+ return `必须是合法 SemVer:${String(version)}`;
3250
+ }
3251
+ const normalized = version.trim();
3252
+ const parsed = semverExports.parse(normalized);
3253
+ if (!parsed) {
3254
+ return `必须是合法 SemVer:${normalized}`;
3255
+ }
3256
+ if (parsed.build.length > 0) {
3257
+ return `不能包含 build metadata:${normalized}`;
3258
+ }
3259
+ if (parsed.version !== normalized) {
3260
+ return `必须是合法 SemVer:${normalized}`;
3261
+ }
3262
+ if (parsed.major === 0 && parsed.minor === 0 && parsed.patch === 0) {
3263
+ return '不能是模板默认版本 0.0.0';
3264
+ }
3265
+ return undefined;
3266
+ }
3267
+ function formatReason$1(error) {
3268
+ if (error instanceof Error && error.message) {
3269
+ return error.message;
3270
+ }
3271
+ return String(error);
3272
+ }
3273
+
3072
3274
  const MINIAPP_UPLOAD_SCOPE = 'activity';
3073
3275
  const ACTIVITY_UPLOAD_KEY_MAX_LENGTH = 64;
3074
3276
  const MINIAPP_UPLOAD_BATCH_SIZE = 50;
3075
3277
  const MINIAPP_UPLOAD_TOTAL_SIZE_LIMIT_BYTES = 100 * 1024 * 1024;
3278
+ /** Phase 0 尚未冻结;当前仅作为可单点替换、可测试的保守临时上限。 */
3279
+ const MINIAPP_COMPANION_UPLOAD_TEMPORARY_SIZE_LIMIT_BYTES = 2 * 1024 * 1024 * 1024;
3076
3280
  const USER_MINIPROGRAM_ACCESS_STATUS_API_PATH = '/mall/developer/user_miniprogram/access_status';
3077
3281
  const DEVELOPER_ENTITY_LIST_API_PATH = '/mall/developer/entity/list';
3078
3282
  const DEVELOPER_ENTITY_SWITCH_API_PATH = '/mall/developer/entity/switch';
@@ -3132,6 +3336,18 @@ function validateUploadTotalSize(items, options = {}) {
3132
3336
  }
3133
3337
  return undefined;
3134
3338
  }
3339
+ function validateMiniappUploadSizeBudgets(items, options = {}) {
3340
+ const companionItems = items.filter((item) => normalizeRelativePath(item.relativePath).startsWith('companions/'));
3341
+ const webItems = items.filter((item) => !normalizeRelativePath(item.relativePath).startsWith('companions/'));
3342
+ const webError = validateUploadTotalSize(webItems, { limitBytes: options.webLimitBytes ?? MINIAPP_UPLOAD_TOTAL_SIZE_LIMIT_BYTES });
3343
+ if (webError)
3344
+ return webError;
3345
+ const companionTotal = companionItems.reduce((sum, item) => sum + (Number.isFinite(item.size) && item.size > 0 ? item.size : 0), 0);
3346
+ const companionLimit = options.companionLimitBytes ?? MINIAPP_COMPANION_UPLOAD_TEMPORARY_SIZE_LIMIT_BYTES;
3347
+ if (companionTotal > companionLimit)
3348
+ return 'Companion 归档总大小超过当前 2GiB 临时上限,请缩减归档后重新 deploy';
3349
+ return undefined;
3350
+ }
3135
3351
  function shouldUploadDistFile(relativePath) {
3136
3352
  const normalized = normalizeRelativePath(relativePath);
3137
3353
  if (!normalized) {
@@ -3230,6 +3446,7 @@ function resolveMiniappUploadSessionFiles(localFiles, serverFiles, uploadedKeys)
3230
3446
  }
3231
3447
  const mappings = new Map();
3232
3448
  const serverSizes = new Map();
3449
+ const serverHashes = new Map();
3233
3450
  const knownKeys = new Set();
3234
3451
  for (const serverFile of serverFiles) {
3235
3452
  const relativePath = normalizeMiniappArtifactRelativePath(serverFile.relative_path);
@@ -3247,8 +3464,13 @@ function resolveMiniappUploadSessionFiles(localFiles, serverFiles, uploadedKeys)
3247
3464
  if (!Number.isSafeInteger(size) || size < 0) {
3248
3465
  throw new Error(`上传会话返回文件大小异常:${relativePath}`);
3249
3466
  }
3467
+ const sha256 = String(serverFile.sha256 || '');
3468
+ if (!/^[a-f0-9]{64}$/.test(sha256)) {
3469
+ throw new Error(`上传会话返回文件 SHA-256 异常:${relativePath}`);
3470
+ }
3250
3471
  mappings.set(relativePath, key);
3251
3472
  serverSizes.set(relativePath, size);
3473
+ serverHashes.set(relativePath, sha256);
3252
3474
  knownKeys.add(key);
3253
3475
  }
3254
3476
  const files = preparedFiles.map((file) => {
@@ -3259,6 +3481,9 @@ function resolveMiniappUploadSessionFiles(localFiles, serverFiles, uploadedKeys)
3259
3481
  if (serverSizes.get(file.relativePath) !== file.size) {
3260
3482
  throw new Error(`上传会话文件大小与本地构建不一致:${file.relativePath}`);
3261
3483
  }
3484
+ if (!('sha256' in file) || serverHashes.get(file.relativePath) !== file.sha256) {
3485
+ throw new Error(`上传会话文件 SHA-256 与本地构建不一致:${file.relativePath}`);
3486
+ }
3262
3487
  return { file, key };
3263
3488
  });
3264
3489
  const completed = new Set();
@@ -3275,6 +3500,41 @@ function resolveMiniappUploadSessionFiles(localFiles, serverFiles, uploadedKeys)
3275
3500
  uploadedKeys: [...completed],
3276
3501
  };
3277
3502
  }
3503
+ /** 校验 Manifest 中所有 Companion 归档都精确属于当前上传 receipt。 */
3504
+ function validateMiniappCompanionFileReceipts(companions, files) {
3505
+ const companionFiles = new Map(files.filter((file) => file.relativePath.startsWith('companions/')).map((file) => [file.relativePath, file]));
3506
+ if (companions === undefined) {
3507
+ if (companionFiles.size > 0)
3508
+ throw new Error('dist 包含未被 manifest.companions 引用的 Companion 归档');
3509
+ return;
3510
+ }
3511
+ if (!isRecord$1(companions))
3512
+ throw new Error('manifest.companions 必须是对象');
3513
+ const referenced = new Set();
3514
+ for (const definition of Object.values(companions)) {
3515
+ if (!isRecord$1(definition) || !isRecord$1(definition.targets))
3516
+ throw new Error('manifest.companions targets 不合法');
3517
+ for (const artifact of Object.values(definition.targets)) {
3518
+ if (!isRecord$1(artifact) || typeof artifact.path !== 'string' || typeof artifact.size !== 'number' || typeof artifact.sha256 !== 'string') {
3519
+ throw new Error('manifest.companions artifact 不合法');
3520
+ }
3521
+ const file = companionFiles.get(artifact.path);
3522
+ if (!file)
3523
+ throw new Error(`manifest.companions 引用的归档不在当前上传 receipt:${artifact.path}`);
3524
+ if (file.size !== artifact.size)
3525
+ throw new Error(`Companion 归档大小与 manifest 不一致:${artifact.path}`);
3526
+ if (file.sha256 !== artifact.sha256)
3527
+ throw new Error(`Companion 归档 SHA-256 与 manifest 不一致:${artifact.path}`);
3528
+ referenced.add(artifact.path);
3529
+ }
3530
+ }
3531
+ const extra = [...companionFiles.keys()].find((relativePath) => !referenced.has(relativePath));
3532
+ if (extra)
3533
+ throw new Error(`Companion 归档未被 manifest.companions 引用:${extra}`);
3534
+ }
3535
+ function isRecord$1(value) {
3536
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
3537
+ }
3278
3538
  function normalizeMiniappArtifactRelativePath(relativePath) {
3279
3539
  const value = String(relativePath || '');
3280
3540
  if (!value) {
@@ -3359,14 +3619,16 @@ function findNearestPackageJsonPath(startDir) {
3359
3619
  current = parent;
3360
3620
  }
3361
3621
  }
3622
+ function readMiniappPlatformsFromPackageJson(root) {
3623
+ const { packageJson } = readMiniappPackageJson(root);
3624
+ const heybox = readMiniappHeyboxConfig(packageJson);
3625
+ return validateMiniappPlatforms(heybox?.platforms, 'package.json#heybox.platforms');
3626
+ }
3362
3627
  function readMiniappPermissionsFromPackageJson(root, sdkVersion) {
3363
3628
  const { packageJson } = readMiniappPackageJson(root);
3364
- const heybox = packageJson.heybox;
3365
- if (heybox !== undefined && !isRecord(heybox)) {
3366
- throw new Error('@heybox/hb-sdk 提示:package.json#heybox 必须是 JSON 对象');
3367
- }
3368
- const present = isRecord(heybox) && Object.prototype.hasOwnProperty.call(heybox, 'permissions');
3369
- return parseMiniappPermissions(isRecord(heybox) ? heybox.permissions : undefined, {
3629
+ const heybox = readMiniappHeyboxConfig(packageJson);
3630
+ const present = heybox !== undefined && Object.prototype.hasOwnProperty.call(heybox, 'permissions');
3631
+ return parseMiniappPermissions(heybox?.permissions, {
3370
3632
  present,
3371
3633
  sdkVersion,
3372
3634
  });
@@ -3395,7 +3657,15 @@ function readMiniappPackageJson(root, requireVersion) {
3395
3657
  catch (error) {
3396
3658
  throw new Error(`@heybox/hb-sdk 解析 package.json 失败:${formatReason(error)}`);
3397
3659
  }
3398
- return { packageJson, version: typeof packageJson.version === 'string' ? packageJson.version.trim() : '' };
3660
+ return { packageJson, packageJsonPath, version: typeof packageJson.version === 'string' ? packageJson.version.trim() : '' };
3661
+ }
3662
+ function readMiniappHeyboxConfig(packageJson) {
3663
+ if (packageJson.heybox === undefined)
3664
+ return undefined;
3665
+ if (!isRecord(packageJson.heybox)) {
3666
+ throw new Error('@heybox/hb-sdk 提示:package.json#heybox 必须是 JSON 对象');
3667
+ }
3668
+ return packageJson.heybox;
3399
3669
  }
3400
3670
  function isRecord(value) {
3401
3671
  return typeof value === 'object' && value !== null && !Array.isArray(value);
@@ -3407,6 +3677,13 @@ function formatReason(error) {
3407
3677
  return String(error);
3408
3678
  }
3409
3679
 
3680
+ Array.from({ length: 256 }, (_, value) => {
3681
+ let crc = value;
3682
+ for (let bit = 0; bit < 8; bit++)
3683
+ crc = (crc >>> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
3684
+ return crc >>> 0;
3685
+ });
3686
+
3410
3687
  const HB_SDK_RUNTIME_USE_OFFICIAL_DOMAIN_ENV = 'HB_SDK_RUNTIME_USE_OFFICIAL_DOMAIN';
3411
3688
  const HB_SDK_RUNTIME_PERMISSION_CONTEXT_ENV = 'HB_SDK_RUNTIME_PERMISSION_CONTEXT';
3412
3689
  const VERIFIED_RUNTIME_PERMISSION_CONTEXT = 'verified';
@@ -3498,23 +3775,27 @@ exports.USER_MINIPROGRAM_ACCESS_STATUS_API_PATH = USER_MINIPROGRAM_ACCESS_STATUS
3498
3775
  exports.USER_MINIPROGRAM_PREVIEW_ALLOWLIST_API_PATH = USER_MINIPROGRAM_PREVIEW_ALLOWLIST_API_PATH;
3499
3776
  exports.USER_MINIPROGRAM_VERSION_PREVIEW_INFO_API_PATH = USER_MINIPROGRAM_VERSION_PREVIEW_INFO_API_PATH;
3500
3777
  exports.WITHDRAW_USER_MINIPROGRAM_VERSION_API_PATH = WITHDRAW_USER_MINIPROGRAM_VERSION_API_PATH;
3778
+ exports.areMiniappPlatformsEqual = areMiniappPlatformsEqual;
3501
3779
  exports.composeMiniappRuntimePermissions = composeMiniappRuntimePermissions;
3502
3780
  exports.createMiniappArtifactFileHeader = createMiniappArtifactFileHeader;
3503
3781
  exports.createMiniappArtifactSignatureHeader = createMiniappArtifactSignatureHeader;
3504
3782
  exports.createMiniappPlatformCspEnv = createMiniappPlatformCspEnv;
3505
3783
  exports.getMissingPermissionsWarning = getMissingPermissionsWarning;
3784
+ exports.isValidMiniappManifestVersion = isValidMiniappManifestVersion;
3506
3785
  exports.normalizeRelativePath = normalizeRelativePath;
3507
3786
  exports.parseMiniProgramRuntimePermissions = parseMiniProgramRuntimePermissions;
3508
- exports.parseMiniappPermissions = parseMiniappPermissions;
3787
+ exports.parseMiniappManifestJson = parseMiniappManifestJson;
3509
3788
  exports.prepareMiniappArtifactFiles = prepareMiniappArtifactFiles;
3510
3789
  exports.readMiniappPermissionsFromPackageJson = readMiniappPermissionsFromPackageJson;
3790
+ exports.readMiniappPlatformsFromPackageJson = readMiniappPlatformsFromPackageJson;
3511
3791
  exports.relativePathContainsNodeModulesSegment = relativePathContainsNodeModulesSegment;
3512
3792
  exports.requireSemver = requireSemver;
3513
3793
  exports.resolveMiniappSdkVersion = resolveMiniappSdkVersion;
3514
3794
  exports.resolveMiniappUploadSessionFiles = resolveMiniappUploadSessionFiles;
3515
- exports.semverExports = semverExports;
3516
3795
  exports.shouldSkipMiniappPlatformCspFromEnv = shouldSkipMiniappPlatformCspFromEnv;
3517
3796
  exports.shouldUploadDistFile = shouldUploadDistFile;
3797
+ exports.validateMiniappCompanionFileReceipts = validateMiniappCompanionFileReceipts;
3798
+ exports.validateMiniappManifestForDeploy = validateMiniappManifestForDeploy;
3518
3799
  exports.validateMiniappUploadPathLengths = validateMiniappUploadPathLengths;
3519
- exports.validateUploadTotalSize = validateUploadTotalSize;
3800
+ exports.validateMiniappUploadSizeBudgets = validateMiniappUploadSizeBudgets;
3520
3801
  exports.withMiniappPlatformCspEnv = withMiniappPlatformCspEnv;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-BEn7WaqA.cjs');
3
+ var index = require('./index-CDwwaNvP.cjs');
4
4
  var node_crypto = require('node:crypto');
5
5
  var path = require('node:path');
6
6
  var require$$0$2 = require('fs');
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
+ var version = require('./version-D19lZmYN.cjs');
4
+ var fs = require('node:fs/promises');
3
5
  var path = require('node:path');
4
- var version = require('./version-BONZQWPR.cjs');
5
6
  var childProcess = require('node:child_process');
6
- var fs = require('node:fs/promises');
7
- var index = require('./index-BEn7WaqA.cjs');
7
+ var index = require('./index-CDwwaNvP.cjs');
8
8
  require('node:module');
9
9
  require('node:fs');
10
10
  require('path');
@@ -17,26 +17,6 @@ require('stream');
17
17
  require('buffer');
18
18
  require('util');
19
19
 
20
- function installSkill(options) {
21
- const binary = require.resolve('skills/bin/cli.mjs');
22
- const args = ['add', path.join(options.packageRoot, 'skill'), '--copy'];
23
- if (options.global)
24
- args.push('--global');
25
- if (options.allAgents)
26
- args.push('--agent', '*');
27
- else if (options.agents?.length)
28
- args.push('--agent', ...options.agents);
29
- if (options.force)
30
- args.push('--force');
31
- const env = { ...process.env, ...options.env, DISABLE_TELEMETRY: '1', DO_NOT_TRACK: '1' };
32
- const run = options.spawnImpl ?? childProcess.spawn;
33
- return new Promise((resolve, reject) => {
34
- const child = run(process.execPath, [binary, ...args], { cwd: options.cwd, env, stdio: 'inherit' });
35
- child.on('error', reject);
36
- child.on('close', (code) => resolve({ code: code ?? 1 }));
37
- });
38
- }
39
-
40
20
  async function findProjectPackageJson(cwd = process.cwd()) {
41
21
  let current = path.resolve(cwd);
42
22
  while (true) {
@@ -45,7 +25,45 @@ async function findProjectPackageJson(cwd = process.cwd()) {
45
25
  await fs.access(candidate);
46
26
  return candidate;
47
27
  }
48
- catch { /* continue */ }
28
+ catch {
29
+ /* continue */
30
+ }
31
+ const parent = path.dirname(current);
32
+ if (parent === current)
33
+ return undefined;
34
+ current = parent;
35
+ }
36
+ }
37
+ async function findSdkPackageRoot(startDir) {
38
+ let current = path.resolve(startDir);
39
+ while (true) {
40
+ const candidate = path.join(current, 'package.json');
41
+ try {
42
+ const pkg = JSON.parse(await fs.readFile(candidate, 'utf8'));
43
+ if (pkg.name === '@heybox/hb-sdk')
44
+ return current;
45
+ }
46
+ catch {
47
+ /* continue */
48
+ }
49
+ const parent = path.dirname(current);
50
+ if (parent === current)
51
+ return undefined;
52
+ current = parent;
53
+ }
54
+ }
55
+ async function readInstalledProjectSdkVersion(projectPackageJson) {
56
+ let current = path.dirname(projectPackageJson);
57
+ while (true) {
58
+ const candidate = path.join(current, 'node_modules', '@heybox', 'hb-sdk', 'package.json');
59
+ try {
60
+ const pkg = JSON.parse(await fs.readFile(candidate, 'utf8'));
61
+ if (pkg.name === '@heybox/hb-sdk' && typeof pkg.version === 'string' && pkg.version)
62
+ return pkg.version;
63
+ }
64
+ catch {
65
+ /* continue */
66
+ }
49
67
  const parent = path.dirname(current);
50
68
  if (parent === current)
51
69
  return undefined;
@@ -60,20 +78,58 @@ async function verifyProjectSdk(cwd, version) {
60
78
  const declared = pkg.dependencies?.['@heybox/hb-sdk'] ?? pkg.devDependencies?.['@heybox/hb-sdk'];
61
79
  if (!declared)
62
80
  throw new Error('项目缺少 @heybox/hb-sdk 依赖');
63
- if (declared !== version && !String(declared).includes(version)) {
81
+ const declaredVersion = String(declared);
82
+ if (declaredVersion.startsWith('workspace:')) {
83
+ const installedVersion = await readInstalledProjectSdkVersion(file);
84
+ if (installedVersion === version)
85
+ return;
86
+ if (installedVersion) {
87
+ throw new Error(`项目 @heybox/hb-sdk 版本 ${declaredVersion}(实际 ${installedVersion})与 CLI ${version} 不一致`);
88
+ }
89
+ }
90
+ if (declared !== version && !declaredVersion.includes(version)) {
64
91
  throw new Error(`项目 @heybox/hb-sdk 版本 ${declared} 与 CLI ${version} 不一致`);
65
92
  }
66
93
  }
67
94
 
95
+ function installSkill(options) {
96
+ const binary = require.resolve('skills/bin/cli.mjs');
97
+ const args = ['add', path.join(options.packageRoot, 'skill'), '--copy'];
98
+ if (options.global)
99
+ args.push('--global');
100
+ if (options.allAgents)
101
+ args.push('--agent', '*');
102
+ else if (options.agents?.length)
103
+ args.push('--agent', ...options.agents);
104
+ if (options.force)
105
+ args.push('--force');
106
+ const env = { ...process.env, ...options.env, DISABLE_TELEMETRY: '1', DO_NOT_TRACK: '1' };
107
+ const run = options.spawnImpl ?? childProcess.spawn;
108
+ return new Promise((resolve, reject) => {
109
+ const child = run(process.execPath, [binary, ...args], { cwd: options.cwd, env, stdio: 'inherit' });
110
+ child.on('error', reject);
111
+ child.on('close', (code) => resolve({ code: code ?? 1 }));
112
+ });
113
+ }
114
+
68
115
  async function runSkillInstallCommand(options = {}) {
69
116
  if (options.agent?.length && options.allAgents)
70
117
  throw new Error('--agent 与 --all-agents 互斥');
71
118
  const logger = options.logger ?? index.createCliLogger();
72
- const packageRoot = options.packageRoot ?? path.resolve(__dirname, '../../..');
119
+ const packageRoot = options.packageRoot ?? (await findSdkPackageRoot(__dirname));
120
+ if (!packageRoot)
121
+ throw new Error('未找到 @heybox/hb-sdk 包目录');
73
122
  const cwd = options.cwd ?? process.cwd();
74
123
  if (!options.global)
75
124
  await verifyProjectSdk(cwd, version.HB_SDK_VERSION);
76
- const result = await installSkill({ packageRoot, cwd, global: options.global, agents: options.agent, allAgents: options.allAgents, force: options.force });
125
+ const result = await installSkill({
126
+ packageRoot,
127
+ cwd,
128
+ global: options.global,
129
+ agents: options.agent,
130
+ allAgents: options.allAgents,
131
+ force: options.force,
132
+ });
77
133
  if (result.code !== 0)
78
134
  throw new Error(`Skill 安装失败(退出码 ${result.code})`);
79
135
  logger.success('hb-sdk Skill 安装完成');
@@ -3,6 +3,6 @@
3
3
  /** 构建时替换为当前发布包的实际版本。 */
4
4
  const HB_SDK_VERSION = typeof undefined === 'string'
5
5
  ? undefined
6
- : '0.8.1-alpha.2';
6
+ : '0.8.1-alpha.6';
7
7
 
8
8
  exports.HB_SDK_VERSION = HB_SDK_VERSION;