@xiashe/skill 0.1.20 → 0.1.22
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/bin/xiashe-skill.mjs +153 -32
- package/package.json +1 -1
package/bin/xiashe-skill.mjs
CHANGED
|
@@ -1,19 +1,97 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { createHash, createHmac } from 'node:crypto';
|
|
4
|
-
import { existsSync } from 'node:fs';
|
|
4
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
5
5
|
import { mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises';
|
|
6
6
|
import os from 'node:os';
|
|
7
7
|
import path from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
8
9
|
import { promisify } from 'node:util';
|
|
9
10
|
import { gzip } from 'node:zlib';
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
function parseEnvFile(filePath) {
|
|
13
|
+
if (!existsSync(filePath)) return {};
|
|
14
|
+
const parsed = {};
|
|
15
|
+
const raw = readFileSync(filePath, 'utf8');
|
|
16
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
17
|
+
const trimmed = line.trim();
|
|
18
|
+
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
19
|
+
const match = trimmed.match(/^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
|
|
20
|
+
if (!match) continue;
|
|
21
|
+
let value = match[2].trim();
|
|
22
|
+
if (
|
|
23
|
+
(value.startsWith('"') && value.endsWith('"')) ||
|
|
24
|
+
(value.startsWith("'") && value.endsWith("'"))
|
|
25
|
+
) {
|
|
26
|
+
value = value.slice(1, -1);
|
|
27
|
+
}
|
|
28
|
+
parsed[match[1]] = value;
|
|
29
|
+
}
|
|
30
|
+
return parsed;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function nearestEnvFiles() {
|
|
34
|
+
const files = [];
|
|
35
|
+
let cursor = process.cwd();
|
|
36
|
+
for (let index = 0; index < 8; index += 1) {
|
|
37
|
+
files.push(path.join(cursor, '.env.local'));
|
|
38
|
+
files.push(path.join(cursor, 'convex', '.env.local'));
|
|
39
|
+
const next = path.dirname(cursor);
|
|
40
|
+
if (next === cursor) break;
|
|
41
|
+
cursor = next;
|
|
42
|
+
}
|
|
43
|
+
return files;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function loadLocalEnvDefaults() {
|
|
47
|
+
const cliDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
|
|
48
|
+
const candidates = [
|
|
49
|
+
path.join(cliDir, '.env.local'),
|
|
50
|
+
path.join(cliDir, 'convex', '.env.local'),
|
|
51
|
+
...nearestEnvFiles()
|
|
52
|
+
];
|
|
53
|
+
const env = {};
|
|
54
|
+
for (const filePath of candidates) {
|
|
55
|
+
Object.assign(env, parseEnvFile(filePath));
|
|
56
|
+
}
|
|
57
|
+
return env;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function normalizeBaseUrl(value) {
|
|
61
|
+
const text = String(value || '').trim().replace(/\/+$/, '');
|
|
62
|
+
return /^https?:\/\//i.test(text) ? text : '';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function isTransportError(error) {
|
|
66
|
+
const message = error instanceof Error ? `${error.name || ''} ${error.message || ''}` : String(error || '');
|
|
67
|
+
return /abort|timeout|fetch failed|network|enotfound|eai_again|econnrefused|econnreset|etimedout|unable to verify|certificate/i.test(message);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const LOCAL_ENV_DEFAULTS = loadLocalEnvDefaults();
|
|
71
|
+
const VERSION = process.env.XIASHE_SKILL_CLI_VERSION || '0.1.22';
|
|
12
72
|
const COMMAND_NAME = process.env.XIASHE_SKILL_CLI_NAME || 'xiashe-skill';
|
|
13
73
|
const PRODUCT_NAME = process.env.XIASHE_SKILL_PRODUCT_NAME || (COMMAND_NAME === 'agentpie-skill' ? 'AgentPie' : 'XiaShe');
|
|
14
74
|
const REGISTRY_PROVIDER = process.env.XIASHE_SKILL_REGISTRY_PROVIDER || (COMMAND_NAME === 'agentpie-skill' ? 'agentpie' : 'xiashe');
|
|
75
|
+
const LOCAL_AGENTPIE_BASE_URL = normalizeBaseUrl(
|
|
76
|
+
process.env.AGENTPIE_SKILL_DEFAULT_BASE_URL ||
|
|
77
|
+
LOCAL_ENV_DEFAULTS.AGENTPIE_SKILL_DEFAULT_BASE_URL ||
|
|
78
|
+
process.env.AGENTPIE_SKILL_REGISTRY_PUBLIC_URL ||
|
|
79
|
+
LOCAL_ENV_DEFAULTS.AGENTPIE_SKILL_REGISTRY_PUBLIC_URL ||
|
|
80
|
+
process.env.AGENTPIE_ACTIONS_URL ||
|
|
81
|
+
LOCAL_ENV_DEFAULTS.AGENTPIE_ACTIONS_URL ||
|
|
82
|
+
process.env.CREATOR_SKILL_REGISTRY_PUBLIC_URL ||
|
|
83
|
+
LOCAL_ENV_DEFAULTS.CREATOR_SKILL_REGISTRY_PUBLIC_URL ||
|
|
84
|
+
process.env.AGENTPIE_MCP_PUBLIC_URL ||
|
|
85
|
+
LOCAL_ENV_DEFAULTS.AGENTPIE_MCP_PUBLIC_URL ||
|
|
86
|
+
process.env.PUBLIC_CONVEX_SITE_URL ||
|
|
87
|
+
LOCAL_ENV_DEFAULTS.PUBLIC_CONVEX_SITE_URL ||
|
|
88
|
+
process.env.CONVEX_SITE_URL ||
|
|
89
|
+
LOCAL_ENV_DEFAULTS.CONVEX_SITE_URL ||
|
|
90
|
+
process.env.EXPO_PUBLIC_CONVEX_SITE_URL ||
|
|
91
|
+
LOCAL_ENV_DEFAULTS.EXPO_PUBLIC_CONVEX_SITE_URL
|
|
92
|
+
);
|
|
15
93
|
const DEFAULT_BASE_URL = process.env.XIASHE_SKILL_DEFAULT_BASE_URL || (COMMAND_NAME === 'agentpie-skill'
|
|
16
|
-
? 'https://
|
|
94
|
+
? LOCAL_AGENTPIE_BASE_URL || 'https://agentpie.app'
|
|
17
95
|
: 'https://actions.xiashe.chat');
|
|
18
96
|
const MANIFEST_FILE = process.env.XIASHE_SKILL_MANIFEST_FILE || (COMMAND_NAME === 'agentpie-skill'
|
|
19
97
|
? 'agentpie.skill.json'
|
|
@@ -32,10 +110,11 @@ const EVENT_SCHEMA_VERSION = process.env.XIASHE_SKILL_EVENT_SCHEMA_VERSION || (R
|
|
|
32
110
|
const RUNTIME_SCHEMA_VERSION = process.env.XIASHE_SKILL_RUNTIME_SCHEMA_VERSION || (REGISTRY_PROVIDER === 'agentpie'
|
|
33
111
|
? 'agentpie.skill.runtime.v1'
|
|
34
112
|
: 'xiashe.skill.runtime.v1');
|
|
35
|
-
const
|
|
36
|
-
const
|
|
113
|
+
const FIRST_PARTY_HUB = REGISTRY_PROVIDER === 'agentpie' ? 'agentpie' : 'xiashe';
|
|
114
|
+
const SUPPORTED_HUBS = ['agentpie', 'xiashe', 'red', 'clawhub', 'skillhub', 'claude', 'codex', 'cursor', 'workbuddy', 'dify', 'coze', 'generic'];
|
|
115
|
+
const DEFAULT_SETUP_HUBS = [FIRST_PARTY_HUB, 'red'];
|
|
37
116
|
const ACK_EVENTS = ['installed', 'used', 'completed', 'failed'];
|
|
38
|
-
const RUNTIME_DISTRIBUTION_PLATFORMS = ['xiaohongshu-redskill', 'xiashe', 'coze-store', 'local', 'unknown'];
|
|
117
|
+
const RUNTIME_DISTRIBUTION_PLATFORMS = ['xiaohongshu-redskill', 'agentpie', 'xiashe', 'coze-store', 'local', 'unknown'];
|
|
39
118
|
const RUNTIME_AGENTS = ['codex', 'workbuddy', 'coze', 'claude', 'cursor', 'dify', 'custom-agent', 'unknown'];
|
|
40
119
|
const RUNTIME_HOSTS = ['codex-desktop', 'coze-app', 'web-chat', 'desktop', 'web', 'server', 'mobile', 'unknown'];
|
|
41
120
|
const RUNTIME_SOURCE_SURFACES = ['install', 'first-use-backfill', 'chat-use', 'manual-test', 'creator-card', 'dashboard', 'unknown'];
|
|
@@ -79,6 +158,16 @@ const FORBIDDEN_ACK_FIELDS = [
|
|
|
79
158
|
'privateResearchMaterial'
|
|
80
159
|
];
|
|
81
160
|
const PLATFORM_REVIEW_PROFILES = {
|
|
161
|
+
agentpie: {
|
|
162
|
+
label: 'AgentPie Registry',
|
|
163
|
+
packageMode: 'full_skill_package',
|
|
164
|
+
manifestPolicy: 'upload_allowed',
|
|
165
|
+
disclosurePlacement: ['Skill public page', 'README', `${WORK_DIR}/REGISTRY_DISCLOSURE.md`],
|
|
166
|
+
runtimeDataPolicy: 'runtime_capable',
|
|
167
|
+
defaultDataSource: 'runtime',
|
|
168
|
+
allowedFilePolicy: 'Upload the complete reviewed Skill package, including the local registry manifest.',
|
|
169
|
+
forbiddenPublicFiles: ['.env', 'credentials', 'node_modules', 'dist', 'build', 'browser profiles', 'SSH keys']
|
|
170
|
+
},
|
|
82
171
|
xiashe: {
|
|
83
172
|
label: 'XiaShe Store',
|
|
84
173
|
packageMode: 'full_skill_package',
|
|
@@ -224,14 +313,14 @@ function usage() {
|
|
|
224
313
|
|
|
225
314
|
Usage:
|
|
226
315
|
${COMMAND_NAME} inspect [skill-dir] [--json]
|
|
227
|
-
${COMMAND_NAME} publish [skill-dir] --code <dynamic-code> [--to
|
|
228
|
-
${COMMAND_NAME} setup [skill-dir] --code <dynamic-code> [--hub all|
|
|
229
|
-
${COMMAND_NAME} setup [skill-dir] --public-token <token> --skill-id <id> [--hub all|
|
|
316
|
+
${COMMAND_NAME} publish [skill-dir] --code <dynamic-code> [--to ${FIRST_PARTY_HUB},red]
|
|
317
|
+
${COMMAND_NAME} setup [skill-dir] --code <dynamic-code> [--hub all|${FIRST_PARTY_HUB}|red]
|
|
318
|
+
${COMMAND_NAME} setup [skill-dir] --public-token <token> --skill-id <id> [--hub all|${FIRST_PARTY_HUB}|red]
|
|
230
319
|
${COMMAND_NAME} doctor [skill-dir] [--json]
|
|
231
320
|
${COMMAND_NAME} verify [skill-dir] [--hub <hub>] [--scenario <label>] [--dry-run]
|
|
232
321
|
${COMMAND_NAME} attach [skill-dir] --code <dynamic-code> [--name <name>]
|
|
233
322
|
${COMMAND_NAME} attach [skill-dir] --public-token <token> [--skill-id <id>] [--name <name>]
|
|
234
|
-
${COMMAND_NAME} prompt [skill-dir] --hub
|
|
323
|
+
${COMMAND_NAME} prompt [skill-dir] --hub <${FIRST_PARTY_HUB}|red> [--source-url <url>] [--out <file>]
|
|
235
324
|
${COMMAND_NAME} snippet [skill-dir] [--target js|curl] [--out <file>]
|
|
236
325
|
${COMMAND_NAME} track [skill-dir] --event <event> [--hub <hub>] [--installation-id <id>] [--invocation-id <id>]
|
|
237
326
|
|
|
@@ -244,7 +333,7 @@ Options:
|
|
|
244
333
|
--agent-ack-url <url> No-secret Agent Ack endpoint written to the local manifest.
|
|
245
334
|
--name <name> Skill display name override.
|
|
246
335
|
--description <text> Skill description override.
|
|
247
|
-
--hub <hub> Target Skill hub prompt style. setup defaults to
|
|
336
|
+
--hub <hub> Target Skill hub prompt style. setup defaults to ${DEFAULT_SETUP_HUBS.join(',')}.
|
|
248
337
|
--to <hub[,hub]> High-level publish targets. Alias for --hub in publish mode.
|
|
249
338
|
--event <event> Runtime event to submit for testing.
|
|
250
339
|
--installation-id <id> Stable anonymous install id for runtime analytics.
|
|
@@ -266,11 +355,12 @@ Options:
|
|
|
266
355
|
--signing-secret <secret> Optional HMAC secret for signed runtime events.
|
|
267
356
|
--source-url <url> User-provided source URL an Agent can use during third-party upload.
|
|
268
357
|
--package-url <url> Deprecated alias for --source-url.
|
|
358
|
+
--skill-version <version> Override the Skill release version without editing package.json.
|
|
269
359
|
--package-upload-url <url> Package upload ticket endpoint. Defaults to ${DEFAULT_PACKAGE_UPLOAD_URL}
|
|
270
360
|
--package-artifact-url <url> Package artifact attach endpoint. Defaults to ${DEFAULT_PACKAGE_ARTIFACT_URL}
|
|
271
361
|
--out <path> Output prompt or snippet file.
|
|
272
362
|
--out-dir <path> Output directory for setup artifacts. Defaults to ${WORK_DIR}/.
|
|
273
|
-
--no-
|
|
363
|
+
--no-package-upload Skip automatic ${PRODUCT_NAME} complete package upload.
|
|
274
364
|
--embed-skill-md Also write a clearly marked registry section into SKILL.md.
|
|
275
365
|
--no-skill-md Do not write registry text into SKILL.md. Red hub embeds by default.
|
|
276
366
|
--no-snippet Setup should skip writing the runtime analytics snippet.
|
|
@@ -289,7 +379,7 @@ function fail(message, code = 1) {
|
|
|
289
379
|
|
|
290
380
|
function parseArgs(argv) {
|
|
291
381
|
const args = { _: [], json: false, dryRun: false };
|
|
292
|
-
const booleanFlags = new Set(['embed-skill-md', 'no-skill-md', 'no-snippet', 'no-track', 'no-xiashe-package-upload']);
|
|
382
|
+
const booleanFlags = new Set(['embed-skill-md', 'no-skill-md', 'no-snippet', 'no-track', 'no-package-upload', 'no-xiashe-package-upload']);
|
|
293
383
|
for (let i = 0; i < argv.length; i += 1) {
|
|
294
384
|
const value = argv[i];
|
|
295
385
|
if (value === '--help' || value === '-h') {
|
|
@@ -486,6 +576,9 @@ function normalizeHub(value) {
|
|
|
486
576
|
if (hub === 'xiashechat' || hub === 'xia-she' || hub === 'xiashe-store') {
|
|
487
577
|
return 'xiashe';
|
|
488
578
|
}
|
|
579
|
+
if (hub === 'agent-pie' || hub === 'agentpieapp' || hub === 'agentpie-registry' || hub === 'agentpieregistry') {
|
|
580
|
+
return 'agentpie';
|
|
581
|
+
}
|
|
489
582
|
if (hub === 'claudecode' || hub === 'claude-code') {
|
|
490
583
|
return 'claude';
|
|
491
584
|
}
|
|
@@ -676,7 +769,7 @@ async function inferSkillMetadata(root, flags = {}) {
|
|
|
676
769
|
name,
|
|
677
770
|
skillKey: safeSkillKey(flags['skill-key'] || manifest?.skillKey || packageJson?.name || name),
|
|
678
771
|
description: normalizeText(flags.description || manifest?.description || packageJson?.description || firstParagraph || '', 500),
|
|
679
|
-
version: normalizeText(flags
|
|
772
|
+
version: normalizeText(flags['skill-version'] || packageJson?.version || manifest?.version || '0.1.0', 80),
|
|
680
773
|
registry: manifest?.registry || null
|
|
681
774
|
};
|
|
682
775
|
}
|
|
@@ -741,6 +834,12 @@ async function postJson(url, body, timeoutMs = 20_000) {
|
|
|
741
834
|
throw new Error(payload.error || payload.message || `HTTP ${response.status}`);
|
|
742
835
|
}
|
|
743
836
|
return payload;
|
|
837
|
+
} catch (error) {
|
|
838
|
+
const message = error instanceof Error ? error.message : String(error || 'unknown error');
|
|
839
|
+
if (!isTransportError(error)) {
|
|
840
|
+
throw error;
|
|
841
|
+
}
|
|
842
|
+
throw new Error(`Network request failed for ${url}: ${message}`);
|
|
744
843
|
} finally {
|
|
745
844
|
clearTimeout(timer);
|
|
746
845
|
}
|
|
@@ -895,10 +994,10 @@ async function buildXiashePackageArtifact(root, inspected, flags = {}) {
|
|
|
895
994
|
const skillMarkdownPresent = files.some((file) => /^SKILL(\.[a-z0-9]+)?$/i.test(file.relative));
|
|
896
995
|
const manifestPresent = files.some((file) => file.relative === manifestRelative);
|
|
897
996
|
if (!skillMarkdownPresent) {
|
|
898
|
-
throw new Error(
|
|
997
|
+
throw new Error(`SKILL.md is required before uploading the ${PRODUCT_NAME} complete package.`);
|
|
899
998
|
}
|
|
900
999
|
if (!manifestPresent) {
|
|
901
|
-
throw new Error(`${manifestRelative} is required before uploading the
|
|
1000
|
+
throw new Error(`${manifestRelative} is required before uploading the ${PRODUCT_NAME} complete package.`);
|
|
902
1001
|
}
|
|
903
1002
|
const artifact = await createTarGz(files);
|
|
904
1003
|
const artifactDir = path.resolve(flags['package-out-dir'] || path.join(absoluteRoot, WORK_DIR, 'package-artifact'));
|
|
@@ -946,13 +1045,19 @@ async function uploadBytesToStorage(uploadUrl, bytes, contentType, timeoutMs = 6
|
|
|
946
1045
|
throw new Error('Upload response did not include storageId.');
|
|
947
1046
|
}
|
|
948
1047
|
return { ...payload, storageId };
|
|
1048
|
+
} catch (error) {
|
|
1049
|
+
const message = error instanceof Error ? error.message : String(error || 'unknown error');
|
|
1050
|
+
if (!isTransportError(error)) {
|
|
1051
|
+
throw error;
|
|
1052
|
+
}
|
|
1053
|
+
throw new Error(`Package upload failed for ${uploadUrl}: ${message}`);
|
|
949
1054
|
} finally {
|
|
950
1055
|
clearTimeout(timer);
|
|
951
1056
|
}
|
|
952
1057
|
}
|
|
953
1058
|
|
|
954
1059
|
async function uploadXiashePackageArtifact(root, flags, manifestResult) {
|
|
955
|
-
if (flags.dryRun || flags['no-xiashe-package-upload']) {
|
|
1060
|
+
if (flags.dryRun || flags['no-package-upload'] || flags['no-xiashe-package-upload']) {
|
|
956
1061
|
return {
|
|
957
1062
|
ok: true,
|
|
958
1063
|
skipped: true,
|
|
@@ -963,7 +1068,7 @@ async function uploadXiashePackageArtifact(root, flags, manifestResult) {
|
|
|
963
1068
|
const registry = manifestResult.manifest?.registry || inspected.registry || {};
|
|
964
1069
|
const publicToken = normalizeText(registry.publicToken, 512);
|
|
965
1070
|
if (!publicToken) {
|
|
966
|
-
throw new Error(
|
|
1071
|
+
throw new Error(`Cannot upload ${PRODUCT_NAME} package without registry publicToken.`);
|
|
967
1072
|
}
|
|
968
1073
|
const artifact = await buildXiashePackageArtifact(root, inspected, flags);
|
|
969
1074
|
const registrySourceSha256 =
|
|
@@ -1003,7 +1108,7 @@ async function uploadXiashePackageArtifact(root, flags, manifestResult) {
|
|
|
1003
1108
|
manifestPresent: artifact.manifestPresent,
|
|
1004
1109
|
skillMarkdownPresent: artifact.skillMarkdownPresent,
|
|
1005
1110
|
creatorCardUrl: normalizeText(registry.creatorCardUrl, 800) || undefined,
|
|
1006
|
-
platformSource:
|
|
1111
|
+
platformSource: REGISTRY_PROVIDER,
|
|
1007
1112
|
source: `${REGISTRY_PROVIDER}_skill_cli`
|
|
1008
1113
|
},
|
|
1009
1114
|
Number(flags['timeout-ms'] || 20_000)
|
|
@@ -1182,6 +1287,9 @@ async function writeManifest(root, flags) {
|
|
|
1182
1287
|
}
|
|
1183
1288
|
|
|
1184
1289
|
function hubInstruction(hub) {
|
|
1290
|
+
if (hub === 'agentpie') {
|
|
1291
|
+
return 'AgentPie Registry publish is the full Skill package and registry manifest flow. Keep public disclosure, attribution, and runtime analytics callbacks; if the local manifest has a registry public token or a creator-authenticated CLI/API session exists, create or reuse the AgentPie registry draft.';
|
|
1292
|
+
}
|
|
1185
1293
|
if (hub === 'xiashe') {
|
|
1186
1294
|
return '虾舍商店发布是完整 Skill 包和 registry manifest 的主流程。请保留公开披露、归因和 runtime analytics 回传能力;如果本地 manifest 有 registry public token 或已有创作者认证 CLI/API 会话,就创建或复用虾舍商店草稿。';
|
|
1187
1295
|
}
|
|
@@ -1216,6 +1324,9 @@ function hubInstruction(hub) {
|
|
|
1216
1324
|
}
|
|
1217
1325
|
|
|
1218
1326
|
function platformPromptPlaceholder(hub) {
|
|
1327
|
+
if (hub === 'agentpie') {
|
|
1328
|
+
return 'If the user is publishing to AgentPie Registry and the current environment has a creator-authenticated CLI/API session, create the AgentPie registry draft first; otherwise finish registry setup, disclosure, platform profile, and handoff files. Do not apply third-party marketplace limits to the AgentPie complete Skill package.';
|
|
1329
|
+
}
|
|
1219
1330
|
if (hub === 'xiashe') {
|
|
1220
1331
|
return '如果用户要发布到虾舍商店,并且当前环境已有创作者认证 CLI/API 会话,请优先创建虾舍商店草稿;如果没有认证会话,请完成 registry setup、披露、平台 profile 和 handoff 文件,不要要求 Agent 宿主登录或索取账号凭证。不要把第三方平台限制套用到虾舍完整 Skill 包。';
|
|
1221
1332
|
}
|
|
@@ -1251,6 +1362,14 @@ function platformPromptPlaceholder(hub) {
|
|
|
1251
1362
|
|
|
1252
1363
|
function uploadCompatibilityLines(hub, manifestFile) {
|
|
1253
1364
|
const localManifest = `${WORK_DIR}/${manifestFile}`;
|
|
1365
|
+
if (hub === 'agentpie') {
|
|
1366
|
+
return [
|
|
1367
|
+
'AgentPie Registry compatibility requirements:',
|
|
1368
|
+
`- AgentPie Registry can receive the complete Skill package and ${localManifest} registry manifest.`,
|
|
1369
|
+
'- Keep public disclosure text, attribution links, and runtime event callbacks; do not remove the registry manifest.',
|
|
1370
|
+
'- Before submitting a draft, still exclude .env, keys, node_modules, dist/build, and unrelated local files.'
|
|
1371
|
+
];
|
|
1372
|
+
}
|
|
1254
1373
|
if (hub === 'xiashe') {
|
|
1255
1374
|
return [
|
|
1256
1375
|
'虾舍商店兼容性要求:',
|
|
@@ -1541,6 +1660,7 @@ function yamlStringList(values, indent = 6) {
|
|
|
1541
1660
|
function runtimeDistributionPlatformForHub(hub) {
|
|
1542
1661
|
const normalized = normalizeHub(hub) || 'unknown';
|
|
1543
1662
|
if (normalized === 'red') return 'xiaohongshu-redskill';
|
|
1663
|
+
if (normalized === 'agentpie') return 'agentpie';
|
|
1544
1664
|
if (normalized === 'xiashe') return 'xiashe';
|
|
1545
1665
|
if (normalized === 'coze') return 'coze-store';
|
|
1546
1666
|
if (normalized === 'codex' || normalized === 'claude' || normalized === 'cursor' || normalized === 'workbuddy') return 'local';
|
|
@@ -2649,12 +2769,13 @@ async function setupAgentWorkflow(root, flags) {
|
|
|
2649
2769
|
promptResults,
|
|
2650
2770
|
packagePlans
|
|
2651
2771
|
});
|
|
2652
|
-
const
|
|
2772
|
+
const firstPartyPackageHubSelected = hubs.includes(FIRST_PARTY_HUB);
|
|
2773
|
+
const firstPartyPackageArtifact = firstPartyPackageHubSelected && (REGISTRY_PROVIDER === 'xiashe' || REGISTRY_PROVIDER === 'agentpie')
|
|
2653
2774
|
? await uploadXiashePackageArtifact(absoluteRoot, flags, manifestResult)
|
|
2654
2775
|
: {
|
|
2655
2776
|
ok: true,
|
|
2656
2777
|
skipped: true,
|
|
2657
|
-
reason:
|
|
2778
|
+
reason: firstPartyPackageHubSelected ? 'unsupported_registry_provider' : 'first_party_registry_not_selected'
|
|
2658
2779
|
};
|
|
2659
2780
|
|
|
2660
2781
|
const warnings = [];
|
|
@@ -2690,14 +2811,14 @@ async function setupAgentWorkflow(root, flags) {
|
|
|
2690
2811
|
agentAckPath,
|
|
2691
2812
|
disclosurePath,
|
|
2692
2813
|
snippetPath: snippetResult ? snippetResult.outPath : null,
|
|
2693
|
-
|
|
2814
|
+
firstPartyPackageArtifact,
|
|
2694
2815
|
promptEvents,
|
|
2695
2816
|
warnings,
|
|
2696
2817
|
publicProtocol,
|
|
2697
2818
|
next: [
|
|
2698
|
-
|
|
2699
|
-
?
|
|
2700
|
-
:
|
|
2819
|
+
firstPartyPackageArtifact?.skipped
|
|
2820
|
+
? `${PRODUCT_NAME} complete package upload was skipped (${firstPartyPackageArtifact.reason}).`
|
|
2821
|
+
: `${PRODUCT_NAME} complete package uploaded: ${path.relative(absoluteRoot, firstPartyPackageArtifact.artifactPath)} (${firstPartyPackageArtifact.publishStatus || 'queued'}).`,
|
|
2701
2822
|
`Use ${path.relative(absoluteRoot, handoffPath)} as the single Agent handoff. The Agent should not ask the user to manually pick registry files.`,
|
|
2702
2823
|
`Use ${path.relative(absoluteRoot, profilesPath)} and package-<hub>.json as the platform review profiles and upload allowlists.`,
|
|
2703
2824
|
publicProtocol
|
|
@@ -2755,7 +2876,7 @@ async function main() {
|
|
|
2755
2876
|
if (command === 'publish') {
|
|
2756
2877
|
const result = await setupAgentWorkflow(root, flags);
|
|
2757
2878
|
if (flags.json) {
|
|
2758
|
-
print({ ok: true, mode:
|
|
2879
|
+
print({ ok: true, mode: `${REGISTRY_PROVIDER}-publish`, ...result }, true);
|
|
2759
2880
|
} else {
|
|
2760
2881
|
const lines = [
|
|
2761
2882
|
`${PRODUCT_NAME} publish handoff prepared.`,
|
|
@@ -2766,8 +2887,8 @@ async function main() {
|
|
|
2766
2887
|
...result.packagePlanPaths.map((item) => `Package plan (${item.hub}): ${item.planPath}`),
|
|
2767
2888
|
result.skillMdPath ? `Updated: ${result.skillMdPath}` : null,
|
|
2768
2889
|
result.publicProtocol ? `Public Red protocol: ${result.publicProtocol.runtimePath}, ${result.publicProtocol.agentAckPath}, ${result.publicProtocol.disclosurePath}` : null,
|
|
2769
|
-
result.
|
|
2770
|
-
?
|
|
2890
|
+
result.firstPartyPackageArtifact && !result.firstPartyPackageArtifact.skipped
|
|
2891
|
+
? `${PRODUCT_NAME} package: ${result.firstPartyPackageArtifact.artifactPath} (${result.firstPartyPackageArtifact.publishStatus || 'queued'})`
|
|
2771
2892
|
: null,
|
|
2772
2893
|
`Disclosure: ${result.disclosurePath}`,
|
|
2773
2894
|
result.snippetPath ? `Runtime snippet: ${result.snippetPath}` : null,
|
|
@@ -2775,8 +2896,8 @@ async function main() {
|
|
|
2775
2896
|
'',
|
|
2776
2897
|
'Next:',
|
|
2777
2898
|
'- Treat the target platform official upload flow as authoritative.',
|
|
2778
|
-
|
|
2779
|
-
|
|
2899
|
+
`- Use the handoff file as the only ${PRODUCT_NAME} registry checklist.`,
|
|
2900
|
+
`- ${PRODUCT_NAME} complete package upload is already handled by this command when the first-party registry target is selected.`,
|
|
2780
2901
|
'- Before uploading to third-party targets, check whether this Skill already has a draft, submitted review, or published listing for the selected target; skip duplicate uploads and verify/update the existing record when possible.',
|
|
2781
2902
|
'- Check upload readiness and runtime readiness separately before submission.',
|
|
2782
2903
|
'- Only ask for creator CLI login if a separate store-management command is needed and the registry public token is missing or rejected.',
|
|
@@ -2801,8 +2922,8 @@ async function main() {
|
|
|
2801
2922
|
result.publicProtocol ? `Wrote ${result.publicProtocol.runtimePath}` : null,
|
|
2802
2923
|
result.publicProtocol ? `Wrote ${result.publicProtocol.agentAckPath}` : null,
|
|
2803
2924
|
result.publicProtocol ? `Wrote ${result.publicProtocol.disclosurePath}` : null,
|
|
2804
|
-
result.
|
|
2805
|
-
? `Uploaded
|
|
2925
|
+
result.firstPartyPackageArtifact && !result.firstPartyPackageArtifact.skipped
|
|
2926
|
+
? `Uploaded ${PRODUCT_NAME} package ${result.firstPartyPackageArtifact.artifactPath} (${result.firstPartyPackageArtifact.publishStatus || 'queued'})`
|
|
2806
2927
|
: null,
|
|
2807
2928
|
`Wrote ${result.disclosurePath}`,
|
|
2808
2929
|
result.snippetPath ? `Wrote ${result.snippetPath}` : null,
|