@heybox/hb-sdk 0.2.0-alpha.0 → 0.2.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +142 -468
- package/bin/hb-sdk.cjs +1 -1
- package/dist/cli.cjs +660 -182
- package/dist/devtools/mock-host/index.html +13 -387
- package/dist/devtools/mock-host/main.js +975 -0
- package/dist/index.cjs.js +50 -63
- package/dist/index.esm.js +51 -50
- package/dist/protocol.cjs.js +72 -13
- package/dist/protocol.esm.js +72 -14
- package/dist/templates/vue3-vite-ts/README.md.ejs +1 -5
- package/dist/templates/vue3-vite-ts/package.json.ejs +0 -1
- package/package.json +3 -1
- package/skill/SKILL.md +95 -0
- package/skill/references/api-protocol.md +135 -0
- package/skill/references/api-root.md +346 -0
- package/skill/references/cli.md +360 -0
- package/skill/references/examples.md +107 -0
- package/skill/references/llms-index.md +44 -0
- package/skill/references/recipes.md +374 -0
- package/skill/references/safety-boundaries.md +28 -0
- package/skill/references/smoke-evaluation.md +24 -0
- package/skill/scripts/check-references.mjs +14 -0
- package/skill/scripts/package-skill.mjs +60 -0
- package/skill/scripts/package-skill.sh +6 -0
- package/skill/scripts/skill-metadata.mjs +74 -0
- package/skill/scripts/sync-references.mjs +541 -0
- package/skill/scripts/validate-skill.mjs +233 -0
- package/skill/skill.json +11 -0
- package/types/index.d.ts +8 -6
- package/types/modules/auth/index.d.ts +2 -9
- package/types/modules/network/index.d.ts +6 -11
- package/types/modules/share/index.d.ts +3 -9
- package/types/modules/share/screenshot.d.ts +1 -7
- package/types/modules/share/show-share-menu.d.ts +1 -7
- package/types/modules/storage/index.d.ts +2 -16
- package/types/modules/user/get-info.d.ts +1 -7
- package/types/modules/user/index.d.ts +2 -8
- package/types/modules/viewport/index.d.ts +2 -9
- package/types/protocol/capabilities.d.ts +180 -0
- package/types/protocol.d.ts +8 -13
package/dist/cli.cjs
CHANGED
|
@@ -5030,26 +5030,27 @@ const TEMPLATE_ROOT_CANDIDATES = [
|
|
|
5030
5030
|
path.resolve(__dirname, '..', 'templates', TEMPLATE_NAME),
|
|
5031
5031
|
path.resolve(__dirname, '..', 'src', 'cli', 'templates', TEMPLATE_NAME),
|
|
5032
5032
|
];
|
|
5033
|
-
const PACKAGE_JSON_CANDIDATES = [
|
|
5034
|
-
path.resolve(__dirname, '..', 'package.json'),
|
|
5035
|
-
path.resolve(__dirname, '..', '..', '..', 'package.json'),
|
|
5036
|
-
];
|
|
5033
|
+
const PACKAGE_JSON_CANDIDATES$3 = [path.resolve(__dirname, '..', 'package.json'), path.resolve(__dirname, '..', '..', '..', 'package.json')];
|
|
5037
5034
|
const UNSCOPED_PACKAGE_NAME_PATTERN = /^(?![._])[a-z0-9._-]+$/;
|
|
5038
|
-
async function runCreateCommand(projectName) {
|
|
5039
|
-
const
|
|
5035
|
+
async function runCreateCommand(projectName, options = {}) {
|
|
5036
|
+
const cwd = options.cwd ?? process.cwd();
|
|
5037
|
+
const targetDir = path.resolve(cwd, projectName);
|
|
5040
5038
|
const packageName = readPackageName(projectName, targetDir);
|
|
5041
5039
|
await assertTargetDirectoryWritable(targetDir);
|
|
5042
|
-
const templateRoot = await resolveTemplateRoot();
|
|
5040
|
+
const templateRoot = await resolveTemplateRoot(options.templateRoots);
|
|
5043
5041
|
const data = {
|
|
5044
5042
|
packageName,
|
|
5045
5043
|
projectName: packageName,
|
|
5046
|
-
sdkVersion: await readCurrentSdkVersion(),
|
|
5044
|
+
sdkVersion: await readCurrentSdkVersion$3(options.packageJsonFiles),
|
|
5047
5045
|
};
|
|
5048
5046
|
await renderTemplateDirectory(templateRoot, targetDir, data);
|
|
5049
|
-
printCreateResult(projectName, targetDir
|
|
5047
|
+
printCreateResult(projectName, targetDir, {
|
|
5048
|
+
console: options.console,
|
|
5049
|
+
cwd,
|
|
5050
|
+
});
|
|
5050
5051
|
}
|
|
5051
5052
|
function readPackageName(projectName, targetDir) {
|
|
5052
|
-
if (projectName.trim().startsWith('@') || projectName.split(/[\\/]/).some(segment => segment.startsWith('@'))) {
|
|
5053
|
+
if (projectName.trim().startsWith('@') || projectName.split(/[\\/]/).some((segment) => segment.startsWith('@'))) {
|
|
5053
5054
|
throw new Error('暂不支持 scoped package name,请使用 my-miniapp 这类普通目录名');
|
|
5054
5055
|
}
|
|
5055
5056
|
const packageName = path.basename(targetDir);
|
|
@@ -5062,7 +5063,7 @@ function readPackageName(projectName, targetDir) {
|
|
|
5062
5063
|
return packageName;
|
|
5063
5064
|
}
|
|
5064
5065
|
async function assertTargetDirectoryWritable(targetDir) {
|
|
5065
|
-
if (!(await pathExists(targetDir))) {
|
|
5066
|
+
if (!(await pathExists$3(targetDir))) {
|
|
5066
5067
|
await fs$2.mkdir(targetDir, { recursive: true });
|
|
5067
5068
|
return;
|
|
5068
5069
|
}
|
|
@@ -5075,25 +5076,25 @@ async function assertTargetDirectoryWritable(targetDir) {
|
|
|
5075
5076
|
throw new Error(`目标目录非空,已拒绝覆盖: ${targetDir}`);
|
|
5076
5077
|
}
|
|
5077
5078
|
}
|
|
5078
|
-
async function resolveTemplateRoot() {
|
|
5079
|
-
for (const candidate of
|
|
5080
|
-
if (await pathExists(candidate)) {
|
|
5079
|
+
async function resolveTemplateRoot(templateRootCandidates = TEMPLATE_ROOT_CANDIDATES) {
|
|
5080
|
+
for (const candidate of templateRootCandidates) {
|
|
5081
|
+
if (await pathExists$3(candidate)) {
|
|
5081
5082
|
return candidate;
|
|
5082
5083
|
}
|
|
5083
5084
|
}
|
|
5084
5085
|
throw new Error(`未找到 hb-sdk create 模板: ${TEMPLATE_NAME}。请先执行 @heybox/hb-sdk 的 build:templates。`);
|
|
5085
5086
|
}
|
|
5086
|
-
async function readCurrentSdkVersion() {
|
|
5087
|
-
const packageJsonPath = await resolvePackageJsonPath();
|
|
5087
|
+
async function readCurrentSdkVersion$3(packageJsonCandidates = PACKAGE_JSON_CANDIDATES$3) {
|
|
5088
|
+
const packageJsonPath = await resolvePackageJsonPath(packageJsonCandidates);
|
|
5088
5089
|
const packageJson = JSON.parse(await fs$2.readFile(packageJsonPath, 'utf8'));
|
|
5089
5090
|
if (typeof packageJson.version !== 'string' || !packageJson.version) {
|
|
5090
5091
|
throw new Error('未能读取 @heybox/hb-sdk 当前版本号');
|
|
5091
5092
|
}
|
|
5092
5093
|
return packageJson.version;
|
|
5093
5094
|
}
|
|
5094
|
-
async function resolvePackageJsonPath() {
|
|
5095
|
-
for (const candidate of
|
|
5096
|
-
if (await pathExists(candidate)) {
|
|
5095
|
+
async function resolvePackageJsonPath(packageJsonCandidates = PACKAGE_JSON_CANDIDATES$3) {
|
|
5096
|
+
for (const candidate of packageJsonCandidates) {
|
|
5097
|
+
if (await pathExists$3(candidate)) {
|
|
5097
5098
|
return candidate;
|
|
5098
5099
|
}
|
|
5099
5100
|
}
|
|
@@ -5124,7 +5125,7 @@ async function renderTemplateDirectory(sourceDir, targetDir, data) {
|
|
|
5124
5125
|
function toOutputFileName(fileName) {
|
|
5125
5126
|
return fileName.endsWith('.ejs') ? fileName.slice(0, -'.ejs'.length) : fileName;
|
|
5126
5127
|
}
|
|
5127
|
-
async function pathExists(filePath) {
|
|
5128
|
+
async function pathExists$3(filePath) {
|
|
5128
5129
|
try {
|
|
5129
5130
|
await fs$2.access(filePath, fs$3.constants.F_OK);
|
|
5130
5131
|
return true;
|
|
@@ -5133,16 +5134,16 @@ async function pathExists(filePath) {
|
|
|
5133
5134
|
return false;
|
|
5134
5135
|
}
|
|
5135
5136
|
}
|
|
5136
|
-
function printCreateResult(inputPath, targetDir) {
|
|
5137
|
-
const
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5137
|
+
function printCreateResult(inputPath, targetDir, options) {
|
|
5138
|
+
const output = options.console ?? console;
|
|
5139
|
+
const cwd = options.cwd;
|
|
5140
|
+
const displayPath = path.isAbsolute(inputPath) ? targetDir : path.relative(cwd, targetDir) || '.';
|
|
5141
|
+
output.log(`[hb-sdk] Created mini program template at ${targetDir}`);
|
|
5142
|
+
output.log('');
|
|
5143
|
+
output.log('Next steps:');
|
|
5144
|
+
output.log(` cd ${quoteShellPath(displayPath)}`);
|
|
5145
|
+
output.log(' npm install');
|
|
5146
|
+
output.log(' npm run dev');
|
|
5146
5147
|
}
|
|
5147
5148
|
function quoteShellPath(value) {
|
|
5148
5149
|
if (!/[\s'"`$\\]/.test(value)) {
|
|
@@ -5946,45 +5947,44 @@ function readErrorMessage(error) {
|
|
|
5946
5947
|
|
|
5947
5948
|
const DEFAULT_APP_PORT = 5173;
|
|
5948
5949
|
const DEFAULT_MOCK_PORT = 5174;
|
|
5949
|
-
const
|
|
5950
|
+
const MINI_PROGRAM_URL_QUERY_PARAM = 'mini_url';
|
|
5950
5951
|
const MOCK_NETWORK_PROXY_PATH = '/__hb_sdk_mock_network__';
|
|
5951
5952
|
const MOCK_NETWORK_PROXY_BODY_LIMIT = 1024 * 1024;
|
|
5952
|
-
|
|
5953
|
-
|
|
5953
|
+
// Shared with Heybox H5 Vite plugins so hb-sdk can own the launch output.
|
|
5954
|
+
const MANAGED_DEV_OUTPUT_ENV = 'HEYBOX_DEV_SERVER_MANAGED_OUTPUT';
|
|
5955
|
+
const VITE_LOG_LEVEL = 'warn';
|
|
5956
|
+
async function runDevCommand(options, runtime = {}) {
|
|
5957
|
+
const output = runtime.console ?? console;
|
|
5958
|
+
const fetchImpl = runtime.fetchImpl ?? fetch;
|
|
5959
|
+
const openUrl = runtime.openExternalUrl ?? openExternalUrl;
|
|
5960
|
+
const projectRoot = findProjectRoot(runtime.cwd ?? process.cwd());
|
|
5954
5961
|
const vite = await loadProjectVite(projectRoot);
|
|
5955
|
-
const appServer = await vite.createServer(createViteServerOptions(projectRoot, options));
|
|
5962
|
+
const appServer = await withManagedDevOutputEnv(() => vite.createServer(createViteServerOptions(projectRoot, options)), runtime.env);
|
|
5956
5963
|
await appServer.listen(options.port ?? DEFAULT_APP_PORT);
|
|
5957
|
-
appServer
|
|
5958
|
-
const appUrl = await resolveViteAppUrl(appServer, options);
|
|
5964
|
+
const appUrl = await resolveViteAppUrl(appServer, options, fetchImpl);
|
|
5959
5965
|
const closers = [() => appServer.close()];
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
if (options.open) {
|
|
5963
|
-
void openExternalUrl(appUrl);
|
|
5964
|
-
}
|
|
5965
|
-
installShutdownHandlers(closers);
|
|
5966
|
-
return;
|
|
5967
|
-
}
|
|
5968
|
-
const mockHostRoot = resolveMockHostRoot();
|
|
5969
|
-
const mockServer = createMockHostServer(mockHostRoot);
|
|
5966
|
+
const mockHostRoot = runtime.mockHostRoot ?? resolveMockHostRoot(runtime.mockHostRootCandidates);
|
|
5967
|
+
const mockServer = createMockHostServer(mockHostRoot, { fetchImpl });
|
|
5970
5968
|
const mockPort = await listenHttpServer(mockServer, {
|
|
5971
5969
|
host: options.host,
|
|
5972
5970
|
port: options.mockPort ?? DEFAULT_MOCK_PORT,
|
|
5973
|
-
});
|
|
5971
|
+
}, runtime.getPort ?? getPorts);
|
|
5974
5972
|
const mockUrl = createMockHostUrl({
|
|
5975
5973
|
appUrl,
|
|
5976
5974
|
host: options.host,
|
|
5977
5975
|
port: mockPort,
|
|
5978
5976
|
});
|
|
5979
|
-
closers.push(() => new Promise((resolve
|
|
5980
|
-
mockServer.close(
|
|
5977
|
+
closers.push(() => new Promise((resolve) => {
|
|
5978
|
+
mockServer.close(() => resolve());
|
|
5981
5979
|
}));
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5980
|
+
output.log(`\n[hb-sdk] Mock runtime host is ready`);
|
|
5981
|
+
output.log(`[hb-sdk] Mock runtime host: ${mockUrl}`);
|
|
5982
|
+
output.log(`[hb-sdk] Mini program URL: ${appUrl}`);
|
|
5983
|
+
output.log(`[hb-sdk] Mac APP: use the button in Mock runtime host`);
|
|
5984
|
+
if (options.open !== false) {
|
|
5985
|
+
void openUrl(mockUrl);
|
|
5986
5986
|
}
|
|
5987
|
-
installShutdownHandlers(closers);
|
|
5987
|
+
installShutdownHandlers(closers, runtime.process ?? process);
|
|
5988
5988
|
}
|
|
5989
5989
|
function findProjectRoot(startDir) {
|
|
5990
5990
|
let current = path.resolve(startDir);
|
|
@@ -6019,22 +6019,24 @@ function createViteServerOptions(projectRoot, options) {
|
|
|
6019
6019
|
if (configFile) {
|
|
6020
6020
|
return {
|
|
6021
6021
|
configFile,
|
|
6022
|
+
logLevel: VITE_LOG_LEVEL,
|
|
6022
6023
|
server,
|
|
6023
6024
|
};
|
|
6024
6025
|
}
|
|
6025
6026
|
return {
|
|
6027
|
+
logLevel: VITE_LOG_LEVEL,
|
|
6026
6028
|
root: projectRoot,
|
|
6027
6029
|
server,
|
|
6028
6030
|
};
|
|
6029
6031
|
}
|
|
6030
6032
|
function resolveProjectViteConfig(projectRoot) {
|
|
6031
6033
|
const candidates = ['vite.config.ts', 'vite.config.mts', 'vite.config.js', 'vite.config.mjs'];
|
|
6032
|
-
return candidates.map(file => path.join(projectRoot, file)).find(file => fs$3.existsSync(file));
|
|
6034
|
+
return candidates.map((file) => path.join(projectRoot, file)).find((file) => fs$3.existsSync(file));
|
|
6033
6035
|
}
|
|
6034
|
-
async function resolveViteAppUrl(server, options) {
|
|
6036
|
+
async function resolveViteAppUrl(server, options, fetchImpl) {
|
|
6035
6037
|
const candidates = createViteAppUrlCandidates(server, options);
|
|
6036
6038
|
for (const candidate of candidates) {
|
|
6037
|
-
if (await canReachDocumentUrl(candidate)) {
|
|
6039
|
+
if (await canReachDocumentUrl(candidate, fetchImpl)) {
|
|
6038
6040
|
return candidate;
|
|
6039
6041
|
}
|
|
6040
6042
|
}
|
|
@@ -6043,10 +6045,7 @@ async function resolveViteAppUrl(server, options) {
|
|
|
6043
6045
|
function createViteAppUrlCandidates(server, options) {
|
|
6044
6046
|
const localUrl = server.resolvedUrls?.local[0];
|
|
6045
6047
|
const origin = readViteOrigin(localUrl, options);
|
|
6046
|
-
const candidates = [
|
|
6047
|
-
localUrl,
|
|
6048
|
-
createH5EntryUrl(origin, readViteBase(server, localUrl)),
|
|
6049
|
-
].filter((url) => Boolean(url));
|
|
6048
|
+
const candidates = [localUrl, createH5EntryUrl(origin, readViteBase(server, localUrl))].filter((url) => Boolean(url));
|
|
6050
6049
|
return Array.from(new Set(candidates));
|
|
6051
6050
|
}
|
|
6052
6051
|
function readViteOrigin(localUrl, options) {
|
|
@@ -6081,9 +6080,9 @@ function createH5EntryUrl(origin, base) {
|
|
|
6081
6080
|
const pathname = `${ensureTrailingSlash(base)}src/index.html`;
|
|
6082
6081
|
return new URL(pathname, `${origin}/`).toString();
|
|
6083
6082
|
}
|
|
6084
|
-
async function canReachDocumentUrl(url) {
|
|
6083
|
+
async function canReachDocumentUrl(url, fetchImpl) {
|
|
6085
6084
|
try {
|
|
6086
|
-
const headResponse = await
|
|
6085
|
+
const headResponse = await fetchImpl(url, {
|
|
6087
6086
|
method: 'HEAD',
|
|
6088
6087
|
redirect: 'follow',
|
|
6089
6088
|
});
|
|
@@ -6093,7 +6092,7 @@ async function canReachDocumentUrl(url) {
|
|
|
6093
6092
|
if (headResponse.status !== 404 && headResponse.status !== 405) {
|
|
6094
6093
|
return false;
|
|
6095
6094
|
}
|
|
6096
|
-
const getResponse = await
|
|
6095
|
+
const getResponse = await fetchImpl(url, {
|
|
6097
6096
|
method: 'GET',
|
|
6098
6097
|
redirect: 'follow',
|
|
6099
6098
|
});
|
|
@@ -6106,24 +6105,25 @@ async function canReachDocumentUrl(url) {
|
|
|
6106
6105
|
function ensureTrailingSlash(value) {
|
|
6107
6106
|
return value.endsWith('/') ? value : `${value}/`;
|
|
6108
6107
|
}
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6108
|
+
const MOCK_HOST_ROOT_CANDIDATES = [
|
|
6109
|
+
path.resolve(__dirname, 'devtools/mock-host'),
|
|
6110
|
+
path.resolve(__dirname, '../devtools/mock-host'),
|
|
6111
|
+
path.resolve(__dirname, '../../devtools/mock-host'),
|
|
6112
|
+
path.resolve(__dirname, '../../../devtools/mock-host'),
|
|
6113
|
+
];
|
|
6114
|
+
function resolveMockHostRoot(candidates = MOCK_HOST_ROOT_CANDIDATES) {
|
|
6115
|
+
const found = candidates.find((candidate) => fs$3.existsSync(path.join(candidate, 'index.html')));
|
|
6116
6116
|
if (!found) {
|
|
6117
6117
|
throw new Error(`未找到 hb-sdk mock host 静态产物。请先执行 @heybox/hb-sdk 的 build:mock-host。`);
|
|
6118
6118
|
}
|
|
6119
6119
|
return found;
|
|
6120
6120
|
}
|
|
6121
|
-
function createMockHostServer(root) {
|
|
6121
|
+
function createMockHostServer(root, runtime) {
|
|
6122
6122
|
return node_http.createServer(async (request, response) => {
|
|
6123
|
-
const requestUrl = new URL(request.url
|
|
6123
|
+
const requestUrl = new URL(request.url, 'http://localhost');
|
|
6124
6124
|
const pathname = decodeURIComponent(requestUrl.pathname);
|
|
6125
6125
|
if (pathname === MOCK_NETWORK_PROXY_PATH) {
|
|
6126
|
-
await handleMockNetworkProxy(request, response);
|
|
6126
|
+
await handleMockNetworkProxy(request, response, runtime.fetchImpl);
|
|
6127
6127
|
return;
|
|
6128
6128
|
}
|
|
6129
6129
|
const targetPath = resolveStaticPath(root, pathname);
|
|
@@ -6151,7 +6151,7 @@ function createMockHostServer(root) {
|
|
|
6151
6151
|
}
|
|
6152
6152
|
});
|
|
6153
6153
|
}
|
|
6154
|
-
async function handleMockNetworkProxy(request, response) {
|
|
6154
|
+
async function handleMockNetworkProxy(request, response, fetchImpl) {
|
|
6155
6155
|
if (request.method === 'OPTIONS') {
|
|
6156
6156
|
writeJsonResponse(response, 204, undefined);
|
|
6157
6157
|
return;
|
|
@@ -6165,27 +6165,25 @@ async function handleMockNetworkProxy(request, response) {
|
|
|
6165
6165
|
}
|
|
6166
6166
|
try {
|
|
6167
6167
|
const payload = await readJsonRequestBody(request);
|
|
6168
|
-
const result = await requestMockNetwork(payload);
|
|
6168
|
+
const result = await requestMockNetwork(payload, fetchImpl);
|
|
6169
6169
|
writeJsonResponse(response, 200, result);
|
|
6170
6170
|
}
|
|
6171
6171
|
catch (error) {
|
|
6172
6172
|
writeJsonResponse(response, readMockNetworkErrorStatus(error), toMockNetworkErrorPayload(error));
|
|
6173
6173
|
}
|
|
6174
6174
|
}
|
|
6175
|
-
async function requestMockNetwork(payload) {
|
|
6175
|
+
async function requestMockNetwork(payload, fetchImpl) {
|
|
6176
6176
|
if (!isRecord$1(payload) || typeof payload.url !== 'string' || !payload.url.trim()) {
|
|
6177
6177
|
throw createMockNetworkError(400, 'INVALID_NETWORK_REQUEST', 'network.request url 必须是非空字符串');
|
|
6178
6178
|
}
|
|
6179
6179
|
const url = createMockNetworkUrl(payload.url, payload.params);
|
|
6180
|
-
const method = typeof payload.method === 'string' && payload.method.trim()
|
|
6181
|
-
? payload.method.trim().toUpperCase()
|
|
6182
|
-
: 'GET';
|
|
6180
|
+
const method = typeof payload.method === 'string' && payload.method.trim() ? payload.method.trim().toUpperCase() : 'GET';
|
|
6183
6181
|
const headers = normalizeMockNetworkHeaders(payload.headers);
|
|
6184
6182
|
const controller = new AbortController();
|
|
6185
6183
|
const timeout = Number(payload.timeout) > 0 ? Number(payload.timeout) : 10000;
|
|
6186
6184
|
const timer = setTimeout(() => controller.abort(), timeout);
|
|
6187
6185
|
try {
|
|
6188
|
-
const response = await
|
|
6186
|
+
const response = await fetchImpl(url.toString(), {
|
|
6189
6187
|
method,
|
|
6190
6188
|
headers,
|
|
6191
6189
|
body: createMockNetworkBody(method, payload.data, headers),
|
|
@@ -6194,6 +6192,7 @@ async function requestMockNetwork(payload) {
|
|
|
6194
6192
|
});
|
|
6195
6193
|
const contentType = response.headers.get('content-type') || '';
|
|
6196
6194
|
const text = await response.text();
|
|
6195
|
+
clearTimeout(timer);
|
|
6197
6196
|
return {
|
|
6198
6197
|
data: contentType.includes('application/json') ? safeJsonParse(text) : text,
|
|
6199
6198
|
status: response.status,
|
|
@@ -6202,12 +6201,8 @@ async function requestMockNetwork(payload) {
|
|
|
6202
6201
|
};
|
|
6203
6202
|
}
|
|
6204
6203
|
catch (error) {
|
|
6205
|
-
throw createMockNetworkError(502, 'MOCK_NETWORK_REQUEST_FAILED', error instanceof Error && error.name === 'AbortError'
|
|
6206
|
-
? `network.request timeout after ${timeout}ms`
|
|
6207
|
-
: readErrorMessage(error));
|
|
6208
|
-
}
|
|
6209
|
-
finally {
|
|
6210
6204
|
clearTimeout(timer);
|
|
6205
|
+
throw createMockNetworkError(502, 'MOCK_NETWORK_REQUEST_FAILED', error instanceof Error && error.name === 'AbortError' ? `network.request timeout after ${timeout}ms` : readErrorMessage(error));
|
|
6211
6206
|
}
|
|
6212
6207
|
}
|
|
6213
6208
|
function createMockNetworkUrl(input, params) {
|
|
@@ -6272,8 +6267,8 @@ function readJsonRequestBody(request) {
|
|
|
6272
6267
|
return new Promise((resolve, reject) => {
|
|
6273
6268
|
const chunks = [];
|
|
6274
6269
|
let size = 0;
|
|
6275
|
-
request.on('data', chunk => {
|
|
6276
|
-
const buffer = Buffer.
|
|
6270
|
+
request.on('data', (chunk) => {
|
|
6271
|
+
const buffer = Buffer.from(chunk);
|
|
6277
6272
|
size += buffer.byteLength;
|
|
6278
6273
|
if (size > MOCK_NETWORK_PROXY_BODY_LIMIT) {
|
|
6279
6274
|
reject(createMockNetworkError(413, 'REQUEST_ENTITY_TOO_LARGE', 'mock network proxy request body too large'));
|
|
@@ -6283,6 +6278,9 @@ function readJsonRequestBody(request) {
|
|
|
6283
6278
|
chunks.push(buffer);
|
|
6284
6279
|
});
|
|
6285
6280
|
request.on('error', reject);
|
|
6281
|
+
request.on('aborted', () => {
|
|
6282
|
+
reject('mock network proxy request aborted');
|
|
6283
|
+
});
|
|
6286
6284
|
request.on('end', () => {
|
|
6287
6285
|
const rawBody = Buffer.concat(chunks).toString('utf8');
|
|
6288
6286
|
if (!rawBody.trim()) {
|
|
@@ -6323,10 +6321,10 @@ function createMockNetworkError(status, code, message) {
|
|
|
6323
6321
|
return error;
|
|
6324
6322
|
}
|
|
6325
6323
|
function readMockNetworkErrorStatus(error) {
|
|
6326
|
-
return
|
|
6324
|
+
return isObjectLike(error) && typeof error.status === 'number' ? error.status : 500;
|
|
6327
6325
|
}
|
|
6328
6326
|
function toMockNetworkErrorPayload(error) {
|
|
6329
|
-
if (
|
|
6327
|
+
if (isObjectLike(error) && typeof error.code === 'string' && typeof error.message === 'string') {
|
|
6330
6328
|
return {
|
|
6331
6329
|
code: error.code,
|
|
6332
6330
|
message: error.message,
|
|
@@ -6337,6 +6335,9 @@ function toMockNetworkErrorPayload(error) {
|
|
|
6337
6335
|
message: readErrorMessage(error),
|
|
6338
6336
|
};
|
|
6339
6337
|
}
|
|
6338
|
+
function isObjectLike(value) {
|
|
6339
|
+
return (typeof value === 'object' || typeof value === 'function') && value !== null;
|
|
6340
|
+
}
|
|
6340
6341
|
function resolveStaticPath(root, pathname) {
|
|
6341
6342
|
const safePathname = pathname === '/' ? '/index.html' : pathname;
|
|
6342
6343
|
const normalizedRoot = path.normalize(root);
|
|
@@ -6364,9 +6365,9 @@ function readContentType(filePath) {
|
|
|
6364
6365
|
}
|
|
6365
6366
|
return 'application/octet-stream';
|
|
6366
6367
|
}
|
|
6367
|
-
async function listenHttpServer(server, options) {
|
|
6368
|
+
async function listenHttpServer(server, options, getPortImpl) {
|
|
6368
6369
|
const maxAttempts = 20;
|
|
6369
|
-
const port = await
|
|
6370
|
+
const port = await getPortImpl({
|
|
6370
6371
|
host: options.host,
|
|
6371
6372
|
port: createPortCandidates(options.port, maxAttempts),
|
|
6372
6373
|
});
|
|
@@ -6387,35 +6388,218 @@ async function listenHttpServer(server, options) {
|
|
|
6387
6388
|
server.listen(port, options.host);
|
|
6388
6389
|
});
|
|
6389
6390
|
const address = server.address();
|
|
6390
|
-
return
|
|
6391
|
+
return address.port;
|
|
6391
6392
|
}
|
|
6392
6393
|
function createPortCandidates(startPort, count) {
|
|
6393
6394
|
return Array.from({ length: count }, (_, index) => startPort + index);
|
|
6394
6395
|
}
|
|
6395
6396
|
function createMockHostUrl(options) {
|
|
6396
6397
|
const url = new URL(`http://${toDisplayHost(options.host)}:${options.port}/`);
|
|
6397
|
-
url.searchParams.set(
|
|
6398
|
+
url.searchParams.set(MINI_PROGRAM_URL_QUERY_PARAM, options.appUrl);
|
|
6398
6399
|
return url.toString();
|
|
6399
6400
|
}
|
|
6401
|
+
async function withManagedDevOutputEnv(action, env = process.env) {
|
|
6402
|
+
const previous = env[MANAGED_DEV_OUTPUT_ENV];
|
|
6403
|
+
env[MANAGED_DEV_OUTPUT_ENV] = '1';
|
|
6404
|
+
try {
|
|
6405
|
+
return await action();
|
|
6406
|
+
}
|
|
6407
|
+
finally {
|
|
6408
|
+
if (previous === undefined) {
|
|
6409
|
+
delete env[MANAGED_DEV_OUTPUT_ENV];
|
|
6410
|
+
}
|
|
6411
|
+
else {
|
|
6412
|
+
env[MANAGED_DEV_OUTPUT_ENV] = previous;
|
|
6413
|
+
}
|
|
6414
|
+
}
|
|
6415
|
+
}
|
|
6400
6416
|
function toDisplayHost(host) {
|
|
6401
6417
|
if (!host || host === '0.0.0.0' || host === '::') {
|
|
6402
6418
|
return 'localhost';
|
|
6403
6419
|
}
|
|
6404
6420
|
return host;
|
|
6405
6421
|
}
|
|
6406
|
-
function installShutdownHandlers(closers) {
|
|
6422
|
+
function installShutdownHandlers(closers, processLike) {
|
|
6407
6423
|
const shutdown = async () => {
|
|
6408
|
-
await Promise.allSettled(closers.map(close => close()));
|
|
6409
|
-
|
|
6424
|
+
await Promise.allSettled(closers.map((close) => close()));
|
|
6425
|
+
processLike.exit(0);
|
|
6410
6426
|
};
|
|
6411
|
-
|
|
6427
|
+
processLike.once('SIGINT', () => {
|
|
6412
6428
|
void shutdown();
|
|
6413
6429
|
});
|
|
6414
|
-
|
|
6430
|
+
processLike.once('SIGTERM', () => {
|
|
6415
6431
|
void shutdown();
|
|
6416
6432
|
});
|
|
6417
6433
|
}
|
|
6418
6434
|
|
|
6435
|
+
const PACKAGE_NAME$1 = '@heybox/hb-sdk';
|
|
6436
|
+
const SKILL_NAME = 'hb-sdk';
|
|
6437
|
+
const DEFAULT_SKILL_SOURCE = 'https://open.xiaoheihe.cn/agent-skills/hb-sdk';
|
|
6438
|
+
const DEFAULT_REMOTE_INDEX_URL = 'https://open.xiaoheihe.cn/agent-skills/.well-known/agent-skills/index.json';
|
|
6439
|
+
const DEFAULT_TIMEOUT_MS$1 = 3000;
|
|
6440
|
+
const SKILL_INSTALL_COMMAND = `npx skills add ${DEFAULT_SKILL_SOURCE}`;
|
|
6441
|
+
const PACKAGE_JSON_CANDIDATES$2 = [
|
|
6442
|
+
path.resolve(__dirname, '..', 'package.json'),
|
|
6443
|
+
path.resolve(__dirname, '..', '..', 'package.json'),
|
|
6444
|
+
path.resolve(__dirname, '..', '..', '..', 'package.json'),
|
|
6445
|
+
];
|
|
6446
|
+
async function runDoctorCommand(runtime = {}) {
|
|
6447
|
+
const output = runtime.console ?? console;
|
|
6448
|
+
const result = await getDoctorResult(runtime);
|
|
6449
|
+
printDoctorResult(result, output);
|
|
6450
|
+
printDoctorNextStep(result, output);
|
|
6451
|
+
return result;
|
|
6452
|
+
}
|
|
6453
|
+
async function getDoctorResult(runtime = {}) {
|
|
6454
|
+
const currentSdkVersion = await readCurrentSdkVersion$2(runtime.packageJsonFiles);
|
|
6455
|
+
const localSkillJsonPath = resolveLocalSkillJsonPath(runtime);
|
|
6456
|
+
let remoteSkill;
|
|
6457
|
+
try {
|
|
6458
|
+
remoteSkill = await fetchRemoteSkill(runtime);
|
|
6459
|
+
}
|
|
6460
|
+
catch {
|
|
6461
|
+
return {
|
|
6462
|
+
currentSdkVersion,
|
|
6463
|
+
localSkillJsonPath,
|
|
6464
|
+
status: 'REMOTE_UNAVAILABLE',
|
|
6465
|
+
};
|
|
6466
|
+
}
|
|
6467
|
+
if (remoteSkill?.sdk?.version !== currentSdkVersion) {
|
|
6468
|
+
return {
|
|
6469
|
+
currentSdkVersion,
|
|
6470
|
+
localSkillJsonPath,
|
|
6471
|
+
remoteSkill,
|
|
6472
|
+
status: 'SDK_MISMATCH',
|
|
6473
|
+
};
|
|
6474
|
+
}
|
|
6475
|
+
const localSkill = await readLocalSkillManifest(localSkillJsonPath);
|
|
6476
|
+
if (!localSkill.exists) {
|
|
6477
|
+
return {
|
|
6478
|
+
currentSdkVersion,
|
|
6479
|
+
localSkillJsonPath,
|
|
6480
|
+
remoteSkill,
|
|
6481
|
+
status: 'SKILL_MISSING',
|
|
6482
|
+
};
|
|
6483
|
+
}
|
|
6484
|
+
if (!localSkill.manifest ||
|
|
6485
|
+
localSkill.manifest.name !== SKILL_NAME ||
|
|
6486
|
+
localSkill.manifest.skillVersion !== remoteSkill.version ||
|
|
6487
|
+
localSkill.manifest.sdk?.version !== remoteSkill.sdk?.version) {
|
|
6488
|
+
return {
|
|
6489
|
+
currentSdkVersion,
|
|
6490
|
+
localSkillJsonPath,
|
|
6491
|
+
localSkillVersion: localSkill.manifest?.skillVersion,
|
|
6492
|
+
remoteSkill,
|
|
6493
|
+
status: 'SKILL_OUTDATED',
|
|
6494
|
+
};
|
|
6495
|
+
}
|
|
6496
|
+
return {
|
|
6497
|
+
currentSdkVersion,
|
|
6498
|
+
localSkillJsonPath,
|
|
6499
|
+
localSkillVersion: localSkill.manifest.skillVersion,
|
|
6500
|
+
remoteSkill,
|
|
6501
|
+
status: 'OK',
|
|
6502
|
+
};
|
|
6503
|
+
}
|
|
6504
|
+
function printDoctorResult(result, output) {
|
|
6505
|
+
output.log('[hb-sdk] Doctor');
|
|
6506
|
+
output.log(`SDK version: ${result.currentSdkVersion}`);
|
|
6507
|
+
output.log(`Remote skill: ${result.remoteSkill?.version ? `${result.remoteSkill.version} (sdk ${result.remoteSkill.sdk?.version ?? 'unknown'})` : 'unavailable'}`);
|
|
6508
|
+
output.log(`Local skill: ${result.localSkillVersion ?? 'missing'} (${result.localSkillJsonPath})`);
|
|
6509
|
+
output.log(`Status: ${result.status}`);
|
|
6510
|
+
}
|
|
6511
|
+
function printDoctorNextStep(result, output) {
|
|
6512
|
+
if (result.status === 'OK') {
|
|
6513
|
+
output.log('[hb-sdk] Skill is up to date.');
|
|
6514
|
+
return;
|
|
6515
|
+
}
|
|
6516
|
+
if (result.status === 'SDK_MISMATCH') {
|
|
6517
|
+
output.log(`[hb-sdk] Current SDK does not match the latest skill metadata. Upgrade with: npm i -D ${PACKAGE_NAME$1}@latest`);
|
|
6518
|
+
output.log(`[hb-sdk] Then install or refresh the skill manually: ${formatSkillInstallCommand(result)}`);
|
|
6519
|
+
return;
|
|
6520
|
+
}
|
|
6521
|
+
if (result.status === 'REMOTE_UNAVAILABLE') {
|
|
6522
|
+
output.log('[hb-sdk] Remote skill metadata is unavailable. Try again later.');
|
|
6523
|
+
output.log(`[hb-sdk] Manual install command: ${SKILL_INSTALL_COMMAND}`);
|
|
6524
|
+
return;
|
|
6525
|
+
}
|
|
6526
|
+
output.log(`[hb-sdk] Install or refresh the skill manually: ${formatSkillInstallCommand(result)}`);
|
|
6527
|
+
}
|
|
6528
|
+
function formatSkillInstallCommand(result) {
|
|
6529
|
+
return `npx skills add ${result.remoteSkill?.source || DEFAULT_SKILL_SOURCE}`;
|
|
6530
|
+
}
|
|
6531
|
+
async function fetchRemoteSkill(runtime) {
|
|
6532
|
+
const fetchImpl = runtime.fetchImpl ?? fetch;
|
|
6533
|
+
const controller = new AbortController();
|
|
6534
|
+
const timeout = setTimeout(() => controller.abort(), runtime.timeoutMs ?? DEFAULT_TIMEOUT_MS$1);
|
|
6535
|
+
try {
|
|
6536
|
+
const response = await fetchImpl(runtime.remoteIndexUrl ?? DEFAULT_REMOTE_INDEX_URL, {
|
|
6537
|
+
headers: {
|
|
6538
|
+
accept: 'application/json',
|
|
6539
|
+
},
|
|
6540
|
+
signal: controller.signal,
|
|
6541
|
+
});
|
|
6542
|
+
if (!response.ok) {
|
|
6543
|
+
throw new Error(`remote skill index returned ${response.status}`);
|
|
6544
|
+
}
|
|
6545
|
+
const index = (await response.json());
|
|
6546
|
+
const skill = index.skills?.find(item => item.name === SKILL_NAME);
|
|
6547
|
+
if (!skill?.version || skill.sdk?.package !== PACKAGE_NAME$1 || !skill.sdk.version) {
|
|
6548
|
+
throw new Error('remote hb-sdk skill metadata is incomplete');
|
|
6549
|
+
}
|
|
6550
|
+
return skill;
|
|
6551
|
+
}
|
|
6552
|
+
finally {
|
|
6553
|
+
clearTimeout(timeout);
|
|
6554
|
+
}
|
|
6555
|
+
}
|
|
6556
|
+
async function readLocalSkillManifest(skillJsonPath) {
|
|
6557
|
+
if (!(await pathExists$2(skillJsonPath))) {
|
|
6558
|
+
return {
|
|
6559
|
+
exists: false,
|
|
6560
|
+
};
|
|
6561
|
+
}
|
|
6562
|
+
try {
|
|
6563
|
+
return {
|
|
6564
|
+
exists: true,
|
|
6565
|
+
manifest: JSON.parse(await fs$2.readFile(skillJsonPath, 'utf8')),
|
|
6566
|
+
};
|
|
6567
|
+
}
|
|
6568
|
+
catch {
|
|
6569
|
+
return {
|
|
6570
|
+
exists: true,
|
|
6571
|
+
};
|
|
6572
|
+
}
|
|
6573
|
+
}
|
|
6574
|
+
async function readCurrentSdkVersion$2(packageJsonCandidates = PACKAGE_JSON_CANDIDATES$2) {
|
|
6575
|
+
for (const candidate of packageJsonCandidates) {
|
|
6576
|
+
if (!(await pathExists$2(candidate))) {
|
|
6577
|
+
continue;
|
|
6578
|
+
}
|
|
6579
|
+
const packageJson = JSON.parse(await fs$2.readFile(candidate, 'utf8'));
|
|
6580
|
+
if (typeof packageJson.version === 'string' && packageJson.version) {
|
|
6581
|
+
return packageJson.version;
|
|
6582
|
+
}
|
|
6583
|
+
}
|
|
6584
|
+
throw new Error('未能读取 @heybox/hb-sdk 当前版本号');
|
|
6585
|
+
}
|
|
6586
|
+
function resolveLocalSkillJsonPath(runtime) {
|
|
6587
|
+
if (runtime.localSkillJsonPath) {
|
|
6588
|
+
return runtime.localSkillJsonPath;
|
|
6589
|
+
}
|
|
6590
|
+
const codexHome = runtime.codexHome ?? runtime.env?.CODEX_HOME ?? process.env.CODEX_HOME ?? path.join(os.homedir(), '.codex');
|
|
6591
|
+
return path.join(codexHome, 'skills', SKILL_NAME, 'skill.json');
|
|
6592
|
+
}
|
|
6593
|
+
async function pathExists$2(filePath) {
|
|
6594
|
+
try {
|
|
6595
|
+
await fs$2.access(filePath, fs$3.constants.F_OK);
|
|
6596
|
+
return true;
|
|
6597
|
+
}
|
|
6598
|
+
catch {
|
|
6599
|
+
return false;
|
|
6600
|
+
}
|
|
6601
|
+
}
|
|
6602
|
+
|
|
6419
6603
|
const HEYBOX_LOGIN_URL = 'https://login.xiaoheihe.cn/';
|
|
6420
6604
|
const HEYBOX_CALLBACK_HOST = '127.0.0.1';
|
|
6421
6605
|
const HEYBOX_CALLBACK_PATH = '/heybox/callback';
|
|
@@ -6446,26 +6630,27 @@ async function waitForHeyboxBrowserCallback(options = {}) {
|
|
|
6446
6630
|
const expectedState = node_crypto.randomBytes(16).toString('hex');
|
|
6447
6631
|
const timeoutMs = options.timeoutMs ?? DEFAULT_HEYBOX_CALLBACK_TIMEOUT_MS;
|
|
6448
6632
|
const openBrowser = options.openBrowser ?? openExternalUrl;
|
|
6449
|
-
let server = null;
|
|
6450
6633
|
let timer = null;
|
|
6634
|
+
const loginCallback = {};
|
|
6635
|
+
const server = node_http.createServer((request, response) => {
|
|
6636
|
+
try {
|
|
6637
|
+
const requestUrl = new URL(request.url, `http://${HEYBOX_CALLBACK_HOST}`);
|
|
6638
|
+
if (requestUrl.pathname === HEYBOX_CALLBACK_DONE_PATH) {
|
|
6639
|
+
sendBrowserResponse(response, 200, 'Heybox 登录成功,可以回到终端继续。');
|
|
6640
|
+
return;
|
|
6641
|
+
}
|
|
6642
|
+
const callbackPayload = parseHeyboxCallbackUrl(request.url, expectedState);
|
|
6643
|
+
redirectToCleanCallbackPage(response, () => loginCallback.resolve(callbackPayload));
|
|
6644
|
+
}
|
|
6645
|
+
catch (error) {
|
|
6646
|
+
sendBrowserResponse(response, 400, `Heybox 登录失败: ${readErrorMessage(error)}`);
|
|
6647
|
+
loginCallback.reject(error);
|
|
6648
|
+
}
|
|
6649
|
+
});
|
|
6451
6650
|
try {
|
|
6452
6651
|
const payload = await new Promise((resolve, reject) => {
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
const requestUrl = new URL(request.url || '/', `http://${HEYBOX_CALLBACK_HOST}`);
|
|
6456
|
-
if (requestUrl.pathname === HEYBOX_CALLBACK_DONE_PATH) {
|
|
6457
|
-
sendBrowserResponse(response, 200, 'Heybox 登录成功,可以回到终端继续。');
|
|
6458
|
-
return;
|
|
6459
|
-
}
|
|
6460
|
-
const callbackPayload = parseHeyboxCallbackUrl(request.url || '', expectedState);
|
|
6461
|
-
redirectToCleanCallbackPage(response, () => resolve(callbackPayload));
|
|
6462
|
-
}
|
|
6463
|
-
catch (error) {
|
|
6464
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
6465
|
-
sendBrowserResponse(response, 400, `Heybox 登录失败: ${message}`);
|
|
6466
|
-
reject(error);
|
|
6467
|
-
}
|
|
6468
|
-
});
|
|
6652
|
+
loginCallback.resolve = resolve;
|
|
6653
|
+
loginCallback.reject = reject;
|
|
6469
6654
|
server.once('error', reject);
|
|
6470
6655
|
server.listen(0, HEYBOX_CALLBACK_HOST, () => {
|
|
6471
6656
|
void handleServerListening(server, expectedState, {
|
|
@@ -6488,10 +6673,7 @@ async function waitForHeyboxBrowserCallback(options = {}) {
|
|
|
6488
6673
|
}
|
|
6489
6674
|
}
|
|
6490
6675
|
async function handleServerListening(server, expectedState, options) {
|
|
6491
|
-
const address = server
|
|
6492
|
-
if (!address || typeof address === 'string') {
|
|
6493
|
-
throw new Error('无法启动 Heybox 登录回调服务');
|
|
6494
|
-
}
|
|
6676
|
+
const address = server.address();
|
|
6495
6677
|
const callbackUrl = `http://${HEYBOX_CALLBACK_HOST}:${address.port}${HEYBOX_CALLBACK_PATH}`;
|
|
6496
6678
|
const loginUrl = createHeyboxLoginUrl(callbackUrl, expectedState);
|
|
6497
6679
|
options.onLoginUrl?.(loginUrl);
|
|
@@ -6519,11 +6701,7 @@ function redirectToCleanCallbackPage(response, onSent) {
|
|
|
6519
6701
|
response.end(onSent);
|
|
6520
6702
|
}
|
|
6521
6703
|
function closeServer(server) {
|
|
6522
|
-
return new Promise(resolve => {
|
|
6523
|
-
if (!server?.listening) {
|
|
6524
|
-
resolve();
|
|
6525
|
-
return;
|
|
6526
|
-
}
|
|
6704
|
+
return new Promise((resolve) => {
|
|
6527
6705
|
server.close(() => resolve());
|
|
6528
6706
|
});
|
|
6529
6707
|
}
|
|
@@ -9436,9 +9614,9 @@ var libExports = /*@__PURE__*/ requireLib();
|
|
|
9436
9614
|
var fs = /*@__PURE__*/getDefaultExportFromCjs(libExports);
|
|
9437
9615
|
|
|
9438
9616
|
const AUTH_CACHE_VERSION = 1;
|
|
9439
|
-
const paths = envPaths('hb-sdk', { suffix: '' });
|
|
9617
|
+
const paths$1 = envPaths('hb-sdk', { suffix: '' });
|
|
9440
9618
|
function getAuthCacheFilePath(options = {}) {
|
|
9441
|
-
return options.cacheFile ?? path.join(paths.cache, 'auth.json');
|
|
9619
|
+
return options.cacheFile ?? path.join(paths$1.cache, 'auth.json');
|
|
9442
9620
|
}
|
|
9443
9621
|
function createHeyboxAuthSession(payload, options = {}) {
|
|
9444
9622
|
return {
|
|
@@ -9531,105 +9709,402 @@ function isRecord(value) {
|
|
|
9531
9709
|
return Object.prototype.toString.call(value) === '[object Object]';
|
|
9532
9710
|
}
|
|
9533
9711
|
|
|
9534
|
-
async function loginToHeybox() {
|
|
9535
|
-
const
|
|
9712
|
+
async function loginToHeybox(options = {}) {
|
|
9713
|
+
const output = options.console ?? console;
|
|
9714
|
+
const waitForBrowserCallback = options.waitForBrowserCallback ?? waitForHeyboxBrowserCallback;
|
|
9715
|
+
const payload = await waitForBrowserCallback({
|
|
9716
|
+
openBrowser: options.openBrowser,
|
|
9536
9717
|
onLoginUrl(loginUrl) {
|
|
9537
|
-
|
|
9538
|
-
|
|
9539
|
-
|
|
9718
|
+
output.log('Heybox 浏览器登录');
|
|
9719
|
+
output.log(`浏览器入口: ${loginUrl}`);
|
|
9720
|
+
output.log('请在打开的页面完成登录,成功后 hb-sdk 会自动接收登录态。');
|
|
9540
9721
|
},
|
|
9541
9722
|
onBrowserOpenResult(opened, loginUrl) {
|
|
9542
9723
|
if (opened) {
|
|
9543
|
-
|
|
9724
|
+
output.log('已打开 Heybox 登录页。');
|
|
9544
9725
|
return;
|
|
9545
9726
|
}
|
|
9546
|
-
|
|
9547
|
-
|
|
9548
|
-
|
|
9727
|
+
output.log('当前环境无法直接打开浏览器。');
|
|
9728
|
+
output.log('请打开这个链接完成 Heybox 登录:');
|
|
9729
|
+
output.log(loginUrl);
|
|
9549
9730
|
},
|
|
9731
|
+
timeoutMs: options.timeoutMs,
|
|
9550
9732
|
});
|
|
9551
|
-
const session = createHeyboxAuthSession(payload);
|
|
9552
|
-
await writeHeyboxAuthSession(session);
|
|
9553
|
-
|
|
9554
|
-
|
|
9555
|
-
|
|
9556
|
-
}
|
|
9557
|
-
async function printLoginStatus() {
|
|
9558
|
-
const
|
|
9733
|
+
const session = createHeyboxAuthSession(payload, options);
|
|
9734
|
+
await writeHeyboxAuthSession(session, options);
|
|
9735
|
+
output.log(`Heybox 登录成功: ${session.heyboxId}`);
|
|
9736
|
+
output.log(`cache: ${getAuthCacheFilePath(options)}`);
|
|
9737
|
+
output.log('验证: hb-sdk login status');
|
|
9738
|
+
}
|
|
9739
|
+
async function printLoginStatus(options = {}) {
|
|
9740
|
+
const output = options.console ?? console;
|
|
9741
|
+
const status = await readRedactedHeyboxAuthStatus(options);
|
|
9559
9742
|
if (!status.loggedIn) {
|
|
9560
|
-
|
|
9561
|
-
|
|
9562
|
-
|
|
9743
|
+
output.log('Heybox 登录态: 未登录');
|
|
9744
|
+
output.log('下一步: hb-sdk login');
|
|
9745
|
+
output.log(`cache: ${status.cacheFile}`);
|
|
9563
9746
|
return;
|
|
9564
9747
|
}
|
|
9565
|
-
|
|
9566
|
-
|
|
9567
|
-
|
|
9568
|
-
|
|
9748
|
+
output.log('Heybox 登录态: 已登录');
|
|
9749
|
+
output.log(`heyboxId: ${status.heyboxId}`);
|
|
9750
|
+
output.log(`loggedInAt: ${status.loggedInAt}`);
|
|
9751
|
+
output.log(`cache: ${status.cacheFile}`);
|
|
9752
|
+
}
|
|
9753
|
+
async function clearLoginStatus(options = {}) {
|
|
9754
|
+
const output = options.console ?? console;
|
|
9755
|
+
await clearHeyboxAuthSession(options);
|
|
9756
|
+
output.log('已清理 Heybox 登录态');
|
|
9757
|
+
output.log(`cache: ${getAuthCacheFilePath(options)}`);
|
|
9758
|
+
}
|
|
9759
|
+
|
|
9760
|
+
const PACKAGE_NAME = '@heybox/hb-sdk';
|
|
9761
|
+
const UPDATE_CHECK_CACHE_VERSION = 1;
|
|
9762
|
+
const UPDATE_CHECK_TTL_MS = 24 * 60 * 60 * 1000;
|
|
9763
|
+
const DEFAULT_TIMEOUT_MS = 1500;
|
|
9764
|
+
const UPDATE_CHECK_CACHE_FILE = 'update-check.json';
|
|
9765
|
+
const NPM_REGISTRY_URL = `https://registry.npmjs.org/${encodeURIComponent(PACKAGE_NAME)}`;
|
|
9766
|
+
const paths = envPaths('hb-sdk', { suffix: '' });
|
|
9767
|
+
const PACKAGE_JSON_CANDIDATES$1 = [
|
|
9768
|
+
path.resolve(__dirname, '..', 'package.json'),
|
|
9769
|
+
path.resolve(__dirname, '..', '..', 'package.json'),
|
|
9770
|
+
path.resolve(__dirname, '..', '..', '..', 'package.json'),
|
|
9771
|
+
];
|
|
9772
|
+
async function printUpdateReminder(options = {}) {
|
|
9773
|
+
try {
|
|
9774
|
+
const reminder = await getUpdateReminder(options);
|
|
9775
|
+
if (!reminder) {
|
|
9776
|
+
return;
|
|
9777
|
+
}
|
|
9778
|
+
const output = options.stderr ?? process.stderr;
|
|
9779
|
+
output.write(`${formatUpdateReminder(reminder)}\n`);
|
|
9780
|
+
}
|
|
9781
|
+
catch {
|
|
9782
|
+
// Version checks must never affect the actual hb-sdk command.
|
|
9783
|
+
}
|
|
9784
|
+
}
|
|
9785
|
+
async function getUpdateReminder(options = {}) {
|
|
9786
|
+
if (isUpdateCheckDisabled(options.env ?? process.env)) {
|
|
9787
|
+
return null;
|
|
9788
|
+
}
|
|
9789
|
+
const now = options.now?.() ?? new Date();
|
|
9790
|
+
const currentVersion = options.currentVersion ?? (await readCurrentSdkVersion$1(options.packageJsonFiles));
|
|
9791
|
+
const cached = await readFreshUpdateCheckCache(getUpdateCheckCacheFilePath(options), now);
|
|
9792
|
+
if (cached) {
|
|
9793
|
+
return createUpdateReminder(currentVersion, cached.latestVersion);
|
|
9794
|
+
}
|
|
9795
|
+
let latestVersion;
|
|
9796
|
+
try {
|
|
9797
|
+
latestVersion = await fetchLatestVersion(options);
|
|
9798
|
+
}
|
|
9799
|
+
catch {
|
|
9800
|
+
await writeUpdateCheckCache({
|
|
9801
|
+
version: UPDATE_CHECK_CACHE_VERSION,
|
|
9802
|
+
checkedAt: now.toISOString(),
|
|
9803
|
+
}, options).catch(() => undefined);
|
|
9804
|
+
return null;
|
|
9805
|
+
}
|
|
9806
|
+
await writeUpdateCheckCache({
|
|
9807
|
+
version: UPDATE_CHECK_CACHE_VERSION,
|
|
9808
|
+
checkedAt: now.toISOString(),
|
|
9809
|
+
latestVersion,
|
|
9810
|
+
}, options).catch(() => undefined);
|
|
9811
|
+
return createUpdateReminder(currentVersion, latestVersion);
|
|
9812
|
+
}
|
|
9813
|
+
function formatUpdateReminder(reminder) {
|
|
9814
|
+
return `[hb-sdk] New version available: ${reminder.currentVersion} -> ${reminder.latestVersion}. Upgrade with: npm i -D ${PACKAGE_NAME}@latest`;
|
|
9815
|
+
}
|
|
9816
|
+
function isVersionGreater(version, baseline) {
|
|
9817
|
+
const compared = compareSemver(version, baseline);
|
|
9818
|
+
return compared !== null && compared > 0;
|
|
9819
|
+
}
|
|
9820
|
+
function createUpdateReminder(currentVersion, latestVersion) {
|
|
9821
|
+
if (!latestVersion || !isVersionGreater(latestVersion, currentVersion)) {
|
|
9822
|
+
return null;
|
|
9823
|
+
}
|
|
9824
|
+
return {
|
|
9825
|
+
currentVersion,
|
|
9826
|
+
latestVersion,
|
|
9827
|
+
};
|
|
9828
|
+
}
|
|
9829
|
+
function getUpdateCheckCacheFilePath(options = {}) {
|
|
9830
|
+
return options.cacheFile ?? path.join(paths.cache, UPDATE_CHECK_CACHE_FILE);
|
|
9569
9831
|
}
|
|
9570
|
-
async function
|
|
9571
|
-
await
|
|
9572
|
-
|
|
9573
|
-
|
|
9832
|
+
async function readFreshUpdateCheckCache(cacheFile, now) {
|
|
9833
|
+
const cache = await readUpdateCheckCache(cacheFile);
|
|
9834
|
+
if (!cache) {
|
|
9835
|
+
return null;
|
|
9836
|
+
}
|
|
9837
|
+
const checkedAt = Date.parse(cache.checkedAt);
|
|
9838
|
+
if (!Number.isFinite(checkedAt) || now.getTime() - checkedAt >= UPDATE_CHECK_TTL_MS) {
|
|
9839
|
+
return null;
|
|
9840
|
+
}
|
|
9841
|
+
return cache;
|
|
9842
|
+
}
|
|
9843
|
+
async function readUpdateCheckCache(cacheFile) {
|
|
9844
|
+
if (!(await pathExists$1(cacheFile))) {
|
|
9845
|
+
return null;
|
|
9846
|
+
}
|
|
9847
|
+
try {
|
|
9848
|
+
const parsed = JSON.parse(await fs$2.readFile(cacheFile, 'utf8'));
|
|
9849
|
+
if (parsed.version !== UPDATE_CHECK_CACHE_VERSION || typeof parsed.checkedAt !== 'string') {
|
|
9850
|
+
return null;
|
|
9851
|
+
}
|
|
9852
|
+
return {
|
|
9853
|
+
version: UPDATE_CHECK_CACHE_VERSION,
|
|
9854
|
+
checkedAt: parsed.checkedAt,
|
|
9855
|
+
...(typeof parsed.latestVersion === 'string' ? { latestVersion: parsed.latestVersion } : {}),
|
|
9856
|
+
};
|
|
9857
|
+
}
|
|
9858
|
+
catch {
|
|
9859
|
+
return null;
|
|
9860
|
+
}
|
|
9861
|
+
}
|
|
9862
|
+
async function writeUpdateCheckCache(cache, options = {}) {
|
|
9863
|
+
const cacheFile = getUpdateCheckCacheFilePath(options);
|
|
9864
|
+
await fs$2.mkdir(path.dirname(cacheFile), { recursive: true });
|
|
9865
|
+
await fs$2.writeFile(cacheFile, JSON.stringify(cache, null, 2), 'utf8');
|
|
9866
|
+
}
|
|
9867
|
+
async function fetchLatestVersion(options) {
|
|
9868
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
9869
|
+
const controller = new AbortController();
|
|
9870
|
+
const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
9871
|
+
try {
|
|
9872
|
+
const response = await fetchImpl(options.registryUrl ?? NPM_REGISTRY_URL, {
|
|
9873
|
+
headers: {
|
|
9874
|
+
accept: 'application/vnd.npm.install-v1+json',
|
|
9875
|
+
},
|
|
9876
|
+
signal: controller.signal,
|
|
9877
|
+
});
|
|
9878
|
+
if (!response.ok) {
|
|
9879
|
+
throw new Error(`npm registry returned ${response.status}`);
|
|
9880
|
+
}
|
|
9881
|
+
const metadata = (await response.json());
|
|
9882
|
+
const latestVersion = metadata['dist-tags']?.latest;
|
|
9883
|
+
if (typeof latestVersion !== 'string' || !latestVersion) {
|
|
9884
|
+
throw new Error('npm registry response missing latest dist-tag');
|
|
9885
|
+
}
|
|
9886
|
+
return latestVersion;
|
|
9887
|
+
}
|
|
9888
|
+
finally {
|
|
9889
|
+
clearTimeout(timeout);
|
|
9890
|
+
}
|
|
9891
|
+
}
|
|
9892
|
+
async function readCurrentSdkVersion$1(packageJsonCandidates = PACKAGE_JSON_CANDIDATES$1) {
|
|
9893
|
+
for (const candidate of packageJsonCandidates) {
|
|
9894
|
+
if (!(await pathExists$1(candidate))) {
|
|
9895
|
+
continue;
|
|
9896
|
+
}
|
|
9897
|
+
const packageJson = JSON.parse(await fs$2.readFile(candidate, 'utf8'));
|
|
9898
|
+
if (typeof packageJson.version === 'string' && packageJson.version) {
|
|
9899
|
+
return packageJson.version;
|
|
9900
|
+
}
|
|
9901
|
+
}
|
|
9902
|
+
throw new Error('未能读取 @heybox/hb-sdk 当前版本号');
|
|
9903
|
+
}
|
|
9904
|
+
function isUpdateCheckDisabled(env) {
|
|
9905
|
+
return env.HB_SDK_NO_UPDATE_CHECK === '1' || env.CI === 'true';
|
|
9906
|
+
}
|
|
9907
|
+
function compareSemver(version, baseline) {
|
|
9908
|
+
const parsedVersion = parseSemver(version);
|
|
9909
|
+
const parsedBaseline = parseSemver(baseline);
|
|
9910
|
+
if (!parsedVersion || !parsedBaseline) {
|
|
9911
|
+
return null;
|
|
9912
|
+
}
|
|
9913
|
+
for (const key of ['major', 'minor', 'patch']) {
|
|
9914
|
+
if (parsedVersion[key] !== parsedBaseline[key]) {
|
|
9915
|
+
return parsedVersion[key] > parsedBaseline[key] ? 1 : -1;
|
|
9916
|
+
}
|
|
9917
|
+
}
|
|
9918
|
+
return comparePrerelease(parsedVersion.prerelease, parsedBaseline.prerelease);
|
|
9919
|
+
}
|
|
9920
|
+
function parseSemver(version) {
|
|
9921
|
+
const matched = version.trim().match(/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-.]+))?(?:\+[0-9A-Za-z-.]+)?$/);
|
|
9922
|
+
if (!matched) {
|
|
9923
|
+
return null;
|
|
9924
|
+
}
|
|
9925
|
+
return {
|
|
9926
|
+
major: Number(matched[1]),
|
|
9927
|
+
minor: Number(matched[2]),
|
|
9928
|
+
patch: Number(matched[3]),
|
|
9929
|
+
prerelease: matched[4]?.split('.') ?? [],
|
|
9930
|
+
};
|
|
9931
|
+
}
|
|
9932
|
+
function comparePrerelease(versionPrerelease, baselinePrerelease) {
|
|
9933
|
+
if (versionPrerelease.length === 0 && baselinePrerelease.length === 0) {
|
|
9934
|
+
return 0;
|
|
9935
|
+
}
|
|
9936
|
+
if (versionPrerelease.length === 0) {
|
|
9937
|
+
return 1;
|
|
9938
|
+
}
|
|
9939
|
+
if (baselinePrerelease.length === 0) {
|
|
9940
|
+
return -1;
|
|
9941
|
+
}
|
|
9942
|
+
const length = Math.max(versionPrerelease.length, baselinePrerelease.length);
|
|
9943
|
+
for (let index = 0; index < length; index += 1) {
|
|
9944
|
+
const left = versionPrerelease[index];
|
|
9945
|
+
const right = baselinePrerelease[index];
|
|
9946
|
+
if (left === undefined) {
|
|
9947
|
+
return -1;
|
|
9948
|
+
}
|
|
9949
|
+
if (right === undefined) {
|
|
9950
|
+
return 1;
|
|
9951
|
+
}
|
|
9952
|
+
const compared = comparePrereleaseIdentifier(left, right);
|
|
9953
|
+
if (compared !== 0) {
|
|
9954
|
+
return compared;
|
|
9955
|
+
}
|
|
9956
|
+
}
|
|
9957
|
+
return 0;
|
|
9958
|
+
}
|
|
9959
|
+
function comparePrereleaseIdentifier(left, right) {
|
|
9960
|
+
const leftNumeric = isNumericPrereleaseIdentifier(left);
|
|
9961
|
+
const rightNumeric = isNumericPrereleaseIdentifier(right);
|
|
9962
|
+
if (leftNumeric && rightNumeric) {
|
|
9963
|
+
const compared = Number(left) - Number(right);
|
|
9964
|
+
return compared === 0 ? 0 : compared > 0 ? 1 : -1;
|
|
9965
|
+
}
|
|
9966
|
+
if (leftNumeric) {
|
|
9967
|
+
return -1;
|
|
9968
|
+
}
|
|
9969
|
+
if (rightNumeric) {
|
|
9970
|
+
return 1;
|
|
9971
|
+
}
|
|
9972
|
+
if (left === right) {
|
|
9973
|
+
return 0;
|
|
9974
|
+
}
|
|
9975
|
+
return left > right ? 1 : -1;
|
|
9976
|
+
}
|
|
9977
|
+
function isNumericPrereleaseIdentifier(value) {
|
|
9978
|
+
return /^\d+$/.test(value);
|
|
9979
|
+
}
|
|
9980
|
+
async function pathExists$1(filePath) {
|
|
9981
|
+
try {
|
|
9982
|
+
await fs$2.access(filePath, fs$3.constants.F_OK);
|
|
9983
|
+
return true;
|
|
9984
|
+
}
|
|
9985
|
+
catch {
|
|
9986
|
+
return false;
|
|
9987
|
+
}
|
|
9988
|
+
}
|
|
9989
|
+
|
|
9990
|
+
const CLI_VERSION_PLACEHOLDER = ['__HB', 'SDK', 'CLI', 'VERSION__'].join('_');
|
|
9991
|
+
const BUILT_CLI_VERSION = '0.2.0-alpha.1';
|
|
9992
|
+
const PACKAGE_JSON_CANDIDATES = [
|
|
9993
|
+
path.resolve(__dirname, '..', '..', 'package.json'),
|
|
9994
|
+
path.resolve(__dirname, '..', 'package.json'),
|
|
9995
|
+
path.resolve(__dirname, '..', '..', '..', 'package.json'),
|
|
9996
|
+
];
|
|
9997
|
+
function getCliVersion(packageJsonCandidates = PACKAGE_JSON_CANDIDATES) {
|
|
9998
|
+
if (BUILT_CLI_VERSION !== CLI_VERSION_PLACEHOLDER) {
|
|
9999
|
+
return BUILT_CLI_VERSION;
|
|
10000
|
+
}
|
|
10001
|
+
return readCurrentSdkVersion(packageJsonCandidates);
|
|
10002
|
+
}
|
|
10003
|
+
function readCurrentSdkVersion(packageJsonCandidates) {
|
|
10004
|
+
for (const candidate of packageJsonCandidates) {
|
|
10005
|
+
if (!pathExists(candidate)) {
|
|
10006
|
+
continue;
|
|
10007
|
+
}
|
|
10008
|
+
const packageJson = JSON.parse(fs$3.readFileSync(candidate, 'utf8'));
|
|
10009
|
+
if (typeof packageJson.version === 'string' && packageJson.version) {
|
|
10010
|
+
return packageJson.version;
|
|
10011
|
+
}
|
|
10012
|
+
}
|
|
10013
|
+
throw new Error('未能读取 @heybox/hb-sdk 当前版本号');
|
|
10014
|
+
}
|
|
10015
|
+
function pathExists(filePath) {
|
|
10016
|
+
try {
|
|
10017
|
+
fs$3.accessSync(filePath, fs$3.constants.F_OK);
|
|
10018
|
+
return true;
|
|
10019
|
+
}
|
|
10020
|
+
catch {
|
|
10021
|
+
return false;
|
|
10022
|
+
}
|
|
9574
10023
|
}
|
|
9575
10024
|
|
|
9576
|
-
|
|
9577
|
-
|
|
9578
|
-
|
|
10025
|
+
async function runCli(options = {}) {
|
|
10026
|
+
const processLike = options.process ?? process;
|
|
10027
|
+
try {
|
|
10028
|
+
await createCliProgram(options).parseAsync(options.argv ?? process.argv);
|
|
9579
10029
|
}
|
|
9580
|
-
|
|
9581
|
-
|
|
10030
|
+
catch (error) {
|
|
10031
|
+
if (error instanceof CommanderError && error.exitCode === 0) {
|
|
10032
|
+
processLike.exit(0);
|
|
10033
|
+
return;
|
|
10034
|
+
}
|
|
10035
|
+
if (!(error instanceof CommanderError)) {
|
|
10036
|
+
(options.printError ?? printError)(error);
|
|
10037
|
+
}
|
|
10038
|
+
processLike.exit(error instanceof CommanderError ? error.exitCode : 1);
|
|
9582
10039
|
}
|
|
9583
|
-
process.exit(error instanceof CommanderError ? error.exitCode : 1);
|
|
9584
|
-
});
|
|
9585
|
-
async function main() {
|
|
9586
|
-
await createCliProgram().parseAsync(process.argv);
|
|
9587
10040
|
}
|
|
9588
|
-
function createCliProgram() {
|
|
10041
|
+
function createCliProgram(overrides = {}) {
|
|
10042
|
+
const handlers = {
|
|
10043
|
+
clearLoginStatus: clearLoginStatus,
|
|
10044
|
+
loginToHeybox: loginToHeybox,
|
|
10045
|
+
printLoginStatus: printLoginStatus,
|
|
10046
|
+
printUpdateReminder: printUpdateReminder,
|
|
10047
|
+
runCreateCommand: runCreateCommand,
|
|
10048
|
+
runDevCommand: runDevCommand,
|
|
10049
|
+
runDoctorCommand: runDoctorCommand,
|
|
10050
|
+
...overrides,
|
|
10051
|
+
};
|
|
9589
10052
|
const program = new Command();
|
|
9590
10053
|
program
|
|
9591
10054
|
.name('hb-sdk')
|
|
9592
10055
|
.description('hb-sdk developer tools')
|
|
10056
|
+
.version(getCliVersion())
|
|
9593
10057
|
.showHelpAfterError()
|
|
9594
10058
|
.exitOverride();
|
|
9595
10059
|
program
|
|
9596
10060
|
.command('create')
|
|
9597
10061
|
.description('创建外部小程序项目开发模板')
|
|
9598
10062
|
.argument('<project-name>', '项目目录名,例如 my-miniapp')
|
|
9599
|
-
.action(async (projectName) => {
|
|
9600
|
-
await runCreateCommand(projectName);
|
|
9601
|
-
});
|
|
10063
|
+
.action(withUpdateReminder(async (projectName) => {
|
|
10064
|
+
await handlers.runCreateCommand(projectName);
|
|
10065
|
+
}, handlers.printUpdateReminder));
|
|
9602
10066
|
program
|
|
9603
10067
|
.command('dev')
|
|
9604
|
-
.description('启动当前小程序项目的 Vite dev server')
|
|
9605
|
-
.option('--mock', '启动内置浏览器 mock runtime host', false)
|
|
10068
|
+
.description('启动当前小程序项目的 Vite dev server 和浏览器 mock runtime host')
|
|
9606
10069
|
.option('--port <port>', 'App dev server 端口', parsePositivePort)
|
|
9607
10070
|
.option('--mock-port <port>', 'Mock host 端口', parsePositivePort)
|
|
9608
10071
|
.option('--host <host>', '传给 Vite 和 mock host 的 host')
|
|
9609
|
-
.option('--open', '
|
|
9610
|
-
.action(async (options) => {
|
|
9611
|
-
await runDevCommand(options);
|
|
10072
|
+
.option('--no-open', '不自动打开浏览器调试页')
|
|
10073
|
+
.action(withUpdateReminder(async (options) => {
|
|
10074
|
+
await handlers.runDevCommand(options);
|
|
10075
|
+
}, handlers.printUpdateReminder));
|
|
10076
|
+
program
|
|
10077
|
+
.command('doctor')
|
|
10078
|
+
.description('诊断 hb-sdk 本地环境和 Agent Skill 版本')
|
|
10079
|
+
.action(async () => {
|
|
10080
|
+
await handlers.runDoctorCommand();
|
|
9612
10081
|
});
|
|
9613
10082
|
const login = program
|
|
9614
10083
|
.command('login')
|
|
9615
10084
|
.description('登录 Heybox 并缓存 CLI 登录态')
|
|
9616
|
-
.action(async () => {
|
|
9617
|
-
await loginToHeybox();
|
|
9618
|
-
});
|
|
10085
|
+
.action(withUpdateReminder(async () => {
|
|
10086
|
+
await handlers.loginToHeybox();
|
|
10087
|
+
}, handlers.printUpdateReminder));
|
|
9619
10088
|
login
|
|
9620
10089
|
.command('status')
|
|
9621
10090
|
.description('查看脱敏后的 Heybox 登录态')
|
|
9622
|
-
.action(async () => {
|
|
9623
|
-
await printLoginStatus();
|
|
9624
|
-
});
|
|
10091
|
+
.action(withUpdateReminder(async () => {
|
|
10092
|
+
await handlers.printLoginStatus();
|
|
10093
|
+
}, handlers.printUpdateReminder));
|
|
9625
10094
|
login
|
|
9626
10095
|
.command('clear')
|
|
9627
10096
|
.description('清理 hb-sdk 命名空间中的 Heybox 登录态')
|
|
9628
|
-
.action(async () => {
|
|
9629
|
-
await clearLoginStatus();
|
|
9630
|
-
});
|
|
10097
|
+
.action(withUpdateReminder(async () => {
|
|
10098
|
+
await handlers.clearLoginStatus();
|
|
10099
|
+
}, handlers.printUpdateReminder));
|
|
9631
10100
|
return program;
|
|
9632
10101
|
}
|
|
10102
|
+
function withUpdateReminder(action, printUpdateReminder) {
|
|
10103
|
+
return async (...args) => {
|
|
10104
|
+
await action(...args);
|
|
10105
|
+
await printUpdateReminder();
|
|
10106
|
+
};
|
|
10107
|
+
}
|
|
9633
10108
|
function parsePositivePort(value) {
|
|
9634
10109
|
const parsed = Number(value);
|
|
9635
10110
|
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
@@ -9637,3 +10112,6 @@ function parsePositivePort(value) {
|
|
|
9637
10112
|
}
|
|
9638
10113
|
return parsed;
|
|
9639
10114
|
}
|
|
10115
|
+
|
|
10116
|
+
exports.createCliProgram = createCliProgram;
|
|
10117
|
+
exports.runCli = runCli;
|