@xiashe/skill 0.1.23 → 0.1.24
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 +3 -2
- package/bin/xiashe-skill.mjs +55 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -51,8 +51,9 @@ Use the `claimUrl` returned with a dashboard dynamic code exactly as issued. `pu
|
|
|
51
51
|
The publish path keeps three different values separate:
|
|
52
52
|
|
|
53
53
|
- **Source fingerprint** — a stable SHA-256 of reviewed Skill source files. It is the idempotency key for the publish job.
|
|
54
|
-
- **Artifact checksum** — SHA-256 of the generated `.tgz` bytes
|
|
55
|
-
- **Storage checksum** —
|
|
54
|
+
- **Artifact checksum** — SHA-256 of the generated `.tgz` bytes, sent with the upload request.
|
|
55
|
+
- **Storage metadata checksum** — an upload-store diagnostic; it is never trusted as the sole proof of the uploaded bytes.
|
|
56
|
+
- **Verified upload checksum** — the backend rehashes the exact stored archive bytes and compares that value with the artifact checksum. None of these are compared with the source fingerprint.
|
|
56
57
|
|
|
57
58
|
If the network breaks after the server receives a dynamic-code claim, rerun the exact same `publish` command before that code expires. The registry accepts only the same code and source fingerprint, returns the original local manifest credentials, and reuses the same package job. It never creates a second Skill or a second upload job. Do not generate a new dashboard code merely because a local HTTP response was interrupted.
|
|
58
59
|
|
package/bin/xiashe-skill.mjs
CHANGED
|
@@ -68,7 +68,7 @@ function isTransportError(error) {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
const LOCAL_ENV_DEFAULTS = loadLocalEnvDefaults();
|
|
71
|
-
const VERSION = process.env.XIASHE_SKILL_CLI_VERSION || '0.1.
|
|
71
|
+
const VERSION = process.env.XIASHE_SKILL_CLI_VERSION || '0.1.24';
|
|
72
72
|
const COMMAND_NAME = process.env.XIASHE_SKILL_CLI_NAME || 'xiashe-skill';
|
|
73
73
|
const PRODUCT_NAME = process.env.XIASHE_SKILL_PRODUCT_NAME || (COMMAND_NAME === 'agentpie-skill' ? 'AgentPie' : 'XiaShe');
|
|
74
74
|
const REGISTRY_PROVIDER = process.env.XIASHE_SKILL_REGISTRY_PROVIDER || (COMMAND_NAME === 'agentpie-skill' ? 'agentpie' : 'xiashe');
|
|
@@ -98,6 +98,7 @@ const MANIFEST_FILE = process.env.XIASHE_SKILL_MANIFEST_FILE || (COMMAND_NAME ==
|
|
|
98
98
|
: 'xiashe.skill.json');
|
|
99
99
|
const WORK_DIR = process.env.XIASHE_SKILL_WORK_DIR || (COMMAND_NAME === 'agentpie-skill' ? '.agentpie' : '.xiashe');
|
|
100
100
|
const PUBLIC_PROTOCOL_DIR = process.env.XIASHE_SKILL_PUBLIC_PROTOCOL_DIR || (REGISTRY_PROVIDER === 'agentpie' ? 'agentpie' : 'xiashe');
|
|
101
|
+
const PUBLIC_PACKAGE_MANIFEST_FILE = 'package-manifest.json';
|
|
101
102
|
const HANDOFF_FILE = 'UPLOAD_HANDOFF.md';
|
|
102
103
|
const DEFAULT_REGISTRY_URL = process.env.XIASHE_SKILL_REGISTRY_URL || `${DEFAULT_BASE_URL}/registry/skill-events`;
|
|
103
104
|
const DEFAULT_AGENT_ACK_URL = process.env.XIASHE_SKILL_AGENT_ACK_URL || `${DEFAULT_BASE_URL}/registry/agent-ack`;
|
|
@@ -163,8 +164,8 @@ const PLATFORM_REVIEW_PROFILES = {
|
|
|
163
164
|
disclosurePlacement: ['Skill public page', 'README', `${WORK_DIR}/REGISTRY_DISCLOSURE.md`],
|
|
164
165
|
runtimeDataPolicy: 'runtime_capable',
|
|
165
166
|
defaultDataSource: 'runtime',
|
|
166
|
-
allowedFilePolicy: 'Upload the complete reviewed Skill package
|
|
167
|
-
forbiddenPublicFiles: ['.env', 'credentials', 'node_modules', 'dist', 'build', 'browser profiles', 'SSH keys']
|
|
167
|
+
allowedFilePolicy: 'Upload the complete reviewed Skill package together with the generated no-secret package manifest. Keep the local registry manifest and runtime credentials on the creator device.',
|
|
168
|
+
forbiddenPublicFiles: [WORK_DIR, '.env', 'credentials', 'node_modules', 'dist', 'build', 'browser profiles', 'SSH keys', 'public tokens', 'signing secrets']
|
|
168
169
|
},
|
|
169
170
|
xiashe: {
|
|
170
171
|
label: 'XiaShe Store',
|
|
@@ -173,8 +174,8 @@ const PLATFORM_REVIEW_PROFILES = {
|
|
|
173
174
|
disclosurePlacement: ['Skill public page', 'README', `${WORK_DIR}/REGISTRY_DISCLOSURE.md`],
|
|
174
175
|
runtimeDataPolicy: 'runtime_capable',
|
|
175
176
|
defaultDataSource: 'runtime',
|
|
176
|
-
allowedFilePolicy: 'Upload the complete reviewed Skill package
|
|
177
|
-
forbiddenPublicFiles: ['.env', 'credentials', 'node_modules', 'dist', 'build', 'browser profiles', 'SSH keys']
|
|
177
|
+
allowedFilePolicy: 'Upload the complete reviewed Skill package together with the generated no-secret package manifest. Keep the local registry manifest and runtime credentials on the creator device.',
|
|
178
|
+
forbiddenPublicFiles: [WORK_DIR, '.env', 'credentials', 'node_modules', 'dist', 'build', 'browser profiles', 'SSH keys', 'public tokens', 'signing secrets']
|
|
178
179
|
},
|
|
179
180
|
red: {
|
|
180
181
|
label: 'Red Skill',
|
|
@@ -1090,11 +1091,16 @@ function shouldIgnorePackageEntry(relativePath, entryName, isDirectory = false)
|
|
|
1090
1091
|
if (entryName === '.env' || entryName.startsWith('.env.')) return true;
|
|
1091
1092
|
if (/\.(pem|key)$/i.test(entryName)) return true;
|
|
1092
1093
|
if (packageArtifactPrefix && normalized.startsWith(packageArtifactPrefix)) return true;
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1094
|
+
// The local registry workspace carries the public token, signing key and
|
|
1095
|
+
// resumable-upload state. It is intentionally never part of an installable
|
|
1096
|
+
// archive, even for first-party distribution. A separate, no-secret
|
|
1097
|
+
// package manifest is written below `PUBLIC_PROTOCOL_DIR` instead.
|
|
1098
|
+
if (normalized === WORK_DIR || normalized.startsWith(localRegistryPrefix)) {
|
|
1096
1099
|
return true;
|
|
1097
1100
|
}
|
|
1101
|
+
if (normalized === PUBLIC_PROTOCOL_DIR || normalized.startsWith(`${PUBLIC_PROTOCOL_DIR}/`)) {
|
|
1102
|
+
return isDirectory ? false : !isXiashePackageRegistryFile(normalized);
|
|
1103
|
+
}
|
|
1098
1104
|
const otherRegistryDir = WORK_DIR === '.xiashe' ? '.agentpie' : '.xiashe';
|
|
1099
1105
|
if (normalized === otherRegistryDir || normalized.startsWith(`${otherRegistryDir}/`)) return true;
|
|
1100
1106
|
return false;
|
|
@@ -1103,17 +1109,45 @@ function shouldIgnorePackageEntry(relativePath, entryName, isDirectory = false)
|
|
|
1103
1109
|
function isXiashePackageRegistryFile(relativePath) {
|
|
1104
1110
|
const normalized = String(relativePath || '').replace(/\\/g, '/');
|
|
1105
1111
|
const allowed = new Set([
|
|
1106
|
-
`${WORK_DIR}/${MANIFEST_FILE}`,
|
|
1107
|
-
`${WORK_DIR}/AGENT_ACK.md`,
|
|
1108
|
-
`${WORK_DIR}/REGISTRY_DISCLOSURE.md`,
|
|
1109
|
-
`${WORK_DIR}/runtime-events.js`,
|
|
1110
1112
|
`${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md`,
|
|
1111
1113
|
`${PUBLIC_PROTOCOL_DIR}/REGISTRY_DISCLOSURE.md`,
|
|
1112
|
-
`${PUBLIC_PROTOCOL_DIR}/runtime.yaml
|
|
1114
|
+
`${PUBLIC_PROTOCOL_DIR}/runtime.yaml`,
|
|
1115
|
+
`${PUBLIC_PROTOCOL_DIR}/${PUBLIC_PACKAGE_MANIFEST_FILE}`
|
|
1113
1116
|
]);
|
|
1114
1117
|
return allowed.has(normalized);
|
|
1115
1118
|
}
|
|
1116
1119
|
|
|
1120
|
+
function publicPackageManifestRelativePath() {
|
|
1121
|
+
return `${PUBLIC_PROTOCOL_DIR}/${PUBLIC_PACKAGE_MANIFEST_FILE}`;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
async function writePublicPackageManifest(root, inspected) {
|
|
1125
|
+
const registry = inspected.registry || {};
|
|
1126
|
+
const outputPath = path.join(root, PUBLIC_PROTOCOL_DIR, PUBLIC_PACKAGE_MANIFEST_FILE);
|
|
1127
|
+
const manifest = {
|
|
1128
|
+
schemaVersion: `${REGISTRY_PROVIDER}.skill.package.v1`,
|
|
1129
|
+
skill: {
|
|
1130
|
+
name: inspected.name,
|
|
1131
|
+
skillKey: inspected.skillKey,
|
|
1132
|
+
description: inspected.description || null,
|
|
1133
|
+
version: inspected.version || null,
|
|
1134
|
+
isPaid: Boolean(inspected.isPaid),
|
|
1135
|
+
requiresEntitlement: Boolean(inspected.requiresEntitlement)
|
|
1136
|
+
},
|
|
1137
|
+
creator: {
|
|
1138
|
+
cardUrl: normalizeText(registry.creatorCardUrl || registry.creatorProfile?.cardUrl, 800) || null
|
|
1139
|
+
},
|
|
1140
|
+
safety: {
|
|
1141
|
+
localRegistryStateIncluded: false,
|
|
1142
|
+
credentialsIncluded: false,
|
|
1143
|
+
signingMaterialIncluded: false
|
|
1144
|
+
}
|
|
1145
|
+
};
|
|
1146
|
+
await mkdir(path.dirname(outputPath), { recursive: true });
|
|
1147
|
+
await writeFile(outputPath, `${JSON.stringify(manifest, null, 2)}\n`, { mode: 0o644 });
|
|
1148
|
+
return { outputPath, manifest };
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1117
1151
|
async function walkXiashePackageFiles(root, current = root, out = []) {
|
|
1118
1152
|
const entries = await readdir(current, { withFileTypes: true });
|
|
1119
1153
|
for (const entry of entries) {
|
|
@@ -1218,8 +1252,9 @@ async function createTarGz(files) {
|
|
|
1218
1252
|
|
|
1219
1253
|
async function buildXiashePackageArtifact(root, inspected, flags = {}) {
|
|
1220
1254
|
const absoluteRoot = path.resolve(root || '.');
|
|
1255
|
+
await writePublicPackageManifest(absoluteRoot, inspected);
|
|
1221
1256
|
const files = await walkXiashePackageFiles(absoluteRoot);
|
|
1222
|
-
const manifestRelative =
|
|
1257
|
+
const manifestRelative = publicPackageManifestRelativePath();
|
|
1223
1258
|
const skillMarkdownPresent = files.some((file) => /^SKILL(\.[a-z0-9]+)?$/i.test(file.relative));
|
|
1224
1259
|
const manifestPresent = files.some((file) => file.relative === manifestRelative);
|
|
1225
1260
|
if (!skillMarkdownPresent) {
|
|
@@ -1639,10 +1674,10 @@ async function writeManifest(root, flags) {
|
|
|
1639
1674
|
|
|
1640
1675
|
function hubInstruction(hub) {
|
|
1641
1676
|
if (hub === 'agentpie') {
|
|
1642
|
-
return 'AgentPie Registry publish is the full Skill package
|
|
1677
|
+
return 'AgentPie Registry publish is the full Skill package flow. The local registry manifest stays on the creator device; the installable package contains only the generated no-secret package manifest. Keep public disclosure, attribution, and runtime analytics callbacks; if a creator-authenticated CLI/API session exists, create or reuse the AgentPie registry draft.';
|
|
1643
1678
|
}
|
|
1644
1679
|
if (hub === 'xiashe') {
|
|
1645
|
-
return '虾舍商店发布是完整 Skill
|
|
1680
|
+
return '虾舍商店发布是完整 Skill 包的主流程。本地 registry manifest 仅保留在创作者设备;安装包只包含自动生成的不含敏感信息的 package manifest。请保留公开披露、归因和 runtime analytics 回传能力;如果已有创作者认证 CLI/API 会话,就创建或复用虾舍商店草稿。';
|
|
1646
1681
|
}
|
|
1647
1682
|
if (hub === 'red') {
|
|
1648
1683
|
return `Red Skill 的官方 uploader.md / skillhub-upload / 页面流程是主流程。请优先使用本机 skillhub-upload;${PRODUCT_NAME} 负责生成平台安全披露、connector/运行时协议和本地 registry handoff,并把 registry id、public token、endpoint 等后台字段保留在本地私有配置或平台私有字段里。`;
|
|
@@ -1716,16 +1751,16 @@ function uploadCompatibilityLines(hub, manifestFile, protectedPaidSkill = false)
|
|
|
1716
1751
|
if (hub === 'agentpie') {
|
|
1717
1752
|
return [
|
|
1718
1753
|
'AgentPie Registry compatibility requirements:',
|
|
1719
|
-
`- AgentPie Registry
|
|
1720
|
-
'- Keep public disclosure text, attribution links, and runtime event callbacks; do not remove the
|
|
1754
|
+
`- AgentPie Registry receives the complete Skill package. Keep ${localManifest} on the creator device; it is not an installable-package file.`,
|
|
1755
|
+
'- Keep public disclosure text, attribution links, and runtime event callbacks; do not remove the generated public protocol files.',
|
|
1721
1756
|
'- Before submitting a draft, still exclude .env, keys, node_modules, dist/build, and unrelated local files.'
|
|
1722
1757
|
];
|
|
1723
1758
|
}
|
|
1724
1759
|
if (hub === 'xiashe') {
|
|
1725
1760
|
return [
|
|
1726
1761
|
'虾舍商店兼容性要求:',
|
|
1727
|
-
`-
|
|
1728
|
-
'- 保留公开披露文本、归因链接和 runtime event callback
|
|
1762
|
+
`- 虾舍商店接收完整 Skill 包;${localManifest} 仅保留在创作者设备,不属于安装包。`,
|
|
1763
|
+
'- 保留公开披露文本、归因链接和 runtime event callback;不要删除生成的公开协议文件。',
|
|
1729
1764
|
'- 提交草稿前仍需排除 .env、密钥、node_modules、dist/build 和无关本地文件。'
|
|
1730
1765
|
];
|
|
1731
1766
|
}
|