@heybox/hb-sdk 0.8.1-alpha.1 → 0.8.1-alpha.11

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 (69) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/README.md +80 -7
  3. package/dist/cli-chunks/{build-kMLIWqWY.cjs → build-DXpmT9rR.cjs} +16 -10
  4. package/dist/cli-chunks/{context-CzFFRcL4.cjs → context-cpQKdAv9.cjs} +17 -3
  5. package/dist/cli-chunks/{create-0ow6gA9w.cjs → create-BBUaKfey.cjs} +1 -1
  6. package/dist/cli-chunks/{dev-CPBPdpyu.cjs → dev-jz2O-8Sf.cjs} +633 -147
  7. package/dist/cli-chunks/{doctor-DQ8ctFKC.cjs → doctor-8tT7UEPZ.cjs} +1 -1
  8. package/dist/cli-chunks/{index-RDcIrvwi.cjs → index-BV_ZCDU1.cjs} +2 -2
  9. package/dist/cli-chunks/{index-Buner4kE.cjs → index-IeNOfmd0.cjs} +87 -15
  10. package/dist/cli-chunks/{index.esm-qwrdRuy-.cjs → index.esm-DiC4hnWh.cjs} +9 -8
  11. package/dist/cli-chunks/{login-DoduAO_f.cjs → login-DipFJGVa.cjs} +2 -2
  12. package/dist/cli-chunks/{project-vite-B-sK-qup.cjs → project-vite-DLIFCiZD.cjs} +1 -1
  13. package/dist/cli-chunks/{remote-CF_SRmnj.cjs → remote-DHlEJtjc.cjs} +41 -28
  14. package/dist/cli-chunks/{runtime-gate-FseEYZze.cjs → runtime-gate-BWb8QIcX.cjs} +0 -107
  15. package/dist/cli-chunks/{runtime-permission-env-DdQtxdut.cjs → runtime-permission-env-B0s4KP_U.cjs} +318 -23
  16. package/dist/cli-chunks/{session-DHbw2Xgh.cjs → session-CUPzN2aa.cjs} +1 -1
  17. package/dist/cli-chunks/{skill-6IVv12JW.cjs → skill-DhgXHAjs.cjs} +83 -27
  18. package/dist/cli-chunks/{version-TXwWxKvv.cjs → version-DOBbqU-f.cjs} +1 -1
  19. package/dist/cli.cjs +1 -1
  20. package/dist/devtools/browser-dev-host/assets/browser-dev-host-C7lX5xaK.js +101 -0
  21. package/dist/devtools/browser-dev-host/assets/desktop-app-launch-DLQ5YSCQ.js +6 -0
  22. package/dist/devtools/browser-dev-host/assets/index-DXd5IZBz.css +1 -0
  23. package/dist/devtools/browser-dev-host/assets/index-DsL03GcE.js +567 -0
  24. package/dist/devtools/browser-dev-host/index.html +3 -3
  25. package/dist/index.cjs.js +1970 -1567
  26. package/dist/index.esm.js +1969 -1568
  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 +9 -9
  37. package/skill/SKILL.md +11 -3
  38. package/skill/references/api-protocol.md +8 -4
  39. package/skill/references/api-root.md +328 -210
  40. package/skill/references/cli.md +11 -3
  41. package/skill/references/examples.md +13 -1
  42. package/skill/references/recipes.md +162 -0
  43. package/skill/references/safety-boundaries.md +9 -3
  44. package/skill/skill.json +5 -5
  45. package/types/core/client.d.ts +9 -1
  46. package/types/core/sdk.d.ts +6 -0
  47. package/types/core/singleton.d.ts +6 -0
  48. package/types/devtools/device-logs.d.ts +48 -0
  49. package/types/index.d.ts +5 -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 +14 -1
  58. package/types/miniapp-publish/index.d.ts +17 -2
  59. package/types/modules/companion/index.d.ts +57 -0
  60. package/types/modules/environment/index.d.ts +70 -0
  61. package/types/modules/network/index.d.ts +1 -4
  62. package/types/modules/network/observability.d.ts +0 -1
  63. package/types/protocol/dev-session.d.ts +8 -1
  64. package/types/protocol.d.ts +1 -1
  65. package/types/vite/index.d.ts +11 -4
  66. package/dist/devtools/browser-dev-host/assets/browser-dev-host-TzYf9L6C.js +0 -99
  67. package/dist/devtools/browser-dev-host/assets/index-C5MZZDa5.js +0 -567
  68. package/dist/devtools/browser-dev-host/assets/index-P-ra4m1y.css +0 -1
  69. 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-TXwWxKvv.cjs');
5
+ var version = require('./version-DOBbqU-f.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,193 @@ function composeMiniappRuntimePermissions(local, approvals) {
3065
3103
  views,
3066
3104
  };
3067
3105
  }
3068
- function isRecord$1(value) {
3106
+ function isRecord$3(value) {
3107
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
3108
+ }
3109
+
3110
+ const MINIAPP_PLATFORM_VALUES = ['android', 'ios', 'ohos', 'windows', 'macos', 'linux'];
3111
+ /**
3112
+ * 桌面平台子集:从唯一平台词表 `MINIAPP_PLATFORM_VALUES` 派生,`satisfies` 阻止它漂移出词表。
3113
+ * 小程序声明其中任一平台,即视为该项目承诺适配 PC / 桌面端;调试台据此取舍桌面调试入口。
3114
+ *
3115
+ * 注意:子集只表达「声明为桌面」,不保证已有可用的客户端基线——例如 `linux` 目前既没有 `@hbPlatform` 声明,
3116
+ * 也没有 Companion target,仅声明 `linux` 的项目会展示入口但未必能真正打开。
3117
+ */
3118
+ const MINIAPP_DESKTOP_PLATFORM_VALUES = ['windows', 'macos', 'linux'];
3119
+ function hasMiniappDesktopPlatform(platforms) {
3120
+ if (!platforms)
3121
+ return false;
3122
+ return MINIAPP_DESKTOP_PLATFORM_VALUES.some((platform) => platforms.includes(platform));
3123
+ }
3124
+ function isValidMiniappManifestVersion(version) {
3125
+ return getMiniappManifestVersionError(version) === undefined;
3126
+ }
3127
+ function validateMiniappManifestVersion(version, sourceLabel = 'manifest.version') {
3128
+ const error = getMiniappManifestVersionError(version);
3129
+ if (error) {
3130
+ throw new Error(`${sourceLabel} ${error}`);
3131
+ }
3132
+ return String(version).trim();
3133
+ }
3134
+ function parseMiniappManifestJson(raw, sourceLabel = 'manifest.json') {
3135
+ const hadBom = raw.charCodeAt(0) === 0xfeff;
3136
+ const text = hadBom ? raw.slice(1) : raw;
3137
+ let parsed;
3138
+ try {
3139
+ parsed = JSON.parse(text);
3140
+ }
3141
+ catch (error) {
3142
+ throw new Error(`${sourceLabel} 不是合法 JSON:${formatReason$1(error)}`);
3143
+ }
3144
+ if (!isManifestRecord(parsed)) {
3145
+ throw new Error(`${sourceLabel} 必须是 JSON 对象`);
3146
+ }
3147
+ return {
3148
+ manifest: parsed,
3149
+ hadBom,
3150
+ };
3151
+ }
3152
+ function validateMiniappManifestForDeploy(manifest) {
3153
+ const version = validateMiniappManifestVersion(manifest.version, 'manifest.version');
3154
+ const sdkVersion = validateSdkVersion(manifest.sdkVersion, 'manifest.sdkVersion');
3155
+ const permissions = parseMiniappPermissions(manifest.permissions, {
3156
+ present: Object.prototype.hasOwnProperty.call(manifest, 'permissions'),
3157
+ sdkVersion,
3158
+ sourceLabel: 'manifest.permissions',
3159
+ });
3160
+ const companions = validateGeneratedCompanions(manifest.companions);
3161
+ return {
3162
+ version,
3163
+ sdkVersion,
3164
+ platforms: validateMiniappPlatforms(manifest.platforms, 'manifest.platforms'),
3165
+ ...(permissions.permissions === undefined ? {} : { permissions: permissions.permissions }),
3166
+ ...(companions === undefined ? {} : { companions }),
3167
+ };
3168
+ }
3169
+ function validateGeneratedCompanions(value) {
3170
+ if (value === undefined)
3171
+ return undefined;
3172
+ if (!isRecord$2(value) || Object.keys(value).length === 0)
3173
+ throw new Error('manifest.companions 必须是非空对象');
3174
+ for (const [alias, definition] of Object.entries(value)) {
3175
+ if (!/^[a-z][a-z0-9-]{0,31}$/.test(alias) ||
3176
+ !isRecord$2(definition) ||
3177
+ typeof definition.displayName !== 'string' ||
3178
+ !definition.displayName ||
3179
+ Array.from(definition.displayName).length > 120 ||
3180
+ !Array.isArray(definition.capabilities) ||
3181
+ definition.capabilities.some((capability) => capability !== 'stdio' && capability !== 'attachments' && capability !== 'notifications') ||
3182
+ new Set(definition.capabilities).size !== definition.capabilities.length ||
3183
+ !isRecord$2(definition.targets) ||
3184
+ Object.keys(definition.targets).length === 0)
3185
+ throw new Error(`manifest.companions.${alias} 不合法`);
3186
+ for (const [target, artifact] of Object.entries(definition.targets)) {
3187
+ if (isRecord$2(artifact) && artifact.elevation === 'required') {
3188
+ throw new Error(`manifest.companions.${alias}.targets.${target}.elevation V1 仅支持 none,暂不支持管理员权限启动`);
3189
+ }
3190
+ if ((target !== 'windows-x64' && target !== 'macos-arm64') ||
3191
+ !isRecord$2(artifact) ||
3192
+ artifact.path !== `companions/${alias}/${target}.zip` ||
3193
+ !Number.isSafeInteger(artifact.size) ||
3194
+ Number(artifact.size) <= 0 ||
3195
+ typeof artifact.sha256 !== 'string' ||
3196
+ !/^[a-f0-9]{64}$/.test(artifact.sha256) ||
3197
+ !isRecord$2(artifact.entrypoint) ||
3198
+ (artifact.entrypoint.kind !== 'executable' && artifact.entrypoint.kind !== 'app-bundle') ||
3199
+ typeof artifact.entrypoint.path !== 'string' ||
3200
+ !artifact.entrypoint.path ||
3201
+ artifact.elevation !== 'none' ||
3202
+ !isValidGeneratedCompanionArgs(artifact.args)) {
3203
+ throw new Error(`manifest.companions.${alias}.targets.${target} 不合法`);
3204
+ }
3205
+ }
3206
+ }
3207
+ return value;
3208
+ }
3209
+ function isValidGeneratedCompanionArgs(value) {
3210
+ if (!Array.isArray(value) || value.length > 64)
3211
+ return false;
3212
+ let totalBytes = 0;
3213
+ for (const arg of value) {
3214
+ if (typeof arg !== 'string' || /[\u0000\r\n]/.test(arg))
3215
+ return false;
3216
+ const bytes = Buffer.byteLength(arg, 'utf8');
3217
+ if (bytes > 1024)
3218
+ return false;
3219
+ totalBytes += bytes;
3220
+ }
3221
+ return totalBytes <= 16_384;
3222
+ }
3223
+ function validateMiniappPlatforms(platforms, sourceLabel = 'platforms') {
3224
+ if (!Array.isArray(platforms) || platforms.length === 0) {
3225
+ throw new Error(`${sourceLabel} 必须是非空平台数组`);
3226
+ }
3227
+ const allowedPlatforms = new Set(MINIAPP_PLATFORM_VALUES);
3228
+ const seen = new Set();
3229
+ for (const platform of platforms) {
3230
+ if (typeof platform !== 'string' || !allowedPlatforms.has(platform)) {
3231
+ throw new Error(`${sourceLabel} 包含不支持的平台:${String(platform)}`);
3232
+ }
3233
+ if (seen.has(platform)) {
3234
+ throw new Error(`${sourceLabel} 包含重复平台:${platform}`);
3235
+ }
3236
+ seen.add(platform);
3237
+ }
3238
+ return Object.freeze(MINIAPP_PLATFORM_VALUES.filter((platform) => seen.has(platform)));
3239
+ }
3240
+ function areMiniappPlatformsEqual(left, right) {
3241
+ return left.length === right.length && left.every((platform, index) => platform === right[index]);
3242
+ }
3243
+ function validateSdkVersion(version, sourceLabel = 'sdkVersion') {
3244
+ if (typeof version !== 'string' || version.trim() === '') {
3245
+ throw new Error(`${sourceLabel} 必须是合法 SemVer:${String(version)}`);
3246
+ }
3247
+ const normalized = version.trim();
3248
+ const parsed = semverExports.parse(normalized);
3249
+ if (!parsed || parsed.version !== normalized || parsed.build.length > 0) {
3250
+ throw new Error(`${sourceLabel} 必须是合法 SemVer:${normalized}`);
3251
+ }
3252
+ return normalized;
3253
+ }
3254
+ function isManifestRecord(value) {
3069
3255
  return typeof value === 'object' && value !== null && !Array.isArray(value);
3070
3256
  }
3257
+ function isRecord$2(value) {
3258
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
3259
+ }
3260
+ function getMiniappManifestVersionError(version) {
3261
+ if (typeof version !== 'string' || version.trim() === '') {
3262
+ return `必须是合法 SemVer:${String(version)}`;
3263
+ }
3264
+ const normalized = version.trim();
3265
+ const parsed = semverExports.parse(normalized);
3266
+ if (!parsed) {
3267
+ return `必须是合法 SemVer:${normalized}`;
3268
+ }
3269
+ if (parsed.build.length > 0) {
3270
+ return `不能包含 build metadata:${normalized}`;
3271
+ }
3272
+ if (parsed.version !== normalized) {
3273
+ return `必须是合法 SemVer:${normalized}`;
3274
+ }
3275
+ if (parsed.major === 0 && parsed.minor === 0 && parsed.patch === 0) {
3276
+ return '不能是模板默认版本 0.0.0';
3277
+ }
3278
+ return undefined;
3279
+ }
3280
+ function formatReason$1(error) {
3281
+ if (error instanceof Error && error.message) {
3282
+ return error.message;
3283
+ }
3284
+ return String(error);
3285
+ }
3071
3286
 
3072
3287
  const MINIAPP_UPLOAD_SCOPE = 'activity';
3073
3288
  const ACTIVITY_UPLOAD_KEY_MAX_LENGTH = 64;
3074
3289
  const MINIAPP_UPLOAD_BATCH_SIZE = 50;
3075
3290
  const MINIAPP_UPLOAD_TOTAL_SIZE_LIMIT_BYTES = 100 * 1024 * 1024;
3291
+ /** 与 Activity 上传后端合同一致的 Companion 归档总大小上限。 */
3292
+ const MINIAPP_COMPANION_UPLOAD_TEMPORARY_SIZE_LIMIT_BYTES = 500 * 1024 * 1024;
3076
3293
  const USER_MINIPROGRAM_ACCESS_STATUS_API_PATH = '/mall/developer/user_miniprogram/access_status';
3077
3294
  const DEVELOPER_ENTITY_LIST_API_PATH = '/mall/developer/entity/list';
3078
3295
  const DEVELOPER_ENTITY_SWITCH_API_PATH = '/mall/developer/entity/switch';
@@ -3132,6 +3349,18 @@ function validateUploadTotalSize(items, options = {}) {
3132
3349
  }
3133
3350
  return undefined;
3134
3351
  }
3352
+ function validateMiniappUploadSizeBudgets(items, options = {}) {
3353
+ const companionItems = items.filter((item) => normalizeRelativePath(item.relativePath).startsWith('companions/'));
3354
+ const webItems = items.filter((item) => !normalizeRelativePath(item.relativePath).startsWith('companions/'));
3355
+ const webError = validateUploadTotalSize(webItems, { limitBytes: options.webLimitBytes ?? MINIAPP_UPLOAD_TOTAL_SIZE_LIMIT_BYTES });
3356
+ if (webError)
3357
+ return webError;
3358
+ const companionTotal = companionItems.reduce((sum, item) => sum + (Number.isFinite(item.size) && item.size > 0 ? item.size : 0), 0);
3359
+ const companionLimit = options.companionLimitBytes ?? MINIAPP_COMPANION_UPLOAD_TEMPORARY_SIZE_LIMIT_BYTES;
3360
+ if (companionTotal > companionLimit)
3361
+ return 'Companion 归档总大小超过 500MiB 上限,请缩减归档后重新 deploy';
3362
+ return undefined;
3363
+ }
3135
3364
  function shouldUploadDistFile(relativePath) {
3136
3365
  const normalized = normalizeRelativePath(relativePath);
3137
3366
  if (!normalized) {
@@ -3230,6 +3459,7 @@ function resolveMiniappUploadSessionFiles(localFiles, serverFiles, uploadedKeys)
3230
3459
  }
3231
3460
  const mappings = new Map();
3232
3461
  const serverSizes = new Map();
3462
+ const serverHashes = new Map();
3233
3463
  const knownKeys = new Set();
3234
3464
  for (const serverFile of serverFiles) {
3235
3465
  const relativePath = normalizeMiniappArtifactRelativePath(serverFile.relative_path);
@@ -3247,8 +3477,13 @@ function resolveMiniappUploadSessionFiles(localFiles, serverFiles, uploadedKeys)
3247
3477
  if (!Number.isSafeInteger(size) || size < 0) {
3248
3478
  throw new Error(`上传会话返回文件大小异常:${relativePath}`);
3249
3479
  }
3480
+ const sha256 = String(serverFile.sha256 || '');
3481
+ if (!/^[a-f0-9]{64}$/.test(sha256)) {
3482
+ throw new Error(`上传会话返回文件 SHA-256 异常:${relativePath}`);
3483
+ }
3250
3484
  mappings.set(relativePath, key);
3251
3485
  serverSizes.set(relativePath, size);
3486
+ serverHashes.set(relativePath, sha256);
3252
3487
  knownKeys.add(key);
3253
3488
  }
3254
3489
  const files = preparedFiles.map((file) => {
@@ -3259,6 +3494,9 @@ function resolveMiniappUploadSessionFiles(localFiles, serverFiles, uploadedKeys)
3259
3494
  if (serverSizes.get(file.relativePath) !== file.size) {
3260
3495
  throw new Error(`上传会话文件大小与本地构建不一致:${file.relativePath}`);
3261
3496
  }
3497
+ if (!('sha256' in file) || serverHashes.get(file.relativePath) !== file.sha256) {
3498
+ throw new Error(`上传会话文件 SHA-256 与本地构建不一致:${file.relativePath}`);
3499
+ }
3262
3500
  return { file, key };
3263
3501
  });
3264
3502
  const completed = new Set();
@@ -3275,6 +3513,41 @@ function resolveMiniappUploadSessionFiles(localFiles, serverFiles, uploadedKeys)
3275
3513
  uploadedKeys: [...completed],
3276
3514
  };
3277
3515
  }
3516
+ /** 校验 Manifest 中所有 Companion 归档都精确属于当前上传 receipt。 */
3517
+ function validateMiniappCompanionFileReceipts(companions, files) {
3518
+ const companionFiles = new Map(files.filter((file) => file.relativePath.startsWith('companions/')).map((file) => [file.relativePath, file]));
3519
+ if (companions === undefined) {
3520
+ if (companionFiles.size > 0)
3521
+ throw new Error('dist 包含未被 manifest.companions 引用的 Companion 归档');
3522
+ return;
3523
+ }
3524
+ if (!isRecord$1(companions))
3525
+ throw new Error('manifest.companions 必须是对象');
3526
+ const referenced = new Set();
3527
+ for (const definition of Object.values(companions)) {
3528
+ if (!isRecord$1(definition) || !isRecord$1(definition.targets))
3529
+ throw new Error('manifest.companions targets 不合法');
3530
+ for (const artifact of Object.values(definition.targets)) {
3531
+ if (!isRecord$1(artifact) || typeof artifact.path !== 'string' || typeof artifact.size !== 'number' || typeof artifact.sha256 !== 'string') {
3532
+ throw new Error('manifest.companions artifact 不合法');
3533
+ }
3534
+ const file = companionFiles.get(artifact.path);
3535
+ if (!file)
3536
+ throw new Error(`manifest.companions 引用的归档不在当前上传 receipt:${artifact.path}`);
3537
+ if (file.size !== artifact.size)
3538
+ throw new Error(`Companion 归档大小与 manifest 不一致:${artifact.path}`);
3539
+ if (file.sha256 !== artifact.sha256)
3540
+ throw new Error(`Companion 归档 SHA-256 与 manifest 不一致:${artifact.path}`);
3541
+ referenced.add(artifact.path);
3542
+ }
3543
+ }
3544
+ const extra = [...companionFiles.keys()].find((relativePath) => !referenced.has(relativePath));
3545
+ if (extra)
3546
+ throw new Error(`Companion 归档未被 manifest.companions 引用:${extra}`);
3547
+ }
3548
+ function isRecord$1(value) {
3549
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
3550
+ }
3278
3551
  function normalizeMiniappArtifactRelativePath(relativePath) {
3279
3552
  const value = String(relativePath || '');
3280
3553
  if (!value) {
@@ -3359,14 +3632,16 @@ function findNearestPackageJsonPath(startDir) {
3359
3632
  current = parent;
3360
3633
  }
3361
3634
  }
3635
+ function readMiniappPlatformsFromPackageJson(root) {
3636
+ const { packageJson } = readMiniappPackageJson(root);
3637
+ const heybox = readMiniappHeyboxConfig(packageJson);
3638
+ return validateMiniappPlatforms(heybox?.platforms, 'package.json#heybox.platforms');
3639
+ }
3362
3640
  function readMiniappPermissionsFromPackageJson(root, sdkVersion) {
3363
3641
  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, {
3642
+ const heybox = readMiniappHeyboxConfig(packageJson);
3643
+ const present = heybox !== undefined && Object.prototype.hasOwnProperty.call(heybox, 'permissions');
3644
+ return parseMiniappPermissions(heybox?.permissions, {
3370
3645
  present,
3371
3646
  sdkVersion,
3372
3647
  });
@@ -3395,7 +3670,15 @@ function readMiniappPackageJson(root, requireVersion) {
3395
3670
  catch (error) {
3396
3671
  throw new Error(`@heybox/hb-sdk 解析 package.json 失败:${formatReason(error)}`);
3397
3672
  }
3398
- return { packageJson, version: typeof packageJson.version === 'string' ? packageJson.version.trim() : '' };
3673
+ return { packageJson, packageJsonPath, version: typeof packageJson.version === 'string' ? packageJson.version.trim() : '' };
3674
+ }
3675
+ function readMiniappHeyboxConfig(packageJson) {
3676
+ if (packageJson.heybox === undefined)
3677
+ return undefined;
3678
+ if (!isRecord(packageJson.heybox)) {
3679
+ throw new Error('@heybox/hb-sdk 提示:package.json#heybox 必须是 JSON 对象');
3680
+ }
3681
+ return packageJson.heybox;
3399
3682
  }
3400
3683
  function isRecord(value) {
3401
3684
  return typeof value === 'object' && value !== null && !Array.isArray(value);
@@ -3407,6 +3690,13 @@ function formatReason(error) {
3407
3690
  return String(error);
3408
3691
  }
3409
3692
 
3693
+ Array.from({ length: 256 }, (_, value) => {
3694
+ let crc = value;
3695
+ for (let bit = 0; bit < 8; bit++)
3696
+ crc = (crc >>> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
3697
+ return crc >>> 0;
3698
+ });
3699
+
3410
3700
  const HB_SDK_RUNTIME_USE_OFFICIAL_DOMAIN_ENV = 'HB_SDK_RUNTIME_USE_OFFICIAL_DOMAIN';
3411
3701
  const HB_SDK_RUNTIME_PERMISSION_CONTEXT_ENV = 'HB_SDK_RUNTIME_PERMISSION_CONTEXT';
3412
3702
  const VERIFIED_RUNTIME_PERMISSION_CONTEXT = 'verified';
@@ -3498,23 +3788,28 @@ exports.USER_MINIPROGRAM_ACCESS_STATUS_API_PATH = USER_MINIPROGRAM_ACCESS_STATUS
3498
3788
  exports.USER_MINIPROGRAM_PREVIEW_ALLOWLIST_API_PATH = USER_MINIPROGRAM_PREVIEW_ALLOWLIST_API_PATH;
3499
3789
  exports.USER_MINIPROGRAM_VERSION_PREVIEW_INFO_API_PATH = USER_MINIPROGRAM_VERSION_PREVIEW_INFO_API_PATH;
3500
3790
  exports.WITHDRAW_USER_MINIPROGRAM_VERSION_API_PATH = WITHDRAW_USER_MINIPROGRAM_VERSION_API_PATH;
3791
+ exports.areMiniappPlatformsEqual = areMiniappPlatformsEqual;
3501
3792
  exports.composeMiniappRuntimePermissions = composeMiniappRuntimePermissions;
3502
3793
  exports.createMiniappArtifactFileHeader = createMiniappArtifactFileHeader;
3503
3794
  exports.createMiniappArtifactSignatureHeader = createMiniappArtifactSignatureHeader;
3504
3795
  exports.createMiniappPlatformCspEnv = createMiniappPlatformCspEnv;
3505
3796
  exports.getMissingPermissionsWarning = getMissingPermissionsWarning;
3797
+ exports.hasMiniappDesktopPlatform = hasMiniappDesktopPlatform;
3798
+ exports.isValidMiniappManifestVersion = isValidMiniappManifestVersion;
3506
3799
  exports.normalizeRelativePath = normalizeRelativePath;
3507
3800
  exports.parseMiniProgramRuntimePermissions = parseMiniProgramRuntimePermissions;
3508
- exports.parseMiniappPermissions = parseMiniappPermissions;
3801
+ exports.parseMiniappManifestJson = parseMiniappManifestJson;
3509
3802
  exports.prepareMiniappArtifactFiles = prepareMiniappArtifactFiles;
3510
3803
  exports.readMiniappPermissionsFromPackageJson = readMiniappPermissionsFromPackageJson;
3804
+ exports.readMiniappPlatformsFromPackageJson = readMiniappPlatformsFromPackageJson;
3511
3805
  exports.relativePathContainsNodeModulesSegment = relativePathContainsNodeModulesSegment;
3512
3806
  exports.requireSemver = requireSemver;
3513
3807
  exports.resolveMiniappSdkVersion = resolveMiniappSdkVersion;
3514
3808
  exports.resolveMiniappUploadSessionFiles = resolveMiniappUploadSessionFiles;
3515
- exports.semverExports = semverExports;
3516
3809
  exports.shouldSkipMiniappPlatformCspFromEnv = shouldSkipMiniappPlatformCspFromEnv;
3517
3810
  exports.shouldUploadDistFile = shouldUploadDistFile;
3811
+ exports.validateMiniappCompanionFileReceipts = validateMiniappCompanionFileReceipts;
3812
+ exports.validateMiniappManifestForDeploy = validateMiniappManifestForDeploy;
3518
3813
  exports.validateMiniappUploadPathLengths = validateMiniappUploadPathLengths;
3519
- exports.validateUploadTotalSize = validateUploadTotalSize;
3814
+ exports.validateMiniappUploadSizeBudgets = validateMiniappUploadSizeBudgets;
3520
3815
  exports.withMiniappPlatformCspEnv = withMiniappPlatformCspEnv;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-Buner4kE.cjs');
3
+ var index = require('./index-IeNOfmd0.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-DOBbqU-f.cjs');
4
+ var fs = require('node:fs/promises');
3
5
  var path = require('node:path');
4
- var version = require('./version-TXwWxKvv.cjs');
5
6
  var childProcess = require('node:child_process');
6
- var fs = require('node:fs/promises');
7
- var index = require('./index-Buner4kE.cjs');
7
+ var index = require('./index-IeNOfmd0.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 安装完成');