create-dwy 0.14.5 → 0.14.6

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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # create-dwy
2
2
 
3
+ ## 0.14.6
4
+
5
+ ### Patch Changes
6
+
7
+ - `dwy` 交互同步时,默认勾选优先读取项目目录下 `/.dwy/sync-state.json` 的上次托管选择结果,减少每次重新勾选 `rules`、`skills`、`commands`、`hooks`。
8
+ - 新增 iOS 适配开发规则 `dwy-ios-layout-adaptation.md`,统一原型基准为 `393×852 pt`,补充 `375 / 393 / 430 pt` 验证矩阵与 Safe Area 约束。
9
+ - 补充 iOS 与 Android 应用图标安全边距规则:iOS 图标源稿使用 `1024x1024` PNG,Android 启动图标源稿使用 `mipmap-xxxhdpi` `192x192`,主体默认预留 `10%` 安全边距。
10
+
3
11
  ## 0.14.5
4
12
 
5
13
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-dwy",
3
- "version": "0.14.5",
3
+ "version": "0.14.6",
4
4
  "description": "项目脚手架与多平台 AI 配置同步工具",
5
5
  "type": "module",
6
6
  "bin": {
package/src/sync-all.js CHANGED
@@ -57,6 +57,29 @@ function unionSets(...sets) {
57
57
  return new Set(sets.flatMap(set => [...set]))
58
58
  }
59
59
 
60
+ function hasSetItems(setsByType) {
61
+ return setsByType.skills.size + setsByType.rules.size + setsByType.commands.size + setsByType.hooks.size > 0
62
+ }
63
+
64
+ export function buildSelectionDefaultsFromSyncState(existing, syncState) {
65
+ const stateDefaults = {
66
+ skills: new Set(),
67
+ rules: new Set(),
68
+ commands: new Set(),
69
+ hooks: new Set(),
70
+ }
71
+
72
+ for (const platformState of Object.values(syncState?.platforms || {})) {
73
+ for (const type of ['skills', 'rules', 'commands', 'hooks']) {
74
+ for (const name of platformState?.[type] || []) {
75
+ stateDefaults[type].add(name)
76
+ }
77
+ }
78
+ }
79
+
80
+ return hasSetItems(stateDefaults) ? stateDefaults : existing
81
+ }
82
+
60
83
  async function scanCombinedExisting(projectDir) {
61
84
  const claudeDir = path.join(projectDir, '.claude')
62
85
  const agentsMdPath = path.join(projectDir, 'AGENTS.md')
@@ -80,7 +103,7 @@ async function scanCombinedExisting(projectDir) {
80
103
  }
81
104
 
82
105
  async function shouldInitialize(projectDir, existing) {
83
- const hasAnyExisting = existing.skills.size + existing.rules.size + existing.commands.size + existing.hooks.size > 0
106
+ const hasAnyExisting = hasSetItems(existing)
84
107
  if (hasAnyExisting) return true
85
108
 
86
109
  const hasConfigDir = await fs.pathExists(path.join(projectDir, '.claude'))
@@ -533,18 +556,20 @@ export async function syncAll({
533
556
  console.log(chalk.yellow(`Found ${scans.skills.length} skills, ${scans.rules.length} rules, ${scans.commands.length} commands, ${scans.hooks.length} hooks\n`))
534
557
 
535
558
  const existing = await scanCombinedExisting(projectDir)
559
+ const syncState = await loadSyncState(projectDir)
560
+ const selectionDefaults = buildSelectionDefaultsFromSyncState(existing, syncState)
536
561
  const skipInitPrompt = !!(selectedOverride || selectedPlatformsOverride)
537
562
  if (!skipInitPrompt && !await shouldInitialize(projectDir, existing)) {
538
563
  console.log(chalk.yellow('\n已取消同步。'))
539
564
  return
540
565
  }
541
566
 
542
- const hasAnyExisting = existing.skills.size + existing.rules.size + existing.commands.size + existing.hooks.size > 0
567
+ const hasAnyExisting = hasSetItems(existing)
543
568
  if (!hasAnyExisting && !selectedOverride) {
544
569
  console.log(chalk.gray('首次同步,进入交互式选择...\n'))
545
570
  }
546
571
 
547
- const selected = selectedOverride || await interactiveSelect(scans, existing)
572
+ const selected = selectedOverride || await interactiveSelect(scans, selectionDefaults)
548
573
  if (selected === null) {
549
574
  console.log(chalk.yellow('\n已取消同步。'))
550
575
  return
@@ -556,7 +581,6 @@ export async function syncAll({
556
581
  return
557
582
  }
558
583
 
559
- const syncState = await loadSyncState(projectDir)
560
584
  const staleEntries = await collectStaleEntries(projectDir, scans, syncState, selectedPlatforms)
561
585
  const approvedStaleRemovals = staleRemovalsOverride
562
586
  ? normalizeRemovalInput(staleRemovalsOverride)
@@ -97,6 +97,8 @@ res/drawable/
97
97
  #### mipmap / 9-patch / 模块前缀
98
98
 
99
99
  - **mipmap 只放启动图标**(`ic_launcher` 系列),其余图片一律放 `drawable` —— mipmap 会跨密度保留资源,普通图放 mipmap 白白增大包体
100
+ - 应用图标设计稿只提供 `mipmap-xxxhdpi` 目录下的 `192x192` 启动图标源图,其余密度版本交给系统或构建流程派生。
101
+ - 图标主体必须预留至少 `10%` 安全边距,避免启动器缩放、遮罩或厂商裁切时贴边缺角。
100
102
  - **9-patch 图保留 `.9` 后缀**:`bg_chat_bubble.9.png`
101
103
  - **模块前缀(可选)**:多模块 / 大型项目推荐资源加业务模块前缀,便于检索、避免跨模块重名 —— `user_activity_login.xml`、id `user_tv_name`;单模块 / 老项目可省略,保持本规范其余示例的无前缀写法
102
104
 
@@ -783,4 +785,4 @@ val result = calculate(x)
783
785
  | 21 | Gradle 脚本(Groovy / kts):锁版本 / `exclude` / 自定义 task / 变体 / 关键魔法值有 why 注释,无复述式、无注释掉的配置块 | ✓ |
784
786
 
785
787
 
786
- **不执行自检就提交代码 = 违规。**
788
+ **不执行自检就提交代码 = 违规。**
@@ -0,0 +1,47 @@
1
+ ---
2
+ description: iOS 适配开发与原型基准规范(393pt 主基准、安全区、自适应布局)
3
+ paths:
4
+ - "**/*.swift"
5
+ ---
6
+
7
+ ## iOS 适配基线
8
+
9
+ - iOS 布局统一使用 `pt`,不要按 `px` 做分辨率换算。
10
+ - iOS 适配依赖 SwiftUI 自适应布局 + Safe Area,不为每个机型单独写一套尺寸。
11
+ - 原型图与开发都以同一套布局意图为准,原型不是按像素缩放给不同机型。
12
+
13
+ ## 原型基准尺寸
14
+
15
+ - 做 iOS 原型图时,统一基于 `393×852 pt` 制作,对齐 `iPhone 15 / iPhone 16` 主流尺寸。
16
+ - `393×852 pt` 是视觉基准,不是要求开发写死页面宽高。
17
+ - 切图资源按系统倍率处理,布局本身仍按 `pt` 思考。
18
+
19
+ ## 适配验证矩阵
20
+
21
+ - 小屏下限按 `375pt` 宽验证,不允许关键内容挤压、截断、横向溢出。
22
+ - 主基准按 `393pt` 宽设计与开发。
23
+ - 大屏上限按 `430pt` 宽验证,要求布局自然放宽,不靠写死间距撑版。
24
+
25
+ ## 布局规则
26
+
27
+ - 页面容器、列表、卡片宽度优先 `maxWidth: .infinity` 或等价自适应写法。
28
+ - 间距优先用 `Spacer`、stack、grid、`safeAreaInset` 等布局系统能力,不用绝对 `offset` 拼版。
29
+ - 禁止用 `UIScreen.main.bounds` 为页面主布局做硬编码换算,优先 `GeometryReader` 或容器相对布局。
30
+ - 具有固定视觉比例的实体控件可以使用固定 `pt` 尺寸,但外层容器必须自适应。
31
+
32
+ ## 安全区
33
+
34
+ - 前景内容默认在安全区内布局,不进入刘海、灵动岛、Home 指示条区域。
35
+ - 全屏背景、遮罩可用 `ignoresSafeArea()`,但不能让主要交互内容越过安全区。
36
+ - 禁止写死状态栏、刘海、底部 Home 条高度,统一依赖系统安全区。
37
+
38
+ ## 字体与可访问性
39
+
40
+ - 字号优先语义化管理,避免页面散落裸值。
41
+ - 关键文案默认兼容 Dynamic Type,系统字体放大后不能破版。
42
+
43
+ ## 开发验证
44
+
45
+ - 至少验证三档宽度:`375pt`、`393pt`、`430pt`。
46
+ - 检查内容是否被刘海、灵动岛、Home 指示条遮挡。
47
+ - 检查滚动页、底部固定栏、弹层在小屏和大屏下都无错位或裁切。
@@ -53,6 +53,8 @@ private let motionSpring = Animation.spring(response: 0.5, dampingFraction: 0.75
53
53
  ## 图标与文案
54
54
 
55
55
  - 图标优先 `Image(systemName:)`,无符号则用成熟 SVG。
56
+ - iOS 应用图标设计稿只提供一张 `1024x1024` 的 PNG 源图,由系统生成各尺寸适配版本。
57
+ - 图标主体必须预留至少 `10%` 安全边距,避免系统缩放、圆角遮罩或视觉放大时被切边。
56
58
  - 文案禁止 emoji,禁止硬编码,统一 `loc("key")`。
57
59
  - 禁止使用 emoji 作为功能说明、状态、提示。
58
60