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.
- package/CHANGELOG.md +17 -0
- package/bin/index.js +23 -19
- package/package.json +1 -1
- package/src/cli-help.js +44 -0
- package/src/sync-all.js +303 -59
- package/src/sync-global-skills.js +167 -0
- package/src/sync.js +21 -11
- package/templates/ai-tools/CHANGELOG.md +134 -0
- package/templates/ai-tools/VERSION +1 -1
- package/templates/ai-tools/rules/Android/dwy-android-core.md +65 -1
- package/templates/ai-tools/rules/Python/dwy-python-core.md +47 -0
- package/templates/ai-tools/rules/Vue/dwy-vue-core.md +55 -0
- package/templates/ai-tools/rules/iOS/dwy-swift-core.md +46 -0
- package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-oss-commercial-license.md +128 -0
- 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
- 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
- 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
- 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
- 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
- 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
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/SKILL.md +11 -8
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/android.md +2 -1
- 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
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/changelog.md +24 -4
- 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
- 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
- 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
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/harmony.md +2 -1
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/ios.md +3 -2
- 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
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-semver/SKILL.md +1 -1
- package/templates/ai-tools/skills//345/237/272/347/241/200/345/272/223/dwy-eapi/references/tasks-integration-guide.md +2 -2
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/README.md +57 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/SKILL.md +147 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/references/api.md +43 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/references/config.example.yaml +33 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/scripts/global_config.py +89 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/scripts/setup_config.py +175 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/scripts/synthesize.py +339 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/media-platform-packaging/SKILL.md +127 -0
- 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
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/media-platform-packaging/references/platform-copy-examples.md +37 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/media-platform-packaging/references/platform-posting-times.md +193 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0005-ideation/SKILL.md +42 -0
- 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
- 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
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0010-product/SKILL.md +106 -0
- 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
- 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
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0030-facts/SKILL.md +60 -0
- 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
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0030-facts/scripts/generate_html.py +1287 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0030-facts/scripts/generate_report.py +189 -0
- 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
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0040-script/SKILL.md +36 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0040-script/templates/README.md +10 -0
- 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
- 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
- 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
- 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
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0050-design/SKILL.md +55 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0060-assets/SKILL.md +29 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0070-package/SKILL.md +42 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0070-package/scripts/validate_shots.py +207 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0070-package/shots.schema.json +186 -0
- 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
- 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
- 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
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-0080-factory/SKILL.md +58 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-comic-kit/SKILL.md +424 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-comic-kit/evals.md +41 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-flow/CONTRACT.md +123 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-flow/SKILL.md +81 -0
- 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
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/SKILL.md +78 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/agents/openai.yaml +4 -0
- 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
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/assets/remotion/AudioTracks.tsx +20 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/assets/remotion/CaptionLayer.tsx +18 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/assets/remotion/CueTimeline.ts +24 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/assets/remotion/KnowledgeTownComposition.tsx +21 -0
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/references/cinematic-direction.md +73 -0
- 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
- package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/uc-media-knowledge-town/references/style-guide.md +43 -0
- 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
- 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
- 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
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/SKILL.md +0 -511
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/references/checks-data.md +0 -126
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/references/checks-network.md +0 -88
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/references/checks-runtime.md +0 -195
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/references/security-doc-search.md +0 -179
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_base.sh +0 -39
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_capacity.sh +0 -278
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_db.sh +0 -147
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_docker.sh +0 -230
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_env.sh +0 -64
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_https.sh +0 -60
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_logs.sh +0 -209
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_nginx.sh +0 -100
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_resilience.sh +0 -157
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_secrets.sh +0 -265
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_services.sh +0 -94
- package/templates/ai-tools/skills/unitcircle/uc-deploy-audit/scripts/check_ssh.sh +0 -56
- 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 <
|
|
268
|
-
const { key, label } =
|
|
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 ===
|
|
285
|
+
if (i === categories.length - 1) break
|
|
276
286
|
|
|
277
|
-
const nextLabel =
|
|
278
|
-
const prevLabel = i > 0 ?
|
|
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
|
|
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
|
-
...
|
|
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 =
|
|
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.
|
|
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 | 无注释掉的代码块(垃圾代码)
|
|
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`。
|