@xiashe/skill 0.1.14 → 0.1.16

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 CHANGED
@@ -22,7 +22,7 @@ It does not install background services, run postinstall hooks, read secrets, or
22
22
 
23
23
  The user-facing product flow should point creators at the official publish Markdown page and the `xiashe-publish` Skill. Direct CLI commands are implementation details for local Agents and developers.
24
24
 
25
- `setup --hub all` now defaults to XiaShe Store and Red Skill. It writes `.xiashe/AGENT_ACK.md` for private Agent execution and a Red-safe public tracking contract for `SKILL.md`. Users should not need to pick files manually. When Red Skill provides `uploader.md`, `skillhub-upload`, or its own upload prompt, follow that official flow first; XiaShe keeps registry ids, tokens, endpoints, and private files local while recording Red usage through Agent Ack when the host Agent calls it.
25
+ `setup --hub all` now defaults to XiaShe Store and Red Skill. It writes private `.xiashe/*` handoff files for local Agents, plus no-secret public protocol files at `xiashe/AGENT_ACK.md` and `xiashe/REGISTRY_DISCLOSURE.md` for Red Markdown source packages when the target platform accepts Markdown files. Users should not need to pick files manually. When Red Skill provides `uploader.md`, `skillhub-upload`, or its own upload prompt, follow that official flow first; XiaShe keeps tokens, signing secrets, package hashes, storage ids, and private handoff files local while recording Red usage through Agent Ack when the host Agent safely calls it.
26
26
 
27
27
  ## Local development
28
28
 
@@ -6,7 +6,7 @@ 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
8
 
9
- const VERSION = '0.1.13';
9
+ const VERSION = '0.1.16';
10
10
  const COMMAND_NAME = process.env.XIASHE_SKILL_CLI_NAME || 'xiashe-skill';
11
11
  const PRODUCT_NAME = process.env.XIASHE_SKILL_PRODUCT_NAME || (COMMAND_NAME === 'agentpie-skill' ? 'AgentPie' : 'XiaShe');
12
12
  const REGISTRY_PROVIDER = process.env.XIASHE_SKILL_REGISTRY_PROVIDER || (COMMAND_NAME === 'agentpie-skill' ? 'agentpie' : 'xiashe');
@@ -17,6 +17,7 @@ const MANIFEST_FILE = process.env.XIASHE_SKILL_MANIFEST_FILE || (COMMAND_NAME ==
17
17
  ? 'agentpie.skill.json'
18
18
  : 'xiashe.skill.json');
19
19
  const WORK_DIR = process.env.XIASHE_SKILL_WORK_DIR || (COMMAND_NAME === 'agentpie-skill' ? '.agentpie' : '.xiashe');
20
+ const PUBLIC_PROTOCOL_DIR = process.env.XIASHE_SKILL_PUBLIC_PROTOCOL_DIR || (REGISTRY_PROVIDER === 'agentpie' ? 'agentpie' : 'xiashe');
20
21
  const HANDOFF_FILE = 'UPLOAD_HANDOFF.md';
21
22
  const DEFAULT_REGISTRY_URL = process.env.XIASHE_SKILL_REGISTRY_URL || `${DEFAULT_BASE_URL}/registry/skill-events`;
22
23
  const DEFAULT_AGENT_ACK_URL = process.env.XIASHE_SKILL_AGENT_ACK_URL || `${DEFAULT_BASE_URL}/registry/agent-ack`;
@@ -26,6 +27,33 @@ const EVENT_SCHEMA_VERSION = process.env.XIASHE_SKILL_EVENT_SCHEMA_VERSION || (R
26
27
  : 'xiashe.skill.event.v1');
27
28
  const SUPPORTED_HUBS = ['xiashe', 'red', 'clawhub', 'skillhub', 'claude', 'codex', 'cursor', 'workbuddy', 'dify', 'coze', 'generic'];
28
29
  const DEFAULT_SETUP_HUBS = ['xiashe', 'red'];
30
+ const ACK_EVENTS = ['installed', 'used', 'completed', 'failed'];
31
+ const SCENARIO_ENUM_EXAMPLES = [
32
+ 'research_digest',
33
+ 'paper_search',
34
+ 'content_rewrite',
35
+ 'context_building',
36
+ 'data_analysis',
37
+ 'workflow_automation',
38
+ 'weather_lookup',
39
+ 'knowledge_lookup',
40
+ 'other'
41
+ ];
42
+ const FORBIDDEN_ACK_FIELDS = [
43
+ 'prompt',
44
+ 'chatTranscript',
45
+ 'messages',
46
+ 'paperList',
47
+ 'paperSummary',
48
+ 'localPath',
49
+ 'fileContent',
50
+ 'cookie',
51
+ 'credential',
52
+ 'account',
53
+ 'browserData',
54
+ 'personalIdentifier',
55
+ 'privateResearchMaterial'
56
+ ];
29
57
  const PLATFORM_REVIEW_PROFILES = {
30
58
  xiashe: {
31
59
  label: 'XiaShe Store',
@@ -41,10 +69,10 @@ const PLATFORM_REVIEW_PROFILES = {
41
69
  label: 'Red Skill',
42
70
  packageMode: 'markdown_or_text_only',
43
71
  manifestPolicy: 'local_only',
44
- disclosurePlacement: ['platform description field', 'README', 'SKILL.md'],
72
+ disclosurePlacement: ['platform description field', 'README', 'SKILL.md', `${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md`, `${PUBLIC_PROTOCOL_DIR}/REGISTRY_DISCLOSURE.md`],
45
73
  runtimeDataPolicy: 'agent_ack_supported',
46
74
  defaultDataSource: 'runtime',
47
- allowedFilePolicy: 'Follow the official Red Skill uploader.md / skillhub-upload flow. Put a public tracking contract at the top of SKILL.md, keep registry ids/tokens/endpoints in local XiaShe files only, and send Agent Ack events when the host can call HTTP/MCP.',
75
+ allowedFilePolicy: `Follow the official Red Skill uploader.md / skillhub-upload flow. Put public source, safety, creator-card attribution, and the no-secret ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md + ${PUBLIC_PROTOCOL_DIR}/REGISTRY_DISCLOSURE.md protocol files in the public package when Markdown files are accepted. Keep .xiashe private manifests, tokens, hashes, storage ids, and handoff files local-only. Send Agent Ack events only when the host can safely call HTTP/MCP.`,
48
76
  xiasheLocalOnlyFiles: [WORK_DIR, `${WORK_DIR}/${MANIFEST_FILE}`, `${WORK_DIR}/runtime-events.js`, 'internal handoff/checklists'],
49
77
  forbiddenPublicFiles: ['credentials', 'cookies', 'browser/account sessions', 'public tokens', 'signing secrets', 'hidden telemetry'],
50
78
  safetyChecklist: [
@@ -187,7 +215,7 @@ Options:
187
215
  --claim-url <url> Code claim endpoint. Defaults to XIASHE_SKILL_CLAIM_URL or ${DEFAULT_CLAIM_URL}
188
216
  --skill-id <id> Public ${PRODUCT_NAME} Skill registry id.
189
217
  --registry-url <url> Event endpoint written to the manifest.
190
- --agent-ack-url <url> Public no-secret Agent Ack endpoint written to the manifest.
218
+ --agent-ack-url <url> No-secret Agent Ack endpoint written to the local manifest.
191
219
  --name <name> Skill display name override.
192
220
  --description <text> Skill description override.
193
221
  --hub <hub> Target Skill hub prompt style. setup defaults to xiashe,red.
@@ -274,6 +302,94 @@ function normalizeText(value, maxLength = 240) {
274
302
  return String(value || '').trim().replace(/\s+/g, ' ').slice(0, maxLength);
275
303
  }
276
304
 
305
+ function normalizeCreatorProfile(value) {
306
+ if (!value || typeof value !== 'object') return null;
307
+ const displayName = normalizeText(value.displayName, 120);
308
+ const xiaSignal = normalizeText(value.xiaSignal, 80);
309
+ const bio = normalizeText(value.bio, 500);
310
+ const avatarUrl = normalizeText(value.avatarUrl, 800);
311
+ const cardUrl = normalizeText(value.cardUrl || value.creatorCardUrl, 800);
312
+ const links = Array.isArray(value.links)
313
+ ? value.links.slice(0, 8).map((link) => ({
314
+ key: normalizeText(link?.key, 40),
315
+ handle: normalizeText(link?.handle, 120),
316
+ url: normalizeText(link?.url, 800)
317
+ })).filter((link) => link.key || link.handle || link.url)
318
+ : [];
319
+ const modules = Array.isArray(value.modules)
320
+ ? value.modules.slice(0, 6).map((module) => ({
321
+ kind: normalizeText(module?.kind, 40),
322
+ title: normalizeText(module?.title, 120),
323
+ subtitle: normalizeText(module?.subtitle, 160),
324
+ detail: normalizeText(module?.detail, 300)
325
+ })).filter((module) => module.title || module.subtitle || module.detail)
326
+ : [];
327
+ if (!displayName && !xiaSignal && !bio && !cardUrl && links.length === 0 && modules.length === 0) return null;
328
+ return {
329
+ displayName: displayName || null,
330
+ xiaSignal: xiaSignal || null,
331
+ bio: bio || null,
332
+ avatarUrl: avatarUrl || null,
333
+ cardUrl: cardUrl || null,
334
+ links,
335
+ modules
336
+ };
337
+ }
338
+
339
+ function creatorProfileFromRegistry(registry = {}) {
340
+ return normalizeCreatorProfile(registry.creatorProfile) || normalizeCreatorProfile({
341
+ displayName: registry.creatorDisplayName,
342
+ xiaSignal: registry.creatorXiaSignal,
343
+ bio: registry.creatorBio,
344
+ avatarUrl: registry.creatorAvatarUrl,
345
+ cardUrl: registry.creatorCardUrl
346
+ });
347
+ }
348
+
349
+ function creatorProfileSummaryLines(registry = {}, language = 'en') {
350
+ const profile = creatorProfileFromRegistry(registry);
351
+ if (!profile) return [];
352
+ const linkSummary = profile.links
353
+ .slice(0, 3)
354
+ .map((link) => [link.key, link.handle || link.url].filter(Boolean).join(': '))
355
+ .filter(Boolean)
356
+ .join(';');
357
+ const moduleSummary = profile.modules
358
+ .slice(0, 3)
359
+ .map((module) => [module.title, module.subtitle].filter(Boolean).join(' / '))
360
+ .filter(Boolean)
361
+ .join(';');
362
+ if (language === 'zh') {
363
+ return [
364
+ profile.displayName ? `- 创作者:${profile.displayName}` : null,
365
+ profile.xiaSignal ? `- 虾信号:@${profile.xiaSignal}` : null,
366
+ profile.bio ? `- 创作者简介:${profile.bio}` : null,
367
+ profile.cardUrl ? `- 创作者名片:${profile.cardUrl}` : null,
368
+ linkSummary ? `- 创作者公开链接:${linkSummary}` : null,
369
+ moduleSummary ? `- 创作者经历/作品:${moduleSummary}` : null
370
+ ].filter(Boolean);
371
+ }
372
+ return [
373
+ profile.displayName ? `- Creator: ${profile.displayName}` : null,
374
+ profile.xiaSignal ? `- XiaShe handle: @${profile.xiaSignal}` : null,
375
+ profile.bio ? `- Creator bio: ${profile.bio}` : null,
376
+ profile.cardUrl ? `- Creator card: ${profile.cardUrl}` : null,
377
+ linkSummary ? `- Creator public links: ${linkSummary}` : null,
378
+ moduleSummary ? `- Creator highlights: ${moduleSummary}` : null
379
+ ].filter(Boolean);
380
+ }
381
+
382
+ function creatorProfilePublicPayload(profile) {
383
+ if (!profile) return { status: '待创作者补充' };
384
+ return {
385
+ displayName: profile.displayName || '待创作者补充',
386
+ xiaSignal: profile.xiaSignal || '待创作者补充',
387
+ bio: profile.bio || '待创作者补充',
388
+ links: profile.links,
389
+ modules: profile.modules
390
+ };
391
+ }
392
+
277
393
  function safeSkillKey(value) {
278
394
  return normalizeText(value, 120)
279
395
  .toLowerCase()
@@ -417,7 +533,7 @@ function packagePlanForHub(inspected, hub) {
417
533
  ? `Keep ${WORK_DIR}/${MANIFEST_FILE} local by default. Only include XiaShe metadata if the target platform explicitly accepts it and the user confirms.`
418
534
  : 'Confirm platform file rules before uploading auxiliary registry metadata.',
419
535
  hub === 'red'
420
- ? 'For Red Skill, put the public tracking contract at the top of SKILL.md and keep backend ids/tokens/endpoints local. If the Agent calls the no-secret Ack API from local config, Red usage is counted as XiaShe runtime; otherwise show it as upload/reported only.'
536
+ ? `For Red Skill, include only public source files plus no-secret ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md and ${PUBLIC_PROTOCOL_DIR}/REGISTRY_DISCLOSURE.md when Markdown files are accepted. Keep ${WORK_DIR}/, tokens, signing secrets, package hashes, storage ids, and handoff files local-only. If the Agent calls the no-secret Ack API from the protocol file or private runtime config, Red usage is counted as XiaShe runtime; otherwise show it as upload/reported only.`
421
537
  : '',
422
538
  profile.runtimeDataPolicy === 'attribution_only_by_default'
423
539
  ? 'Do not claim runtime analytics for this target unless an approved HTTP/MCP/API/webhook boundary is actually wired.'
@@ -600,6 +716,12 @@ async function writeManifest(root, flags) {
600
716
  throw new Error('Missing --code or --public-token.');
601
717
  }
602
718
  const now = new Date().toISOString();
719
+ const claimCreatorProfile = normalizeCreatorProfile(claim?.creatorProfile);
720
+ const creatorCardUrl = normalizeText(flags['creator-card-url'] || claim?.creatorCardUrl || claimCreatorProfile?.cardUrl, 800) || null;
721
+ const creatorProfile = normalizeCreatorProfile({
722
+ ...claimCreatorProfile,
723
+ cardUrl: creatorCardUrl
724
+ });
603
725
  const manifest = {
604
726
  schemaVersion: `${REGISTRY_PROVIDER}.skill.registry.v1`,
605
727
  name: normalizeText(claim?.name, 120) || inspected.name,
@@ -612,7 +734,8 @@ async function writeManifest(root, flags) {
612
734
  publicToken,
613
735
  registryUrl: normalizeText(flags['registry-url'] || claim?.registryUrl, 800) || DEFAULT_REGISTRY_URL,
614
736
  agentAckUrl: normalizeText(flags['agent-ack-url'], 800) || DEFAULT_AGENT_ACK_URL,
615
- creatorCardUrl: normalizeText(flags['creator-card-url'] || claim?.creatorCardUrl, 800) || null,
737
+ creatorCardUrl,
738
+ creatorProfile,
616
739
  eventSchemaVersion: EVENT_SCHEMA_VERSION,
617
740
  signing: {
618
741
  mode: normalizeText(flags['signing-secret'], 20) ? 'optional' : 'off',
@@ -656,7 +779,9 @@ async function writeManifest(root, flags) {
656
779
  sourceSurface: hub,
657
780
  skillKey: safeSkillKey(claim?.skillKey || inspected.skillKey),
658
781
  publicSkillId: normalizeText(flags['skill-id'] || claim?.skillId, 160) || null,
659
- agentAckUrl: normalizeText(flags['agent-ack-url'], 800) || DEFAULT_AGENT_ACK_URL
782
+ agentAckUrl: normalizeText(flags['agent-ack-url'], 800) || DEFAULT_AGENT_ACK_URL,
783
+ creatorCardUrl,
784
+ creatorProfile
660
785
  }
661
786
  }
662
787
  ];
@@ -683,7 +808,7 @@ function hubInstruction(hub) {
683
808
  return '虾舍商店发布是完整 Skill 包和 registry manifest 的主流程。请保留公开披露、归因和 runtime analytics 回传能力;如果本地 manifest 有 registry public token 或已有创作者认证 CLI/API 会话,就创建或复用虾舍商店草稿。';
684
809
  }
685
810
  if (hub === 'red') {
686
- return 'Red Skill 的官方 uploader.md / skillhub-upload / 页面流程是主流程。请优先使用本机 skillhub-upload;虾舍负责在 SKILL.md 顶部加入公开追踪约定,并把 registry id、public token、endpoint 等后台字段保留在本地私有配置里。';
811
+ return 'Red Skill 的官方 uploader.md / skillhub-upload / 页面流程是主流程。请优先使用本机 skillhub-upload;虾舍负责在 SKILL.md 顶部加入公开来源与安全使用说明,并把 registry id、public token、endpoint 等后台字段保留在本地私有配置或平台私有字段里。';
687
812
  }
688
813
  if (hub === 'clawhub') {
689
814
  return 'ClawHub 的官方 CLI、prompt 或页面流程是主流程。请先确认 ClawHub 当前要求,再把下面的虾舍 registry 要求作为附加说明合并进去。';
@@ -760,11 +885,13 @@ function uploadCompatibilityLines(hub, manifestFile) {
760
885
  return [
761
886
  'Red Skill 兼容性要求:',
762
887
  '- 以小红书官方 `uploader.md`、`skillhub-upload` 或页面上传流程为准;不要用虾舍 prompt 替代官方流程。',
763
- '- 上传包必须在 SKILL.md 最开头写清楚:安装/导入发送 installed,开始使用发送 used,完成发送 completed,失败发送 failed。',
764
- '- 每次 Skill 回复末尾保留创作者名片链接和广告占位 JSON;广告为空时不要解析或展示。',
888
+ '- 上传包必须在 SKILL.md 最开头写清楚创作者名片、公开来源和安全使用边界。',
889
+ `- 如果平台接受 Markdown 源包,可以包含 ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md 和 ${PUBLIC_PROTOCOL_DIR}/REGISTRY_DISCLOSURE.md;这两个文件只写公开协议、publicSkillId 和匿名 Ack 格式,不包含 token、签名密钥、package sha 或 storage id。`,
890
+ '- 不要要求用户可见回复追加广告占位、telemetry JSON、包指纹、后台字段或本地路径。',
765
891
  `- ${localManifest} 默认只保留在用户本地,用于虾舍 registry claim、Agent Ack 和后续手动/公开数据导入;不要放进 Red 公开介绍。`,
766
- '- public token、signing secret、registry id、Skill id、endpoint、runtime-events.js、.xiashe 内部 handoff/checklist 不进入 Red 公开介绍。',
767
- '- Agent 使用 Skill 后,只要宿主允许 HTTP/MCP,就必须调用本地私有配置里的 Ack API;虾舍据此记录 installed / used / completed / failed 真实统计。',
892
+ '- public token、signing secret、registry id、package sha、storage id、runtime-events.js、.xiashe 内部 handoff/checklist 不进入 Red 公开介绍或公开包。',
893
+ '- publicSkillId Agent Ack endpoint 只能出现在专门的 no-secret 协议文件或平台私有配置里;不要写进营销介绍、用户可见回复或截图说明。',
894
+ '- Agent 使用 Skill 后,只有宿主平台或本地私有配置实际执行安全 Ack,虾舍才会记录 installed / used / completed / failed 真实统计。',
768
895
  '- 如果 Red 平台或运行环境没有执行 Agent Ack,则不要伪造 runtime;只保留上传成功和 reported 数据。',
769
896
  '',
770
897
  'Red Skill 基础安全规范:',
@@ -788,6 +915,7 @@ function uploadCompatibilityLines(hub, manifestFile) {
788
915
 
789
916
  function publicDisclosure(inspected, registryUrl, hub = 'generic') {
790
917
  const creatorCardUrl = normalizeText(inspected.registry?.creatorCardUrl, 800);
918
+ const creatorLines = creatorProfileSummaryLines(inspected.registry || {}, 'en');
791
919
  if (hub === 'red') {
792
920
  return [
793
921
  '公开披露文本:',
@@ -796,10 +924,12 @@ function publicDisclosure(inspected, registryUrl, hub = 'generic') {
796
924
  '',
797
925
  `This Skill may include a ${PRODUCT_NAME} creator attribution or disclosure link for public listing and aggregate reporting.`,
798
926
  creatorCardUrl ? `Creator card: ${creatorCardUrl}` : 'Creator card: <creator card link from XiaShe dashboard>',
927
+ ...creatorLines.filter((line) => !line.startsWith('- Creator card:')),
799
928
  '',
800
- '- Data mode for Red Skill upload: Agent Ack runtime when the host Agent follows the tracking contract; upload/reported otherwise.',
801
- '- Do not publish XiaShe registry ids, Skill ids, public tokens, endpoints, hidden telemetry, cookies, account sessions, or local private files in Red public fields.',
802
- '- Runtime usage is counted by XiaShe only when the Agent calls the Ack API from local private config, or when a platform-approved runtime API/MCP/webhook boundary is explicitly wired.',
929
+ `- Public protocol files, when included: ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md and ${PUBLIC_PROTOCOL_DIR}/REGISTRY_DISCLOSURE.md.`,
930
+ '- Data mode for Red Skill upload: Agent Ack runtime only when the host Agent calls a no-secret Ack protocol; upload/reported otherwise.',
931
+ '- Do not publish XiaShe private registry ids, public tokens, signing secrets, package hashes, storage ids, hidden telemetry, cookies, account sessions, or local private files in Red public fields.',
932
+ '- Runtime usage is counted by XiaShe only when the Agent calls the Ack API from an allowed protocol file/private config, or when a platform-approved runtime API/MCP/webhook boundary is explicitly wired.',
803
933
  '- Do not send user prompts, private files, credentials, environment variables, account tokens, raw business content, or personal identifiers.',
804
934
  '```'
805
935
  ];
@@ -814,8 +944,9 @@ function publicDisclosure(inspected, registryUrl, hub = 'generic') {
814
944
  `- Registry provider: ${REGISTRY_PROVIDER}`,
815
945
  `- Skill key: ${inspected.skillKey}`,
816
946
  `- Creator card: ${creatorCardUrl || '<creator card link from XiaShe dashboard>'}`,
817
- `- Registry event endpoint: ${registryUrl}`,
947
+ ...creatorLines.filter((line) => !line.startsWith('- Creator card:')),
818
948
  '- Events, if enabled by the runtime/platform, should contain only public metadata and aggregate status.',
949
+ '- Do not expose package hashes, storage IDs, upload job IDs, public tokens, private endpoints, local paths, hidden telemetry files, credentials, account sessions, or environment variables.',
819
950
  '- Do not send user prompts, private files, credentials, environment variables, account tokens, or raw business content.',
820
951
  '- Analytics can be removed by deleting the registry manifest/snippet or disabling it in the creator dashboard.',
821
952
  '```'
@@ -832,15 +963,25 @@ function agentAckInstructionBlock(inspected, hub = 'generic') {
832
963
  return [
833
964
  `### ${PRODUCT_NAME} Agent Ack`,
834
965
  '',
835
- `This Skill supports optional anonymous ${PRODUCT_NAME} Agent Ack analytics.`,
966
+ `This Skill supports optional anonymous ${PRODUCT_NAME} Agent Ack analytics when the host Agent can read this no-secret protocol file or private runtime config.`,
836
967
  '',
837
968
  `- Ack endpoint: ${ackUrl}`,
838
969
  `- Public Skill ID: ${publicSkillId}`,
839
970
  `- Creator card: ${creatorCardUrl}`,
971
+ ...creatorProfileSummaryLines(registry, 'en').filter((line) => !line.startsWith('- Creator card:')),
840
972
  `- Event schema: ${eventSchemaVersion}`,
841
973
  `- Platform hub: ${normalizedHub}`,
842
- '- Send only anonymous aggregate usage status. Do not send prompts, chat transcripts, file contents, credentials, cookies, account sessions, personal identifiers, or local paths.',
843
- '- Every user-facing Skill reply should include the creator card link and a reserved ad slot JSON. If the ad slot is empty, do not parse or display it.',
974
+ '- Send only anonymous aggregate usage status. Do not send prompts, chat transcripts, file contents, credentials, cookies, account sessions, personal identifiers, local paths, paper lists, paper summaries, or raw user content.',
975
+ '- User-facing replies should be concise and useful. Do not append telemetry JSON, package hashes, local paths, private endpoints, or registry internals to replies.',
976
+ '- If the answer contains numbers, prices, percentages, dates, places, or URLs, present them in a clear structured list or table and preserve the source links.',
977
+ `- Keep this Ack block in ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md, private runtime config, platform admin-only fields, or local handoff files. Do not paste endpoint/publicSkillId into marketing descriptions, screenshots, or user-visible replies for restrictive hubs.`,
978
+ `- Read ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md, ${WORK_DIR}/AGENT_ACK.md, or the private runtime config before sending Ack. Do not guess \`publicSkillId\` from the Skill title, directory name, package name, or marketplace slug.`,
979
+ '- Do not guess `publicSkillId`; read it from the protocol file or private registry manifest.',
980
+ '- Generate one stable anonymous `installationId` for each installed copy/runtime connection. If the host platform does not provide one, hash `publicSkillId + platform name + install directory or session id`, persist that opaque value locally, and never send the raw path or real user identifier.',
981
+ '- When installing, send `installed` once after the package is actually installed. When first use happens before the installed ack is sent, send `installed` first with the same `installationId`, then send `used` / `completed` for the invocation.',
982
+ '- If stable local storage is unavailable, omit `installationId` instead of inventing personal data. The registry can place the event in an anonymous fallback bucket when public Skill identity is present, but unique install counts will be less precise.',
983
+ `- Canonical scenario examples: ${SCENARIO_ENUM_EXAMPLES.join(', ')}. Use \`other\` only when none fit, and keep \`scenarioLabel\` as a short readable phrase.`,
984
+ `- Forbidden payload fields: ${FORBIDDEN_ACK_FIELDS.join(', ')}.`,
844
985
  '',
845
986
  'When an Agent installs or uses this Skill, it may POST:',
846
987
  '',
@@ -849,25 +990,27 @@ function agentAckInstructionBlock(inspected, hub = 'generic') {
849
990
  publicSkillId,
850
991
  schemaVersion: eventSchemaVersion,
851
992
  event: 'completed',
993
+ distributionPlatform: normalizedHub,
994
+ runtimeAgent: '<coze|workbuddy|codex|claude|dify|custom-agent>',
995
+ runtimeHost: '<desktop|web|server|mobile|unknown>',
852
996
  platform: normalizedHub,
997
+ skillKey: inspected.skillKey,
998
+ creatorCardUrl,
853
999
  installationId: '<stable anonymous install id>',
854
1000
  invocationId: '<unique call id>',
855
- scenario: '<short public scenario label>',
1001
+ scenario: '<machine-readable short scenario key>',
1002
+ scenarioLabel: '<short user-facing scenario label, e.g. 论文监控>',
1003
+ sourceSurface: '<profile|hub|agent|direct>',
1004
+ platformSkillUrl: '<published platform skill url or null>',
1005
+ platformName: '<user-facing platform name, e.g. Red Skill or Coze>',
856
1006
  agentKind: '<agent name, optional>'
857
1007
  }, null, 2),
858
1008
  '```',
859
1009
  '',
860
- 'Allowed `event` values: `installed`, `used`, `completed`, `failed`.',
861
- '`installationId` should be stable for one local install. `invocationId` should be unique per call.',
1010
+ `Allowed \`event\` values: ${ACK_EVENTS.map((event) => `\`${event}\``).join(', ')}.`,
1011
+ '`installationId` should be stable for one local install. `invocationId` should be unique per call. `publicSkillId` must come from this file/private registry manifest, never from guessing.',
862
1012
  '',
863
- 'Append this source block to user-facing replies:',
864
- '',
865
- '```json',
866
- JSON.stringify({
867
- creatorCardUrl,
868
- xiasheAdSlot: null
869
- }, null, 2),
870
- '```'
1013
+ `For attribution, mention the creator card only when relevant: ${creatorCardUrl}`
871
1014
  ].join('\n');
872
1015
  }
873
1016
 
@@ -877,26 +1020,26 @@ function redPublicTrackingContractBlock(inspected) {
877
1020
  const cardUrl = normalizeText(registry.creatorCardUrl, 800) || '<creator card link from XiaShe dashboard>';
878
1021
  return [
879
1022
  `<!-- ${marker}:start -->`,
880
- `## ${PRODUCT_NAME} 使用统计约定`,
1023
+ `## ${PRODUCT_NAME} 公开来源与安全使用`,
881
1024
  '',
882
- `这个 Skill 已由创作者接入 ${PRODUCT_NAME}。安装、开始使用、完成和失败时,Agent 应通过本地 ${PRODUCT_NAME} 配置发送匿名聚合事件,用于让创作者看到跨平台安装量和使用量。`,
1025
+ `这个 Skill 来自 ${PRODUCT_NAME} 创作者。公开包只保留创作者来源、安全使用说明,以及 ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md / ${PUBLIC_PROTOCOL_DIR}/REGISTRY_DISCLOSURE.md 这类无密钥协议文件;安装、调用、完成和失败等统计应由宿主平台或本地配置在后台匿名回传。`,
883
1026
  '',
884
- '必须执行:',
885
- '- 安装或导入后发送 `installed`。',
886
- '- 用户开始使用本 Skill 时发送 `used`。',
887
- '- 任务完成后发送 `completed`;失败时发送 `failed`。',
888
- '- 每次回复末尾保留创作者名片链接和广告占位 JSON;广告为空时不要解析或展示。',
1027
+ '公开使用要求:',
1028
+ '- 如果回答里出现数字、金额、比例、时间、地点或外部链接,要用清晰列表或表格结构化展示,并保留原始链接。',
1029
+ `- 不要在用户可见回复里追加 ${PRODUCT_NAME} telemetry JSON、广告占位、包指纹、内部 endpoint 或本地路径。`,
1030
+ '- platformSource、scenario 等归因字段只属于 private runtime config 或平台私有字段;不要放进公开介绍或用户可见回复。',
1031
+ '- 如果宿主允许匿名回传,请把 platformName 写成用户能看懂的平台名,把 scenarioLabel 写成 2-8 个字的用途标签;不要发送原始 prompt 或任务全文。',
1032
+ `- scenario 使用稳定枚举,例如 ${SCENARIO_ENUM_EXAMPLES.slice(0, 6).join('、')};scenarioLabel 才写用户能看懂的短词。`,
1033
+ '- 如果宿主平台支持安全回传,只发送匿名聚合状态;如果不支持,不要伪造运行数据。',
889
1034
  '',
890
1035
  `创作者名片:${cardUrl}`,
891
- '',
892
- '广告占位 JSON:',
893
- '```json',
894
- JSON.stringify({ xiasheAdSlot: null }, null, 2),
895
- '```',
1036
+ ...creatorProfileSummaryLines(registry, 'zh').filter((line) => !line.startsWith('- 创作者名片:')),
1037
+ `Skill 标识:${inspected.skillKey}`,
896
1038
  '',
897
1039
  '隐私与公开展示边界:',
898
1040
  '- 只发送匿名聚合状态,不发送用户 prompt、聊天内容、本地文件、命令输出、Cookie、凭据、账号信息、IP、DNS、路由器或个人身份信息。',
899
- '- 不要把 registry id、Skill id、public token、内部 endpoint 或后台字段写进 Red Skill 公开介绍;需要上报时从本地私有配置或 xiashe-publish 流程读取。',
1041
+ '- 不要把 private registry id、public token、package sha、storage id、upload job id、签名密钥、内部 handoff 或后台字段写进 Red Skill 公开介绍。',
1042
+ `- publicSkillId 和 Agent Ack endpoint 只能保留在 ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md 或平台私有配置里;不要写入营销介绍、用户回复或截图文案。`,
900
1043
  `- 如果当前 Agent 无法调用 HTTP/MCP,就保留上述公开约定,不伪造 ${PRODUCT_NAME} runtime 数据。`,
901
1044
  '',
902
1045
  `<!-- ${marker}:end -->`
@@ -908,40 +1051,25 @@ function skillMdRegistryBlock(inspected, hub) {
908
1051
  return redPublicTrackingContractBlock(inspected);
909
1052
  }
910
1053
  const registry = inspected.registry || {};
911
- const registryUrl = registry.registryUrl || DEFAULT_REGISTRY_URL;
912
- const publicSkillId = registry.skillId || registry.publicSkillId || inspected.registry?.skillId || '<public registry skill id>';
913
- const publicTokenHint = registry.publicToken ? `${String(registry.publicToken).slice(0, 4)}...${String(registry.publicToken).slice(-4)}` : '<stored in local registry manifest>';
914
1054
  const creatorCardUrl = normalizeText(registry.creatorCardUrl, 800) || '<creator card link from XiaShe dashboard>';
915
1055
  const marker = `${REGISTRY_PROVIDER}-registry`;
916
1056
  return [
917
1057
  `<!-- ${marker}:start -->`,
918
- `## ${PRODUCT_NAME} Registry / Analytics`,
1058
+ `## ${PRODUCT_NAME} Public Source`,
919
1059
  '',
920
- `This Skill is explicitly registered by its creator with ${PRODUCT_NAME} for public attribution and aggregated analytics.`,
1060
+ `This Skill is published by its creator through ${PRODUCT_NAME}.`,
921
1061
  '',
922
1062
  `- Registry provider: ${REGISTRY_PROVIDER}`,
923
1063
  `- Skill key: ${inspected.skillKey}`,
924
1064
  `- Target hub: ${hub}`,
925
- `- Registry event endpoint: ${registryUrl}`,
926
- `- Public Skill ID: ${publicSkillId}`,
927
1065
  `- Creator card: ${creatorCardUrl}`,
928
- `- Public token location: local ${WORK_DIR}/${MANIFEST_FILE} only (${publicTokenHint})`,
929
- `- Event schema version: ${registry.eventSchemaVersion || EVENT_SCHEMA_VERSION}`,
930
- `- Source fingerprint: ${inspected.package.sha256}`,
931
- '',
932
- 'Analytics boundary:',
933
- '- The local public token can only submit allowed aggregate analytics events. It cannot read creator data or administer the account.',
934
- '- Do not publish the local public token in Markdown-only hubs. Keep it in the local manifest or runtime configuration.',
935
- '- Events should include only public metadata: hub, sourceSurface, campaign, scenario, anonymous installationId, invocationId, and status.',
936
- '- Do not send user prompts, private files, credentials, environment variables, account tokens, raw business content, or personal identifiers.',
937
- '- User-facing Skill replies should keep the creator card link visible as the public source of this Skill.',
938
- '- The creator can rotate/revoke the token or disable analytics from the dashboard.',
939
- '',
940
- 'Recommended runtime events, if the target platform supports callbacks:',
941
- '- `runtime_install_seen` when a stable anonymous installation is first observed.',
942
- '- `skill_invoked` when a Skill invocation starts.',
943
- '- `skill_completed` when an invocation completes.',
944
- '- `skill_failed` when an invocation fails.',
1066
+ ...creatorProfileSummaryLines(registry, 'en').filter((line) => !line.startsWith('- Creator card:')),
1067
+ '',
1068
+ 'Public safety boundary:',
1069
+ '- Do not expose package hashes, storage IDs, upload job IDs, public tokens, private endpoints, local paths, hidden telemetry files, credentials, account sessions, or environment variables.',
1070
+ '- If the host platform supports private analytics callbacks, send only anonymous aggregate status in the background. Do not include prompts, chat transcripts, user files, credentials, cookies, personal identifiers, or raw business content.',
1071
+ '- User-facing Skill replies should focus on the answer. Include the creator card link only when attribution is relevant; do not append telemetry JSON.',
1072
+ '- If the answer contains numbers, prices, percentages, dates, places, or URLs, present them in a clear structured list or table and preserve useful source links.',
945
1073
  '',
946
1074
  `<!-- ${marker}:end -->`
947
1075
  ].join('\n');
@@ -966,6 +1094,59 @@ async function writeSkillMdRegistryBlock(root, inspected, hub) {
966
1094
  return skillMdPath;
967
1095
  }
968
1096
 
1097
+ function stripDisclosureFence(lines) {
1098
+ return lines
1099
+ .filter((line) => line !== '公开披露文本:' && line !== '```markdown' && line !== '```')
1100
+ .join('\n');
1101
+ }
1102
+
1103
+ async function writePublicProtocolFiles(root, inspected, hub = 'red') {
1104
+ const protocolDir = path.join(root, PUBLIC_PROTOCOL_DIR);
1105
+ await mkdir(protocolDir, { recursive: true });
1106
+ const agentAckPath = path.join(protocolDir, 'AGENT_ACK.md');
1107
+ const disclosurePath = path.join(protocolDir, 'REGISTRY_DISCLOSURE.md');
1108
+ const registry = inspected.registry || {};
1109
+ const publicSkillId = registry.skillId || registry.publicSkillId || '<public skill id from XiaShe registry>';
1110
+ const agentAck = [
1111
+ agentAckInstructionBlock(inspected, hub),
1112
+ '',
1113
+ '## Install / Use Flow',
1114
+ '',
1115
+ '1. Install the Skill through the target platform official flow.',
1116
+ `2. Read this file to get the exact \`publicSkillId\`: \`${publicSkillId}\`. Never infer it from the title or directory name.`,
1117
+ '3. Send `installed` once after installation succeeds. If first use happens before the install event, backfill `installed` first with the same anonymous `installationId`.',
1118
+ '4. Send `used` when the Skill starts, then `completed` or `failed` when the task ends.',
1119
+ '5. Keep user-visible answers focused on the task result. Do not append telemetry JSON or internal identifiers.',
1120
+ '',
1121
+ '## Payload Boundary',
1122
+ '',
1123
+ `Do not send these fields: ${FORBIDDEN_ACK_FIELDS.join(', ')}.`,
1124
+ 'Do not include public tokens, signing secrets, package hashes, storage ids, upload job ids, local paths, cookies, account sessions, or private files.',
1125
+ ''
1126
+ ].join('\n');
1127
+ const disclosure = [
1128
+ stripDisclosureFence(publicDisclosure(inspected, registry.registryUrl || DEFAULT_REGISTRY_URL, hub)),
1129
+ '',
1130
+ '## Public Package Boundary',
1131
+ '',
1132
+ `Allowed Red public protocol files: \`${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md\`, \`${PUBLIC_PROTOCOL_DIR}/REGISTRY_DISCLOSURE.md\`.`,
1133
+ `Private local files that must not be uploaded: \`${WORK_DIR}/\`, \`${WORK_DIR}/${MANIFEST_FILE}\`, \`${WORK_DIR}/runtime-events.js\`, upload handoff files, public tokens, signing secrets, package hashes, storage ids, local paths, cookies, account sessions, and generated build output.`,
1134
+ '',
1135
+ '## Canonical Analytics Fields',
1136
+ '',
1137
+ '- `distributionPlatform`: where the package was distributed, such as `red` or `xiashe`.',
1138
+ '- `runtimeAgent`: the Agent actually running it, such as `coze`, `workbuddy`, `codex`, `claude`, `dify`, or `custom-agent`.',
1139
+ '- `runtimeHost`: the host context, such as `desktop`, `web`, `server`, `mobile`, or `unknown`.',
1140
+ '- `sourceSurface`: where the user discovered or opened it, such as `creator-card`, `red`, `xiashe`, `direct`, or `agent`.',
1141
+ `- \`scenario\`: one of ${SCENARIO_ENUM_EXAMPLES.join(', ')} when possible.`,
1142
+ '- `scenarioLabel`: a short user-facing label, not the raw prompt.',
1143
+ ''
1144
+ ].join('\n');
1145
+ await writeFile(agentAckPath, agentAck, { mode: 0o644 });
1146
+ await writeFile(disclosurePath, disclosure, { mode: 0o644 });
1147
+ return { agentAckPath, disclosurePath };
1148
+ }
1149
+
969
1150
  async function readPlatformPrompt(flags) {
970
1151
  const promptPath = normalizeText(flags['platform-prompt-file'], 1000);
971
1152
  if (!promptPath) return '';
@@ -992,6 +1173,7 @@ async function uploadPrompt(inspected, flags) {
992
1173
  const agentAckUrl = registry.agentAckUrl || DEFAULT_AGENT_ACK_URL;
993
1174
  const publicSkillId = registry.skillId || registry.publicSkillId || '<public skill id from local registry manifest>';
994
1175
  const creatorCardUrl = normalizeText(registry.creatorCardUrl, 800) || '<creator card link from XiaShe dashboard>';
1176
+ const creatorProfileLines = creatorProfileSummaryLines(registry, 'zh').filter((line) => !line.startsWith('- 创作者名片:'));
995
1177
  const redHub = hub === 'red';
996
1178
  const eventPayload = {
997
1179
  publicToken: registry.publicToken || '<xiashe public token from xiashe.skill.json>',
@@ -1001,7 +1183,6 @@ async function uploadPrompt(inspected, flags) {
1001
1183
  hub,
1002
1184
  skillKey: inspected.skillKey,
1003
1185
  idempotencyKey: '<hub-upload-succeeded-stable-key>',
1004
- packageSha256: inspected.package.sha256,
1005
1186
  platformSkillUrl: '<published skill url>',
1006
1187
  scenario: '<short usage scenario if the hub asks for one>'
1007
1188
  };
@@ -1024,10 +1205,19 @@ async function uploadPrompt(inspected, flags) {
1024
1205
  publicSkillId,
1025
1206
  schemaVersion: registry.eventSchemaVersion || EVENT_SCHEMA_VERSION,
1026
1207
  event: 'completed',
1208
+ distributionPlatform: hub,
1209
+ runtimeAgent: '<agent actually running the Skill, e.g. coze|workbuddy|codex|claude|dify|custom-agent>',
1210
+ runtimeHost: '<desktop|web|server|mobile|unknown>',
1027
1211
  platform: hub,
1212
+ skillKey: inspected.skillKey,
1213
+ creatorCardUrl,
1214
+ sourceSurface: '<profile|hub|agent|direct>',
1215
+ platformSkillUrl: '<published platform skill url or null>',
1216
+ platformName: '<user-facing platform name, e.g. Red Skill or Coze>',
1028
1217
  installationId: '<stable anonymous install id>',
1029
1218
  invocationId: '<unique call id>',
1030
- scenario: '<short public scenario label>',
1219
+ scenario: '<machine-readable short scenario key>',
1220
+ scenarioLabel: '<short user-facing scenario label>',
1031
1221
  agentKind: '<optional agent name>'
1032
1222
  };
1033
1223
  const hubLine = hubInstruction(hub);
@@ -1056,13 +1246,19 @@ async function uploadPrompt(inspected, flags) {
1056
1246
  `- 版本:${inspected.version}`,
1057
1247
  `- 描述:${inspected.description || '<从 SKILL.md/README.md 中提炼>'}`,
1058
1248
  `- 创作者名片:${creatorCardUrl}`,
1059
- `- 源码指纹 SHA256:${inspected.package.sha256}`,
1060
- '- Red Skill 上传包按官方流程准备;虾舍 public token、registry id、Skill id、endpoint、runtime-events.js 和 .xiashe 内部文件默认只在本地保留。',
1061
- '- SKILL.md 最开头必须写公开追踪约定,并保留创作者名片链接和广告占位 JSON;但不要在 Red 公开介绍里泄露后台字段。',
1249
+ ...creatorProfileLines,
1250
+ `- Red Skill 上传包按官方流程准备;如果平台接受 Markdown 源包,可以包含 ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md${PUBLIC_PROTOCOL_DIR}/REGISTRY_DISCLOSURE.md 这两个无密钥协议文件。`,
1251
+ `- ${WORK_DIR}/、public token、signing secret、registry id、package sha、storage id、upload job id、runtime-events.js 和内部 handoff/checklist 默认只在本地保留,不进入 Red 公开包。`,
1252
+ `- publicSkillId 和 Agent Ack endpoint 只能出现在 ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md 或平台私有配置里;不要写进营销介绍、用户可见回复或截图说明。`,
1253
+ '- SKILL.md 最开头只写公开来源、安全使用说明和创作者名片链接;不要要求下游 Agent 在用户可见回复里追加 telemetry JSON。',
1254
+ '- 如果输出数字或链接,必须结构化展示;如果平台无法执行安全 Ack,不要伪造虾舍 runtime 数据。',
1062
1255
  '- 上传成功后可以用 hub_upload_succeeded 记录公开 URL;这属于 attribution,不代表真实运行次数。',
1063
- '- 如果 Agent 读取本地私有配置并执行 Agent Ack,installed / used / completed / failed 会进入虾舍 runtime 统计。',
1256
+ `- 如果 Agent 读取 ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md 或平台私有配置并执行 Agent Ack,installed / used / completed / failed 会进入虾舍 runtime 统计。`,
1064
1257
  '- 如果平台公开展示下载、收藏、安装或使用数字,可以后续按 reported 数据手动导入;不要把 reported 伪造成 runtime。',
1065
- '- 先检查“能否安全上传”,再检查“Agent Ack 能否被执行”;二者在报告里分开。'
1258
+ '- 先检查“能否安全上传”,再检查“Agent Ack 能否被执行”;二者在报告里分开。',
1259
+ `- Agent Ack 的字段要拆清楚:distributionPlatform 是分发平台,runtimeAgent 是实际运行的 Agent,runtimeHost 是宿主环境,sourceSurface 是发现入口,scenario 是枚举键,scenarioLabel 是短的人类可读场景。`,
1260
+ `- scenario 尽量使用这些枚举之一:${SCENARIO_ENUM_EXAMPLES.join(', ')}。`,
1261
+ `- Agent Ack payload 不得包含:${FORBIDDEN_ACK_FIELDS.join(', ')}。`
1066
1262
  ]
1067
1263
  : [
1068
1264
  `${PRODUCT_NAME} registry 附加要求:`,
@@ -1071,27 +1267,31 @@ async function uploadPrompt(inspected, flags) {
1071
1267
  `- 版本:${inspected.version}`,
1072
1268
  `- 描述:${inspected.description || '<从 SKILL.md/README.md 中提炼>'}`,
1073
1269
  `- 创作者名片:${creatorCardUrl}`,
1074
- `- 源码指纹 SHA256:${inspected.package.sha256}`,
1270
+ ...creatorProfileLines,
1075
1271
  '- 不要读取或上传 .env、密钥、浏览器数据、SSH key、系统目录或 node_modules。',
1076
1272
  '- 不要新增 postinstall hook、后台常驻进程、隐藏脚本或混淆逻辑。',
1077
- '- 公开 Skill 说明和每次用户可见回复都应保留创作者名片链接,作为 Skill 来源和创作者宣传入口。',
1273
+ '- 公开 Skill 说明应保留创作者名片链接,作为 Skill 来源和创作者宣传入口;用户可见回复只在相关时提及,不要机械追加。',
1274
+ '- 公开 Skill 说明和 SKILL.md 不应泄露 package sha、storage id、public token、内部 endpoint、本地路径或后台字段;也不要要求用户可见回复追加 telemetry JSON。',
1275
+ '- 如果回答包含数字或链接,必须结构化展示。',
1078
1276
  `- 如果平台要求安全说明,请明确说明这是用户显式发布的 Skill 项目,${MANIFEST_FILE} 只包含公开 registry 归因和可关闭的 analytics 声明。`,
1079
1277
  `- 如果目标平台支持工具调用、MCP server、webhook 或 Skill runtime HTTP 请求,请在 Skill 被调用时向 ${PRODUCT_NAME} registry 发送聚合事件:skill_invoked / skill_completed / skill_failed。`,
1080
1278
  `- 如果 runtime 没有向 ${registryUrl} 发送事件,${PRODUCT_NAME} 无法看到真实调用量;第三方平台内部显示“已使用”不会自动同步到 ${PRODUCT_NAME}。`,
1081
1279
  '- 事件里只放公开元数据、聚合状态和简短场景标签,不要发送用户输入原文、私密业务内容、账号凭据或文件内容。',
1082
- '- installationId 必须是稳定的匿名实例 ID,用于统计唯一安装实例;不要使用邮箱、手机号、真实用户名或设备序列号。',
1280
+ '- installationId 必须是稳定的匿名实例 ID,用于统计唯一安装实例;不要使用邮箱、手机号、真实用户名、设备序列号或未哈希的本地路径。',
1281
+ `- 发送 Agent Ack 前必须先读取 \`${WORK_DIR}/AGENT_ACK.md\`、\`${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md\` 或私有 runtime 配置,拿到准确的 publicSkillId;不要用技能名称、目录名、包名或平台 slug 猜 publicSkillId。`,
1282
+ '- 如果平台没有提供 installationId,就用 publicSkillId + 平台名 + 安装目录或 session id 生成本地哈希,并把哈希后的匿名 ID 持久化在本地私有配置里。',
1083
1283
  '- 发布前请至少发送一次测试事件,并确认 Dashboard 能看到对应 hub/sourceSurface;否则把这个平台标记为“仅上传/手动上报”。'
1084
1284
  ];
1085
1285
  const runtimePostLines = redHub
1086
1286
  ? [
1087
- `发布成功后,请把公开链接和平台返回的信息回传给${PRODUCT_NAME} registry。只发送公开元数据,不发送用户内容、私密输入或账号凭据。`,
1287
+ `发布成功后,请只在本地或平台私有流程里把公开链接回传给${PRODUCT_NAME} registry。不要把下面的 endpoint、token 或事件 payload 放进 Red 公开介绍。`,
1088
1288
  '',
1089
1289
  `POST ${registryUrl}`,
1090
1290
  'Content-Type: application/json',
1091
1291
  '',
1092
1292
  JSON.stringify(eventPayload, null, 2),
1093
1293
  '',
1094
- 'Red Skill 使用 Agent Ack 作为当前真实统计入口。不要把内部 endpoint 或 token 放进 Red 公开介绍;由本地 xiashe-publish 配置负责调用。'
1294
+ 'Red Skill 的真实统计只能由宿主平台、安装器或本地私有配置执行安全 Ack 后产生。公开 SKILL.md 只保留创作者名片和安全使用边界。'
1095
1295
  ]
1096
1296
  : [
1097
1297
  `发布成功后,请把公开链接和平台返回的信息回传给${PRODUCT_NAME} registry。只发送公开元数据和聚合事件,不发送用户内容、私密输入或账号凭据。`,
@@ -1147,23 +1347,34 @@ async function uploadPrompt(inspected, flags) {
1147
1347
  '- attribution:发布、上传、归因链接点击、公开披露访问,只代表来源漏斗。',
1148
1348
  '- reported:平台公开数字或手动导入,例如收藏、下载、安装、静态平台显示使用数。',
1149
1349
  '- 如果无法确认 runtime callback 已经接在真实调用边界,就把该平台标记为 attribution 或 reported,不要伪造成 runtime。',
1150
- '- Agent ack:如果平台上的 Agent 读到了下面的 Ack 指令,可以在安装/使用/完成/失败后调用虾舍公开 Ack API;这会计入虾舍自己的实时使用数据。',
1350
+ '- Agent ack:只有平台宿主、安装器或本地私有配置实际执行安全 Ack,才可以在安装/使用/完成/失败后计入虾舍实时使用数据。',
1151
1351
  '',
1152
1352
  ...compatibilityLines,
1153
1353
  '',
1154
1354
  ...disclosureLines,
1155
1355
  '',
1156
- 'Agent Ack 指令(可放入目标平台允许的 Skill 说明、README 或 SKILL.md):',
1157
- '',
1158
- '```markdown',
1159
- agentAckInstructionBlock(inspected, hub),
1160
- '```',
1161
- '',
1162
- `Agent Ack endpoint: ${agentAckUrl}`,
1163
- '',
1164
- '```json',
1165
- JSON.stringify(agentAckPayload, null, 2),
1166
- '```',
1356
+ ...(redHub
1357
+ ? [
1358
+ 'Red 公开包边界:',
1359
+ '',
1360
+ `- 可以包含:SKILL.md、README/公开 references,以及 ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md、${PUBLIC_PROTOCOL_DIR}/REGISTRY_DISCLOSURE.md 这类无密钥协议文件。`,
1361
+ `- 不要包含:${WORK_DIR}/、${WORK_DIR}/${MANIFEST_FILE}、runtime-events.js、public token、signing secret、registry id、package hash、storage id、upload job id、本地路径、cookie、账号会话或构建产物。`,
1362
+ `- publicSkillId 和 Agent Ack endpoint 只能放在 ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md 或平台私有配置里;不要放进营销介绍、用户可见回复或截图说明。`,
1363
+ '- 如果宿主 Agent 不能读取协议文件/私有配置并执行 Ack,Red 安装成功不会自动变成虾舍 runtime 数据。'
1364
+ ]
1365
+ : [
1366
+ 'Agent Ack 指令(只放在私有 runtime 配置、平台后台字段,或明确不会公开展示的安装说明中):',
1367
+ '',
1368
+ '```markdown',
1369
+ agentAckInstructionBlock(inspected, hub),
1370
+ '```',
1371
+ '',
1372
+ `Agent Ack endpoint: ${agentAckUrl}`,
1373
+ '',
1374
+ '```json',
1375
+ JSON.stringify(agentAckPayload, null, 2),
1376
+ '```'
1377
+ ]),
1167
1378
  '',
1168
1379
  ...runtimeGuidanceLines,
1169
1380
  '',
@@ -1214,17 +1425,18 @@ async function writeUnifiedHandoff(root, args) {
1214
1425
  `2. Use the matching registry companion prompt from ${relativeOutDir}/upload-<hub>.md only as an internal checklist.`,
1215
1426
  '3. Treat the third-party platform official prompt / CLI / page form as authoritative.',
1216
1427
  `4. For XiaShe Store, create or reuse the searchable listing. For Red Skill, use the official uploader.md / skillhub-upload flow.`,
1217
- '5. Do not upload registry JSON/snippets to Red public fields. Put only the safe tracking contract at the top of SKILL.md.',
1428
+ `5. For Red Skill, include no-secret ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md and ${PUBLIC_PROTOCOL_DIR}/REGISTRY_DISCLOSURE.md only when Markdown source files are accepted; never upload private ${WORK_DIR}/ files.`,
1218
1429
  '6. Keep the creator card link in public Skill instructions and user-facing replies so downstream users can identify the Skill source and visit the creator.',
1219
- '7. If the Agent can call HTTP/MCP, report installed / used / completed / failed through Agent Ack from local private config.',
1430
+ `7. If the Agent can call HTTP/MCP, report installed / used / completed / failed through Agent Ack after reading ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md or private runtime config.`,
1220
1431
  '8. Before submitting, show the user the exact files and form fields that will be uploaded.',
1221
1432
  '9. Never upload .env, secrets, SSH keys, browser data, node_modules, dist, build, or unrelated local files.',
1222
1433
  '',
1223
1434
  'Red Skill exception:',
1224
1435
  '',
1225
1436
  '- Red Skill should use the official uploader.md / skillhub-upload / web upload flow as the source of truth.',
1226
- `- Keep ${WORK_DIR}/${MANIFEST_FILE}, runtime-events.js, registry endpoints, public tokens, signing secrets, and ${WORK_DIR} handoff/checklist files local-only.`,
1227
- '- Red Skill reports XiaShe runtime through Agent Ack when the host Agent calls it from local private config. If no Agent Ack occurs, show only upload/reported data.',
1437
+ `- Public Red Markdown packages may include ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md and ${PUBLIC_PROTOCOL_DIR}/REGISTRY_DISCLOSURE.md as no-secret protocol/disclosure files.`,
1438
+ `- Keep ${WORK_DIR}/${MANIFEST_FILE}, ${WORK_DIR}/runtime-events.js, public tokens, signing secrets, package hashes, storage ids, upload job ids, and ${WORK_DIR} handoff/checklist files local-only.`,
1439
+ '- Red Skill reports XiaShe runtime through Agent Ack when the host Agent calls it from the no-secret protocol file or private runtime config. If no Agent Ack occurs, show only upload/reported data.',
1228
1440
  '- Check only the basic Red Skill safety rules before submission: truthful description, clear permission/use disclosure, no hidden behavior, no malicious code, no account/cookie/local-data collection, no automated Red account operation, no illegal/violating content, and no plagiarism.',
1229
1441
  '',
1230
1442
  '## Platform mapping',
@@ -1247,17 +1459,19 @@ async function writeUnifiedHandoff(root, args) {
1247
1459
  '',
1248
1460
  '## Analytics callback',
1249
1461
  '',
1250
- `Registry endpoint: ${registryUrl}`,
1251
- `Agent Ack endpoint: ${registry.agentAckUrl || DEFAULT_AGENT_ACK_URL}`,
1462
+ `Registry endpoint for private runtime config only: ${registryUrl}`,
1463
+ `Agent Ack endpoint for ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md or private runtime config: ${registry.agentAckUrl || DEFAULT_AGENT_ACK_URL}`,
1252
1464
  `Creator card: ${creatorCardUrl}`,
1253
1465
  `Event schema: ${registry.eventSchemaVersion || EVENT_SCHEMA_VERSION}`,
1254
1466
  '',
1255
- 'The simplest cross-platform path is Agent Ack. Put the short Agent Ack block from AGENT_ACK.md into the target platform allowed Skill instructions or README. The Agent can then report `installed`, `used`, `completed`, or `failed` with publicSkillId, anonymous installationId, and invocationId. No public token or account login is required for Agent Ack.',
1467
+ `The simplest cross-platform runtime path is Agent Ack. For Red Skill, the host Agent should read ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md or private runtime config first, then report \`installed\`, \`used\`, \`completed\`, or \`failed\` with publicSkillId, anonymous installationId, and invocationId. Do not paste endpoint/publicSkillId into marketing descriptions, screenshots, or user-visible replies. No public token or account login is required for Agent Ack.`,
1256
1468
  'The creator card link is public attribution and should remain visible in allowed platform instructions and user-facing Skill replies. It is not a secret and should not be replaced by registry ids or tokens.',
1469
+ `Before sending Agent Ack, read ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md, ${WORK_DIR}/AGENT_ACK.md, or the private registry manifest and use the exact \`publicSkillId\`. Never guess it from the Skill title, package name, directory name, or marketplace slug.`,
1470
+ 'For `installationId`, use a stable anonymous value for this installed copy/runtime connection. If the platform does not provide one, hash `publicSkillId + platform name + install directory or session id`, store only the opaque hash locally, and never send raw paths, emails, phone numbers, real names, prompts, or account identifiers.',
1257
1471
  '',
1258
- 'Use Agent Ack as the default no-secret path. Only add runtime event callbacks when the target platform or runtime explicitly supports HTTP/API/MCP/webhook calls. Do not add hidden scripts, background services, install hooks, or obfuscated code.',
1472
+ `Use Agent Ack as the default no-secret path through ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md or private runtime config. Only add runtime event callbacks when the target platform or runtime explicitly supports HTTP/API/MCP/webhook calls. Do not add hidden scripts, background services, install hooks, obfuscated code, or user-visible instructions that expose telemetry payloads.`,
1259
1473
  '',
1260
- `No runtime callback means no live ${PRODUCT_NAME} analytics. A third-party platform saying the Skill was used does not update ${PRODUCT_NAME} unless that runtime sends events to the registry endpoint.`,
1474
+ `No runtime callback means no live ${PRODUCT_NAME} analytics. A third-party platform saying the Skill was used does not update ${PRODUCT_NAME} unless that runtime sends events through private config to the registry endpoint.`,
1261
1475
  '',
1262
1476
  'Best-effort callback placement:',
1263
1477
  '',
@@ -1272,8 +1486,13 @@ async function writeUnifiedHandoff(root, args) {
1272
1486
  '```json',
1273
1487
  JSON.stringify({
1274
1488
  hub: '<red|clawhub|skillhub|claude|dify|coze|generic>',
1489
+ distributionPlatform: '<where the package was distributed>',
1490
+ runtimeAgent: '<agent actually running the Skill>',
1491
+ runtimeHost: '<desktop|web|server|mobile|unknown>',
1275
1492
  sourceSurface: '<same as hub unless the platform requires another public label>',
1276
- scenario: '<short public label only>',
1493
+ scenario: '<machine-readable short scenario key>',
1494
+ scenarioLabel: '<short user-facing scenario label only>',
1495
+ platformName: '<user-facing platform name only>',
1277
1496
  installationId: '<stable anonymous install id>',
1278
1497
  invocationId: '<unique invocation id>'
1279
1498
  }, null, 2),
@@ -1329,7 +1548,9 @@ async function writeRuntimeSnippet(root, flags) {
1329
1548
  installationId: '<anonymous-stable-install-id>',
1330
1549
  invocationId: '<unique-call-id>',
1331
1550
  idempotencyKey: '<unique-call-id>:skill_invoked',
1332
- scenario: '<short-scenario-label>'
1551
+ scenario: '<short-scenario-key>',
1552
+ scenarioLabel: '<short user-facing scenario label>',
1553
+ platformName: '<user-facing platform name>'
1333
1554
  }))
1334
1555
  ].join('\n')
1335
1556
  : [
@@ -1373,9 +1594,10 @@ async function writeRuntimeSnippet(root, flags) {
1373
1594
  ' invocationId,',
1374
1595
  ' idempotencyKey: options.idempotencyKey || `${invocationId || options.installationId || "runtime"}:${eventType}:${occurredAt}`,',
1375
1596
  ' scenario: options.scenario,',
1597
+ ' scenarioLabel: options.scenarioLabel,',
1598
+ ' platformName: options.platformName,',
1376
1599
  ' sourceSurface: options.sourceSurface,',
1377
1600
  ' campaign: options.campaign,',
1378
- ' packageSha256: options.packageSha256,',
1379
1601
  ' occurredAt',
1380
1602
  ' };',
1381
1603
  ' const signature = await hmacSha256(XIASHE_SKILL_SIGNING_SECRET, canonicalSignaturePayload(payload));',
@@ -1431,7 +1653,7 @@ async function submitTrackEvent(root, flags) {
1431
1653
  sourceSurface: normalizeText(flags['source-surface'] || 'cli', 120),
1432
1654
  campaign: normalizeText(flags.campaign, 120) || undefined,
1433
1655
  platformSkillUrl: normalizeText(flags['platform-skill-url'], 1000) || undefined,
1434
- packageSha256: inspected.package.sha256,
1656
+ creatorCardUrl: normalizeText(inspected.registry?.creatorCardUrl, 1000) || undefined,
1435
1657
  idempotencyKey: normalizeText(flags.idempotencyKey || flags['idempotency-key'], 220) || `${invocationId}:${eventType}`,
1436
1658
  occurredAt: Number.isFinite(occurredAt) ? occurredAt : Date.now()
1437
1659
  };
@@ -1470,6 +1692,10 @@ function registryBlockPresent(text) {
1470
1692
  return /<!--\s*(?:xiashe|agentpie)-registry:start\s*-->[\s\S]*?<!--\s*(?:xiashe|agentpie)-registry:end\s*-->/i.test(text || '');
1471
1693
  }
1472
1694
 
1695
+ function redPublicTrackingBlockPresent(text) {
1696
+ return /<!--\s*(?:xiashe|agentpie)-red-public-tracking:start\s*-->[\s\S]*?<!--\s*(?:xiashe|agentpie)-red-public-tracking:end\s*-->/i.test(text || '');
1697
+ }
1698
+
1473
1699
  function hasEntryInstructions(text, packageJson) {
1474
1700
  if (packageJson?.main || packageJson?.bin || packageJson?.scripts) return true;
1475
1701
  return /(入口|使用|安装|运行|调用|命令|Usage|Install|Quick start|Getting started|CLI|MCP|API|Entrypoint|Run)/i.test(text || '');
@@ -1492,12 +1718,17 @@ async function runDoctor(root, flags) {
1492
1718
  const manifestPath = path.join(inspected.root, MANIFEST_FILE);
1493
1719
  const localManifestPath = path.join(inspected.root, WORK_DIR, MANIFEST_FILE);
1494
1720
  const disclosurePath = path.join(inspected.root, WORK_DIR, 'REGISTRY_DISCLOSURE.md');
1721
+ const publicAgentAckPath = path.join(inspected.root, PUBLIC_PROTOCOL_DIR, 'AGENT_ACK.md');
1722
+ const publicDisclosurePath = path.join(inspected.root, PUBLIC_PROTOCOL_DIR, 'REGISTRY_DISCLOSURE.md');
1495
1723
  const handoffPath = path.join(inspected.root, WORK_DIR, HANDOFF_FILE);
1496
1724
  const snippetPath = path.join(inspected.root, WORK_DIR, 'runtime-events.js');
1497
1725
  const packageJson = await readJsonFile(path.join(inspected.root, 'package.json')).catch(() => null);
1498
1726
  const skillMd = await readSmallTextFile(skillMdPath);
1499
1727
  const readme = await readSmallTextFile(readmePath);
1728
+ const publicAgentAck = await readSmallTextFile(publicAgentAckPath);
1729
+ const publicDisclosure = await readSmallTextFile(publicDisclosurePath);
1500
1730
  const snippet = await readSmallTextFile(snippetPath);
1731
+ const packagePlan = packagePlanForHub(inspected, hub);
1501
1732
  const scannedCallbackFiles = [];
1502
1733
  let scannedCallbackText = '';
1503
1734
  for (const file of inspected.package.files.slice(0, 160)) {
@@ -1536,16 +1767,37 @@ async function runDoctor(root, flags) {
1536
1767
  registryBlockPresent(skillMd)
1537
1768
  ? doctorCheck('registry_block', 'Registry block', 'pass', 'SKILL.md contains the explicit registry disclosure block.')
1538
1769
  : redHub
1539
- ? doctorCheck('registry_block', 'Registry block', 'pass', 'Full internal registry block is not public for Red Skill. Use the safe Red tracking contract at the top of SKILL.md.')
1770
+ ? redPublicTrackingBlockPresent(skillMd)
1771
+ ? doctorCheck('registry_block', 'Registry block', 'pass', 'SKILL.md contains the safe Red public tracking contract.')
1772
+ : doctorCheck('registry_block', 'Registry block', 'warn', 'SKILL.md is missing the safe Red public tracking contract.', `Run ${COMMAND_NAME} setup . --code <code> --hub red to write the Red-safe public source block.`)
1540
1773
  : doctorCheck('registry_block', 'Registry block', 'warn', 'SKILL.md does not contain a registry block.', `Run ${COMMAND_NAME} setup . --code <code> --embed-skill-md if the target hub allows public registry disclosure in SKILL.md.`),
1541
1774
  runtimeCallbackPresent
1542
1775
  ? doctorCheck('runtime_callback', 'Runtime callback', 'pass', scannedCallbackFiles.length > 0 ? `Runtime callback references found in ${scannedCallbackFiles.slice(0, 5).join(', ')}.` : 'Runtime callback snippet/reference detected.')
1543
1776
  : redHub
1544
- ? doctorCheck('runtime_callback', 'Runtime callback', 'pass', 'Red Skill uses Agent Ack from local private config for no-secret runtime tracking. Do not expose internal ids or endpoints in public Red fields.')
1777
+ ? doctorCheck('runtime_callback', 'Runtime callback', 'pass', `Red Skill uses Agent Ack from ${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md or private runtime config for no-secret runtime tracking. Do not expose telemetry payloads in public Red descriptions.`)
1545
1778
  : doctorCheck('runtime_callback', 'Runtime callback', 'warn', 'No runtime callback reference detected.', `Use ${COMMAND_NAME} snippet . --target js and ask the Agent to wire it at the real invocation boundary if the hub allows HTTP/API/MCP callbacks.`),
1546
- existsSync(disclosurePath)
1779
+ redHub
1780
+ ? existsSync(publicDisclosurePath) && publicDisclosure.includes('distributionPlatform') && publicDisclosure.includes('runtimeAgent') && publicDisclosure.includes('scenario')
1781
+ ? doctorCheck('public_disclosure', 'Public Red disclosure', 'pass', `Found ${path.relative(inspected.root, publicDisclosurePath)} with canonical analytics fields.`)
1782
+ : doctorCheck('public_disclosure', 'Public Red disclosure', 'warn', `${PUBLIC_PROTOCOL_DIR}/REGISTRY_DISCLOSURE.md is missing or incomplete.`, `Run ${COMMAND_NAME} setup . --code <code> --hub red to generate the no-secret public disclosure.`)
1783
+ : existsSync(disclosurePath)
1547
1784
  ? doctorCheck('disclosure', 'Read-only disclosure', 'pass', `Found ${path.relative(inspected.root, disclosurePath)}.`)
1548
1785
  : doctorCheck('disclosure', 'Read-only disclosure', 'warn', 'REGISTRY_DISCLOSURE.md is missing.', `Run ${COMMAND_NAME} setup . --code <code> to generate platform review disclosure.`),
1786
+ redHub && existsSync(publicAgentAckPath) && ACK_EVENTS.every((event) => publicAgentAck.includes(event)) && publicAgentAck.includes('publicSkillId') && publicAgentAck.includes('Do not guess')
1787
+ ? doctorCheck('public_agent_ack', 'Public Agent Ack protocol', 'pass', `Found ${path.relative(inspected.root, publicAgentAckPath)} with install/use/complete/fail Ack rules.`)
1788
+ : redHub
1789
+ ? doctorCheck('public_agent_ack', 'Public Agent Ack protocol', 'warn', `${PUBLIC_PROTOCOL_DIR}/AGENT_ACK.md is missing or incomplete.`, `Run ${COMMAND_NAME} setup . --code <code> --hub red to generate the no-secret Agent Ack protocol.`)
1790
+ : doctorCheck('public_agent_ack', 'Public Agent Ack protocol', 'pass', 'Not required for this hub.'),
1791
+ redHub && packagePlan.candidateUploadFiles.some((file) => file.startsWith(`${WORK_DIR}/`) || file.startsWith('.agentpie/'))
1792
+ ? doctorCheck('red_upload_allowlist', 'Red upload allowlist', 'fail', `Red candidate upload files include private registry files: ${packagePlan.candidateUploadFiles.filter((file) => file.startsWith(`${WORK_DIR}/`) || file.startsWith('.agentpie/')).join(', ')}`, `Remove private ${WORK_DIR}/ files from Red public packages.`)
1793
+ : redHub
1794
+ ? doctorCheck('red_upload_allowlist', 'Red upload allowlist', 'pass', 'Red candidate upload files exclude private registry directories.')
1795
+ : doctorCheck('red_upload_allowlist', 'Red upload allowlist', 'pass', 'Not required for this hub.'),
1796
+ redHub && (publicAgentAck.includes(FORBIDDEN_ACK_FIELDS[0]) || publicDisclosure.includes('package hashes'))
1797
+ ? doctorCheck('red_payload_boundary', 'Red payload boundary', 'pass', 'Public protocol documents describe forbidden private payload fields and package boundaries.')
1798
+ : redHub
1799
+ ? doctorCheck('red_payload_boundary', 'Red payload boundary', 'warn', 'Public Red protocol documents do not clearly state payload boundaries.', `Regenerate with ${COMMAND_NAME} setup . --code <code> --hub red.`)
1800
+ : doctorCheck('red_payload_boundary', 'Red payload boundary', 'pass', 'Not required for this hub.'),
1549
1801
  existsSync(handoffPath)
1550
1802
  ? doctorCheck('handoff', 'Agent handoff', 'pass', `Found ${path.relative(inspected.root, handoffPath)}.`)
1551
1803
  : doctorCheck('handoff', 'Agent handoff', 'warn', 'Unified upload handoff is missing.', `Run ${COMMAND_NAME} setup . --code <code> --hub all.`),
@@ -1678,6 +1930,10 @@ async function setupAgentWorkflow(root, flags) {
1678
1930
  'local-manifest': true,
1679
1931
  'manifest-path': flags['manifest-path'] || path.join(outDir, MANIFEST_FILE)
1680
1932
  });
1933
+ const inspectedAfterManifestForPublicFiles = await inspectSkill(absoluteRoot, flags);
1934
+ const publicProtocol = hubs.includes('red')
1935
+ ? await writePublicProtocolFiles(absoluteRoot, inspectedAfterManifestForPublicFiles, 'red')
1936
+ : null;
1681
1937
 
1682
1938
  const promptResults = [];
1683
1939
  const packagePlans = [];
@@ -1767,10 +2023,13 @@ async function setupAgentWorkflow(root, flags) {
1767
2023
  snippetPath: snippetResult ? snippetResult.outPath : null,
1768
2024
  promptEvents,
1769
2025
  warnings,
2026
+ publicProtocol,
1770
2027
  next: [
1771
2028
  `Use ${path.relative(absoluteRoot, handoffPath)} as the single Agent handoff. The Agent should not ask the user to manually pick registry files.`,
1772
2029
  `Use ${path.relative(absoluteRoot, profilesPath)} and package-<hub>.json as the platform review profiles and upload allowlists.`,
1773
- `Use ${path.relative(absoluteRoot, agentAckPath)} as the public-safe Agent Ack block. Add it to target platform instructions where allowed so Agents can report anonymous installs and calls without a secret token.`,
2030
+ publicProtocol
2031
+ ? `For Red public Markdown packages, include ${path.relative(absoluteRoot, publicProtocol.agentAckPath)} and ${path.relative(absoluteRoot, publicProtocol.disclosurePath)} when accepted by the platform; keep ${WORK_DIR}/ private.`
2032
+ : `Use ${path.relative(absoluteRoot, agentAckPath)} only in private runtime config, platform admin-only fields, or non-public handoff notes. Do not publish endpoint/publicSkillId in restrictive marketplace descriptions.`,
1774
2033
  'When the user later pastes a Red Skill / ClawHub / SkillHub / Claude / Dify / Coze official prompt, the Agent should identify the platform and merge only the matching platform-safe checklist internally.',
1775
2034
  'Each prepared upload-<hub>.md pins the correct hub/sourceSurface value so platform analytics stay separated, but those files are internal checklists for the Agent.',
1776
2035
  skillMdPath
@@ -1833,6 +2092,7 @@ async function main() {
1833
2092
  `Platform profiles: ${result.profilesPath}`,
1834
2093
  ...result.packagePlanPaths.map((item) => `Package plan (${item.hub}): ${item.planPath}`),
1835
2094
  result.skillMdPath ? `Updated: ${result.skillMdPath}` : null,
2095
+ result.publicProtocol ? `Public Red protocol: ${result.publicProtocol.agentAckPath}, ${result.publicProtocol.disclosurePath}` : null,
1836
2096
  `Disclosure: ${result.disclosurePath}`,
1837
2097
  result.snippetPath ? `Runtime snippet: ${result.snippetPath}` : null,
1838
2098
  ...result.warnings.map((warning) => `Warning: ${warning}`),
@@ -1862,6 +2122,8 @@ async function main() {
1862
2122
  ...result.promptPaths.map((item) => `Wrote ${item.promptPath}`),
1863
2123
  `Wrote ${result.profilesPath}`,
1864
2124
  ...result.packagePlanPaths.map((item) => `Wrote ${item.planPath}`),
2125
+ result.publicProtocol ? `Wrote ${result.publicProtocol.agentAckPath}` : null,
2126
+ result.publicProtocol ? `Wrote ${result.publicProtocol.disclosurePath}` : null,
1865
2127
  `Wrote ${result.disclosurePath}`,
1866
2128
  result.snippetPath ? `Wrote ${result.snippetPath}` : null,
1867
2129
  ...result.warnings.map((warning) => `Warning: ${warning}`),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiashe/skill",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "xiashe-skill": "bin/xiashe-skill.mjs"