create-dwy 0.16.1 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/bin/index.js +23 -19
  3. package/package.json +1 -1
  4. package/src/cli-help.js +44 -0
  5. package/src/sync-all.js +303 -59
  6. package/src/sync-global-skills.js +167 -0
  7. package/src/sync.js +21 -11
  8. package/templates/ai-tools/CHANGELOG.md +134 -0
  9. package/templates/ai-tools/VERSION +1 -1
  10. package/templates/ai-tools/rules/Android/dwy-android-core.md +65 -1
  11. package/templates/ai-tools/rules/Python/dwy-python-core.md +47 -0
  12. package/templates/ai-tools/rules/Vue/dwy-vue-core.md +55 -0
  13. package/templates/ai-tools/rules/iOS/dwy-swift-core.md +46 -0
  14. package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-oss-commercial-license.md +128 -0
  15. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-ios-app-store-release/SKILL.md +65 -0
  16. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-ios-app-store-release/assets/appstore-submission.yaml +43 -0
  17. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-ios-app-store-release/references/api-workflow.md +17 -0
  18. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-ios-app-store-release/references/in-app-purchase-review.md +16 -0
  19. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-ios-app-store-release/references/screenshot-workflow.md +16 -0
  20. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-ios-app-store-release/scripts/appstore_config.sh +140 -0
  21. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/SKILL.md +11 -8
  22. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/android.md +2 -1
  23. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/backend-deploy.md +2 -1
  24. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/changelog.md +24 -4
  25. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/frontend-deploy.md +2 -1
  26. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/generic-release.md +2 -1
  27. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/git-tag.md +82 -0
  28. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/harmony.md +2 -1
  29. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/ios.md +3 -2
  30. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/monitor-notify.md +2 -2
  31. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-semver/SKILL.md +1 -1
  32. package/templates/ai-tools/skills//345/237/272/347/241/200/345/272/223/dwy-eapi/references/tasks-integration-guide.md +2 -2
  33. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/README.md +57 -0
  34. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/SKILL.md +147 -0
  35. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/references/api.md +43 -0
  36. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/references/config.example.yaml +33 -0
  37. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/scripts/global_config.py +89 -0
  38. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/scripts/setup_config.py +175 -0
  39. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/scripts/synthesize.py +339 -0
  40. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/media-platform-packaging/SKILL.md +127 -0
  41. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/media-platform-packaging/assets/cover-style-master-v1.png +0 -0
  42. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/media-platform-packaging/references/platform-copy-examples.md +37 -0
  43. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/media-platform-packaging/references/platform-posting-times.md +193 -0
  44. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0005-ideation/SKILL.md +42 -0
  45. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0005-ideation/templates/topic-backlog.template.md +50 -0
  46. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0005-ideation/templates//351/200/211/351/242/230/346/261/240.template.md +16 -0
  47. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0010-product/SKILL.md +106 -0
  48. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0010-product/templates/channel-profile.template.md +52 -0
  49. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0010-product/templates//344/272/247/345/223/201/345/215/241.template.md +132 -0
  50. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0030-facts/SKILL.md +60 -0
  51. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0030-facts/scripts/build_facts_html.py +430 -0
  52. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0030-facts/scripts/generate_html.py +1287 -0
  53. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0030-facts/scripts/generate_report.py +189 -0
  54. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0030-facts/templates//344/272/213/345/256/236/350/265/204/346/226/231/345/272/223.template.md +55 -0
  55. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0040-script/SKILL.md +36 -0
  56. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0040-script/templates/README.md +10 -0
  57. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0040-script/templates//344/272/213/345/256/236.template.md +82 -0
  58. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0040-script/templates//345/215/225/351/233/206/346/226/207/346/241/243.template.md +175 -0
  59. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0040-script/templates//350/204/232/346/234/254.template.md +69 -0
  60. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0040-script/templates//351/252/250/346/236/266-v1.1.md +174 -0
  61. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0050-design/SKILL.md +55 -0
  62. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0060-assets/SKILL.md +29 -0
  63. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0070-package/SKILL.md +42 -0
  64. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0070-package/scripts/validate_shots.py +207 -0
  65. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0070-package/shots.schema.json +186 -0
  66. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0070-package//344/272/272/345/256/241/345/214/205.template.md +1 -0
  67. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0070-package//344/272/272/345/256/241/350/257/264/346/230/216.md +15 -0
  68. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0070-package//346/210/220/347/211/207/345/214/205.template.md +49 -0
  69. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0080-factory/SKILL.md +58 -0
  70. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-comic-kit/SKILL.md +424 -0
  71. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-comic-kit/evals.md +41 -0
  72. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-flow/CONTRACT.md +123 -0
  73. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-flow/SKILL.md +81 -0
  74. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-flow//346/211/247/350/241/214/346/270/205/345/215/225.template.md +60 -0
  75. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/SKILL.md +78 -0
  76. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/agents/openai.yaml +4 -0
  77. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/assets/knowledge-town-paper-film-v1.json +80 -0
  78. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/assets/remotion/AudioTracks.tsx +20 -0
  79. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/assets/remotion/CaptionLayer.tsx +18 -0
  80. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/assets/remotion/CueTimeline.ts +24 -0
  81. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/assets/remotion/KnowledgeTownComposition.tsx +21 -0
  82. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/references/cinematic-direction.md +73 -0
  83. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/references/sticker-asset-production.md +30 -0
  84. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/references/style-guide.md +43 -0
  85. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/scripts/build_cue_timeline.py +75 -0
  86. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/scripts/validate_cue_timeline.py +68 -0
  87. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/scripts/validate_style_preset.py +22 -0
  88. package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/SKILL.md +0 -511
  89. package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/references/checks-data.md +0 -126
  90. package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/references/checks-network.md +0 -88
  91. package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/references/checks-runtime.md +0 -195
  92. package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/references/security-doc-search.md +0 -179
  93. package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_base.sh +0 -39
  94. package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_capacity.sh +0 -278
  95. package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_db.sh +0 -147
  96. package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_docker.sh +0 -230
  97. package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_env.sh +0 -64
  98. package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_https.sh +0 -60
  99. package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_logs.sh +0 -209
  100. package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_nginx.sh +0 -100
  101. package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_resilience.sh +0 -157
  102. package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_secrets.sh +0 -265
  103. package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_services.sh +0 -94
  104. package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_ssh.sh +0 -56
  105. package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/run_all.sh +0 -105
@@ -0,0 +1,167 @@
1
+ /**
2
+ * 将已选 skill 额外拷到用户全局目录。
3
+ * 项目目录同步仍由各平台 sync 负责;本模块只处理 ~/.claude / ~/.grok 等 home 下目录。
4
+ * 只覆盖本次点名的 skill,不删除全局目录里其它个人 skill。
5
+ */
6
+
7
+ import fs from 'fs-extra'
8
+ import os from 'node:os'
9
+ import path from 'path'
10
+ import { copyFilter, logAction } from './sync.js'
11
+
12
+ /** 项目目录:随所选平台落到 .claude/skills、.agents/skills 等 */
13
+ export const SKILL_DEST_PROJECT = 'project'
14
+
15
+ /** 默认同步位置:只写项目,不碰用户 home */
16
+ export const DEFAULT_SKILL_DESTINATIONS = [SKILL_DEST_PROJECT]
17
+
18
+ /**
19
+ * 全局 dest id → home 下相对路径。
20
+ * 路径跟各工具官方发现目录对齐;测试通过 homeDir 注入,避免写真实 $HOME。
21
+ */
22
+ const GLOBAL_SKILL_DIR_SEGMENTS = {
23
+ claude: ['.claude', 'skills'],
24
+ grok: ['.grok', 'skills'],
25
+ agents: ['.agents', 'skills'],
26
+ cursor: ['.cursor', 'skills'],
27
+ opencode: ['.config', 'opencode', 'skills'],
28
+ }
29
+
30
+ export const GLOBAL_SKILL_DEST_IDS = Object.keys(GLOBAL_SKILL_DIR_SEGMENTS)
31
+
32
+ /**
33
+ * 项目内 skill 目录(按已选平台)。Cursor 无 skills,不列入。
34
+ * 仅 Skills 模式用这张表写项目,避免走完整 sync 误改 rules/commands/hooks。
35
+ */
36
+ export const PROJECT_SKILL_DIR_BY_PLATFORM = {
37
+ claude: ['.claude', 'skills'],
38
+ codex: ['.agents', 'skills'],
39
+ opencode: ['.opencode', 'skills'],
40
+ }
41
+
42
+ /**
43
+ * 解析某平台在项目内的 skills 目录。不支持的平台返回 null。
44
+ *
45
+ * @param {string} projectDir
46
+ * @param {string} platform
47
+ */
48
+ export function resolveProjectSkillDir(projectDir, platform) {
49
+ const segments = PROJECT_SKILL_DIR_BY_PLATFORM[platform]
50
+ if (!segments) return null
51
+ return path.join(projectDir, ...segments)
52
+ }
53
+
54
+ const DEST_LABELS = {
55
+ project: '项目目录',
56
+ claude: 'Claude Code 全局',
57
+ grok: 'Grok 全局',
58
+ agents: 'Codex / 跨运行时全局',
59
+ cursor: 'Cursor 全局',
60
+ opencode: 'OpenCode 全局',
61
+ }
62
+
63
+ /**
64
+ * 规范化交互/缓存里的 skill 同步范围。
65
+ * 未知 dest、空 skill 名丢弃;无 destinations 时回退到仅项目。
66
+ *
67
+ * @param {{ destinations?: string[], globalSkills?: string[] } | null | undefined} raw
68
+ */
69
+ export function normalizeSkillScope(raw) {
70
+ const allowed = new Set([SKILL_DEST_PROJECT, ...GLOBAL_SKILL_DEST_IDS])
71
+ const destinations = (raw?.destinations || [])
72
+ .filter(id => allowed.has(id))
73
+ const globalSkills = [...new Set((raw?.globalSkills || []).filter(name => typeof name === 'string' && name.trim()))]
74
+
75
+ return {
76
+ destinations: destinations.length > 0 ? destinations : [...DEFAULT_SKILL_DESTINATIONS],
77
+ globalSkills,
78
+ }
79
+ }
80
+
81
+ /**
82
+ * 解析全局 dest 的绝对目录。project 返回 null(由平台 sync 写项目)。
83
+ *
84
+ * @param {string} destId
85
+ * @param {string} [homeDir]
86
+ */
87
+ export function resolveGlobalSkillDir(destId, homeDir = os.homedir()) {
88
+ const segments = GLOBAL_SKILL_DIR_SEGMENTS[destId]
89
+ if (!segments) return null
90
+ return path.join(homeDir, ...segments)
91
+ }
92
+
93
+ /**
94
+ * 最后一步 UI 的位置选项。project 放第一项,默认勾选。
95
+ *
96
+ * @param {string} [homeDir]
97
+ * @returns {Array<{ value: string, label: string, description: string }>}
98
+ */
99
+ export function listSkillDestOptions(homeDir = os.homedir()) {
100
+ return [
101
+ {
102
+ value: SKILL_DEST_PROJECT,
103
+ label: DEST_LABELS.project,
104
+ description: '默认。随上面所选平台写入项目 .claude/skills、.agents/skills 等',
105
+ },
106
+ ...GLOBAL_SKILL_DEST_IDS.map(id => {
107
+ const dir = resolveGlobalSkillDir(id, homeDir)
108
+ return {
109
+ value: id,
110
+ label: DEST_LABELS[id],
111
+ description: dir,
112
+ }
113
+ }),
114
+ ]
115
+ }
116
+
117
+ /**
118
+ * 把 skill 目录拷到已选全局 dest。destIds 含 project 时跳过(项目侧已同步)。
119
+ * 只写传入的 skills,不清理目标根目录里其它条目。
120
+ *
121
+ * @param {{ skills: Array<{ name: string, sourcePath: string }>, destIds: string[], homeDir?: string }} opts
122
+ * @returns {Promise<number>} 写入次数(每个 dest × 每个 skill)
123
+ */
124
+ export async function copySkillsToGlobalDirs({ skills, destIds, homeDir = os.homedir() }) {
125
+ let count = 0
126
+
127
+ for (const destId of destIds) {
128
+ const destRoot = resolveGlobalSkillDir(destId, homeDir)
129
+ if (!destRoot) continue
130
+
131
+ for (const skill of skills) {
132
+ const dest = path.join(destRoot, skill.name)
133
+ await fs.ensureDir(path.dirname(dest))
134
+ await fs.copy(skill.sourcePath, dest, { overwrite: true, filter: copyFilter })
135
+ logAction(`${DEST_LABELS[destId] || destId}/${skill.name}`)
136
+ count++
137
+ }
138
+ }
139
+
140
+ return count
141
+ }
142
+
143
+ /**
144
+ * 仅 Skills 模式:把 skill 拷到项目内已选平台的 skills 目录。
145
+ * 不写 rules / commands / hooks。
146
+ *
147
+ * @param {{ projectDir: string, platforms: string[], skills: Array<{ name: string, sourcePath: string }> }} opts
148
+ * @returns {Promise<number>}
149
+ */
150
+ export async function copySkillsToProjectPlatforms({ projectDir, platforms, skills }) {
151
+ let count = 0
152
+
153
+ for (const platform of platforms) {
154
+ const destRoot = resolveProjectSkillDir(projectDir, platform)
155
+ if (!destRoot) continue
156
+
157
+ for (const skill of skills) {
158
+ const dest = path.join(destRoot, skill.name)
159
+ await fs.ensureDir(path.dirname(dest))
160
+ await fs.copy(skill.sourcePath, dest, { overwrite: true, filter: copyFilter })
161
+ logAction(`${path.relative(projectDir, destRoot)}/${skill.name}`)
162
+ count++
163
+ }
164
+ }
165
+
166
+ return count
167
+ }
package/src/sync.js CHANGED
@@ -257,25 +257,35 @@ async function promptSelection(items, label, defaultNames) {
257
257
 
258
258
  /**
259
259
  * 交互式选择:每步可回退到上一步,最后总览支持任意类别重选。
260
+ * categories 可缩成仅 Skills,未出现的类别返回空数组(调用方不得据此删除已有项)。
260
261
  * 返回 { skills, rules, commands, hooks } 或 null(取消)。
262
+ *
263
+ * @param {object} scans
264
+ * @param {object} existing
265
+ * @param {{ categories?: Array<{ key: string, label: string }> }} [opts]
261
266
  */
262
- export async function interactiveSelect(scans, existing) {
263
- const sel = {}
267
+ export async function interactiveSelect(scans, existing, { categories = CATEGORIES } = {}) {
268
+ const sel = {
269
+ skills: [],
270
+ rules: [],
271
+ commands: [],
272
+ hooks: [],
273
+ }
264
274
 
265
275
  // 第一轮:顺序遍历,每步给导航
266
276
  let i = 0
267
- while (i < CATEGORIES.length) {
268
- const { key, label } = CATEGORIES[i]
269
- const defaultNames = sel[key]
277
+ while (i < categories.length) {
278
+ const { key, label } = categories[i]
279
+ const defaultNames = sel[key]?.length
270
280
  ? new Set(sel[key].map(x => x.name))
271
281
  : existing[key]
272
282
  sel[key] = await promptSelection(scans[key], label, defaultNames)
273
283
  if (sel[key] === null) return null
274
284
 
275
- if (i === CATEGORIES.length - 1) break
285
+ if (i === categories.length - 1) break
276
286
 
277
- const nextLabel = CATEGORIES[i + 1].label
278
- const prevLabel = i > 0 ? CATEGORIES[i - 1].label : null
287
+ const nextLabel = categories[i + 1].label
288
+ const prevLabel = i > 0 ? categories[i - 1].label : null
279
289
  // 导航步可搜索单选(选项少,交互与多选一致)
280
290
  const nav = await searchableSelect({
281
291
  message: `${label} 已选 ${sel[key].length} 项。下一步:`,
@@ -294,14 +304,14 @@ export async function interactiveSelect(scans, existing) {
294
304
  // 第二轮:总览 + 任意重选
295
305
  while (true) {
296
306
  console.log(chalk.gray('\n选择汇总:'))
297
- for (const { key, label } of CATEGORIES) {
307
+ for (const { key, label } of categories) {
298
308
  console.log(chalk.gray(` ${label.padEnd(10)} ${sel[key].length} 项`))
299
309
  }
300
310
  const final = await searchableSelect({
301
311
  message: '确认提交还是重选?',
302
312
  options: [
303
313
  { label: '确认提交', value: 'confirm' },
304
- ...CATEGORIES.map(c => ({ label: `重选 ${c.label}`, value: c.key })),
314
+ ...categories.map(c => ({ label: `重选 ${c.label}`, value: c.key })),
305
315
  { label: '取消同步', value: 'cancel' },
306
316
  ],
307
317
  initialValue: 'confirm',
@@ -309,7 +319,7 @@ export async function interactiveSelect(scans, existing) {
309
319
  })
310
320
  if (isCancel(final) || final === 'cancel') return null
311
321
  if (final === 'confirm') return sel
312
- const cat = CATEGORIES.find(c => c.key === final)
322
+ const cat = categories.find(c => c.key === final)
313
323
  sel[final] = await promptSelection(scans[final], cat.label, new Set(sel[final].map(x => x.name)))
314
324
  if (sel[final] === null) return null
315
325
  }
@@ -52,6 +52,140 @@
52
52
 
53
53
  ---
54
54
 
55
+ ## 0.10.0 — 2026-08-13
56
+
57
+ ### Added
58
+
59
+ - `skills/自媒体/dwy-doubao-tts`:豆包声音复刻 2.0 口播配音
60
+ - 脚本随 skill 同步,不放 `~/.grok/skills`
61
+ - API Key / 音色 ID 只读用户全局 `~/.dwy/config.yaml` 的 `doubao_tts`,禁止写入仓库
62
+
63
+ ---
64
+
65
+ ## 0.9.0 — 2026-08-11
66
+
67
+ ### Changed
68
+
69
+ - **0010 合并竞品 + 演讲地图**:删除分步 `uc-media-0010-topic` / `uc-media-0020-product`
70
+ - 新单一 skill `uc-media-0010-product`:竞品/差异化后 **AI 强制自动填写** 讲/不讲/内容柱/时长
71
+ - 主文档 `0010-product/产品卡-*.md`(§1 竞品 · §2 洞察 · §3 AI 地图)
72
+ - 内容轨:`主题 → 0010 → 0030 按地图扩事实 → 0040`(无 0020 步)
73
+ - flow / CONTRACT / 清单 v7 / 0005 / 0030 / 0040 / README 对齐
74
+
75
+ ---
76
+
77
+ ## 0.8.0 — 2026-08-11
78
+
79
+ ### Changed
80
+
81
+ - **内容轨因果修正**:`主题 → 0010 竞品 → 0020 演讲地图 → 0030 按地图扩事实 → 0040 蒸馏`
82
+ - skill 重命名:`uc-media-0010-topic`(竞品)、`uc-media-0020-product`(产品卡/地图)
83
+ - 目录:`0010-topic/竞品-*.md`、`0020-product/产品卡-*.md`
84
+ - 0030/0040/0005/flow/CONTRACT/README 全量对齐;清单 version 6
85
+ - 兼容:旧先产品后竞品、旧路径映射表
86
+
87
+ ---
88
+
89
+ ## 0.7.0 — 2026-08-11
90
+
91
+ ### Changed
92
+
93
+ - **流程优化(P0/P1)**
94
+ - `uc-media-0005-ideation`:候选强制 `seed_links`;人选带入 0020
95
+ - `uc-media-0020-topic`:先消化 seed 再补检;「不做」回写池 `rejected`;正文称竞品包
96
+ - `uc-media-flow` / `CONTRACT`:fast 下 **0050 确认后连跑 0060→0070**;硬停收敛;风格 skill 挂载表
97
+ - `uc-media-0050-design`:可选跨集 `design-defaults.md`,本集只写增量
98
+ - `media-platform-packaging`:登记为可选 **0090 packaging**
99
+ - 执行清单 **version 5**;README 总览流程图
100
+
101
+ ---
102
+
103
+ ## 0.6.0 — 2026-08-11
104
+
105
+ ### Added
106
+
107
+ - `skills/自媒体/uc-media-0005-ideation/`:选题发现 skill
108
+ - 硬依赖频道档案;多 agent(B站 / YouTube / 短视频 / 可选社区)搜集受众兴趣主题
109
+ - 跨集真源 `.dwy/uc-media/topic-backlog.md`;可选本集快照 `0005-ideation/选题池-*.md`
110
+ - **人选定**后进 0010;禁止自动代选;支持「刷新选题」force
111
+ - 模板:`topic-backlog.template.md` · `选题池.template.md`
112
+
113
+ ### Changed
114
+
115
+ - `skills/自媒体/uc-media-flow/CONTRACT.md` · `SKILL.md` · `执行清单.template.md`(version 4):接入 stage `ideation`、PATHS `topic_backlog`、硬停「0005 人选」
116
+ - `skills/自媒体/uc-media-0010-product/`:无主题优先导向 0005;主题可来自选题池 `picked`
117
+ - `skills/自媒体/uc-media-0020-topic/`:明确为单题竞品,选题发现归 0005
118
+ - `skills/自媒体/README.md`:登记 0005 与 `topic-backlog.md`
119
+
120
+ ---
121
+
122
+ ## 0.5.0 — 2026-08-11
123
+
124
+ ### Added
125
+
126
+ - `skills/自媒体/uc-media-0010-product/templates/channel-profile.template.md`:频道定位·受众·默认分发跨集模板
127
+ - `skills/自媒体/uc-media-0010-product/templates/产品卡.template.md`:本集产品卡模板(§0 只读引用频道档案)
128
+
129
+ ### Changed
130
+
131
+ - `skills/自媒体/uc-media-0010-product/SKILL.md`:拆分双真源——频道档案写 `<project_root>/.dwy/uc-media/channel-profile.md`(有则复用),本集产品卡只写主题·讲/不讲·分块时长;支持「更新频道定位 / 重写受众」强制刷新
132
+ - `skills/自媒体/uc-media-flow/CONTRACT.md` · `SKILL.md` · `执行清单.template.md`:频道闸门、PATHS `channel_profile`、进度表 channel 行
133
+ - `skills/自媒体/uc-media-0020-topic/` · `uc-media-0040-script/` · `uc-media-0050-design/`:上游必读频道档案;受众/语气/气质不再从本集卡重生成
134
+ - `skills/自媒体/README.md`:目录结构补充 `.dwy/uc-media/`
135
+
136
+ ---
137
+
138
+ ## 0.4.2 — 2026-08-10
139
+
140
+ ### Added
141
+
142
+ - `skills/自媒体/media-platform-packaging/assets/cover-style-master-v1.png`:封面视觉母版(style reference)
143
+
144
+ ### Changed
145
+
146
+ - `skills/自媒体/media-platform-packaging/SKILL.md`:固定视觉母版约束 + 提示词骨架强制引用该母版;生成后 25% 缩放可读性检查
147
+
148
+ ---
149
+
150
+ ## 0.4.1 — 2026-08-10
151
+
152
+ ### Changed
153
+
154
+ - `skills/自媒体/media-platform-packaging/`:同步源仓更新
155
+ - 平台表拆分 B站 / YouTube:B站用 `#标签`,YouTube 标签字段用英文逗号分隔关键词
156
+ - `references/platform-copy-examples.md` 增补 YouTube 标签格式示例
157
+
158
+ ---
159
+
160
+ ## 0.4.0 — 2026-08-10
161
+
162
+ ### Added
163
+
164
+ - `skills/自媒体/media-platform-packaging/`:多平台自媒体包装与封面(源:`xiaoyuan-knowledge-town/.agents/skills/media-platform-packaging`)
165
+ - B站 / 抖音 / 小红书 / 微信视频号标题、简介、标签规则
166
+ - 16:9、4:3、3:4 封面版式与生图流程(依赖 `imagegen`)
167
+ - `references/platform-copy-examples.md`:标题长度与封面文字优先级示例
168
+ - 产出约定写入 `media/0070-package/` 包装清单
169
+
170
+ ### Changed
171
+
172
+ - `skills/自媒体/README.md`:Skills 表登记 `media-platform-packaging`
173
+
174
+ ---
175
+
176
+ ## 0.3.0 — 2026-08-07
177
+
178
+ ### Added
179
+
180
+ - 新分类 `skills/自媒体/`:迁入短视频 / 科普自媒体全流程 skills(源:`xiaoyuan-knowledge-town/function-tools/skills`)
181
+ - **编排**:`uc-media-flow`(CONTRACT + 执行清单模板,`fast`/`standard`)
182
+ - **流水线**:`uc-media-0010-product` → `0020-topic` → `0030-facts` → `0040-script` → `0050-design` → `0060-assets` → `0070-package` → `0080-factory`
183
+ - **扩展**:`uc-media-comic-kit`(漫画科普表达)、`uc-media-knowledge-town`(知识小城视觉 / Remotion 预设)
184
+ - 含 scripts(facts HTML、shots 校验、cue timeline)、templates、schema、Remotion 组件资产
185
+ - 硬编路径 `templates/skills/…` 改为 skill 包相对路径,适配 `dwy` sync 后 `.claude/skills/` / `.agents/skills/`
186
+
187
+ ---
188
+
55
189
  ## 0.2.0 — 2026-07-23
56
190
 
57
191
  ### Added
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.10.0
@@ -454,6 +454,70 @@ val data = newService.fetch()
454
454
  // TODO(zhang, 2026-05-30): 兼容企业微信扫码,关联 issue #1234
455
455
  ```
456
456
 
457
+ ### 2.9.1 临时代码标识(强制 · Java / Kotlin / XML)
458
+
459
+ 产品源码(`src/main` 等)中的业务待办、调试旁路、假数据**必须**用固定标签,便于 AS TODO 窗口 / 全局搜索定位。`src/test`、`androidTest` 正规测试 mock **不强制**。
460
+
461
+ | 标签 | 用途 | 格式 |
462
+ |---|---|---|
463
+ | `TODO` | 业务/技术未完成 | `// TODO(name, YYYY-MM-DD): 说明`(同 §2.9) |
464
+ | `TESTCODE` | 临时调试、跳过校验、试验开关 | `// TESTCODE: 说明 + 移除条件` |
465
+ | `MOCK` | 假数据、假接口、stub 实现 | `// MOCK: 说明 + 将来替换点` |
466
+
467
+ - 注释符:Java/Kotlin 用 `//`;XML 用 `<!-- -->`
468
+ - 写 mock/调试代码的**同一 diff 必须带标**;接真实现后**删标签与包夹**
469
+ - 禁止无标签假返回;禁止自造 `// 假数据`、`// test only` 等替代词
470
+ - 发版/提测前搜 `MOCK`、`TESTCODE`,清单交给负责人确认(允许残留但须知情)
471
+
472
+ **单行**(仅一行代码):行上写标签即可。
473
+
474
+ ```kotlin
475
+ // MOCK: 用户列表假数据,接 UserRepository.list() 后删除
476
+ fun users() = listOf(User("张三"))
477
+
478
+ // TESTCODE: 本地跳过登录,联调完删除
479
+ if (BuildConfig.DEBUG) return true
480
+ ```
481
+
482
+ **多行 / 大段(≥2 行逻辑)强制包夹**——标签在前、`BEGIN`/`END` 成对,说明写在 `BEGIN` 行:
483
+
484
+ ```text
485
+ // MOCK BEGIN: <说明 + 将来替换点>
486
+ ... 多行假数据 / stub ...
487
+ // MOCK END
488
+
489
+ // TESTCODE BEGIN: <说明 + 移除条件>
490
+ ... 多行调试 / 旁路 ...
491
+ // TESTCODE END
492
+ ```
493
+
494
+ ```kotlin
495
+ // ❌ 大段无包夹
496
+ fun loadHome(): HomeData {
497
+ val banners = listOf(Banner("a"), Banner("b"))
498
+ val user = User("张三")
499
+ return HomeData(banners, user)
500
+ }
501
+
502
+ // ✅
503
+ // MOCK BEGIN: 首页假数据,接 HomeRepository.fetch 后删除
504
+ fun loadHome(): HomeData {
505
+ val banners = listOf(Banner("a"), Banner("b"))
506
+ val user = User("张三")
507
+ return HomeData(banners, user)
508
+ }
509
+ // MOCK END
510
+ ```
511
+
512
+ ```xml
513
+ <!-- MOCK BEGIN: 预览占位,接 CMS 后删除 -->
514
+ <TextView android:text="占位标题" />
515
+ <TextView android:text="占位副标题" />
516
+ <!-- MOCK END -->
517
+ ```
518
+
519
+ AS 默认 TODO 窗主要扫 `TODO`;`TESTCODE`/`MOCK` 用全局搜索,或在 Settings → Editor → TODO 增加 pattern `\bTESTCODE\b.*`、`\bMOCK\b.*`。
520
+
457
521
  ### 2.10 Gradle 脚本注释(Groovy)
458
522
 
459
523
  老项目的 `build.gradle` / `settings.gradle` 多用 **Groovy** 编写(新项目 Kotlin DSL `*.gradle.kts` 同理)。构建脚本是声明式配置,注释**只解释"为什么这样配",不复述配置项字面**。
@@ -995,7 +1059,7 @@ if (trimmed.isNotEmpty()) { ... }
995
1059
  | 15 | 无空 `catch` 块、无 `catch (Throwable)`、无 `e.printStackTrace()` | ✓ |
996
1060
  | 16 | 嵌套不超过 3 层,函数体不超过 50 行,单文件不超过 500 行 | ✓ |
997
1061
  | 17 | 资源命名遵守:layout 前缀(`activity_`* / `fragment_*` / `item_*`)、id 控件缩写(`tv_*` / `et_*` / `btn_*` / `rv_*` …)、drawable / selector 状态后缀(`_normal` / `_pressed` / `_disabled` …)、anim / menu / style / mipmap 命名,9-patch 带 `.9` 后缀 | ✓ |
998
- | 18 | 无注释掉的代码块(垃圾代码),TODO 必须带责任人 + 日期 + 上下文 | ✓ |
1062
+ | 18 | 无注释掉的代码块(垃圾代码);业务 TODO 带责任人+日期;产品源码假数据/调试旁路带 `MOCK:` / `TESTCODE:` | ✓ |
999
1063
  | 19 | `if` / `else` / `else if` / `for` / `while` / `do-while` 语句即使单行也带 `{}`(Kotlin 表达式 `if` 除外) | ✓ |
1000
1064
  | 20 | 新增类按**功能聚合**放对应功能包(`login/` / `order/`),不按 `activities/` / `models/` 分层横切;仅多功能共享才放 `common/` | ✓ |
1001
1065
  | 21 | Gradle 脚本(Groovy / kts):锁版本 / `exclude` / 自定义 task / 变体 / 关键魔法值有 why 注释,无复述式、无注释掉的配置块 | ✓ |
@@ -282,6 +282,53 @@ class CreateUserRequest(BaseModel):
282
282
  - 所有类、所有方法/函数(含私有)**必须**有 docstring
283
283
  - docstring 统一使用 **Google 风格**
284
284
 
285
+ ### 临时代码标识(强制)
286
+
287
+ 产品源码中的业务待办、调试旁路、假数据**必须**用固定标签,便于编辑器全局搜索。`tests/` 内正规 mock / fixture **不强制**。
288
+
289
+ | 标签 | 用途 | 格式 |
290
+ |---|---|---|
291
+ | `TODO` | 业务/技术未完成 | `# TODO(name, YYYY-MM-DD): 说明`(推荐带责任人与日期) |
292
+ | `TESTCODE` | 临时调试、跳过校验、试验开关 | `# TESTCODE: 说明 + 移除条件` |
293
+ | `MOCK` | 假数据、假接口、stub 实现 | `# MOCK: 说明 + 将来替换点` |
294
+
295
+ - 写 mock/调试代码的**同一 diff 必须带标**;接真实现后**删标签与包夹**
296
+ - 禁止无标签假返回;禁止自造 `# 假数据`、`# test only` 等替代词
297
+ - 发版/提测前 `rg 'MOCK|TESTCODE'`,清单交给负责人确认(允许残留但须知情)
298
+
299
+ **单行**(仅一行代码):
300
+
301
+ ```python
302
+ # MOCK: 登录假 token,接 POST /auth/login 后删除
303
+ return {"token": "fake-token"}
304
+
305
+ # TESTCODE: 强制测试账号,提测前删除
306
+ user_id = 1
307
+ ```
308
+
309
+ **多行 / 大段(≥2 行逻辑)强制包夹**:
310
+
311
+ ```text
312
+ # MOCK BEGIN: <说明 + 将来替换点>
313
+ ...
314
+ # MOCK END
315
+
316
+ # TESTCODE BEGIN: <说明 + 移除条件>
317
+ ...
318
+ # TESTCODE END
319
+ ```
320
+
321
+ ```python
322
+ # MOCK BEGIN: 用户详情假数据,接 UserRepository.get 后删除
323
+ user = {
324
+ "id": 1,
325
+ "name": "张三",
326
+ "roles": ["admin"],
327
+ }
328
+ return user
329
+ # MOCK END
330
+ ```
331
+
285
332
  ### 完整示例(模块 / 类 / 方法 / 私有方法 docstring)
286
333
 
287
334
  ```python
@@ -453,6 +453,60 @@ import type { UserInfo } from '@/features/users/types'
453
453
  5. 全部使用**中文**,**禁止**混用中英文
454
454
  6. 代码改了,注释**必须**同步更新
455
455
 
456
+ ### 临时代码标识(强制 · TS / Vue)
457
+
458
+ 产品源码(`src/`)中的业务待办、调试旁路、假数据**必须**用固定标签。`tests/` 内 Vitest mock **不强制**。
459
+
460
+ | 标签 | 用途 | 格式 |
461
+ |---|---|---|
462
+ | `TODO` | 业务/技术未完成 | `// TODO(name, YYYY-MM-DD): 说明`(推荐) |
463
+ | `TESTCODE` | 临时调试、`console` 后门、试验开关 | `// TESTCODE: 说明 + 移除条件` |
464
+ | `MOCK` | 假数据、假接口、stub | `// MOCK: 说明 + 将来替换点` |
465
+
466
+ - `<script>` / `.ts` 用 `//`;模板用 `<!-- ... -->`
467
+ - 写 mock/调试的**同一 diff 必须带标**;接真实现后**删标签与包夹**
468
+ - 禁止无标签假返回;禁止自造 `// 假数据` 等替代词
469
+ - 发版前搜 `MOCK`、`TESTCODE`,清单确认(允许残留但须知情)
470
+
471
+ **单行**(仅一行代码):
472
+
473
+ ```ts
474
+ // MOCK: 首页 banner 假数据,接 GET /banners 后删除
475
+ const banners = ref([{ id: 1, title: 'demo' }])
476
+
477
+ // TESTCODE: 打开时 dump store,上线前删除
478
+ // console.log(store.$state)
479
+ ```
480
+
481
+ **多行 / 大段(≥2 行逻辑)强制包夹**:
482
+
483
+ ```text
484
+ // MOCK BEGIN: <说明 + 将来替换点>
485
+ ...
486
+ // MOCK END
487
+
488
+ // TESTCODE BEGIN: <说明 + 移除条件>
489
+ ...
490
+ // TESTCODE END
491
+ ```
492
+
493
+ ```ts
494
+ // MOCK BEGIN: 首页假数据,接 GET /home 后删除
495
+ const banners = ref([
496
+ { id: 1, title: 'demo-a' },
497
+ { id: 2, title: 'demo-b' },
498
+ ])
499
+ const user = ref({ name: '张三' })
500
+ // MOCK END
501
+ ```
502
+
503
+ ```vue
504
+ <!-- MOCK BEGIN: 无接口时的占位,接 CMS 后删除 -->
505
+ <div>占位标题</div>
506
+ <div>占位副标题</div>
507
+ <!-- MOCK END -->
508
+ ```
509
+
456
510
  ### 示例
457
511
 
458
512
  ```typescript
@@ -509,6 +563,7 @@ AI 编写或审查 Vue 代码时,**必须**检查以下违规模式:
509
563
  | 解构 store 丢响应性 | `const { x } = store`(应用 `storeToRefs`) | 高 |
510
564
  | 注释缺失 | 导出函数 / 类型 / 接口字段无中文注释 | 中 |
511
565
  | 注释为英文 | 项目中文环境下写英文注释 | 中 |
566
+ | 无标签 mock/调试 | `src/` 假数据或调试旁路未标 `MOCK:` / `TESTCODE:` | 高 |
512
567
  | 硬编码 API 地址 | URL 直接写在代码里,未走 `import.meta.env` | 高 |
513
568
  | 相对路径回溯 | `../../../` 跨层导入 | 中 |
514
569
  | scoped 替代 Tailwind | 大段 scoped CSS 实现可用 Tailwind 表达的样式 | 中 |
@@ -36,6 +36,52 @@ final class TaskListViewModel {}
36
36
  - 统一 `guard` + early return,不要多层 `else`。
37
37
  - 禁止 `try?` 吞异常;不写无意义 `value ?? default`。
38
38
 
39
+ ### 临时代码标识(强制)
40
+
41
+ 产品源码中的业务待办、调试旁路、假数据**必须**用固定标签(`//`,勿写进正式 `///` 文档注释)。单元测试 / UITest 正规 mock **不强制**。
42
+
43
+ | 标签 | 用途 | 格式 |
44
+ |---|---|---|
45
+ | `TODO` | 业务/技术未完成 | `// TODO(name, YYYY-MM-DD): 说明`(推荐) |
46
+ | `TESTCODE` | 临时调试、跳过生物识别/鉴权等 | `// TESTCODE: 说明 + 移除条件` |
47
+ | `MOCK` | 假数据、stub Service | `// MOCK: 说明 + 将来替换点` |
48
+
49
+ - 写 mock/调试的**同一 diff 必须带标**;接真实现后**删标签与包夹**
50
+ - 禁止无标签假返回;禁止自造 `// 假数据` 等替代词
51
+ - 发版/提测前搜 `MOCK`、`TESTCODE`,清单确认(允许残留但须知情)
52
+
53
+ **单行**(仅一行代码):
54
+
55
+ ```swift
56
+ // MOCK: 个人资料假数据,接 ProfileService.fetch 后删除
57
+ let profile = Profile(name: "Demo", avatarURL: nil)
58
+
59
+ // TESTCODE: 跳过生物识别,提测包删除
60
+ // return true
61
+ ```
62
+
63
+ **多行 / 大段(≥2 行逻辑)强制包夹**:
64
+
65
+ ```text
66
+ // MOCK BEGIN: <说明 + 将来替换点>
67
+ ...
68
+ // MOCK END
69
+
70
+ // TESTCODE BEGIN: <说明 + 移除条件>
71
+ ...
72
+ // TESTCODE END
73
+ ```
74
+
75
+ ```swift
76
+ // MOCK BEGIN: 个人资料假数据,接 ProfileService.fetch 后删除
77
+ let profile = Profile(
78
+ name: "Demo",
79
+ avatarURL: nil,
80
+ roles: ["user"]
81
+ )
82
+ // MOCK END
83
+ ```
84
+
39
85
  ## 全面屏与布局
40
86
 
41
87
  - 默认尊重安全区;固定内容区用 `safeAreaInset` / `safeAreaPadding`。