create-dwy 0.26.0 → 0.28.0

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 (101) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/package.json +1 -1
  3. package/src/cli-help.js +11 -13
  4. package/src/sync-all.js +86 -11
  5. package/src/sync-plan.js +9 -1
  6. package/templates/ai-tools/CHANGELOG.md +13 -0
  7. package/templates/ai-tools/VERSION +1 -1
  8. package/templates/ai-tools/skills/Android/dwy-android-architecture/SKILL.md +10 -0
  9. package/templates/ai-tools/skills/Android/dwy-android-development/SKILL.md +16 -0
  10. package/templates/ai-tools/skills/Apple/dwy-apple-appkit/SKILL.md +17 -0
  11. package/templates/ai-tools/skills/Apple/dwy-apple-architecture/SKILL.md +12 -0
  12. package/templates/ai-tools/skills/Apple/dwy-apple-architecture/references/extraction.md +9 -0
  13. package/templates/ai-tools/{rules/iOS/dwy-apple-layering.md → skills/Apple/dwy-apple-architecture/references/layering.md} +2 -10
  14. package/templates/ai-tools/skills/Apple/dwy-apple-architecture/references/pitfalls.md +3 -0
  15. package/templates/ai-tools/skills/Apple/dwy-ios-development/SKILL.md +14 -0
  16. package/templates/ai-tools/skills/Apple/dwy-ios-development/references/appearance.md +6 -0
  17. package/templates/ai-tools/{rules/iOS/dwy-ios-layout-adaptation.md → skills/Apple/dwy-ios-development/references/layout.md} +0 -6
  18. package/templates/ai-tools/{rules/iOS/dwy-ios-pitfalls.md → skills/Apple/dwy-ios-development/references/pitfalls.md} +1 -9
  19. package/templates/ai-tools/skills/Apple/dwy-ios-development/references/presentations.md +11 -0
  20. package/templates/ai-tools/skills/Apple/dwy-macos-development/SKILL.md +14 -0
  21. package/templates/ai-tools/skills/Apple/dwy-macos-development/references/pitfalls.md +9 -0
  22. package/templates/ai-tools/skills/Apple/dwy-macos-development/references/presentations.md +5 -0
  23. package/templates/ai-tools/skills/Apple/dwy-macos-development/references/ui-adaptation.md +6 -0
  24. package/templates/ai-tools/skills/Apple/dwy-swift-development/SKILL.md +16 -0
  25. package/templates/ai-tools/{rules/iOS/dwy-swift-core.md → skills/Apple/dwy-swift-development/references/conventions.md} +2 -8
  26. package/templates/ai-tools/skills/Apple/dwy-swift-development/references/pitfalls.md +5 -0
  27. package/templates/ai-tools/skills/Apple/dwy-swift-development/references/presentations.md +8 -0
  28. package/templates/ai-tools/skills/Docker/dwy-docker/SKILL.md +2 -0
  29. package/templates/ai-tools/skills/Flutter/dwy-flutter-development/SKILL.md +15 -0
  30. package/templates/ai-tools/skills/HarmonyOS/dwy-harmony-development/SKILL.md +15 -0
  31. package/templates/ai-tools/skills/Python/dwy-apple-notify/SKILL.md +24 -0
  32. package/templates/ai-tools/skills/Python/dwy-apple-notify/references/v0/0.1.6.md +81 -0
  33. package/templates/ai-tools/skills/Python/dwy-auth/SKILL.md +24 -0
  34. package/templates/ai-tools/skills/Python/dwy-auth/references/v0/0.2.0.md +163 -0
  35. package/templates/ai-tools/skills/Python/dwy-device-fingerprint/SKILL.md +19 -0
  36. package/templates/ai-tools/skills/Python/dwy-device-fingerprint/references/v0/0.1.1.md +90 -0
  37. package/templates/ai-tools/skills/Python/dwy-eapi/SKILL.md +1 -1
  38. package/templates/ai-tools/skills/Python/dwy-eapi/versions.yml +3 -3
  39. package/templates/ai-tools/skills/Python/dwy-email-notify/SKILL.md +19 -0
  40. package/templates/ai-tools/skills/Python/dwy-email-notify/references/v0/0.1.0.md +31 -0
  41. package/templates/ai-tools/skills/Python/dwy-notify/SKILL.md +24 -0
  42. package/templates/ai-tools/skills/Python/dwy-notify/references/v0/0.3.2.md +128 -0
  43. package/templates/ai-tools/skills/Python/dwy-payment/SKILL.md +19 -0
  44. package/templates/ai-tools/skills/Python/dwy-payment/references/v0/0.3.0.md +90 -0
  45. package/templates/ai-tools/skills/Python/dwy-python-api/SKILL.md +8 -0
  46. package/templates/ai-tools/skills/Python/dwy-python-architecture/SKILL.md +8 -0
  47. package/templates/ai-tools/skills/Python/dwy-python-development/SKILL.md +17 -0
  48. package/templates/ai-tools/{rules/Python → skills/Python/dwy-python-development/references}/dwy-python-base-lib.md +3 -3
  49. package/templates/ai-tools/skills/Python/dwy-webhooks/SKILL.md +24 -0
  50. package/templates/ai-tools/skills/Python/dwy-webhooks/references/v0/0.6.2.md +238 -0
  51. package/templates/ai-tools/skills/Python/dwy-wechatpay-notify/SKILL.md +19 -0
  52. package/templates/ai-tools/skills/Python/dwy-wechatpay-notify/references/v0/0.1.1.md +101 -0
  53. package/templates/ai-tools/skills/Vue/dwy-admin-kit/SKILL.md +12 -0
  54. package/templates/ai-tools/skills/Vue/dwy-admin-kit/references/v0/0.3.0.md +176 -0
  55. package/templates/ai-tools/skills/Vue/dwy-auth-web/SKILL.md +10 -0
  56. package/templates/ai-tools/skills/Vue/dwy-ekit/SKILL.md +2 -3
  57. package/templates/ai-tools/skills/Vue/dwy-eui/SKILL.md +1 -1
  58. package/templates/ai-tools/skills/Vue/dwy-eui/versions.yml +2 -2
  59. package/templates/ai-tools/skills/Vue/dwy-vue-architecture/SKILL.md +8 -0
  60. package/templates/ai-tools/skills/Vue/dwy-vue-development/SKILL.md +16 -0
  61. package/templates/ai-tools/{rules/Vue → skills/Vue/dwy-vue-development/references}/dwy-vue-base-lib.md +3 -3
  62. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-architecture/SKILL.md +7 -7
  63. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/SKILL.md +2 -0
  64. package/templates/ai-tools/skills//346/225/260/346/215/256/345/272/223/dwy-alembic/SKILL.md +8 -0
  65. package/templates/ai-tools/skills//346/225/260/346/215/256/345/272/223/dwy-postgres/SKILL.md +10 -0
  66. package/templates/ai-tools/skills//346/225/260/346/215/256/345/272/223/dwy-redis/SKILL.md +8 -0
  67. package/templates/ai-tools/skills//351/200/232/347/224/250/dwy-dependency-choice/SKILL.md +1 -1
  68. package/templates/ai-tools/skills//351/200/232/347/224/250/dwy-development-review/SKILL.md +2 -0
  69. package/templates/ai-tools/skills//351/200/232/347/224/250/dwy-git-commit/SKILL.md +1 -1
  70. /package/templates/ai-tools/{rules/Android → skills/Android/dwy-android-architecture/references}/dwy-android-layering.md +0 -0
  71. /package/templates/ai-tools/{rules/Android → skills/Android/dwy-android-architecture/references}/dwy-android-mvp.md +0 -0
  72. /package/templates/ai-tools/{rules/Android → skills/Android/dwy-android-development/references}/dwy-android-core.md +0 -0
  73. /package/templates/ai-tools/{rules/Android → skills/Android/dwy-android-development/references}/dwy-android-pitfalls.md +0 -0
  74. /package/templates/ai-tools/{rules/Android → skills/Android/dwy-android-development/references}/dwy-android-support-only.md +0 -0
  75. /package/templates/ai-tools/{rules/Docker → skills/Docker/dwy-docker/references}/dwy-docker.md +0 -0
  76. /package/templates/ai-tools/{rules/Flutter → skills/Flutter/dwy-flutter-development/references}/dwy-flutter-core.md +0 -0
  77. /package/templates/ai-tools/{rules/Flutter → skills/Flutter/dwy-flutter-development/references}/dwy-flutter-network.md +0 -0
  78. /package/templates/ai-tools/{rules/Flutter → skills/Flutter/dwy-flutter-development/references}/dwy-flutter-router.md +0 -0
  79. /package/templates/ai-tools/{rules/Flutter → skills/Flutter/dwy-flutter-development/references}/dwy-flutter-testing.md +0 -0
  80. /package/templates/ai-tools/{rules/HarmonyOS → skills/HarmonyOS/dwy-harmony-development/references}/dwy-arkts-strict.md +0 -0
  81. /package/templates/ai-tools/{rules/HarmonyOS → skills/HarmonyOS/dwy-harmony-development/references}/dwy-arkts-ui-build.md +0 -0
  82. /package/templates/ai-tools/{rules/HarmonyOS → skills/HarmonyOS/dwy-harmony-development/references}/dwy-arkts-ui-design.md +0 -0
  83. /package/templates/ai-tools/{rules/HarmonyOS → skills/HarmonyOS/dwy-harmony-development/references}/dwy-harmony-pitfalls.md +0 -0
  84. /package/templates/ai-tools/{rules/Python → skills/Python/dwy-python-api/references}/dwy-python-backend.md +0 -0
  85. /package/templates/ai-tools/{rules/Python → skills/Python/dwy-python-architecture/references}/dwy-python-layering.md +0 -0
  86. /package/templates/ai-tools/{rules/Python → skills/Python/dwy-python-development/references}/dwy-python-core.md +0 -0
  87. /package/templates/ai-tools/{rules/Python → skills/Python/dwy-python-development/references}/dwy-python-pitfalls.md +0 -0
  88. /package/templates/ai-tools/{rules/Python → skills/Python/dwy-python-development/references}/dwy-python-testing.md +0 -0
  89. /package/templates/ai-tools/{rules/Vue → skills/Vue/dwy-vue-architecture/references}/dwy-vue-layering.md +0 -0
  90. /package/templates/ai-tools/{rules/Vue → skills/Vue/dwy-vue-development/references}/dwy-vue-core.md +0 -0
  91. /package/templates/ai-tools/{rules/Vue → skills/Vue/dwy-vue-development/references}/dwy-vue-pinia.md +0 -0
  92. /package/templates/ai-tools/{rules/Vue → skills/Vue/dwy-vue-development/references}/dwy-vue-pitfalls.md +0 -0
  93. /package/templates/ai-tools/{rules/Vue → skills/Vue/dwy-vue-development/references}/dwy-vue-testing.md +0 -0
  94. /package/templates/ai-tools/{rules//345/274/200/345/217/221/346/265/201/347/250/213 → skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references}/dwy-prod-branch.md" +0 -0
  95. /package/templates/ai-tools/{rules//346/225/260/346/215/256/345/272/223 → skills//346/225/260/346/215/256/345/272/223/dwy-alembic/references}/dwy-db-migration.md" +0 -0
  96. /package/templates/ai-tools/{rules//346/225/260/346/215/256/345/272/223 → skills//346/225/260/346/215/256/345/272/223/dwy-postgres/references}/dwy-postgres.md" +0 -0
  97. /package/templates/ai-tools/{rules//346/225/260/346/215/256/345/272/223 → skills//346/225/260/346/215/256/345/272/223/dwy-redis/references}/dwy-redis.md" +0 -0
  98. /package/templates/ai-tools/{rules//345/274/200/345/217/221/346/265/201/347/250/213 → skills//351/200/232/347/224/250/dwy-dependency-choice/references}/dwy-dependency-freshness.md" +0 -0
  99. /package/templates/ai-tools/{rules//345/274/200/345/217/221/346/265/201/347/250/213 → skills//351/200/232/347/224/250/dwy-dependency-choice/references}/dwy-oss-commercial-license.md" +0 -0
  100. /package/templates/ai-tools/{rules//345/274/200/345/217/221/346/265/201/347/250/213 → skills//351/200/232/347/224/250/dwy-development-review/references}/dwy-code-craft.md" +0 -0
  101. /package/templates/ai-tools/{rules//345/274/200/345/217/221/346/265/201/347/250/213 → skills//351/200/232/347/224/250/dwy-git-commit/references}/dwy-git-commit.md" +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # create-dwy
2
2
 
3
+ ## [0.28.0] - 2026-11-08
4
+
5
+ ### Changed
6
+
7
+ - 将 Android、Flutter、HarmonyOS、数据库、Docker 和开发流程的剩余 Rules 迁移到按需安装的 Skills;补充旧项目的安全迁移与选择。
8
+ - 同步交互不再分发或选择 Rules;Claude Code、Codex 和 OpenCode 保持支持,原 Cursor 配置保留且不再提供同步入口。
9
+ - 模板详情见 ai-tools 0.35.0。
10
+
11
+ ---
12
+
13
+ ## [0.27.0] - 2026-11-07
14
+
15
+ ### Changed
16
+
17
+ - 新增 Python、Vue 和 Apple 按需开发、架构与基础库 Skills;按版本查找公开接口和接入说明。
18
+ - 迁移 Python、Vue 旧托管 Rules,推荐对应 Skills;未选择替代项时保留旧内容,预览并保护个人配置。其他技术栈 Rules 保持可用。
19
+ - 修正 EUI、EAPI 版本线匹配范围和 Ekit Skill 元数据;模板详情见 ai-tools 0.34.0。
20
+
21
+ ---
22
+
3
23
  ## [0.26.0] - 2026-11-06
4
24
 
5
25
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-dwy",
3
- "version": "0.26.0",
3
+ "version": "0.28.0",
4
4
  "description": "项目脚手架与多平台 AI 配置同步工具",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli-help.js CHANGED
@@ -25,24 +25,23 @@ export function buildHelpText(version) {
25
25
  '同步步骤:',
26
26
  ' 1. 选择同步范围:当前项目或全局。',
27
27
  ' 2. 选择 Skills。',
28
- ' 3. 仅项目范围选择 Rules;全局跳过。',
29
- ' 4. 选择 AGENTS.md 通用规范,默认启用。',
30
- ' 5. 选择 Hooks,默认启用。',
28
+ ' 3. 选择 AGENTS.md 通用规范,默认启用。',
29
+ ' 4. 选择 Hooks,默认启用。',
31
30
  ' 项目已有有效全局规范或全部所需全局 Hooks 时,跳过对应操作页。',
32
- ' 6. 最后选择 CLI;首次只选 Codex,后续恢复当前范围同步过的 CLI 与有效旧托管入口。',
33
- ' 7. 按最终 CLI 重新核算覆盖,预览实际写入、迁移、备份和清理清单。',
34
- ' 8. 确认后执行,显示实际完成信息;取消不改同步目标。',
31
+ ' 5. 最后选择 CLI;首次只选 Codex,后续恢复当前范围同步过的 CLI 与有效旧托管入口。',
32
+ ' 6. 按最终 CLI 重新核算覆盖,预览实际写入、迁移、备份和清理清单。',
33
+ ' 7. 确认后执行,显示实际完成信息;取消不改同步目标。',
35
34
  ' Commands 不参与同步。',
36
35
  '',
37
36
  '交互按键:',
38
- ' Skills / Rules:←/→ 切分类,↑/↓ 移动,Space 勾选,a 全选/清空当前分类。',
37
+ ' Skills:←/→ 切分类,↑/↓ 移动,Space 勾选,a 全选/清空当前分类。',
39
38
  ' 范围 / 通用规范 / Hooks / CLI:↑/↓ 移动;CLI 用 Space 勾选,可输入关键字筛选。',
40
39
  ' Enter 确认当前步骤,Esc 或 Ctrl+C 取消。',
41
40
  '',
42
41
  '常见用法:',
43
42
  ' 同步当前项目:cd your-project 后执行 dwy,选择「当前项目」。',
44
43
  ' 同步全局:执行 dwy,选择「全局」。',
45
- ' 移除配置:在当前范围取消 Skills / Rules 勾选,或关闭 Hooks / 通用规范,再确认。',
44
+ ' 移除配置:在当前范围取消 Skills 勾选,或关闭 Hooks / 通用规范,再确认。',
46
45
  ' 更新或调整配置:再次执行 dwy sync,检查勾选项,再确认同步。',
47
46
  ' 更新 CLI:dwy upgrade(全局安装时可用;更新后执行 dwy --version 查看版本)。',
48
47
  ' 迁移老项目:cd your-project 后执行 dwy migrate,无需重新勾选。',
@@ -50,10 +49,9 @@ export function buildHelpText(version) {
50
49
  ' 首次安装:npm install -g create-dwy@latest',
51
50
  '',
52
51
  '平台支持:',
53
- ' Claude Code:全局 ~/.claude/CLAUDE.md;项目 Rules 使用根 AGENTS.md。',
52
+ ' Claude Code:全局 ~/.claude/CLAUDE.md;项目可使用根 AGENTS.md。',
54
53
  ' Codex:全局 $CODEX_HOME/AGENTS.md(默认 ~/.codex/AGENTS.md);项目根 AGENTS.md。',
55
54
  ' OpenCode:全局 ~/.config/opencode/AGENTS.md;项目根 AGENTS.md;当前不支持 Hooks。',
56
- ' Cursor:仅项目 Rules;全局规则在 Cursor 设置中管理。',
57
55
  '',
58
56
  '同步按当前范围和最终 CLI 执行;项目 AGENTS.md 由多个 CLI 共享。',
59
57
  '用户主目录不能作为项目范围同步,请选择全局或进入项目目录。',
@@ -64,8 +62,8 @@ export function buildHelpText(version) {
64
62
  'Hooks 与 Skills 独立;整组管理,项目仅安装缺少有效全局注册的 Hooks。',
65
63
  '全局 Hook 的脚本与对应事件、matcher、完整命令注册均有效时,项目禁止重复安装。',
66
64
  '任一适用 CLI 已有 dwy 全局通用规范时,项目继承并清理重复基线;其他 CLI 缺失的全局规范另选全局范围补齐。',
67
- '手写 AGENTS.md 本身不算全局已安装;通用规范与 Rules 共用文件但独立管理。',
68
- '移除通用规范仅删除基线块;项目 Rules 独立管理,保留手写内容。',
65
+ '手写 AGENTS.md 本身不算全局已安装;通用规范仅管理其托管块,保留手写内容。',
66
+ '旧托管 Rules 在选中替代 Skills 并确认后迁移,无法确认归属的内容保留。',
69
67
  '全局启用会明确列出当前项目重复项清理;全局移除不会自动向项目补装。',
70
68
  '项目同步只清理项目重复入口,不改写有效全局提供者;真实目录先备份。',
71
69
  '确认前不改项目/全局配置或已安装共享内容;确认后才同步配置,并刷新所选共享 Skills。',
@@ -74,7 +72,7 @@ export function buildHelpText(version) {
74
72
  '产品流程缺失的外部依赖也列入清单,确认后联网补齐,已有内容保留。',
75
73
  '旧真实目录备份到同步根的 .dwy/skill-backups;个人 Skills、Rules、Hooks 不参与 migrate。',
76
74
  '旧项目首次需执行 dwy migrate;迁移后无需逐项目刷新 Skills。',
77
- 'Rules / Hooks 的模板更新仍需执行 dwy sync;已有会话缓存的 Skill 可能需要重新加载。',
75
+ 'Hooks 的模板更新仍需执行 dwy sync;已有会话缓存的 Skill 可能需要重新加载。',
78
76
  '',
79
77
  '模板更新:',
80
78
  ' 模板随 CLI 包分发,启动不联网检查模板。',
package/src/sync-all.js CHANGED
@@ -15,10 +15,9 @@ import { buildSyncPlan, contentOptions, projectSkillChoices, PLATFORM_LABELS, PL
15
15
  import { assertConfigPath, baselineProviders, globalBaselinePath, globalHookNames, hasManagedHookConfig } from './sync-inheritance.js'
16
16
 
17
17
  const PLATFORM_OPTIONS = [
18
- { value: 'claude', label: 'Claude Code', description: '支持 Skills、项目 Rules、Hooks 和全局通用规范' },
19
- { value: 'codex', label: 'Codex', description: '支持 Skills、项目 Rules、Hooks 和全局通用规范' },
20
- { value: 'opencode', label: 'OpenCode', description: '支持 Skills、项目 Rules 和全局通用规范;不支持 Hooks' },
21
- { value: 'cursor', label: 'Cursor', description: '只支持项目 Rules' },
18
+ { value: 'claude', label: 'Claude Code', description: '支持 Skills、Hooks 和全局通用规范' },
19
+ { value: 'codex', label: 'Codex', description: '支持 Skills、Hooks 和全局通用规范' },
20
+ { value: 'opencode', label: 'OpenCode', description: '支持 Skills 和全局通用规范;不支持 Hooks' },
22
21
  ]
23
22
  const SYNC_STATE_PATH = ['.dwy', 'sync-state.json']
24
23
  /** 按显式选中的内容同步;保留已有脚本的模式标识。 */
@@ -96,7 +95,7 @@ async function selectPlatforms(root, scope, initialValues) {
96
95
  options: PLATFORM_OPTIONS.filter(option => scope === 'project' || option.value !== 'cursor')
97
96
  .map(option => ({ ...option, description: [state.platforms[option.value] ? '已有同步记录,将核对并修复本地配置' : '',
98
97
  contentOptions(scope, [option.value]).map(item => item.label).join('、')].filter(Boolean).join(';') })),
99
- initialValues,
98
+ initialValues: initialValues.filter(platform => PLATFORM_OPTIONS.some(option => option.value === platform)),
100
99
  required: true, maxItems: 6, placeholder: SEARCH_PLACEHOLDER,
101
100
  })
102
101
  return isCancel(result) ? null : result
@@ -134,6 +133,7 @@ async function managedNames(root, global, codexHome) {
134
133
  for (const name of await fs.readdir(path.join(codexHome, 'skills'))) codexSkills.add(name)
135
134
  }
136
135
  return {
136
+ projectRules,
137
137
  claude: { skills: await scanExisting(claude, 'skills'), rules: unionSets(projectRules, await scanExisting(claude, 'rules')), hooks: await scanExisting(claude, 'hooks') },
138
138
  codex: { skills: codexSkills, rules: projectRules, hooks: await scanExistingCodexHooks(root, global ? codexHome : path.join(root, '.codex')) },
139
139
  opencode: { skills: await scanExisting(opencode, 'skills'), rules: projectRules, hooks: new Set() },
@@ -141,13 +141,62 @@ async function managedNames(root, global, codexHome) {
141
141
  }
142
142
  }
143
143
 
144
+ const RULE_SKILL_MIGRATIONS = {
145
+ 'dwy-python-core.md': ['dwy-python-development'],
146
+ 'dwy-python-testing.md': ['dwy-python-development'],
147
+ 'dwy-python-pitfalls.md': ['dwy-python-development'],
148
+ 'dwy-python-base-lib.md': ['dwy-python-development', 'dwy-eapi'],
149
+ 'dwy-python-backend.md': ['dwy-python-api'],
150
+ 'dwy-python-layering.md': ['dwy-python-architecture'],
151
+ 'dwy-vue-core.md': ['dwy-vue-development'],
152
+ 'dwy-vue-testing.md': ['dwy-vue-development'],
153
+ 'dwy-vue-pitfalls.md': ['dwy-vue-development'],
154
+ 'dwy-vue-pinia.md': ['dwy-vue-development'],
155
+ 'dwy-vue-base-lib.md': ['dwy-vue-development', 'dwy-eui', 'dwy-ekit'],
156
+ 'dwy-vue-layering.md': ['dwy-vue-architecture'],
157
+ 'dwy-swift-core.md': ['dwy-swift-development'],
158
+ 'dwy-apple-layering.md': ['dwy-apple-architecture'],
159
+ 'dwy-ios-layout-adaptation.md': ['dwy-ios-development'],
160
+ 'dwy-ios-pitfalls.md': ['dwy-ios-development'],
161
+ 'dwy-android-core.md': ['dwy-android-development'],
162
+ 'dwy-android-pitfalls.md': ['dwy-android-development'],
163
+ 'dwy-android-support-only.md': ['dwy-android-development'],
164
+ 'dwy-android-layering.md': ['dwy-android-architecture'],
165
+ 'dwy-android-mvp.md': ['dwy-android-architecture'],
166
+ 'dwy-flutter-core.md': ['dwy-flutter-development'],
167
+ 'dwy-flutter-network.md': ['dwy-flutter-development'],
168
+ 'dwy-flutter-router.md': ['dwy-flutter-development'],
169
+ 'dwy-flutter-testing.md': ['dwy-flutter-development'],
170
+ 'dwy-arkts-strict.md': ['dwy-harmony-development'],
171
+ 'dwy-arkts-ui-build.md': ['dwy-harmony-development'],
172
+ 'dwy-arkts-ui-design.md': ['dwy-harmony-development'],
173
+ 'dwy-harmony-pitfalls.md': ['dwy-harmony-development'],
174
+ 'dwy-postgres.md': ['dwy-postgres'],
175
+ 'dwy-redis.md': ['dwy-redis'],
176
+ 'dwy-db-migration.md': ['dwy-alembic'],
177
+ 'dwy-docker.md': ['dwy-docker'],
178
+ 'dwy-code-craft.md': ['dwy-development-review'],
179
+ 'dwy-dependency-freshness.md': ['dwy-dependency-choice'],
180
+ 'dwy-oss-commercial-license.md': ['dwy-dependency-choice'],
181
+ 'dwy-git-commit.md': ['dwy-git-commit'],
182
+ 'dwy-prod-branch.md': ['dwy-publish'],
183
+ }
184
+
185
+ /** 将旧托管规则映射为可选的对应技能,保留用户最终选择。 */
186
+ export function migratedRuleSkills(names) {
187
+ return new Set([...names].flatMap(name => RULE_SKILL_MIGRATIONS[name] || []))
188
+ }
189
+
144
190
  function staleEntries(scans, state, existing, platforms) {
145
191
  const current = Object.fromEntries(['skills', 'rules', 'hooks'].map(type => [type, new Set(scans[type].map(item => item.name))]))
146
192
  const result = {}
147
193
  for (const platform of platforms) {
148
194
  result[platform] = {}
149
195
  for (const type of PLATFORM_SYNC_TYPES[platform].filter(type => current[type])) {
150
- result[platform][type] = (state.platforms[platform]?.[type] || []).filter(name =>
196
+ const historical = state.platforms[platform]?.[type] || []
197
+ const knownRules = type === 'rules' && platform !== 'cursor'
198
+ ? [...existing.projectRules].filter(name => !scans.rules.length || RULE_SKILL_MIGRATIONS[name]) : []
199
+ result[platform][type] = [...new Set([...historical, ...knownRules])].filter(name =>
151
200
  !current[type].has(name) && existing[platform][type].has(platform === 'cursor' && type === 'rules' ? buildCursorRuleName(name) : name))
152
201
  }
153
202
  }
@@ -159,7 +208,7 @@ function normalizeRemovals(raw) {
159
208
  Object.fromEntries(Object.entries(types).map(([type, names]) => [type, new Set(names)]))]))
160
209
  }
161
210
 
162
- /** `dwy` 和 `dwy sync` 共用范围 → Skills → 项目 Rules → 规范 → Hooks → CLI → 确认。 */
211
+ /** `dwy` 和 `dwy sync` 共用范围 → Skills → 规范 → Hooks → CLI → 确认。 */
163
212
  export async function runDwy(opts = {}) {
164
213
  console.log(chalk.bold.cyan('\ndwy') + chalk.gray(' · AI 开发工具\n'))
165
214
  const action = normalizeAction(opts.action)
@@ -248,7 +297,7 @@ export async function syncAll({
248
297
  const scope = scopeOverride || (selectedOverride || platformsOverride ? 'project' : await searchableSelect({
249
298
  message: '选择同步范围',
250
299
  options: [
251
- { value: 'project', label: '当前项目', description: '管理 Skills、Hooks、Rules 和通用规范;继承有效全局配置' },
300
+ { value: 'project', label: '当前项目', description: '管理 Skills、Hooks 和通用规范;继承有效全局配置' },
252
301
  { value: 'global', label: '全局', description: '管理 Skills、Hooks 和通用规范;清理当前项目重复入口' },
253
302
  ], initialValue: 'project',
254
303
  }))
@@ -256,6 +305,7 @@ export async function syncAll({
256
305
  if (!['project', 'global'].includes(scope)) throw new Error('无效同步范围')
257
306
  const global = scope === 'global', targetRoot = global ? homeDir : projectDir
258
307
  let platforms = platformsOverride || await buildPlatformDefaultsFromLocalState(targetRoot, scope, codexHome)
308
+ if (!platformsOverride) platforms = platforms.filter(platform => PLATFORM_OPTIONS.some(option => option.value === platform))
259
309
  if (platforms.length === 0 || platforms.some(platform => !PLATFORM_SYNC_TYPES[platform] || (global && platform === 'cursor'))) throw new Error('所选平台不支持此同步范围')
260
310
  const projectState = await loadSyncState(projectDir), globalState = await loadSyncState(homeDir)
261
311
  const targetState = global ? globalState : projectState
@@ -274,11 +324,16 @@ export async function syncAll({
274
324
  if (contentTypes.some(type => !allowed.has(type))) throw new Error('所选范围或平台不支持此同步内容')
275
325
  if (contentTypes.length === 0) { console.log('未选择处理内容。'); return }
276
326
  const existing = await managedNames(targetRoot, global, codexHome)
277
- const cursorRules = new Set(scans.rules.filter(rule => existing.cursor.rules.has(buildCursorRuleName(rule.name))).map(rule => rule.name))
327
+ const cursorRules = new Set([...scans.rules.map(rule => rule.name), ...Object.keys(RULE_SKILL_MIGRATIONS)]
328
+ .filter(name => existing.cursor.rules.has(buildCursorRuleName(name))))
278
329
  const current = Object.fromEntries(['skills', 'rules', 'hooks'].map(type => [type,
279
330
  unionSets(...platforms.map(platform => platform === 'cursor' && type === 'rules' ? cursorRules : existing[platform][type]))]))
280
331
  const defaults = buildSelectionDefaultsFromSyncState(current, targetState, platforms)
281
332
  for (const type of ['skills', 'rules', 'hooks']) defaults[type] = unionSets(defaults[type], current[type])
333
+ if (!global && contentTypes.includes('skills')) {
334
+ const oldRules = unionSets(current.rules, ...platforms.map(platform => new Set(targetState.platforms[platform]?.rules || [])))
335
+ defaults.skills = unionSets(defaults.skills, migratedRuleSkills(oldRules))
336
+ }
282
337
  const choices = !global && contentTypes.includes('skills')
283
338
  ? { ...scans, skills: await projectSkillChoices(scans.skills, platforms, { homeDir, codexHome }) } : scans
284
339
  const selected = selectedOverride
@@ -329,10 +384,28 @@ export async function syncAll({
329
384
  if (mainFlow) contentTypes = contentTypes.filter(type => options.some(option => option.value === type))
330
385
  const stale = staleEntries(scans, targetState, existing, platforms)
331
386
  const removals = normalizeRemovals(removalsOverride || stale)
387
+ if (!removalsOverride) {
388
+ const availableSkills = new Set(scans.skills.map(skill => skill.name))
389
+ const selectedSkills = new Set(selected.skills.map(skill => skill.name).filter(name => availableSkills.has(name)))
390
+ for (const platform of platforms) for (const name of removals[platform]?.rules || []) {
391
+ const required = RULE_SKILL_MIGRATIONS[name]
392
+ if (!required && !scans.rules.length) {
393
+ removals[platform].rules.delete(name)
394
+ continue
395
+ }
396
+ if (required && (platform === 'cursor' || !contentTypes.includes('skills') || required.some(skill => !selectedSkills.has(skill)))) {
397
+ removals[platform].rules.delete(name)
398
+ }
399
+ }
400
+ }
332
401
  const baseline = contentTypes.some(type => type === 'rules' || type === 'baseline') ? await readBaselineDoc(sourceDir) : ''
333
402
  const plan = await buildSyncPlan({
334
403
  scope, platforms, contentTypes, selected, scans, sourceDir, projectDir, homeDir, codexHome,
335
404
  projectState, globalState, staleRemovals: removals, staleEntries: stale, baseline,
405
+ migratedRuleSources: Object.fromEntries(Object.entries(RULE_SKILL_MIGRATIONS).flatMap(([name, skills]) => {
406
+ const skill = scans.skills.find(item => item.name === skills[0])
407
+ return skill ? [[name, path.join(skill.sourcePath, 'references', name)]] : []
408
+ })),
336
409
  contentActions,
337
410
  refreshSkills: mainFlow,
338
411
  skillScope: normalizeSkillScope(skillScopeOverride),
@@ -353,9 +426,11 @@ export async function syncAll({
353
426
  })
354
427
  if (global && plan.projectChanged) await assertConfigPath(path.join(projectDir, ...SYNC_STATE_PATH), projectDir)
355
428
  console.log(`\n同步范围:${global ? '全局' : '当前项目'};平台:${platforms.map(p => PLATFORM_LABELS[p]).join('、')}`)
356
- console.log(`处理内容:${contentTypes.map(type => options.find(option => option.value === type).label).join('、')}`)
429
+ console.log(`处理内容:${contentTypes.map(type => type === 'rules' && !scans.rules.length ? '旧规则迁移' : options.find(option => option.value === type).label).join('、')}`)
357
430
  if (contentTypes.includes('skills')) console.log(`Skills:${selected.skills.map(item => item.name).join('、') || '无项目安装选择;已有全局入口仅去重'}`)
358
- if (contentTypes.includes('rules')) console.log(`Rules:${selected.rules.map(item => item.name).join('、') || '移除当前项目托管规则'}`)
431
+ if (contentTypes.includes('rules')) console.log(scans.rules.length
432
+ ? `Rules:${selected.rules.map(item => item.name).join('、') || '移除当前项目托管规则'}`
433
+ : '旧 Rules:仅迁移已选择替代 Skill 的托管项,其他内容保留')
359
434
  if (contentTypes.includes('baseline')) console.log(`通用规范:${contentActions.baseline === 'remove' ? '显式移除' : baseline.split('\n').filter(line => /^#/.test(line)).slice(0,3).join(';')}`)
360
435
  for (const operation of plan.operations) {
361
436
  console.log(operation.label)
package/src/sync-plan.js CHANGED
@@ -74,6 +74,7 @@ function ownedGlobalRoots(platform, homeDir, codexHome) {
74
74
  export async function buildSyncPlan({
75
75
  scope, platforms, contentTypes, selected, scans, sourceDir, projectDir, homeDir, codexHome,
76
76
  projectState, globalState, staleRemovals = {}, staleEntries = {}, baseline,
77
+ migratedRuleSources = {},
77
78
  contentActions = {},
78
79
  refreshSkills = false,
79
80
  skillScope = { destinations: ['project'], globalSkills: [] },
@@ -229,8 +230,9 @@ export async function buildSyncPlan({
229
230
  const selectedNames = new Set(selected.rules.map(item => item.name))
230
231
  const rules = scans.rules.filter(rule => selectedNames.has(rule.name))
231
232
  const preserved = new Set(cliPlatforms.flatMap(platform => retained(platform, 'rules')))
233
+ const removed = [...new Set(cliPlatforms.flatMap(platform => approved(platform, 'rules')))]
232
234
  if (cliPlatforms.length) {
233
- await addConfig('rules', '更新项目 Rules(保留通用规范和手写内容)', [path.join(projectDir, 'AGENTS.md')], projectDir,
235
+ await addConfig('rules', `更新项目 Rules(保留通用规范和手写内容)${removed.length ? `;移除旧托管项:${removed.join('、')}` : ''}`, [path.join(projectDir, 'AGENTS.md')], projectDir,
234
236
  () => syncProjectAgentsMd(projectDir, rules, { preservedRuleNames: preserved }))
235
237
  const names = [...new Set([...rules.map(rule => rule.name), ...preserved])].sort()
236
238
  for (const platform of ['claude', 'codex', 'opencode']) {
@@ -251,7 +253,13 @@ export async function buildSyncPlan({
251
253
  if (platforms.includes('claude')) {
252
254
  const names = new Set([...scans.rules.map(rule => rule.name), ...approved('claude', 'rules')])
253
255
  for (const name of names) {
256
+ if (!scans.rules.some(rule => rule.name === name) && !(projectState.platforms.claude?.rules || []).includes(name)) continue
254
257
  const dest = path.join(projectDir, '.claude', 'rules', name)
258
+ if (migratedRuleSources[name] && await existsEntry(dest)) {
259
+ const reference = migratedRuleSources[name]
260
+ if (!(await fs.lstat(dest)).isFile()) continue
261
+ if (!await fs.pathExists(reference) || await fs.readFile(dest, 'utf8') !== await fs.readFile(reference, 'utf8')) continue
262
+ }
255
263
  if (safeName(name) && await existsEntry(dest)) add('legacy-rule', '清理旧项目规则入口', [dest], () => fs.remove(dest))
256
264
  }
257
265
  }
@@ -1,5 +1,18 @@
1
1
  # ai-tools 内部版本
2
2
 
3
+ ## 0.35.0 - 2026-11-08
4
+
5
+ - 新增 Android 开发与架构、Flutter、HarmonyOS、PostgreSQL、Redis 和 Alembic Skills,按任务加载迁移后的规范和踩坑。
6
+ - Docker、Git 提交、依赖选型、开发审查和发布 Skills 吸收原有流程资料,不再分发项目 Rules。
7
+ - 更新技术架构的 Android Skill 引用;历史项目规则仅在替代 Skills 已选中并确认后迁移,无法确认归属的旧文件保留。
8
+
9
+ ## 0.34.0 - 2026-11-07
10
+
11
+ - 新增 `skills/Python/dwy-python-*`、Python 基础包 Skills、`skills/Vue/dwy-vue-*`、管理与认证包 Skills,以及 `skills/Apple/dwy-apple-appkit`;按能力和实际版本导航,保留已发布版本接入资料。
12
+ - 将 `rules/Python/` 和 `rules/Vue/` 的技术规范迁入对应 Skills 的参考资料;Apple 开发规范使用 Swift、iOS、macOS 和架构 Skills。
13
+ - 修复 `skills/Vue/dwy-ekit/SKILL.md` 的非标准元数据,收紧 EUI 和 EAPI 版本线;无法确定安装版本时不再假定版本。
14
+
15
+
3
16
  本目录(`dwy-cli/templates/ai-tools`)rules / skills / hooks / commands / CLAUDE.md 等模板资产的**内部版本**,与 `create-dwy` npm 版本**解耦**。
4
17
 
5
18
  - 当前版本:见同目录 `VERSION`(单一事实源)
@@ -1 +1 @@
1
- 0.33.0
1
+ 0.35.0
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: dwy-android-architecture
3
+ description: 设计、开发或评审 Android 的模块分层、依赖方向或 MVP 页面架构时使用。
4
+ ---
5
+
6
+ # Android 架构
7
+
8
+ 先检查项目实际结构、依赖方向、调用方和页面模式,不因启用本技能重建已有工程。需要模块边界时读 [分层与依赖](references/dwy-android-layering.md),项目采用 MVP 或用户明确要求时读 [MVP](references/dwy-android-mvp.md)。新项目按照团队约定和实际规模决定,现有架构及用户要求优先。
9
+
10
+ 历史资料中的 `dwy-android-core` 指 `dwy-android-development`;`dwy-android-layering` 和 `dwy-android-mvp` 指本 Skill 的对应资料。
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: dwy-android-development
3
+ description: 开发、修改或排查 Android 原生应用时使用;覆盖 Java、Kotlin、XML、系统适配及常见问题。
4
+ ---
5
+
6
+ # Android 开发
7
+
8
+ 先检查项目现有语言、SDK、Gradle、依赖与设备目标;已有项目遵循实际技术栈,不擅自替换 Support、AndroidX 或 UI 框架。需要架构设计时同时使用可用的 `dwy-android-architecture`。
9
+
10
+ - [开发规范与界面适配](references/dwy-android-core.md):按任务阅读语言、布局、资源和生命周期相关部分;其中 AndroidAutoSize 是团队特定选型,新项目也需按依赖选型规则核实,不能在未授权时自动添加。
11
+ - [Support 老项目兼容](references/dwy-android-support-only.md):仅项目实际使用 Support 时阅读。
12
+ - [常见踩坑](references/dwy-android-pitfalls.md):按工程、设备、界面或生命周期问题查阅。
13
+
14
+ 涉及 UI、系统权限或设备行为时,区分编译通过和目标设备实际验证。
15
+
16
+ 历史资料中的 `dwy-android-layering`、`dwy-android-mvp` 指 `dwy-android-architecture` 的对应参考资料,不是独立 Rule 或 Skill。
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: dwy-apple-appkit
3
+ description: 使用或排查 AppleAppKit SwiftPM 自有基础库时使用,按模块和项目锁定版本查证接口。
4
+ ---
5
+
6
+ # AppleAppKit 自有基础库
7
+
8
+ 先查项目 Package.resolved、实际 checkout 和已使用的产品;版本范围不是锁定版本。源码及示例只在与项目锁定版本一致时作为依据。
9
+
10
+ - SyncCore:同步;CoreKit、LogKit、L10nKit、CacheKit:基础功能、日志、本地化与缓存。
11
+ - DesignCore、DesignKitIOS、DesignKitMac:跨平台及平台界面能力。
12
+ - AuthCore、AuthUI、AuthGoogleIOS、AuthAppleIOS、AuthGoogleMac:认证核心与平台接入。
13
+ - PurchaseCore:购买能力。
14
+
15
+ 按目标平台查 Package.swift、对应公开声明和 ios/README.md,再核对初始化、生命周期、系统版本与错误处理。找不到确切版本时查对应语义化 Git tag;不可用时说明缺口,不以默认分支替代。使用新产品或新增依赖遵守项目选择和授权,不擅自安装。
16
+
17
+ 查到对应版本源码后:同步查 `ios/Docs/SYNC_CORE.md` 与 `ios/Examples/OfflineSync/`;Apple 登录、Google 登录和邮箱密码分别查 `ios/Docs/APPLE_AUTH.md`、`ios/Docs/GOOGLE_AUTH.md`、`ios/Docs/EMAIL_PASSWORD_AUTH.md` 与相应示例。具体文件是否存在以所选 tag 为准。
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: dwy-apple-architecture
3
+ description: 设计、开发、排查或评审 iOS、macOS 的模块架构、依赖方向、共享基础库及代码抽取时使用。
4
+ ---
5
+
6
+ # Apple 架构与复用
7
+
8
+ 同时使用可用的 `dwy-swift-development` 和受影响的平台 Skill;缺少时按现有项目约定继续,不自动安装。先检查项目结构、已有基础库、调用方和依赖边界;不因启用 Skill 重建现有工程。
9
+
10
+ 需要分层与依赖判断时读 [分层与依赖](references/layering.md),需要共用或抽取时读 [共享与抽取](references/extraction.md),遇到架构问题读 [架构踩坑](references/pitfalls.md)。新项目遵循团队分层;既有项目先尊重实际架构,若与团队规范冲突,说明影响并在授权范围内处理。
11
+
12
+ 新项目默认 iOS 17+、macOS 15+;现有项目以实际 deployment target 为准,不擅自抬高。针对当前任务查找适用的 Apple 官方 Skill;缺失时使用官方文档。目标平台和 SDK 版本决定 API 可用性。
@@ -0,0 +1,9 @@
1
+ # 共享与抽取
2
+
3
+ 1. 查项目已有模块、团队基础库、实际调用方与依赖版本,优先复用可满足需求的能力;不能把抽取候选当作已存在的能力。
4
+ 2. 区分跨产品基础能力、跨 Feature 的本产品业务能力和某个平台的壳或界面状态,按职责及依赖方向确定落点。
5
+ 3. 一次性业务留在原处;有第二个实际消费者或明确已授权需求,再按收益、接口稳定性和迁移成本考虑抽取,不为假设复用提前建层。
6
+ 4. 共享逻辑只抽真正相同的部分;平台生命周期、窗口、导航和平台专属状态留在对应端。改基础库与业务侧修复按实际成本、复用收益及授权判断。
7
+ 5. 验证现有调用方、公开接口、依赖边、受影响平台和测试。跨仓库修改、破坏性接口变更、新增依赖或发布须有相应授权。
8
+
9
+ 通用缺口本轮落在业务侧时,遵循项目关于基础库抽取候选的记录和确认规则;不自行扩展本轮范围。
@@ -1,14 +1,6 @@
1
- ---
2
- description: iOS / macOS 四层分包与依赖方向(双壳 Assembly + Features / BizFoundation / Foundation);根 Package.swift 锁定第三方版本
3
- paths:
4
- - "**/*.swift"
5
- - "**/Package.swift"
6
- - "**/project.yml"
7
- ---
8
-
9
1
  # Apple 四层架构与依赖
10
2
 
11
- 适用于 iOS 17+ / macOS 14+ 的 SwiftUI 双端或单端应用。风格 / 安全区 / 国际化见 `dwy-swift-core`。本文件只管**层、引用边、版本写在哪**。
3
+ 团队新项目默认 iOS 17+ / macOS 15+;既有项目以实际 deployment target 和现有架构为准,不为套用层名而擅自重构或抬高版本。风格与国际化见 `dwy-swift-development`。本文件只管**层、引用边、版本写在哪**;以下目录和分层适用于采用该架构的项目。
12
4
 
13
5
  单壳(只有 iPhone 或只有 Mac)**不建** PlatformFoundation。双壳且某端领域字节级不同时才加 `DesktopKit`。
14
6
 
@@ -31,7 +23,7 @@ paths:
31
23
 
32
24
  | **PlatformFoundation** | 同一业务多个壳,且某端领域字节级不同 | 被其他壳 import;塞回 BizFoundation |
33
25
 
34
- 升层:第二个 Feature 或第二个产品**真在用**,才升到 BizFoundation / Foundation。禁止「可能复用」提前抽。禁止为了共用而抽 `AppShared` 把壳状态(Store / Session)塞进 BizFoundation。
26
+ 升层:第二个 Feature 或第二个产品**真在用**,或用户明确授权本次抽取时,才考虑升到 BizFoundation / Foundation;仍需评估依赖方向和迁移成本。禁止因「可能复用」提前抽。禁止为了共用而抽 `AppShared` 把壳状态(Store / Session)塞进 BizFoundation。
35
27
 
36
28
  业务内聚:一个业务域 = 壳内 `Features/<Name>/`。禁止按 `Views/` `ViewModels/` 横切。目录不等于层:Features 若与壳同一 target,仍遵守互不 import 的源码边界。
37
29
 
@@ -0,0 +1,3 @@
1
+ # 架构踩坑
2
+
3
+ 记录已验证的模块职责、反向依赖、跨端生命周期或抽取失败;先查重。每条写现象、适用范围、根因与证据、处理方式、验证状态和未验证项。项目特有约束留在项目,写共享 Skill 须有来源仓库的修改授权。
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: dwy-ios-development
3
+ description: 开发、排查、评审或适配 iOS、iPadOS 应用时使用,涵盖界面、系统版本、弹层、Liquid Glass 和目标设备验证。
4
+ ---
5
+
6
+ # iOS 开发
7
+
8
+ 同时使用可用的 `dwy-swift-development`;涉及模块边界或公共代码时使用 `dwy-apple-architecture`。缺少其他 Skill 时说明并按现有项目约定继续,不自动安装。按任务使用 Apple 官方 Skill;没有适用项时查官方文档。
9
+
10
+ 新项目默认最低 iOS 17;现有项目先读取实际 deployment target,发现差异时说明,不擅自升级。新 API 按 SDK 与运行时版本判断,保留低版本可用体验。
11
+
12
+ 按需阅读:[布局与安全区](references/layout.md)、[系统外观与 Liquid Glass](references/appearance.md)、[弹窗和锚点](references/presentations.md)、[iOS 踩坑](references/pitfalls.md)。界面变更先确定受影响系统、屏幕尺寸、滚动和交互,再验证布局、可访问性与视觉;编译通过不等于设备验收。
13
+
14
+ 发现可复用新坑先查重:只在 iOS 证实的放本 Skill;双端均有证据时将共通部分放 Swift Skill,保留平台差异。记录现象、范围、根因及证据、处理方法、验证状态和未验证项;未确认标记待验证,项目专属问题留项目内。修改共享 Skill 必须已有来源仓库授权。
@@ -0,0 +1,6 @@
1
+ # iOS 系统外观与 Liquid Glass
2
+
3
+ - iOS 26+ 使用适配 SDK 构建时,先检查系统导航、工具栏、控件和弹层的原生外观;自定义背景可能遮挡系统效果。根据产品设计适配,勿给所有内容叠加玻璃。
4
+ - 仅在适合的自定义控件使用系统玻璃 API,检查 SDK 和运行时可用性;iOS 17–25 保留可用、可读的原生或项目既有外观,不将普通透明背景称作 Liquid Glass。
5
+ - 在受影响的目标系统检查深浅色、减少透明度、增加对比度、动态字体、触控区域和内容遮挡。记录 SDK、系统、设备及实际交互与视觉验证;只编译或截图空白不能证明通过。
6
+ - 具体行为以 Apple 官方文档及当前 SDK 为准:https://developer.apple.com/documentation/technologyoverviews/adopting-liquid-glass
@@ -1,9 +1,3 @@
1
- ---
2
- description: iOS 适配开发与原型基准规范(393pt 主基准、安全区、自适应布局)
3
- paths:
4
- - "**/*.swift"
5
- ---
6
-
7
1
  ## iOS 适配基线
8
2
 
9
3
  - iOS 布局统一使用 `pt`,不要按 `px` 做分辨率换算。
@@ -1,14 +1,6 @@
1
- ---
2
- description: iOS / Swift / SwiftUI 开发避坑清单(XcodeGen / 签名 / 真机部署 / SwiftUI 代码踩坑)
3
- paths:
4
- - "**/*.swift"
5
- - "**/project.yml"
6
- - "**/Package.swift"
7
- ---
8
-
9
1
  # iOS 开发坑清单
10
2
 
11
- > 动手前先对照本清单避开已知坑;踩到新坑随手按四栏格式(现象 / 根因 / 正确做法 / 适用)追加到对应分类,没有合适分类就新建一个。
3
+ > 以下为迁移自旧规则的经验,适用范围和结论须结合当前 SDK、系统及现场证据核实。新增记录遵循 SKILL.md 的证据和权限要求。
12
4
 
13
5
  ## 分类索引
14
6
 
@@ -0,0 +1,11 @@
1
+ # iOS 弹窗差异与案例
2
+
3
+ - 共通锚点规则和验证见 `dwy-swift-development` 的弹层参考。
4
+ - iPhone 的 popover 默认适配为 sheet,垂直紧凑环境可适配为全屏;iOS 常规尺寸类别的 confirmation dialog 可以呈现为 popover。按设备和尺寸类别验证,勿假设始终有箭头。
5
+ - 对指定 `arrowEdge` 的 SwiftUI popover,iOS 18.1 前系统不遵循指定边;新行为还要求使用 iOS 18.1 或更新 SDK 编译并运行在对应系统。允许系统选方向时使用不指定边的重载;按支持版本验证。
6
+
7
+ ## 卸载插件弹窗案例:待目标环境验证
8
+
9
+ - 现象:点击页面底部卸载行后,截图中的带箭头确认框出现在页面上方。
10
+ - 证据:触发行只更改状态,`confirmationDialog` 挂在外层滚动视图;这与错误锚点一致,但未在截图对应系统实测,根因仍待验证。
11
+ - 排查:将确认框关联触发行后,在相同环境和滚动位置比较箭头与入口,并检查取消和确认目标。未验证的修复不宣称已通过。
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: dwy-macos-development
3
+ description: 开发、排查、评审或适配 macOS 应用时使用,涵盖窗口、菜单、键鼠、系统版本、Liquid Glass 和目标系统验证。
4
+ ---
5
+
6
+ # macOS 开发
7
+
8
+ 同时使用可用的 `dwy-swift-development`;涉及模块边界或公共代码时使用 `dwy-apple-architecture`。缺少其他 Skill 时说明并按现有项目约定继续,不自动安装。按任务使用 Apple 官方 Skill;没有适用项时查官方文档。
9
+
10
+ 新项目默认最低 macOS 15;现有项目先读取实际 deployment target,发现差异时说明,不擅自升级。新 API 按 SDK 与运行时版本判断,保留低版本可用体验。
11
+
12
+ 按需阅读 [窗口与系统外观](references/ui-adaptation.md)、[弹窗差异](references/presentations.md) 和 [macOS 踩坑](references/pitfalls.md)。界面变更先确定目标系统、窗口尺寸、键鼠和辅助功能验证;签名或启动通过不等于目标系统交互与视觉验收。
13
+
14
+ 发现可复用新坑先查重:只在 macOS 证实的放本 Skill;双端均有证据时将共通部分放 Swift Skill,保留平台差异。记录现象、范围、根因及证据、处理方法、验证状态和未验证项;未确认标记待验证,项目专属问题留项目内。修改共享 Skill 必须已有来源仓库授权。
@@ -0,0 +1,9 @@
1
+ # macOS 踩坑
2
+
3
+ 记录已验证的 macOS 专属问题;每条写现象、适用系统与条件、根因及证据、处理方式、验证状态和未验证项。先查重;未证实的推断不能写成事实,项目专属问题留在项目中。
4
+
5
+ ## macOS 15 原生外观与 Liquid Glass
6
+
7
+ - 现象:系统组件在 macOS 15 上可以呈现原生外观,但这不能证明使用了 macOS 26 的 Liquid Glass API。
8
+ - 依据:曾有项目通过系统导航和表单完成 macOS 15 样式适配,源码未使用玻璃 API;当时目标系统的完整视觉交互验收尚未完成。
9
+ - 处理:分别检查 API 实际使用与目标系统的显示、交互,不以构建或签名通过替代验收。
@@ -0,0 +1,5 @@
1
+ # macOS 弹窗差异
2
+
3
+ - 共通锚点规则和验证见 `dwy-swift-development` 的弹层参考。窗口可移动和缩放,检查窗口及入口位置变化后,popover 是否仍指向正确控件。
4
+ - Apple 文档说明 SwiftUI popover 的指定 `arrowEdge` 在 macOS 上一直受尊重;系统边界和内容仍须在目标系统实测。若允许系统选择方向,使用不指定边的重载。
5
+ - 结合产品交互检查键盘、焦点、取消和点击外部关闭;不要把 iOS 的紧凑尺寸适配行为直接套到 macOS。
@@ -0,0 +1,6 @@
1
+ # macOS 窗口与系统外观
2
+
3
+ - 使用现有系统窗口、侧栏、工具栏、菜单和焦点行为;验证窗口缩放、最小尺寸、键盘、鼠标、菜单和辅助功能。不要把 iPhone 的固定尺寸布局搬到 Mac。
4
+ - macOS 26+ 使用适配 SDK 构建时先检查系统组件的 Liquid Glass;仅在适合的自定义控件使用系统 API,避免叠加遮挡内容。macOS 15 上保留可用的原生外观,不把普通材质或系统旧样式称为 Liquid Glass API。
5
+ - 根据 SDK 和运行时版本判断 API 可用性;检查深浅色、减少透明度、增加对比度和可读性。按任务在目标 macOS 版本启动、操作并观察界面;编译、签名或进程存在不能代替视觉与交互验收。
6
+ - 具体行为以 Apple 官方文档及当前 SDK 为准:https://developer.apple.com/documentation/technologyoverviews/adopting-liquid-glass
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: dwy-swift-development
3
+ description: 开发、排查或评审 Swift、SwiftUI 和 Apple 平台共享代码时使用;提供团队 Swift 规范、Apple 官方技能查找和共通问题处理。
4
+ ---
5
+
6
+ # Swift 开发基线
7
+
8
+ 先确认任务范围、项目现有约定、调用方和实际 SDK;用户明确要求优先。阅读 [团队写法](references/conventions.md) 中与任务有关的部分;iOS 专属要求不套用到 macOS。架构、公共模块或抽取涉及 `dwy-apple-architecture` 时同时使用它;涉及 iOS / iPadOS 或 macOS 时分别使用 `dwy-ios-development` 或 `dwy-macos-development`。若其他 Skill 未安装,说明缺口并按项目现有约定继续,不自动安装。
9
+
10
+ SwiftUI、App Intents 等具体技术优先查找当前环境中与任务匹配的 Apple 官方 Skill,阅读相关参考;确认其来源后使用。不存在或不可用时查 Apple 官方文档,不强制安装、不把第三方 Skill 冒充官方。
11
+
12
+ 项目使用 AppleAppKit 时先查可用的 `dwy-apple-appkit`,按项目锁定版本复用同步、基础工具、设计、认证和购买等已有能力;未安装该 Skill 时核实实际依赖与源码,不自动安装依赖。
13
+
14
+ 涉及弹窗、popover 或其锚点时读取 [弹层与锚点](references/presentations.md),再读取对应平台 Skill 中的差异。
15
+
16
+ 排查共通问题时读 [共通踩坑](references/pitfalls.md)。新增经验先查重,记录现象、适用平台和版本、根因与证据、处理方式、验证及未验证项;未证实的推断明确标记。仅单项目成立的经验留在项目中。共享 Skill 属于其来源仓库:只有已获授权才修改,否则在结果中提出候选;不擅自写全局配置。
@@ -1,14 +1,8 @@
1
- ---
2
- description: iOS 17+ SwiftUI 开发基线规则(全局适配、动画、国际化、注释)
3
- paths:
4
- - "**/*.swift"
5
- ---
6
-
7
- 分层、双壳依赖、Package.swift 版本锁定见 `dwy-apple-layering`。本文件只管写法与体验基线。
1
+ 以下是迁移自原 Swift 基线的团队约定;先遵循用户要求和现有项目约定,平台专属内容仅在相应平台使用。架构和依赖方向使用 `dwy-apple-architecture`。
8
2
 
9
3
  ## iOS 目标与写法
10
4
 
11
- - iOS 最低版本 17.0+,不为 16 及以下做兼容分支。
5
+ - 新项目默认 iOS 17+、macOS 15+;既有项目以实际 deployment target 为准,不擅自抬高。
12
6
  - 统一 Observation + `@MainActor`,状态对象默认 `final class`。
13
7
 
14
8
  ```swift
@@ -0,0 +1,5 @@
1
+ # Swift 共通踩坑
2
+
3
+ 仅收录有证据适用于多个 Apple 平台或 Swift 语言本身的问题。只在一个平台复现时先记在该平台;跨平台证实后提炼共同原因,平台差异仍留在各自参考中。项目专属问题不放这里。
4
+
5
+ 每条写:现象、适用范围、根因与证据、解决方法、验证状态与未验证项。先查重,避免把猜测写成结论。
@@ -0,0 +1,8 @@
1
+ # SwiftUI 弹层与锚点
2
+
3
+ - 需要指向入口的 `popover` 或可能以 popover 呈现的 `confirmationDialog`,把呈现修饰符关联实际触发按钮或行;列表须对应当前目标,工具栏须对应入口。自定义锚点时检查其坐标和所属视图。
4
+ - 呈现方式由平台、系统和窗口环境决定;普通系统通知、居中 alert 等不一定有入口锚点,不按弹出位置错误处理。
5
+ - 在相关平台验证触发入口、滚动或窗口变化、屏幕边缘、取消和实际目标;以目标系统的交互及视觉为准,编译通过不能证明位置正确。
6
+ - 平台差异分别见 `dwy-ios-development` 的弹窗参考和 `dwy-macos-development` 的弹窗参考;这些 Skill 不可用时查 Apple 官方文档。
7
+
8
+ 依据:[SwiftUI popover](https://developer.apple.com/documentation/swiftui/view/popover(ispresented:attachmentanchor:arrowedge:content:))、[弹层设计指引](https://developer.apple.com/design/human-interface-guidelines/popovers)。