create-dwy 0.19.1 → 0.20.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 (98) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/package.json +1 -1
  3. package/src/cli-help.js +28 -2
  4. package/src/sync-all.js +95 -583
  5. package/src/sync-codex.js +14 -7
  6. package/src/sync-opencode.js +8 -22
  7. package/src/sync.js +60 -149
  8. package/src/tab-multiselect.js +15 -53
  9. package/templates/ai-tools/CHANGELOG.md +195 -0
  10. package/templates/ai-tools/CLAUDE.md +39 -58
  11. package/templates/ai-tools/VERSION +1 -1
  12. package/templates/ai-tools/hooks/Git/pre-git-commit-ai-signature-check.sh +5 -4
  13. package/templates/ai-tools/rules/Android/dwy-android-core.md +147 -13
  14. package/templates/ai-tools/rules/Android/dwy-android-layering.md +142 -0
  15. package/templates/ai-tools/rules/Android/dwy-android-mvp.md +55 -0
  16. package/templates/ai-tools/rules/Android/dwy-android-support-only.md +2 -0
  17. package/templates/ai-tools/rules/Docker/dwy-docker.md +23 -1
  18. package/templates/ai-tools/rules/Flutter/dwy-flutter-core.md +2 -0
  19. package/templates/ai-tools/rules/Flutter/dwy-flutter-testing.md +1 -1
  20. package/templates/ai-tools/rules/HarmonyOS/dwy-arkts-ui-build.md +12 -8
  21. package/templates/ai-tools/rules/Python/dwy-python-backend.md +4 -43
  22. package/templates/ai-tools/rules/Python/dwy-python-layering.md +169 -0
  23. package/templates/ai-tools/rules/Vue/dwy-vue-core.md +11 -49
  24. package/templates/ai-tools/rules/Vue/dwy-vue-layering.md +153 -0
  25. package/templates/ai-tools/rules/iOS/dwy-apple-layering.md +133 -0
  26. package/templates/ai-tools/rules/iOS/dwy-swift-core.md +2 -0
  27. package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-code-craft.md +83 -0
  28. package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-dependency-freshness.md +27 -66
  29. package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-git-commit.md +8 -219
  30. package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-oss-commercial-license.md +27 -123
  31. package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prod-branch.md +31 -0
  32. package/templates/ai-tools/rules//346/225/260/346/215/256/345/272/223/dwy-postgres.md +17 -10
  33. package/templates/ai-tools/rules//346/225/260/346/215/256/345/272/223/dwy-redis.md +6 -3
  34. package/templates/ai-tools/skills/Docker/dwy-deploy-first/SKILL.md +14 -14
  35. package/templates/ai-tools/skills/Docker/dwy-deploy-first/references/chapter-01-mirrors.md +2 -2
  36. package/templates/ai-tools/skills/Docker/dwy-docker/SKILL.md +21 -13
  37. package/templates/ai-tools/skills/Docker/dwy-docker/references/ask-templates.md +13 -12
  38. package/templates/ai-tools/skills/Docker/dwy-docker/references/templates.md +3 -1
  39. package/templates/ai-tools/skills/Docker/dwy-docker/references/version-rules.md +10 -6
  40. package/templates/ai-tools/skills/Docker/dwy-docker/scripts/query_dockerhub.py +21 -6
  41. package/templates/ai-tools/skills/Docker/dwy-docker/scripts/scan_images.sh +2 -2
  42. package/templates/ai-tools/skills/Docker/dwy-mirror-source/SKILL.md +44 -30
  43. package/templates/ai-tools/skills/Docker/dwy-mirror-source/references/dockerfile-snippets.md +2 -0
  44. package/templates/ai-tools/skills/Docker/dwy-mirror-source/references/mirror-providers.md +8 -8
  45. package/templates/ai-tools/skills/Docker/dwy-mirror-source/scripts/apply_mirrors.py +14 -1
  46. package/templates/ai-tools/skills/Docker/dwy-mirror-source/scripts/check_mirrors.py +4 -0
  47. package/templates/ai-tools/skills/DolphinDB/dwy-dolphindb/SKILL.md +8 -6
  48. package/templates/ai-tools/skills/DolphinDB/dwy-dolphindb/references/digest/python-sdk.md +3 -3
  49. package/templates/ai-tools/skills/DolphinDB/dwy-dolphindb/references/digest/stream-engine.md +2 -2
  50. package/templates/ai-tools/skills/DolphinDB/dwy-dolphindb/references/review-rules/anti-patterns.md +3 -1
  51. package/templates/ai-tools/skills/DolphinDB/dwy-dolphindb/references/review-rules/change-checklist.md +4 -4
  52. package/templates/ai-tools/skills/DolphinDB/dwy-dolphindb/references/review-rules/lethal-violations.md +5 -5
  53. package/templates/ai-tools/skills/DolphinDB/dwy-dolphindb/references/review-rules/perf-baselines.md +5 -5
  54. package/templates/ai-tools/skills/Python/dwy-eapi/SKILL.md +2 -2
  55. package/templates/ai-tools/skills/Python/dwy-eapi/v0/breaking.md +3 -0
  56. package/templates/ai-tools/skills/Python/dwy-eapi/v0/email-canonical.md +28 -3
  57. package/templates/ai-tools/skills/Python/dwy-eapi/v0/index.md +2 -2
  58. package/templates/ai-tools/skills/Python/dwy-eapi/v0/providers-email.md +12 -2
  59. package/templates/ai-tools/skills/Vue/dwy-eui/references/eui-design-guide.md +1 -1
  60. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-architecture/SKILL.md +11 -14
  61. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-product-launcher/references/state-and-contract.md +1 -1
  62. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-prototype/SKILL.md +1 -1
  63. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-github-action-publish/SKILL.md +32 -15
  64. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-github-action-publish/references/electron-release-workflow-template.yml +3 -1
  65. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-github-action-publish/references/release-workflow-template.yml +8 -5
  66. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-ios-app-store-release/SKILL.md +1 -1
  67. 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 +1 -1
  68. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-ios-app-store-release/references/aso.md +2 -0
  69. 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 +1 -1
  70. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/SKILL.md +4 -3
  71. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/android.md +1 -1
  72. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/backend-deploy.md +1 -1
  73. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/changelog.md +45 -27
  74. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/frontend-deploy.md +1 -1
  75. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/generic-release.md +1 -1
  76. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/git-tag.md +1 -1
  77. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/harmony.md +1 -1
  78. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/ios.md +1 -1
  79. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-semver/SKILL.md +8 -0
  80. package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/SKILL.md +7 -7
  81. package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/references/checks-runtime.md +63 -59
  82. package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/scripts/check_base.sh +10 -1
  83. package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/scripts/check_capacity.sh +21 -23
  84. package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/scripts/check_db.sh +9 -1
  85. package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/scripts/check_docker.sh +20 -24
  86. package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/scripts/check_logs.sh +3 -3
  87. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/SKILL.md +4 -2
  88. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/references/api.md +1 -1
  89. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/scripts/synthesize.py +1 -0
  90. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/media-platform-packaging/SKILL.md +7 -5
  91. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/media-platform-packaging/references/platform-copy-examples.md +5 -3
  92. package/templates/ai-tools/skills//351/200/232/347/224/250/dwy-dependency-choice/SKILL.md +140 -0
  93. package/templates/ai-tools/skills//351/200/232/347/224/250/dwy-git-commit/SKILL.md +113 -0
  94. package/templates/ai-tools/skills//351/200/232/347/224/250/dwy-shared/SKILL.md +16 -13
  95. package/templates/ai-tools/skills//351/200/232/347/224/250/dwy-whiteboard-prototype/SKILL.md +1 -1
  96. package/src/sync-packs.js +0 -223
  97. package/src/sync-scene.js +0 -178
  98. package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-tdd-development.md +0 -115
@@ -1,7 +1,7 @@
1
1
  # DolphinDB 反模式与最佳实践
2
2
 
3
3
  > 何时引用:审查 DDB 代码 / SQL / Python SDK 用法,命中具体反模式时引用对应章节。
4
- > 来源:dwy-dolphindb skill 内部规则(基于真实踩坑总结,非官方文档可替代)。
4
+ > 来源:真实踩坑。语言语义以本文件为准,直到官方文档改写了这条语义。字节上限、分区数、行数以当前 server 文档和报错为准,下面的数字是当时的上限。
5
5
 
6
6
  ## 类型陷阱
7
7
 
@@ -55,6 +55,8 @@ DDB 和 Python/SQL **相反**!老手都踩过。要小数结果用 `\`。
55
55
 
56
56
  ### 5. SYMBOL ≤255 字节 / STRING 64KB / BLOB 64MB 静默截断(**1.30.23 / 2.00.11 起**)
57
57
 
58
+ 255 字节、64KB、64MB 是这些版本起的已知上限。连上的 server 文档或实际报错不同,以那次为准。
59
+
58
60
  | 类型 | 上限 | 超限行为 |
59
61
  |---|---|---|
60
62
  | `SYMBOL` | **≤ 255 字节** | **整批 append 直接抛异常**,写入失败 |
@@ -7,18 +7,18 @@
7
7
 
8
8
  - [ ] WHERE 是否命中分区列?分区列是否被函数包裹(`year()` / `date()` / `temporalAdd()`)?
9
9
  - [ ] 范围条件用了 `between ... and ...` 或两个独立条件?没有链式比较 `a <= col <= b`?
10
- - [ ] 单次 `append` ≤ 500K 行?循环里有 `del + gc.collect()`?
10
+ - [ ] 单次 `append` 低于当前 server 的单消息上限?写作时常见约 500K 行,以本次报错为准。循环里有 `del + gc.collect()`?
11
11
  - [ ] 大文件用 pyarrow `read_table + slice`,不是 `pd.read_feather` 全量加载?
12
12
  - [ ] 拼接 DDB 脚本时,外部输入有正则白名单校验?(防注入)
13
13
  - [ ] `pool.run()` 用 `await`(原生 async),`Session.run()` 用 `asyncio.to_thread()`?
14
- - [ ] 连接池大小 ≤ CPU 核数 × 2(社区版 4 worker → pool 3)?
14
+ - [ ] 连接池大小按本次 worker?2 核 8G、4 worker 的先验是 pool 3,不是所有集群的上限。
15
15
  - [ ] `select` 只取需要的列?没有 `select *`?
16
16
  - [ ] 多次聚合查询能否合并为一次?
17
17
  - [ ] 多因子横向查询用了 `pivot by`,不是 Python 端 merge?
18
18
  - [ ] backtick 列名定义在单行内?
19
19
  - [ ] 分页用 `limit offset, count`(**不是** `LIMIT x OFFSET y`)?
20
- - [ ] 新建库表:单分区估算大小落在引擎区间?总分区数远低于 65536?二级高基数列走 `HASH` 不是 `VALUE`?
21
- - [ ] 写入 SYMBOL 列前校验 ≤ 255 字节?STRING/BLOB 有长度断言防静默截断?
20
+ - [ ] 新建库表:单分区估算大小落在引擎区间?总分区数低于该节点 `maxPartitionNumPerQuery`(默认常见 65536)?二级高基数列走 `HASH` 不是 `VALUE`?
21
+ - [ ] 写入 SYMBOL 列前校验当前版本字节上限(常见 255)?STRING/BLOB 有长度断言防静默截断?
22
22
  - [ ] 删数据用 `dropPartition`,不是 `delete from`?
23
23
  - [ ] pandas → DDB:`uint` 是否 `.astype('int64')`?NaN→int 是否 `.fillna(0)`?
24
24
  - [ ] Session / Pool 有 `try/finally close()`?
@@ -1,20 +1,20 @@
1
1
  # 10 条致命违规(零容忍)
2
2
 
3
- > 何时引用:审查 DDB 代码 / SQL / Python SDK 用法。命中任意一条都属于零容忍违规,必须修复。
4
- > 来源:dwy-dolphindb skill 内部规则(非官方文档可替代)。
3
+ > 何时引用:审查 DDB 代码 / SQL / Python SDK 用法。
4
+ > 分区剪枝、注入、连接池变量这些是语言约束,命中就要改。行数、字节、分区数是当时 server 的上限。官方文档或这次报错更准时,以那次为准,不要用本表压过当前版本文档。
5
5
 
6
6
  | # | 违规 | 后果 |
7
7
  |---|---|---|
8
8
  | 1 | 分区列被函数包裹(`date(col)` / `year(col)` / `temporalAdd(col,...)`) | 全表扫 → OOM |
9
9
  | 2 | 链式比较 `a <= col <= b` | 不触发剪枝 → 全表扫 |
10
- | 3 | 单次 `append` > 500K 行 | TSDB 报 `exceeds max limit` |
10
+ | 3 | 单次 `append` 超过当前 server 的单消息上限(写作时常见约 500K 行) | TSDB 报 `exceeds max limit`。不是永远 500K |
11
11
  | 4 | 未校验外部输入拼到脚本 | 脚本注入 |
12
12
  | 5 | 连接池里 upload + run(变量跨连接不可见) | 变量找不到 |
13
13
  | 6 | `select *`(30+ 列全传) | 浪费带宽和内存 |
14
14
  | 7 | 分页用 `LIMIT x OFFSET y` | DDB 不支持 OFFSET 关键字(要用 `limit offset, count`) |
15
15
  | 8 | `asyncio.to_thread(pool.run, script)` | SDK v3 `pool.run` 已是原生 async |
16
- | 9 | SYMBOL 列写入未校验 ≤255 字节 | 整批写入失败 |
17
- | 10 | 单分区 < 100MB 且总分区数 > 65536 | 触达 `maxPartitionNumPerQuery` 上限 |
16
+ | 9 | SYMBOL 列写入未校验当前版本字节上限(1.30.23 / 2.00.11 起常见 255 字节) | 整批写入失败。以本次 server 文档为准 |
17
+ | 10 | 单分区过小且总分区数超过该节点 `maxPartitionNumPerQuery`(默认常见 65536) | 触达查询分区上限。配置改过就用配置值 |
18
18
 
19
19
  ## 审查输出格式
20
20
 
@@ -1,9 +1,9 @@
1
1
  # 性能基线(DolphinDB 3.0 社区版 2 核 8G)
2
2
 
3
3
  > 何时引用:评估查询/写入性能、判断是否需要优化、配置 dolphindb.cfg。
4
- > 来源:dwy-dolphindb skill 内部规则 + 社区版实测数据。
4
+ > 来源:一次 2 核 8G 社区版实测。有 `getClusterPerf`、license 或节点配置时以实测为准。偏离下表不是违规。超过表只说明要排查。
5
5
 
6
- ## 资源预算(死守)
6
+ ## 资源预算(这次 2 核 8G 的冷启动先验)
7
7
 
8
8
  ```
9
9
  总内存 8 GB
@@ -29,7 +29,7 @@ where TradeDate between 2024.01.01 and 2024.01.05
29
29
 
30
30
  ## 配置调优(社区版 dolphindb.cfg)
31
31
 
32
- 社区版固定 2 核 8G,可调的关键参数:
32
+ 下面是 2 核 8G 社区版的起点。许可或机器不同,按本次核数和内存重算,不要照抄。
33
33
 
34
34
  | 参数 | 建议值 | 说明 |
35
35
  |---|---|---|
@@ -54,7 +54,7 @@ where TradeDate between 2024.01.01 and 2024.01.05
54
54
  | Python 拉 100 万行 → DataFrame | 2-5s |
55
55
  | `PartitionedTableAppender` 写入 | 200-400 万行/s |
56
56
 
57
- **超过基线 2-3x 必须排查**:剪枝是否生效(`select [HINT_EXPLAIN]`)、索引是否覆盖、并发是否争抢同分区。
57
+ **比这张表慢 2-3 倍要排查**,不是判死刑:剪枝是否生效(`select [HINT_EXPLAIN]`)、索引是否覆盖、并发是否争抢同分区。机器不同,时延表本身就作废。
58
58
 
59
59
  ## 分区粒度目标
60
60
 
@@ -63,7 +63,7 @@ where TradeDate between 2024.01.01 and 2024.01.05
63
63
  | TSDB | 400 MB - 1 GB |
64
64
  | OLAP | 100 MB - 300 MB |
65
65
 
66
- 总分区数 < 65536,否则触达 `maxPartitionNumPerQuery` 上限。
66
+ 总分区数不要超过该节点的 `maxPartitionNumPerQuery`。默认常见 65536,配置改过就用配置值,不要死守 65536。
67
67
 
68
68
  ## 连接池大小
69
69
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: dwy-eapi
3
- description: "Use when building or changing FastAPI backends that use dwyeapi: Pydantic Settings, async SQLAlchemy, Redis, JWT/bcrypt, AppError/NotFoundError/BusinessError, ApiResponse/PageData, pagination, loguru, health checks, PII masking, timezone-aware dt, ARQ tasks, email verification codes, Gmail alias canonicalization. The single navigation skill for dwyeapi."
3
+ description: "Use when building or changing FastAPI backends that use dwyeapi: Pydantic Settings, async SQLAlchemy, Redis, JWT/bcrypt, AppError/NotFoundError/BusinessError, ApiResponse/PageData, pagination, loguru, health checks, PII masking, timezone-aware dt, ARQ tasks, email verification codes, Gmail alias canonicalization, common email-domain allowlist. The single navigation skill for dwyeapi."
4
4
  ---
5
5
 
6
6
  # dwyeapi
@@ -71,7 +71,7 @@ editable 安装时这个路径就是消费方正在跑的代码,当作安装
71
71
  | `shared/anticorruption.md` | 禁止直调 redis/jwt/logging |
72
72
  | `v0/index.md` | 0.x 模块清单、接入、陷阱 |
73
73
  | `v0/providers-email.md` | 邮件 Provider 注册表 |
74
- | `v0/email-canonical.md` | Gmail 规范化(≥0.9.6) |
74
+ | `v0/email-canonical.md` | Gmail 规范化(≥0.9.6)+ 常见域名白名单 / 发码校验(≥0.10.0) |
75
75
  | `v0/breaking.md` | 0.x 内部 breaking |
76
76
  | `references/tasks-integration-guide.md` | 只用 tasks 时读 |
77
77
 
@@ -8,5 +8,8 @@
8
8
  |------|--------|
9
9
  | 0.6.0 | 信封改为 `ApiResponse[T]` / `PageData[T]`;删除 `success` / `fail` / `paginated`;`code` 成功态从 int `200` 改为 `"SUCCESS"` |
10
10
  | 0.9.0 | 删除 `MockEmailProvider`、`AliyunEmailProvider`、整个 `providers.sms`;`EMAIL__PROVIDER` 改为自由字符串;mock/阿里云改业务 `register_email_provider` |
11
+ | 0.10.0 | `send_code` 默认校验常见邮箱域名;非白名单抛 `EMAIL_DOMAIN_NOT_ALLOWED`。B2B 设 `EMAIL__REQUIRE_COMMON_DOMAIN=false` |
11
12
 
12
13
  0.9.6 起新增 `dwyeapi.email` 与 Redis key 规范化,对旧调用方兼容(发码 key 折到同一收件箱)。能力下限见 `email-canonical.md`。
14
+
15
+ 常见域名白名单:`send_code` 默认启用 `require_common_email_domain`(≥0.10.0,`EMAIL__REQUIRE_COMMON_DOMAIN=true`)。B2B 可关。
@@ -1,4 +1,4 @@
1
- # 邮箱规范化(≥0.9.6)
1
+ # 邮箱规范化与常见域名白名单(≥0.9.6)
2
2
 
3
3
  安装版本 `< 0.9.6`:没有 `dwyeapi.email`,不要 import。
4
4
 
@@ -9,10 +9,35 @@ canonicalize_email("Bai.Wen+1@Gmail.com") # baiwen@gmail.com
9
9
  canonicalize_email("a.b@googlemail.com") # ab@gmail.com
10
10
  canonicalize_email("a+x@icloud.com") # a+x@icloud.com
11
11
  is_folded_alias("a+x@gmail.com") # True
12
- is_folded_alias("A@gmail.com") # False
12
+ is_folded_alias("A@gmail.com") # False
13
13
  ```
14
14
 
15
15
  - 注册查重、登录查找、用户表写入 **必须** 走 `canonicalize_email`
16
16
  - Gmail 把 plus / 点号 / `googlemail.com` 当成同一收件箱,不折会开多个号、绕过发码冷却
17
17
  - 其它域名只做 strip + lower,保留 `+` 与点
18
- - `send_code` / `verify_code` 的 Redis key 已自动规范化;业务存库仍要自己调
18
+ - `send_code` / `verify_code` 的 Redis key 已自动规范化;发信信封仍用用户输入地址
19
+
20
+ ## 常见域名白名单(≥0.10.0)
21
+
22
+ 安装版本 `< 0.10.0`:没有 `is_common_email_domain`,不要 import。一次性邮箱会换马甲域,黑名单跟不上。
23
+
24
+ **`send_code` 默认校验**(`EMAIL__REQUIRE_COMMON_DOMAIN=true`)。不在白名单:抛 `BusinessError(code="EMAIL_DOMAIN_NOT_ALLOWED")`,不发信、不写 Redis。B2B 可关。
25
+
26
+ ```python
27
+ from dwyeapi.email import require_common_email_domain
28
+ from dwyeapi.providers.email import EmailSettings
29
+
30
+ # 发码已默认走白名单;业务也可在注册/换绑再调一次
31
+ email = require_common_email_domain(raw)
32
+
33
+ # .env
34
+ # EMAIL__REQUIRE_COMMON_DOMAIN=true
35
+ # EMAIL__EXTRA_ALLOW_DOMAINS=chances.com.cn
36
+ # EMAIL__ALLOW_EDU=true
37
+ # EMAIL__ALLOW_EDU_CN=true
38
+ ```
39
+
40
+ - 精确匹配 `COMMON_EMAIL_DOMAINS`(qq / 163 / gmail / outlook / icloud / proton 等),`mail.qq.com` 不等于 `qq.com`
41
+ - 默认放行美国 `.edu`(`columbia.edu`)与 `edu.cn` / `*.edu.cn`;**不**放行 `edu.kg` / `edu.pl` 等国家教育后缀
42
+ - 企业 / 机构域用 `extra_allow` / `EMAIL__EXTRA_ALLOW_DOMAINS`(如 `chances.com.cn`),不要把公司域写进框架常量表
43
+ - 自定义 provider 的 factory 必须把 `require_common_domain` / `extra_allow_domain_list()` / `allow_edu` / `allow_edu_cn` 传给 `EmailProviderBase`
@@ -19,7 +19,7 @@
19
19
  | `dt` | 中国时区时间工具 | ≥0.7 左右;`timedelta`/`after` ≥0.9.4 |
20
20
  | `logger` | loguru | |
21
21
  | `masking` | PII 脱敏 | |
22
- | `email` | Gmail 规范化 | ≥0.9.6 |
22
+ | `email` | Gmail 规范化 + 常见域名白名单 | 规范化 ≥0.9.6;白名单 / 发码校验 ≥0.10.0 |
23
23
  | `health` | 只探活健康检查 | ≥0.7.0 |
24
24
  | `tasks` | ARQ 异步任务,需 `[tasks]` | ≥0.7 后 |
25
25
  | `providers.email` | 邮件验证码,内置 resend | 工厂注册表 ≥0.9.0 |
@@ -100,4 +100,4 @@ app.include_router(create_health_router(service_name=settings.service_name, vers
100
100
  ### 邮件 / Gmail
101
101
 
102
102
  - Provider:`v0/providers-email.md`
103
- - 规范化:`v0/email-canonical.md`(≥0.9.6)
103
+ - 规范化 / 常见域名白名单:`v0/email-canonical.md`(规范化 ≥0.9.6;白名单 / 发码校验 ≥0.10.0)
@@ -13,7 +13,7 @@ from dwyeapi.providers.email import (
13
13
  )
14
14
 
15
15
  provider = make_email_provider(settings.email)
16
- await provider.send_code("user@example.com")
16
+ await provider.send_code("user@qq.com")
17
17
  ```
18
18
 
19
19
  自定义(**不用改 eapi**):
@@ -25,7 +25,16 @@ class TencentSesProvider(EmailProviderBase):
25
25
  text = self._render_code_text(code)
26
26
  return True
27
27
 
28
- register_email_provider("tencent_ses", lambda s: TencentSesProvider(code_ttl=s.code_ttl))
28
+ register_email_provider(
29
+ "tencent_ses",
30
+ lambda s: TencentSesProvider(
31
+ code_ttl=s.code_ttl,
32
+ require_common_domain=s.require_common_domain,
33
+ extra_allow_domains=s.extra_allow_domain_list(),
34
+ allow_edu=s.allow_edu,
35
+ allow_edu_cn=s.allow_edu_cn,
36
+ ),
37
+ )
29
38
  # .env: EMAIL__PROVIDER=tencent_ses
30
39
  ```
31
40
 
@@ -34,6 +43,7 @@ register_email_provider("tencent_ses", lambda s: TencentSesProvider(code_ttl=s.c
34
43
  - 自定义同名二次注册会覆盖并 warning
35
44
  - 必须在 `make_email_provider` **之前** register
36
45
  - `send_code` / `verify_code` 的 Redis key 自 **0.9.6** 走 `canonicalize_email`;发信信封仍用用户输入地址
46
+ - `send_code` **默认**校验常见邮箱域名(`EMAIL__REQUIRE_COMMON_DOMAIN`,≥0.10.0);失败不发信。详见 `email-canonical.md`
37
47
  - 缺 extra 构造内置 provider → `ImportError`,提示 `pip install dwyeapi[email-resend]`
38
48
 
39
49
  0.9.0 删除了内置 mock / 阿里云占位 / 整个 sms 模块,见 `breaking.md`。
@@ -218,7 +218,7 @@ neutral(默认)| blue | green | rose | orange | violet | slate
218
218
  | 场景 | 要求 |
219
219
  |------|------|
220
220
  | 布局壳 | `EAdminLayout` 375px 可开抽屉;顶栏不裁切 |
221
- | 列表 | 表格允许横滑;`EPagination` 默认 `mode="auto"` |
221
+ | 列表 | 默认横滑。内容型列表(摘要、说明)用 `mobile-layout="stack"` 出卡片键值。操作密的后台表保持 `scroll`。**禁止**页面 `if (isMobile) 删 columns`。`EPagination` 默认 `mode="auto"` |
222
222
  | 表单 | 标签置顶 / `EField orientation="responsive"` |
223
223
  | 提示 | 禁止 hover-only 作为唯一入口(`ETooltip trigger="auto"`) |
224
224
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: dwy-architecture
3
- description: "【dwy·技术架构】产品 0 到 1 设计与架构阶段。触发场景:用户说『设计架构 / 出技术方案 / 设计库表 / 定接口契约 / 技术架构 / architecture』,要在开发前定下技术架构、数据库设计和接口契约时。按四层架构(Assembly/Features/BizFoundation/Foundation)+ 统一选型(Python+FastAPI、Vue+Vite)产出。"
3
+ description: "【dwy·技术架构】产品 0 到 1 设计与架构阶段。触发场景:用户说『设计架构 / 出技术方案 / 设计库表 / 定接口契约 / 技术架构 / architecture』,要在开发前定下技术架构、数据库设计和接口契约时。按对应栈 dwy-*-layering(四层 + 单向依赖)+ 统一选型(Python+FastAPI、Vue+Vite)产出。"
4
4
  ---
5
5
 
6
6
  ## 职责(单一)
@@ -37,24 +37,21 @@ description: "【dwy·技术架构】产品 0 到 1 设计与架构阶段。触
37
37
  - **CI/CD 走 GitHub Actions + OIDC**(发布鉴权用 OIDC,禁长期静态凭据)
38
38
  - **基线不适用就先确认**:任一项基线与上下文冲突(如纯前端无需 Docker/DB、要换其他 DB/MQ/中间件、不能用某项)→ 先 `AskUserQuestion` 跟用户确认,确认后在架构文档写明偏离基线的理由
39
39
 
40
- ### 四层架构(依赖严格单向向下:Assembly → Features → BizFoundation → Foundation)
40
+ ### 四层架构
41
41
 
42
- | 层 | 职责 | 后端示例 | 前端示例 |
43
- |---|---|---|---|
44
- | **装配层 (Assembly)** | 实例化 / 依赖注入 / 路由挂载 / 生命周期,**零业务逻辑** | `src/app/`(main.py 装 Provider/Hook、factories) | `apps/web`(路由、stores、main.ts) |
45
- | **Features (业务功能层)** | 各业务域领域逻辑,域内 router+service+schema+model **聚在同一目录** | `<域>/`(如 `factor/`、`plan/`、`quota/`) | `features/*`(如 auth、settings) |
46
- | **业务基础层 (BizFoundation)** | 业务相关但跨业务域复用:鉴权、领域协议/Provider、领域设施 | `auth`、各包 `protocols.py`/`providers` | 跨域复用的业务 composable/store |
47
- | **业务无关层 (Foundation)** | 与业务完全无关的 kernel | `shared`(DB/Redis/签名/中间件) | `core`(httpClient/格式化/常量) |
42
+ 层名、依赖边、分包树以对应栈的 layering rule 为准,本 skill **不另定义目录**:
48
43
 
49
- ### 三条铁律
50
- - **依赖单向向下,绝不反向**:下层禁止 import 上层;Foundation 禁止 import 任何业务包;跨业务域**不直接互 import**,靠装配层用 Protocol/Hook 桥接。
51
- - **业务内聚**:一个业务域 = 一个目录,域内 router/service/schema/model 聚在一起。✅ `factor/`(含 router+service+validators);❌ 顶层 `routers/`+`services/`+`models/` 三个大锅各塞所有域。
52
- - **装配层是唯一能 import 具体实现的地方**:业务代码只通过 `get_xxx_provider()` 取实例,换实现不改业务代码。
44
+ - Python → `dwy-python-layering`
45
+ - Vue → `dwy-vue-layering`
46
+ - Android → `dwy-android-layering`
47
+ - iOS / macOS → `dwy-apple-layering`
48
+
49
+ 铁律(细节与正反例见上列 rule):依赖只许向下;`features/*` 互不依赖;具体实现只在 Assembly 注入;第三方版本只写在仓库根 catalog。
53
50
 
54
51
  ## 实现
55
52
  [自写型]
56
53
  1. 读项目 `.claude/rules/`,结合上方架构约束产出架构(项目 rules 优先,本约束兜底)
57
- 2. 技术架构:**先按四层归位模块、按业务域聚目录**,再写分层/模块边界/选型理由;选型不确定处走 `AskUserQuestion`
54
+ 2. 技术架构:**先读对应栈 `dwy-*-layering` 按四层归位模块、按业务域聚目录**,再写分层/模块边界/选型理由;选型不确定处走 `AskUserQuestion`
58
55
  3. **判有无后端**(读选型/PRD:有 API / 持久化 / 账户体系 → 有后端):
59
56
  - **有后端** → 必出数据库设计,且**建模到位**:库表清单 / 字段(类型·约束·默认·可空) / 主外键关系 / 索引 / 必要的范式或反范式说明,与接口契约 schema 对齐
60
57
  - **纯前端**(无后端)→ 跳过数据库设计,在 `技术架构.md` 注明「无后端,不涉及库表」
@@ -64,7 +61,7 @@ description: "【dwy·技术架构】产品 0 到 1 设计与架构阶段。触
64
61
  ## 产出契约(硬约束)
65
62
  - 落到:`.dwy/prod/[项目]/04-架构设计/技术架构.md`、`接口契约.md`,**有后端时**加 `数据库设计.md`
66
63
  - 固定章节:
67
- - 技术架构.md:**四层划分 + 各业务域目录结构** / 模块边界 / 技术选型(按缺省基线写明 Python+FastAPI+uv+Alembic+pydantic-settings+JWT、前端 Vue+Vite+TS+Tailwind+pnpm+Pinia+axios+Playwright、CI/CD GitHub Actions OIDC;有 DB 写明 PostgreSQL+Redis+Docker+Nginx;偏离基线处写明原因)/ 选型不明或偏离基线处的 AskUserQuestion 确认记录 / 有无后端结论
64
+ - 技术架构.md:**按对应 `dwy-*-layering` 写四层划分 + 各业务域目录结构** / 模块边界 / 技术选型(按缺省基线写明 Python+FastAPI+uv+Alembic+pydantic-settings+JWT、前端 Vue+Vite+TS+Tailwind+pnpm+Pinia+axios+Playwright、CI/CD GitHub Actions OIDC;有 DB 写明 PostgreSQL+Redis+Docker+Nginx;偏离基线处写明原因)/ 选型不明或偏离基线处的 AskUserQuestion 确认记录 / 有无后端结论
68
65
  - 数据库设计.md(**有后端必出**):库表清单 / 字段定义(类型·约束·默认·可空) / 主外键关系与索引 / 与接口契约对齐
69
66
  - 接口契约.md:接口清单 / 请求响应 schema / 错误码
70
67
  - 回写 state.json:`confirmed.architecture`
@@ -106,7 +106,7 @@
106
106
 
107
107
  - 每个外部 skill 是**整个目录**(含 scripts/ 与配套 .md,不止 SKILL.md)
108
108
  - 由 `dwy` 选「刷新全局外部 skill」安装/更新(clone 两仓库的指定 stable tag → 搬整目录 + LICENSE → 写 `VERSIONS.json`)
109
- - `dwy claude sync` 自检:`~/.dwy/skills/` 缺失时自动装一次
109
+ - `dwy` 日常同步自检:`~/.dwy/skills/` 缺失时自动装一次
110
110
  - 当前 stable:pm-skills **v2.0.0** | superpowers **v6.0.3**(升级改 cli 的 `skills-install.js` 清单 tag)
111
111
  - 原子 skill 运行时**只读** `~/.dwy/skills/<name>/`,缺失则提示用户先跑 `dwy`,选「刷新全局外部 skill」,不自己拉、不降级
112
112
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: dwy-prototype
3
- description: "【dwy·UI原型】产品 0 到 1 设计与架构阶段。触发场景:用户说『画原型 / 出原型 / 做 UI 原型 / 把页面画出来 / prototype』,要在写 UI 代码前把页面画成静态原型图时。两轮串行门控:先低保真线框初稿,用户讨论通过后再做高保真平面图,过了才进架构。"
3
+ description: "【dwy·UI原型】产品 0 到 1 的静态原型。触发场景:用户说『产品流程出原型 / 线框初稿 / 高保真平面图 / 0到1 原型』。两轮串行门控:先低保真线框,用户通过后再做高保真平面图。可交互白板、状态跳转连线不走本 skill,走 dwy-whiteboard-prototype。"
4
4
  ---
5
5
 
6
6
  ## 职责(单一)
@@ -56,13 +56,26 @@ gh run view <run-id> --json jobs,conclusion
56
56
  - PyPI Trusted Publisher 需要 `permissions: id-token: write`,并绑定 workflow 和 environment。
57
57
  - artifact 名称必须包含平台和架构,避免多个 matrix 上传时互相覆盖。
58
58
 
59
+ ## 模板里的 tag、runner、依赖下限是先验
60
+
61
+ `references/*.yml` 里的 `actions/*@v4`、`pypa/cibuildwheel@v3.4`、`ubuntu-24.04-arm`、`macos-15-intel`、`macos-14`、`manylinux_2_28`、`musllinux_1_2`、`setuptools>=77`、`packaging>=24.2`、`Cython>=3.0.10`、`node-version: 20` 是写作时能用的起点。
62
+
63
+ 复制前核对:
64
+
65
+ - `uses:` 的 tag 在该 action 仓库里真实存在。没有 major alias(例如曾经的 `cibuildwheel@v3`)就换本次查到的 minor 或精确 tag。
66
+ - runner label 在 `actions/runner-images` 当前 supported 列表里。已知退役:`macos-13` / `macos-12` / `macos-11` / `ubuntu-20.04`。新退役的同样不能用。表里没写但还在支持的不要判死。
67
+ - manylinux / musllinux 按这次要装的 wheel 实际 platform tag 选。旧镜像装不上就换,不要把 `_2_28` 当成永远唯一。
68
+ - `setuptools` / `packaging` / `Cython` 的下限来自 PEP 639 把旧 packaging 打爆那次。license expression 仍缺 `packaging.licenses` 时,按这几个包当前 release 的依赖说明抬下限。数字对不上就换,不要把 77 / 24.2 写成唯一修复。
69
+
70
+ 当次选出的 tag 和 label 不要写回本 skill 或模板,当成新的永远默认。
71
+
59
72
  ---
60
73
 
61
74
  ## 场景 1:Python Cython wheel + PyPI OIDC
62
75
 
63
76
  适用:含 Cython 编译扩展的 Python 包、跨平台 wheel 分发(linux x86_64/aarch64 + macOS x86_64/arm64 + Windows AMD64)、GitHub Actions + cibuildwheel + PyPI Trusted Publisher OIDC 发版。
64
77
 
65
- 模板:复制 `./references/release-workflow-template.yml` 到目标项目 `.github/workflows/release.yml`,只改:
78
+ 模板:复制 `./references/release-workflow-template.yml` 到目标项目 `.github/workflows/release.yml`。action tag、runner label、manylinux 镜像先按上一节核对,再改:
66
79
 
67
80
  1. `package-dir: <PACKAGE_DIR>`:实际 SDK 子目录;单包仓库填 `.` 或省略。
68
81
  2. `CIBW_BUILD`:按需调整 Python 版本枚举。
@@ -75,13 +88,13 @@ rg -n "Cython|ext_modules|Extension|cibuildwheel|pypa/gh-action-pypi-publish|lic
75
88
 
76
89
  检查点:
77
90
 
78
- - `[build-system].requires` 含 `setuptools>=77`、`packaging>=24.2`、`wheel`、`Cython>=3.0.10`。
79
- - `pypa/cibuildwheel` 用 minor tag 或精确 tag,例如 `pypa/cibuildwheel@v3.4`,不要写 `@v3`。
91
+ - `[build-system].requires` 要能通过当前的 license expression 检查。当时踩坑的下限是 `setuptools>=77`、`packaging>=24.2`、`wheel`、`Cython>=3.0.10`,以这几个包当前 release 说明为准。
92
+ - `pypa/cibuildwheel` 用仓库里真实存在的 minor tag 或精确 tag。`@v3.4` 是当时的例子,不要写不存在的 `@v3`。复制前再查一次 tag。
80
93
  - monorepo 用 `with.package-dir`,测试命令使用 `{package}`,不要用 `{project}/tests`。
81
94
  - 跨平台 shell 参数用外单内双:`'pytest {package}/tests -v -k "not requires_server"'`。
82
- - Linux 依赖 pyarrow / pandas / numpy / scipy / lxml 时,manylinux 镜像用 `manylinux_2_28`。
95
+ - Linux 依赖 pyarrow / pandas / numpy / scipy / lxml 时,manylinux 镜像按这些 wheel 当前的 platform tag 选。当时需要 `manylinux_2_28`。
83
96
  - test 阶段大依赖用 binary-only 预装:`CIBW_BEFORE_TEST: "pip install --only-binary=:all: pyarrow pandas"`。
84
- - macOS x86_64 用 `macos-15-intel`,不要用 `macos-13`。
97
+ - macOS x86_64 用当次 supported 的 intel label。写作时是 `macos-15-intel`。不要用已退役的 `macos-13`。
85
98
  - 默认只发布 wheel。不要发布 sdist,避免 Cython 编译模块源码随 sdist 泄漏。
86
99
 
87
100
  ### Python 8 个高频坑
@@ -164,7 +177,9 @@ CIBW_TEST_COMMAND: "pytest {package}/tests -v -k 'not requires_server'"
164
177
  CIBW_TEST_COMMAND: 'pytest {package}/tests -v -k "not requires_server"'
165
178
  ```
166
179
 
167
- #### 坑 6:manylinux 镜像必须升到 `_2_28`
180
+ #### 坑 6:manylinux 镜像低于 wheel 要求的 platform tag
181
+
182
+ 当时 pyarrow 等需要 `manylinux_2_28`。以这次要装的 wheel 为准,不要把 `_2_28` 当成永远唯一。
168
183
 
169
184
  ```yaml
170
185
  env:
@@ -181,7 +196,9 @@ env:
181
196
  CIBW_TEST_COMMAND: 'pytest {package}/tests -v -k "not requires_server"'
182
197
  ```
183
198
 
184
- #### 坑 8:macos-13 runner 已退休
199
+ #### 坑 8:退役 runner
200
+
201
+ `macos-13` 当时已退休。下面这组 label 是当时的 supported 先验,写之前再查 `actions/runner-images`。
185
202
 
186
203
  ```yaml
187
204
  matrix:
@@ -212,17 +229,17 @@ rg -n "electron|electron-builder|electron-forge|pack|dist|dmg|AppImage|nsis|appx
212
229
  检查点:
213
230
 
214
231
  - `package.json` 明确 `electron` 和打包工具版本,例如 `electron-builder`。
215
- - workflow 用 `actions/checkout@v4`,项目依赖 submodule 时必须 `submodules: true`。
216
- - Node 版本固定,例如 `actions/setup-node@v4` + `node-version: 20`。
232
+ - workflow 用当前仍存在的 checkout tag(写作时常见 `actions/checkout@v4`)。项目依赖 submodule 时必须 `submodules: true`。tag 404 或已废弃就换本次查到的 tag。
233
+ - Node 版本按项目引擎固定到具体版本。`actions/setup-node@v4` + `node-version: 20` 只是当时的例子,不是唯一合法版本。
217
234
  - 使用锁文件安装:npm 项目用 `npm ci`,pnpm 项目用 `pnpm install --frozen-lockfile`。
218
235
  - 每个平台在对应 runner 上打包,不要指望一个 Linux runner 交叉产出 macOS / Windows 完整安装包。
219
- - macOS x64 和 arm64 分开:x64 用 `macos-15-intel`,arm64 用 `macos-latest` / `macos-14`。
236
+ - macOS x64 和 arm64 分开。写作时 x64 是 `macos-15-intel`,arm64 是 `macos-latest` / `macos-14`。写之前再查 supported labels。
220
237
  - Linux AppImage 需要系统依赖,常见为 `icnsutils graphicsmagick xz-utils`。
221
238
  - Linux runner 上 `apt-get update` 前可移除易失效的 Microsoft / Azure apt source,避免第三方源拖死打包。
222
239
  - 未配置证书但要产出 unsigned 包时,设置 `CSC_IDENTITY_AUTO_DISCOVERY: false`,避免 electron-builder 自动找证书导致 macOS job 失败。
223
240
  - 产物命名必须包含 `${version}`、`${os}`、`${arch}`,避免 Release asset 覆盖。
224
241
  - upload-artifact 只上传最终安装包:`*.dmg`、`*.exe`、`*.AppImage`;不要上传 `win-unpacked/`。
225
- - GitHub Release job 需要 `permissions: contents: write`,用 `actions/download-artifact@v4` + `merge-multiple: true` 汇总产物。
242
+ - GitHub Release job 需要 `permissions: contents: write`。汇总产物用当前仍存在的 `actions/download-artifact` tag(写作时常见 `@v4`)+ `merge-multiple: true`。
226
243
 
227
244
  ### Electron 推荐 workflow 形态
228
245
 
@@ -232,7 +249,7 @@ rg -n "electron|electron-builder|electron-forge|pack|dist|dmg|AppImage|nsis|appx
232
249
 
233
250
  #### 坑 1:macOS x64 / arm64 不能混跑
234
251
 
235
- macOS x64 用 `macos-15-intel`。macOS arm64 用 `macos-latest` / `macos-14`。不要用已退役的 `macos-13`。
252
+ macOS x64 用当次 supported 的 intel label(写作时是 `macos-15-intel`)。macOS arm64 用当次 arm label(写作时是 `macos-latest` / `macos-14`)。不要用已退役的 `macos-13`。
236
253
 
237
254
  #### 坑 2:Linux 打 AppImage 缺系统依赖
238
255
 
@@ -353,12 +370,12 @@ git push origin v1.2.3
353
370
  |---|---|---|
354
371
  | YAML 解析 | env / run 含 `:` 未加引号,run 几秒 fail 且 jobs 为空 | 致命 |
355
372
  | action tag | `pypa/cibuildwheel@v3` 等不存在 alias | 致命 |
356
- | runner | `macos-13` / `macos-12` / `ubuntu-20.04` | 致命 |
373
+ | runner | 不在当次 supported 列表里。已知退役:`macos-13` / `macos-12` / `ubuntu-20.04` | 致命 |
357
374
  | artifact | matrix 上传同名产物或未带平台架构 | 高 |
358
- | Python build-system | PEP 639 license 但缺 `packaging>=24.2` | 致命 |
375
+ | Python build-system | license expression 但构建环境缺 `packaging.licenses`(当时的下限是 `packaging>=24.2`) | 致命 |
359
376
  | Python test path | monorepo 子目录用 `{project}/tests` | 高 |
360
377
  | Python shell 引号 | Windows 跨平台命令里用单引号包参数 | 高 |
361
- | Python manylinux | 大型 C 库依赖仍用 manylinux2014 | 高 |
378
+ | Python manylinux | 镜像低于这次 wheel 要求的 platform tag(当时常见仍停在 manylinux2014) | 高 |
362
379
  | Electron macOS | x64 / arm64 未拆 runner | 高 |
363
380
  | Electron Linux | AppImage 缺 `icnsutils graphicsmagick xz-utils` | 高 |
364
381
  | Electron 签名 | unsigned 构建未设 `CSC_IDENTITY_AUTO_DISCOVERY: false` | 中 |
@@ -3,12 +3,14 @@
3
3
  # 来源参考: 某 Electron 桌面应用多平台打包实战 (release.yml + pack.mjs)
4
4
  #
5
5
  # 使用前按项目实际情况替换:
6
- # 1. node-version
6
+ # 1. node-version(模板里的 20 只是当时的例子)
7
7
  # 2. 包管理器安装命令(npm ci / pnpm install --frozen-lockfile)
8
8
  # 3. build / pack 命令
9
9
  # 4. Linux 系统依赖
10
10
  # 5. 签名 / 公证 secrets
11
11
  # 6. artifact path 和文件命名
12
+ # 7. uses: 的 action tag 和 runs-on label。对照该 action 仓库的 tag 和 runner-images。
13
+ # 模板里的 @v4 / @v2、macos-14、ubuntu-latest 只是起点,不是必须版本。
12
14
 
13
15
  name: Build and Release
14
16
 
@@ -1,13 +1,16 @@
1
1
  # Python Cython SDK 跨平台 wheel + PyPI Trusted Publisher 发版 workflow 模板
2
2
  #
3
- # 已内置 dwy-github-action-publish skill Python wheel 场景 8 个避坑修复,开箱即用。
4
- # 复制到项目 .github/workflows/release.yml,只改两处:
3
+ # action tag、runner label、manylinux 镜像、setuptools/packaging/Cython 下限都是写作时的先验。
4
+ # 复制前对照 action 仓库的 tag 和 actions/runner-images 的 supported labels。
5
+ # tag 404、label 退役、wheel 的 platform tag 对不上,就换这次查到的值。不要把新值写回本模板。
6
+ #
7
+ # 复制到项目 .github/workflows/release.yml 后还要改:
5
8
  # 1. package-dir: <PACKAGE_DIR> —— 实际 SDK 子目录(monorepo 必填,单包仓库填 . 或省略)
6
9
  # 2. CIBW_BUILD —— 按需调整 Python 版本枚举
7
10
  #
8
- # 配套要求(缺一不可):
9
- # 1. <PACKAGE_DIR>/pyproject.toml 的 [build-system].requires 含:
10
- # "setuptools>=77", "packaging>=24.2", "wheel", "Cython>=3.0.10"
11
+ # 配套:
12
+ # 1. license expression 仍缺 packaging.licenses 时,按当前 release 说明抬 setuptools/packaging 下限。
13
+ # 当时踩坑的起点是 "setuptools>=77", "packaging>=24.2", "wheel", "Cython>=3.0.10"
11
14
  # 2. PyPI Trusted Publisher 已配(owner/repo/workflow=release.yml/environment=pypi)
12
15
  # 3. GitHub Settings → Environments 存在名为 "pypi" 的 environment
13
16
 
@@ -34,7 +34,7 @@ description: "Use when 用户要上架、发 iOS/macOS 版本、填 App Store Co
34
34
 
35
35
  ## 每版本处理
36
36
 
37
- 1. **推广文本不向用户询问**。现网有内容则原样拷进 `promotional_text`。与本版卖点明显不符时自行改写,改前可上网核对卖点是否仍准确;双语各 ≤170 字。首次无现网则按名称/副标题/描述生成。细则见 [aso.md](references/aso.md)。
37
+ 1. **推广文本不向用户询问**。现网有内容则原样拷进 `promotional_text`。与本版卖点明显不符时自行改写,改前可上网核对卖点是否仍准确。双语各不超过 [aso.md](references/aso.md) 的推广文本上限(当前先验 170)。Connect 拒收后改用当前字段限制。首次无现网则按名称/副标题/描述生成。
38
38
  2. **更新说明**:后续版本 `whats_new` 双语必填。给用户看的概览,写「新增某某功能」这类句子,机制细节不写,可用「等等」。禁止把 `dwy-publish` 的 git `CHANGELOG` 或实现细节贴进商店。首次上架可空。
39
39
  3. **截图**:默认 `screenshots.update=false`,拷上一版本,不问。出现任一情况必须更新:新主界面、新核心能力、旧图已不能代表产品、**What's New 写了的能力在现网截图里看不到**。按 [screenshot-specs.yaml](references/screenshot-specs.yaml) 处理;已送审版本改图见 [screenshot-workflow.md](references/screenshot-workflow.md)「送审后锁死」。
40
40
  4. **发布策略**:向用户确认二选一——过审即发(`AFTER_APPROVAL`),或过审后几天再发(`SCHEDULED` + `delay_days`)。选几天则再问天数。未选不得提交。
@@ -52,7 +52,7 @@ localizations:
52
52
  screenshots:
53
53
  ios: { zh-Hans: [], en-US: [] }
54
54
  macos: { zh-Hans: [], en-US: [] }
55
- # 每个内购条目必须带 `review_screenshot`,尺寸固定为 1280x800 像素。
55
+ # 每个内购条目必须带 `review_screenshot`。像素只读 references/screenshot-specs.yaml 的 macos_iap_review,不要在这里另写尺寸。
56
56
  in_app_purchases: []
57
57
  subscriptions: []
58
58
  review:
@@ -4,6 +4,8 @@
4
4
 
5
5
  ## 字数(按字符计,含中文一字)
6
6
 
7
+ 这些上限是 App Store Connect 的当前先验。提交若被拒说超长,以 Connect 当前字段限制改文案。不要用本表旧数字硬裁,也不要把新上限写回本文件。
8
+
7
9
  | 字段 | 上限 | 每版本 |
8
10
  |------|------|--------|
9
11
  | 名称 | 30 | 继承后可优化 |
@@ -7,7 +7,7 @@
7
7
  ## 采集与上传
8
8
 
9
9
  1. 使用审核账号或 StoreKit 测试环境进入目标商品购买页。
10
- 2. 在 macOS 16:10 画布导出 `1280 × 800` PNG 或 JPG,移除用户身份、支付凭据和生产数据。
10
+ 2. 按 [screenshot-specs.yaml](screenshot-specs.yaml) 的 `macos_iap_review.preferred` 导出 PNG 或 JPG,移除用户身份、支付凭据和生产数据。该条目当前先验是 `1280 × 800`。被拒后改那份规格,不要在这里另写像素。
11
11
  3. 上传前校验精确像素、RGB、无透明通道和单张文件约束。
12
12
  4. 通过 `inAppPurchaseAppStoreReviewScreenshots` 的预留、上传、提交流程写入对应内购;上传后读取资源状态确认成功。
13
13
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: dwy-publish
3
- description: "发版/部署编排器。触发条件:用户说\"发版\"\"部署\"\"发布上线\"\"release\"\"publish\"\"走发版流程\"时。按应用目录确认发布方式并缓存,串起定版本→changelog→安全检查→打 tag→build/发布→监控→通知。每次更新版本必须打 git tag,tag 版本串与 changelog 新版本标题完全一致。版本号决策单独走 dwy-semver,GA 打包走 dwy-github-action-publish,发布前安全检查走 dwy-sdk-spec——本 skill 负责编排,按路径主动调它们。"
3
+ description: "发版/部署编排器。触发条件:用户说\"发版\"\"部署\"\"发布上线\"\"release\"\"publish\"\"走发版流程\"时。按应用目录确认发布方式并缓存,串起定版本→changelog→安全检查→打 tag→build/发布→监控→通知。工厂里有多个项目时,先查出哪些项目的前端或后端有变更,再分别写 changelog。每次更新版本必须打 git tag,tag 版本串与该份 changelog 新版本标题完全一致。版本号决策单独走 dwy-semver,GA 打包走 dwy-github-action-publish,发布前安全检查走 dwy-sdk-spec——本 skill 负责编排,按路径主动调它们。"
4
4
  ---
5
5
 
6
6
  # 发版编排器
@@ -14,7 +14,7 @@ description: "发版/部署编排器。触发条件:用户说\"发版\"\"部
14
14
  | 1 | 确认发布方式 + 探测 build/publish 命令 | 项目步 | `scripts/release_config.sh` + `references/publish-config.md` |
15
15
  | 2 | 写/校验发布配置(GA workflow / TestFlight 就绪) | 项目步 | `references/publish-config.md` |
16
16
  | 3 | 定版本号 + 多文件同步 | 通用步 | `../dwy-semver` + `references/version-sync.md` |
17
- | 4 | 写 changelog(按平台子目录) | 通用步 | `references/changelog.md` |
17
+ | 4 | 写 changelog(先扫工厂内要发的项目,再按每个项目的前端/后端分别写) | 通用步 | `references/changelog.md` |
18
18
  | 5 | 安全检查(闸门,未过不发) | 通用步 | `../dwy-sdk-spec` |
19
19
  | 6 | commit 版本变更 + 打 tag 并推送 | 通用步 | `references/git-tag.md` |
20
20
  | 7 | build + 触发发布 | 项目步 | `references/<平台>.md`;走 GA 引 `../dwy-github-action-publish` |
@@ -29,6 +29,7 @@ description: "发版/部署编排器。触发条件:用户说\"发版\"\"部
29
29
  - 安全检查(第 5 步)是闸门,未过不进 tag / 发布。
30
30
  - **每次更新版本必须打 tag**(第 6 步):tag 版本串与本次 changelog 新版本标题(`## x.y.z`)完全一致;细则见 `references/git-tag.md`。无 bump 的纯重发可不打新 tag。
31
31
  - 若 GA workflow 由 tag 触发,第 6 步 push tag 即触发第 7 步发布。
32
- - 全程 AI 自动判断、自动跑,仅搞不定时才问用户(版本级别拿不准、命令探测不到、配置缺失、构建/发布失败、需删远端 tag)。
32
+ - **正式环境分支**:只有 `develop` 和 `preview`。`develop` 发测试环境,版本只能是 `beta` 或 `rc`。正式版只从 `preview` 发。仓库没有这两条分支就先提醒,不自行建分支。用 `develop` 发正式版时,先按 `rules/开发流程/dwy-prod-branch.md` 问用户,未确认不发。
33
+ - 全程 AI 自动判断、自动跑,仅搞不定时才问用户(版本级别拿不准、命令探测不到、配置缺失、构建/发布失败、需删远端 tag)。用 `develop` 部署正式环境时除外,须先问用户。
33
34
  - 编排时按文件路径主动加载子 skill(`../dwy-semver`、`../dwy-sdk-spec`、`../dwy-github-action-publish`);这些 skill 也可被用户独立触发。
34
35
  - `.dwy/` 缓存提醒用户加进 `.gitignore`。
@@ -26,7 +26,7 @@
26
26
 
27
27
  ## changelog / tag / 安全检查 / 监控
28
28
 
29
- - changelog → `changelog.md`(写 `android/CHANGELOG.md`)
29
+ - changelog → `changelog.md`(写该项目的 `android/CHANGELOG.md`;工厂里多个项目时每个项目各一份)
30
30
  - tag → `git-tag.md`(每次 bump 必打;版本串与 changelog `##` 标题一致)
31
31
  - 安全检查 → `../dwy-sdk-spec`
32
32
  - 监控 + 结果 → `monitor-notify.md`
@@ -19,6 +19,6 @@
19
19
 
20
20
  ## changelog / tag / 监控
21
21
 
22
- - changelog → `changelog.md`(写 `backend/CHANGELOG.md`)
22
+ - changelog → `changelog.md`(写该项目的 `backend/CHANGELOG.md`;工厂里多个项目时每个项目各一份)
23
23
  - tag → `git-tag.md`(每次 bump 必打;版本串与 changelog `##` 标题一致)
24
24
  - 监控 + verify → `monitor-notify.md`(后端信号:健康检查 / 版本接口 / 运行日志 / 镜像 tag)