@heybox/hb-sdk 0.5.9 → 0.5.10

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.
@@ -5,7 +5,7 @@ var fs = require('node:fs/promises');
5
5
  var path = require('node:path');
6
6
  var require$$0 = require('fs');
7
7
  var require$$1 = require('path');
8
- var index = require('./index-BpVGoWHu.cjs');
8
+ var index = require('./index-BBatNb1l.cjs');
9
9
  require('node:module');
10
10
  require('os');
11
11
  require('readline');
@@ -9,7 +9,7 @@ var node_url = require('node:url');
9
9
  var net = require('node:net');
10
10
  var node_http = require('node:http');
11
11
  var browser = require('./browser-RAy8e8cV.cjs');
12
- var index = require('./index-BpVGoWHu.cjs');
12
+ var index = require('./index-BBatNb1l.cjs');
13
13
  require('node:process');
14
14
  require('node:buffer');
15
15
  require('node:util');
@@ -4,7 +4,7 @@ var fs$1 = require('node:fs');
4
4
  var fs = require('node:fs/promises');
5
5
  var os = require('node:os');
6
6
  var path = require('node:path');
7
- var index = require('./index-BpVGoWHu.cjs');
7
+ var index = require('./index-BBatNb1l.cjs');
8
8
  require('node:module');
9
9
  require('path');
10
10
  require('os');
@@ -234,19 +234,19 @@ function requireArgument () {
234
234
 
235
235
  var command = {};
236
236
 
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-BpVGoWHu.cjs', document.baseURI).href)));
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-BBatNb1l.cjs', document.baseURI).href)));
238
238
  function __require$4() { return require$5("node:events"); }
239
239
 
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-BpVGoWHu.cjs', document.baseURI).href)));
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-BBatNb1l.cjs', document.baseURI).href)));
241
241
  function __require$3() { return require$4("node:child_process"); }
242
242
 
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-BpVGoWHu.cjs', document.baseURI).href)));
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-BBatNb1l.cjs', document.baseURI).href)));
244
244
  function __require$2() { return require$3("node:path"); }
245
245
 
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-BpVGoWHu.cjs', document.baseURI).href)));
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-BBatNb1l.cjs', document.baseURI).href)));
247
247
  function __require$1() { return require$2("node:fs"); }
248
248
 
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-BpVGoWHu.cjs', document.baseURI).href)));
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-BBatNb1l.cjs', document.baseURI).href)));
250
250
  function __require() { return require$1("node:process"); }
251
251
 
252
252
  var help = {};
@@ -13094,7 +13094,7 @@ function readErrorMessage(error, options = {}) {
13094
13094
  }
13095
13095
 
13096
13096
  const CLI_VERSION_PLACEHOLDER = ['__HB', 'SDK', 'CLI', 'VERSION__'].join('_');
13097
- const BUILT_CLI_VERSION = '0.5.9';
13097
+ const BUILT_CLI_VERSION = '0.5.10';
13098
13098
  const PACKAGE_JSON_CANDIDATES = [
13099
13099
  path.resolve(__dirname, '..', '..', 'package.json'),
13100
13100
  path.resolve(__dirname, '..', 'package.json'),
@@ -13374,31 +13374,31 @@ function createCommandLoggerResolver(options) {
13374
13374
  };
13375
13375
  }
13376
13376
  const defaultClearLoginStatus = async (...args) => {
13377
- const { clearLoginStatus } = await Promise.resolve().then(function () { return require('./login-DhKNZpl4.cjs'); });
13377
+ const { clearLoginStatus } = await Promise.resolve().then(function () { return require('./login-BX0YmVyi.cjs'); });
13378
13378
  return clearLoginStatus(...args);
13379
13379
  };
13380
13380
  const defaultLoginToHeybox = async (...args) => {
13381
- const { loginToHeybox } = await Promise.resolve().then(function () { return require('./login-DhKNZpl4.cjs'); });
13381
+ const { loginToHeybox } = await Promise.resolve().then(function () { return require('./login-BX0YmVyi.cjs'); });
13382
13382
  return loginToHeybox(...args);
13383
13383
  };
13384
13384
  const defaultPrintLoginStatus = async (...args) => {
13385
- const { printLoginStatus } = await Promise.resolve().then(function () { return require('./login-DhKNZpl4.cjs'); });
13385
+ const { printLoginStatus } = await Promise.resolve().then(function () { return require('./login-BX0YmVyi.cjs'); });
13386
13386
  return printLoginStatus(...args);
13387
13387
  };
13388
13388
  const defaultRunCreateCommand = async (...args) => {
13389
- const { runCreateCommand } = await Promise.resolve().then(function () { return require('./create-zJEmBOvP.cjs'); });
13389
+ const { runCreateCommand } = await Promise.resolve().then(function () { return require('./create-D1W2pkHZ.cjs'); });
13390
13390
  return runCreateCommand(...args);
13391
13391
  };
13392
13392
  const defaultRunDevCommand = async (...args) => {
13393
- const { runDevCommand } = await Promise.resolve().then(function () { return require('./dev-DsqPSgeJ.cjs'); });
13393
+ const { runDevCommand } = await Promise.resolve().then(function () { return require('./dev-DwbE-c1x.cjs'); });
13394
13394
  return runDevCommand(...args);
13395
13395
  };
13396
13396
  const defaultRunDoctorCommand = async (...args) => {
13397
- const { runDoctorCommand } = await Promise.resolve().then(function () { return require('./doctor-DZkEwLT9.cjs'); });
13397
+ const { runDoctorCommand } = await Promise.resolve().then(function () { return require('./doctor-Bx71WFjM.cjs'); });
13398
13398
  return runDoctorCommand(...args);
13399
13399
  };
13400
13400
  const defaultRunRemoteCommand = async (...args) => {
13401
- const { runRemoteCommand } = await Promise.resolve().then(function () { return require('./remote-D0izsd5c.cjs'); }).then(function (n) { return n.remote; });
13401
+ const { runRemoteCommand } = await Promise.resolve().then(function () { return require('./remote-YDmSxyYi.cjs'); }).then(function (n) { return n.remote; });
13402
13402
  return runRemoteCommand(...args);
13403
13403
  };
13404
13404
  function resolveStandaloneLogger(options, verbose) {
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var index$2 = require('./index-BpVGoWHu.cjs');
3
+ var index$2 = require('./index-BBatNb1l.cjs');
4
4
  var require$$0$2 = require('fs');
5
5
  var require$$2$1 = require('crypto');
6
6
  var require$$1$2 = require('path');
7
7
  var require$$0$3 = require('assert');
8
8
  var require$$4$2 = require('events');
9
9
  var require$$1$1 = require('util');
10
- var remote = require('./remote-D0izsd5c.cjs');
10
+ var remote = require('./remote-YDmSxyYi.cjs');
11
11
  var require$$0$5 = require('net');
12
12
  var require$$0$4 = require('url');
13
13
  var require$$2$2 = require('http');
@@ -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-O_NdH1Z2.cjs');
6
+ var session = require('./session-BxZBXDZ-.cjs');
7
7
  var browser = require('./browser-RAy8e8cV.cjs');
8
- var index = require('./index-BpVGoWHu.cjs');
8
+ var index = require('./index-BBatNb1l.cjs');
9
9
  require('node:path');
10
10
  require('fs');
11
11
  require('constants');
@@ -1,12 +1,12 @@
1
1
  'use strict';
2
2
 
3
3
  var promises = require('node:readline/promises');
4
- var session = require('./session-O_NdH1Z2.cjs');
4
+ var session = require('./session-BxZBXDZ-.cjs');
5
5
  var childProcess = require('node:child_process');
6
6
  var fs = require('node:fs');
7
7
  var fs$1 = require('node:fs/promises');
8
8
  var path = require('node:path');
9
- var index = require('./index-BpVGoWHu.cjs');
9
+ var index = require('./index-BBatNb1l.cjs');
10
10
 
11
11
  var re = {exports: {}};
12
12
 
@@ -3111,7 +3111,7 @@ async function createDefaultCosClient(uploadToken) {
3111
3111
  };
3112
3112
  }
3113
3113
  async function loadCosConstructor() {
3114
- const cosModule = await Promise.resolve().then(function () { return require('./index-CU-8dVKo.cjs'); }).then(function (n) { return n.index; });
3114
+ const cosModule = await Promise.resolve().then(function () { return require('./index-D5bZjpH9.cjs'); }).then(function (n) { return n.index; });
3115
3115
  return cosModule.default;
3116
3116
  }
3117
3117
  function formatSize(bytes) {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-BpVGoWHu.cjs');
3
+ var index = require('./index-BBatNb1l.cjs');
4
4
  var node_crypto = require('node:crypto');
5
5
  var path = require('node:path');
6
6
  var require$$0$2 = require('fs');
package/dist/cli.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./cli-chunks/index-BpVGoWHu.cjs');
3
+ var index = require('./cli-chunks/index-BBatNb1l.cjs');
4
4
  require('node:module');
5
5
  require('node:fs');
6
6
  require('node:fs/promises');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heybox/hb-sdk",
3
- "version": "0.5.9",
3
+ "version": "0.5.10",
4
4
  "description": "",
5
5
  "exports": {
6
6
  ".": {
@@ -117,6 +117,8 @@
117
117
  "build:types": "tsc -p tsconfig.dts.json",
118
118
  "check:boundary": "node scripts/check-boundary.cjs",
119
119
  "check:docs-sync": "node scripts/check-docs-sync.cjs",
120
+ "sync:agent-skills-payload": "node skill/scripts/sync-agent-skills-payload.mjs",
121
+ "check:agent-skills-payload": "node skill/scripts/sync-agent-skills-payload.mjs --check",
120
122
  "clean": "rimraf ./dist && rimraf ./types",
121
123
  "test:unit": "NODE_OPTIONS='--conditions=heybox' vitest run",
122
124
  "test:unit:coverage": "NODE_OPTIONS='--conditions=heybox' vitest run --coverage",
package/skill/SKILL.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: hb-sdk
3
- description: Uses @heybox/hb-sdk and its hb-sdk CLI for Heybox external mini-program iframe pages, local mock development, template creation, skill version checks, and host/runtime protocol integration. Use for ready/auth/user/share/viewport/storage/network APIs, lifecycle events, hb-sdk create/dev/login/doctor, mock runtime debugging, custom SDK instances, or @heybox/hb-sdk/protocol contracts. Don't use for raw postMessage bridge construction in app code, direct cookie/token access, internal Heybox client protocols, separate mock runtimes, or non-Heybox SDKs.
3
+ description: Uses @heybox/hb-sdk and its hb-sdk CLI for Heybox external mini-program iframe pages, local mock development, template creation, skill version checks, host/runtime protocol integration, and mini-program listing/audit/compliance review. Use for ready/auth/user/share/viewport/storage/network APIs, lifecycle events, hb-sdk create/dev/login/doctor, mock runtime debugging, custom SDK instances, or @heybox/hb-sdk/protocol contracts. Don't use for raw postMessage bridge construction in app code, direct cookie/token access, internal Heybox client protocols, separate mock runtimes, or non-Heybox SDKs.
4
4
  ---
5
5
 
6
6
  # hb-sdk Agent Procedure
@@ -12,8 +12,9 @@ Apply these instructions when writing, reviewing, or debugging code that consume
12
12
  1. If the task is iframe mini-program business code, use the root package import path `@heybox/hb-sdk`.
13
13
  2. If the task is parent-container runtime, bridge-server, protocol contract, or `@heybox/hb-sdk-runtime` work, use `@heybox/hb-sdk/protocol` only for shared constants and types.
14
14
  3. If the task is project scaffolding, local Vite startup, browser mock runtime, CLI login cache, Agent Skill version diagnosis, or CLI troubleshooting, use the `hb-sdk` CLI workflow.
15
- 4. If the task asks for direct login-state extraction, cookies, tokens, raw Heybox client protocols, or internal hb-sdk package paths, refuse that approach and use the public SDK or CLI boundary instead.
16
- 5. If the task is not about Heybox external mini-program SDK usage, CLI usage, mock runtime, or protocol contracts, do not apply this skill.
15
+ 4. If the task is reviewing a mini-program for submission, listing, audit, publishing, content compliance, data/privacy compliance, runtime quality, or icon/cover design requirements, use the online publishing rules workflow.
16
+ 5. If the task asks for direct login-state extraction, cookies, tokens, raw Heybox client protocols, or internal hb-sdk package paths, refuse that approach and use the public SDK or CLI boundary instead.
17
+ 6. If the task is not about Heybox external mini-program SDK usage, CLI usage, mock runtime, protocol contracts, or mini-program listing/audit/compliance review, do not apply this skill.
17
18
 
18
19
  ## Step 2: Load only the needed reference
19
20
 
@@ -26,6 +27,7 @@ Apply these instructions when writing, reviewing, or debugging code that consume
26
27
  7. For generated documentation provenance and deeper API lookup paths, read `references/llms-index.md`.
27
28
  8. For smoke-test expectations, positive examples, and anti-examples, read `references/examples.md`.
28
29
  9. For evaluating whether another agent followed this skill, read `references/smoke-evaluation.md`.
30
+ 10. For mini-program listing/audit/compliance review, fetch the online rules Markdown from `https://open.xiaoheihe.cn/docs/hb_sdk/llms/guide/mini-program-publishing-rules.md`. Do not rely on a bundled `references/` copy of this document; if the URL is unavailable or returns the docs app shell instead of Markdown, report that the online rules are unavailable and do not complete the review from stale local text.
29
31
 
30
32
  ## Step 3: Follow import rules
31
33
 
@@ -35,6 +35,7 @@ This site documents the iframe-side SDK for external mini programs. For AI retri
35
35
  - [错误处理](./llms/guide/error-handling.md): SDK 对外抛出的标准错误类型是 `HbMiniProgramSDKError`。
36
36
  - [安装与运行环境](./llms/guide/installation.md): 如果工坊小程序只是普通展示页面,不调用黑盒开放能力,也不监听 SDK 生命周期事件,可以不安装、不引用、不初始化 `@heybox/hb-sdk`。父容器仍可能在 URL 上注入 `hb_mini_bridge_nonce`,业务页可以直接忽略。
37
37
  - [事件与生命周期](./llms/guide/lifecycle.md): SDK 通过 `on` 监听父容器派发的小程序生命周期和业务事件。
38
+ - [小程序工坊上架规则 v2(试行)](./llms/guide/mini-program-publishing-rules.md): 本规则用于说明小程序工坊的小程序发布、上架和持续在线要求。通过审核不等于获得推荐或公开展示;工坊广场、推荐位、搜索等流量分发规则另行制定。
38
39
  - [快速开始](./llms/guide/quick-start.md): 如果页面不需要黑盒开放能力,可以不接入 SDK。这是一条需要用户能力时的最短接入路径:等待 SDK 完成握手,然后读取当前用户登录态。
39
40
  ## Recipes
40
41
  - [独立 SDK 实例](./llms/recipes/custom-instance.md): 大多数业务页使用默认单例即可。只有在需要隔离上下文时,再创建独立实例。
@@ -0,0 +1,359 @@
1
+ #!/usr/bin/env node
2
+ import { Buffer } from 'node:buffer';
3
+ import { promises as fs } from 'node:fs';
4
+ import path from 'node:path';
5
+ import { fileURLToPath, pathToFileURL } from 'node:url';
6
+ import { HB_SDK_PACKAGE_NAME } from './skill-metadata.mjs';
7
+
8
+ const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
9
+ const HB_SDK_ROOT = path.resolve(SCRIPT_DIR, '../..');
10
+ const REPO_ROOT = path.resolve(HB_SDK_ROOT, '../..');
11
+ const WELL_KNOWN_ROOT = path.join('.well-known', 'agent-skills');
12
+ const AGENT_SKILL_PACKAGES = [
13
+ {
14
+ packageName: HB_SDK_PACKAGE_NAME,
15
+ skillDir: 'skill',
16
+ },
17
+ ];
18
+
19
+ const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---\n?/;
20
+ const TEXT_FILE_RE = /\.(?:md|mjs|js|cjs|ts|tsx|json|txt|sh|yaml|yml)$/i;
21
+ const PREFERRED_ORDER = new Map([
22
+ ['SKILL.md', 0],
23
+ ['skill.json', 1],
24
+ ['references/api-root.md', 100],
25
+ ['references/api-protocol.md', 101],
26
+ ['references/cli.md', 102],
27
+ ['references/recipes.md', 103],
28
+ ['references/safety-boundaries.md', 104],
29
+ ['references/llms-index.md', 105],
30
+ ['references/examples.md', 106],
31
+ ['references/smoke-evaluation.md', 107],
32
+ ['scripts/sync-references.mjs', 200],
33
+ ['scripts/check-references.mjs', 201],
34
+ ['scripts/validate-skill.mjs', 202],
35
+ ['scripts/package-skill.mjs', 203],
36
+ ['scripts/package-skill.sh', 204],
37
+ ]);
38
+
39
+ function parseCliArgs(argv) {
40
+ const args = argv.slice(2);
41
+ let outDir = path.resolve(process.cwd(), '.agent-skills-payload');
42
+ let check = false;
43
+
44
+ for (let index = 0; index < args.length; index += 1) {
45
+ const arg = args[index];
46
+ if (arg === '--check') {
47
+ check = true;
48
+ continue;
49
+ }
50
+ if (arg === '--out-dir') {
51
+ const value = args[index + 1];
52
+ if (!value) {
53
+ throw new Error('--out-dir requires a path argument');
54
+ }
55
+ outDir = path.resolve(process.cwd(), value);
56
+ index += 1;
57
+ }
58
+ }
59
+
60
+ return { outDir, check };
61
+ }
62
+
63
+ function toPosixPath(value) {
64
+ return value.split(path.sep).join('/');
65
+ }
66
+
67
+ function assertSafeRelativePath(relativePath, context) {
68
+ const normalized = path.posix.normalize(relativePath);
69
+
70
+ if (path.isAbsolute(relativePath) || normalized.startsWith('../') || normalized === '..') {
71
+ throw new Error(`${context} has unsafe path: ${relativePath}`);
72
+ }
73
+
74
+ if (normalized !== relativePath) {
75
+ throw new Error(`${context} must be normalized: ${relativePath}`);
76
+ }
77
+
78
+ if (relativePath.includes('/../') || relativePath.endsWith('/..')) {
79
+ throw new Error(`${context} cannot contain parent traversal: ${relativePath}`);
80
+ }
81
+
82
+ if (/\.zip$/i.test(relativePath)) {
83
+ throw new Error(`${context} must not include zip archives: ${relativePath}`);
84
+ }
85
+ }
86
+
87
+ function parseFrontmatter(skillText, skillPath) {
88
+ const match = skillText.match(FRONTMATTER_RE);
89
+ if (!match) {
90
+ throw new Error(`${skillPath} is missing YAML frontmatter`);
91
+ }
92
+
93
+ const metadata = {};
94
+ for (const rawLine of match[1].split('\n')) {
95
+ const line = rawLine.trim();
96
+ if (!line || line.startsWith('#') || line.startsWith('metadata:')) {
97
+ continue;
98
+ }
99
+
100
+ const keyValue = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
101
+ if (!keyValue) {
102
+ continue;
103
+ }
104
+
105
+ const [, key, rawValue] = keyValue;
106
+ metadata[key] = rawValue.replace(/^['"]|['"]$/g, '').trim();
107
+ }
108
+
109
+ return metadata;
110
+ }
111
+
112
+ async function exists(filePath) {
113
+ try {
114
+ await fs.access(filePath);
115
+ return true;
116
+ } catch {
117
+ return false;
118
+ }
119
+ }
120
+
121
+ async function readJsonFile(filePath) {
122
+ return JSON.parse(await fs.readFile(filePath, 'utf8'));
123
+ }
124
+
125
+ async function resolvePackageRoot(packageSource) {
126
+ if (packageSource.packageName !== HB_SDK_PACKAGE_NAME) {
127
+ throw new Error(`Unsupported agent skill package: ${packageSource.packageName}`);
128
+ }
129
+
130
+ if (!(await exists(path.join(HB_SDK_ROOT, 'package.json')))) {
131
+ throw new Error(`Cannot resolve ${packageSource.packageName}: missing package root at ${toPosixPath(HB_SDK_ROOT)}`);
132
+ }
133
+
134
+ return HB_SDK_ROOT;
135
+ }
136
+
137
+ async function listFilesRecursive(rootDir, relativeBase = '', options = {}) {
138
+ if (!(await exists(rootDir))) {
139
+ return [];
140
+ }
141
+
142
+ const entries = await fs.readdir(rootDir, { withFileTypes: true });
143
+ const files = [];
144
+
145
+ for (const entry of entries) {
146
+ if (!options.includeHidden && entry.name.startsWith('.')) {
147
+ continue;
148
+ }
149
+
150
+ const absolutePath = path.join(rootDir, entry.name);
151
+ const relativePath = path.posix.join(relativeBase, entry.name);
152
+
153
+ if (entry.isDirectory()) {
154
+ files.push(...(await listFilesRecursive(absolutePath, relativePath, options)));
155
+ continue;
156
+ }
157
+
158
+ if (entry.isFile()) {
159
+ files.push(relativePath);
160
+ }
161
+ }
162
+
163
+ return files;
164
+ }
165
+
166
+ function sortSkillFiles(files) {
167
+ return [...files].sort((left, right) => {
168
+ const leftOrder = PREFERRED_ORDER.get(left) ?? 10_000;
169
+ const rightOrder = PREFERRED_ORDER.get(right) ?? 10_000;
170
+ return leftOrder - rightOrder || left.localeCompare(right);
171
+ });
172
+ }
173
+
174
+ async function discoverSkill(packageSource) {
175
+ const packageRoot = await resolvePackageRoot(packageSource);
176
+ const skillDir = path.join(packageRoot, packageSource.skillDir);
177
+ const skillMarkdownPath = path.join(skillDir, 'SKILL.md');
178
+
179
+ if (!(await exists(skillMarkdownPath))) {
180
+ throw new Error(`${packageSource.packageName} must provide ${packageSource.skillDir}/SKILL.md.`);
181
+ }
182
+
183
+ const skillMarkdown = await fs.readFile(skillMarkdownPath, 'utf8');
184
+ const frontmatter = parseFrontmatter(skillMarkdown, skillMarkdownPath);
185
+ const skillName = frontmatter.name;
186
+
187
+ if (!skillName) {
188
+ throw new Error(`${skillMarkdownPath} frontmatter must include name`);
189
+ }
190
+
191
+ if (!frontmatter.description) {
192
+ throw new Error(`${skillMarkdownPath} frontmatter must include description`);
193
+ }
194
+
195
+ const files = ['SKILL.md'];
196
+ const skillJsonPath = path.join(skillDir, 'skill.json');
197
+ let metadata = null;
198
+
199
+ if (await exists(skillJsonPath)) {
200
+ const relativeFile = 'skill.json';
201
+ assertSafeRelativePath(relativeFile, `${skillName} source file`);
202
+ files.push(relativeFile);
203
+ metadata = await readJsonFile(skillJsonPath);
204
+ if (metadata.name !== skillName) {
205
+ throw new Error(`${skillJsonPath} name (${metadata.name}) must match SKILL.md frontmatter (${skillName})`);
206
+ }
207
+ }
208
+
209
+ for (const topLevelDir of ['references', 'scripts', 'assets']) {
210
+ const nestedFiles = await listFilesRecursive(path.join(skillDir, topLevelDir), topLevelDir);
211
+ for (const relativeFile of nestedFiles) {
212
+ if (!TEXT_FILE_RE.test(relativeFile)) {
213
+ continue;
214
+ }
215
+ assertSafeRelativePath(relativeFile, `${skillName} source file`);
216
+ files.push(relativeFile);
217
+ }
218
+ }
219
+
220
+ return {
221
+ sourceDir: skillDir,
222
+ name: skillName,
223
+ description: frontmatter.description,
224
+ files: sortSkillFiles(files),
225
+ metadata,
226
+ };
227
+ }
228
+
229
+ async function discoverSkills() {
230
+ const skills = [];
231
+
232
+ for (const packageSource of AGENT_SKILL_PACKAGES) {
233
+ skills.push(await discoverSkill(packageSource));
234
+ }
235
+
236
+ if (skills.length === 0) {
237
+ throw new Error('No configured agent skills found.');
238
+ }
239
+
240
+ return skills;
241
+ }
242
+
243
+ export function createSkillIndex(skills) {
244
+ return {
245
+ skills: skills.map((skill) => ({
246
+ name: skill.name,
247
+ description: skill.description,
248
+ ...(skill.metadata
249
+ ? {
250
+ version: skill.metadata.skillVersion,
251
+ sdk: skill.metadata.sdk,
252
+ source: skill.metadata.source,
253
+ integrity: skill.metadata.integrity,
254
+ }
255
+ : {}),
256
+ files: skill.files,
257
+ })),
258
+ };
259
+ }
260
+
261
+ async function addIndexFile(outputFiles, baseDir, skills) {
262
+ const indexPath = path.join(baseDir, WELL_KNOWN_ROOT, 'index.json');
263
+ const index = createSkillIndex(skills);
264
+
265
+ outputFiles.set(indexPath, Buffer.from(`${JSON.stringify(index, null, 2)}\n`, 'utf8'));
266
+ }
267
+
268
+ async function addSkillFiles(outputFiles, baseDir, skills) {
269
+ for (const skill of skills) {
270
+ for (const relativeFile of skill.files) {
271
+ assertSafeRelativePath(relativeFile, `${skill.name} generated file`);
272
+ const sourcePath = path.join(skill.sourceDir, ...relativeFile.split('/'));
273
+ const targetPath = path.join(baseDir, WELL_KNOWN_ROOT, skill.name, ...relativeFile.split('/'));
274
+ outputFiles.set(targetPath, await fs.readFile(sourcePath));
275
+ }
276
+ }
277
+ }
278
+
279
+ async function buildExpectedOutput(skills, targetRoot) {
280
+ const outputFiles = new Map();
281
+
282
+ await addIndexFile(outputFiles, targetRoot, skills);
283
+ await addSkillFiles(outputFiles, targetRoot, skills);
284
+
285
+ return outputFiles;
286
+ }
287
+
288
+ async function listExistingGeneratedFiles(targetRoot) {
289
+ if (!(await exists(targetRoot))) {
290
+ return [];
291
+ }
292
+
293
+ const relativeFiles = await listFilesRecursive(targetRoot, '', { includeHidden: true });
294
+ return relativeFiles.map((relativeFile) => path.join(targetRoot, ...relativeFile.split('/')));
295
+ }
296
+
297
+ async function syncFiles(expectedOutput, targetRoot) {
298
+ await fs.rm(targetRoot, { recursive: true, force: true });
299
+
300
+ for (const [targetPath, content] of [...expectedOutput.entries()].sort(([left], [right]) => left.localeCompare(right))) {
301
+ await fs.mkdir(path.dirname(targetPath), { recursive: true });
302
+ await fs.writeFile(targetPath, content);
303
+ }
304
+ }
305
+
306
+ async function checkFiles(expectedOutput, targetRoot) {
307
+ const expectedPaths = new Set(expectedOutput.keys());
308
+ const existingPaths = new Set(await listExistingGeneratedFiles(targetRoot));
309
+ const problems = [];
310
+
311
+ for (const expectedPath of [...expectedPaths].sort()) {
312
+ if (!existingPaths.has(expectedPath)) {
313
+ problems.push(`missing ${path.relative(REPO_ROOT, expectedPath)}`);
314
+ continue;
315
+ }
316
+
317
+ const actual = await fs.readFile(expectedPath);
318
+ const expected = expectedOutput.get(expectedPath);
319
+ if (!actual.equals(expected)) {
320
+ problems.push(`stale ${path.relative(REPO_ROOT, expectedPath)}`);
321
+ }
322
+ }
323
+
324
+ for (const existingPath of [...existingPaths].sort()) {
325
+ if (!expectedPaths.has(existingPath)) {
326
+ problems.push(`extra ${path.relative(REPO_ROOT, existingPath)}`);
327
+ }
328
+ }
329
+
330
+ if (problems.length > 0) {
331
+ throw new Error(`Agent skills payload is out of sync:\n${problems.map((problem) => `- ${problem}`).join('\n')}`);
332
+ }
333
+ }
334
+
335
+ async function main() {
336
+ const { outDir, check } = parseCliArgs(process.argv);
337
+ const skills = await discoverSkills();
338
+ const expectedOutput = await buildExpectedOutput(skills, outDir);
339
+
340
+ if (check) {
341
+ await checkFiles(expectedOutput, outDir);
342
+ console.log(
343
+ `Agent skills payload is in sync at ${toPosixPath(path.relative(REPO_ROOT, outDir))} (${expectedOutput.size} files, ${skills.length} skills).`,
344
+ );
345
+ return;
346
+ }
347
+
348
+ await syncFiles(expectedOutput, outDir);
349
+ console.log(
350
+ `Synced ${skills.length} skills to ${toPosixPath(path.relative(REPO_ROOT, outDir))} (${expectedOutput.size} files).`,
351
+ );
352
+ }
353
+
354
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
355
+ main().catch((error) => {
356
+ console.error(error.message);
357
+ process.exitCode = 1;
358
+ });
359
+ }
package/skill/skill.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "hb-sdk",
3
- "skillVersion": "0.5.9+skill.06627017a5ee",
3
+ "skillVersion": "0.5.9+skill.02be68ce07ce",
4
4
  "sdk": {
5
5
  "package": "@heybox/hb-sdk",
6
6
  "version": "0.5.9",
7
7
  "compatibility": "0.5.9"
8
8
  },
9
9
  "source": "https://open.xiaoheihe.cn/agent-skills/hb-sdk",
10
- "integrity": "sha256-06627017a5ee6a42c9d684c5d498bd255857a256139547fc5683f9a0af269f9a"
10
+ "integrity": "sha256-02be68ce07ce1cf0ecba354d764a47977e4fc3c189b5e4aed3cee1f844fddfd4"
11
11
  }