create-dwy 0.14.7 → 0.16.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 (95) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/bin/index.js +8 -2
  3. package/package.json +1 -1
  4. package/src/skills-install.js +154 -0
  5. package/src/sync-all.js +7 -0
  6. package/templates/ai-tools/CLAUDE.md +28 -1
  7. package/templates/ai-tools/hooks/Git/pre-git-commit-sensitive-check.sh +10 -2
  8. package/templates/ai-tools/rules/Android/dwy-android-pitfalls.md +52 -0
  9. package/templates/ai-tools/rules/HarmonyOS/dwy-arkts-strict.md +221 -0
  10. package/templates/ai-tools/rules/HarmonyOS/dwy-arkts-ui-build.md +193 -0
  11. package/templates/ai-tools/rules/Python/dwy-python-backend.md +16 -63
  12. package/templates/ai-tools/rules/Python/dwy-python-base-lib.md +89 -0
  13. package/templates/ai-tools/rules/Python/dwy-python-pitfalls.md +49 -0
  14. package/templates/ai-tools/rules/Vue/dwy-vue-base-lib.md +127 -0
  15. package/templates/ai-tools/rules/Vue/dwy-vue-core.md +22 -86
  16. package/templates/ai-tools/rules/Vue/dwy-vue-pitfalls.md +66 -0
  17. package/templates/ai-tools/rules/iOS/dwy-ios-pitfalls.md +159 -0
  18. package/templates/ai-tools/rules/iOS/dwy-swift-core.md +35 -0
  19. package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-dependency-freshness.md +59 -0
  20. package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-tdd-development.md +47 -2
  21. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-acceptance/SKILL.md +24 -0
  22. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-architecture/SKILL.md +70 -0
  23. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-commercial/SKILL.md +58 -0
  24. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-competitor/SKILL.md +23 -0
  25. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-explore/SKILL.md +83 -0
  26. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-mvp/SKILL.md +24 -0
  27. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-poc/SKILL.md +24 -0
  28. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-prd/SKILL.md +23 -0
  29. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-product-launcher/SKILL.md +73 -0
  30. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-product-launcher/references/state-and-contract.md +155 -0
  31. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-prototype/SKILL.md +42 -0
  32. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-release/SKILL.md +27 -0
  33. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-design/SKILL.md +30 -0
  34. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-dev/SKILL.md +54 -0
  35. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-launch/SKILL.md +37 -0
  36. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-prd/SKILL.md +31 -0
  37. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-ship/SKILL.md +30 -0
  38. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-tasks/SKILL.md +32 -0
  39. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-tdd-dev/SKILL.md +34 -0
  40. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-validate/SKILL.md +29 -0
  41. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-version/SKILL.md +24 -0
  42. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-github-action-publish/SKILL.md +365 -0
  43. 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 +98 -0
  44. package/templates/ai-tools/skills//{350/277/220/347/273/264/345/217/221/345/270/203/dwy-cibuildwheel → 345/217/221/345/270/203/345/217/221/347/211/210/dwy-github-action-publish}/references/release-workflow-template.yml +3 -3
  45. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/SKILL.md +31 -0
  46. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/android.md +31 -0
  47. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/backend-deploy.md +23 -0
  48. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/changelog.md +37 -0
  49. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/frontend-deploy.md +23 -0
  50. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/generic-release.md +27 -0
  51. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/harmony.md +25 -0
  52. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/ios.md +32 -0
  53. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/monitor-notify.md +36 -0
  54. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/publish-config.md +65 -0
  55. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/version-sync.md +30 -0
  56. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/scripts/release_config.sh +115 -0
  57. package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/SKILL.md +31 -21
  58. package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/references/python-commercial-guide.md +1 -1
  59. package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/references/sensitive-patterns.md +1 -1
  60. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-sdk-spec/scripts/init_config.sh +91 -0
  61. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-whiteboard-prototype/SKILL.md +70 -0
  62. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-whiteboard-prototype/assets/template.html +353 -0
  63. package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-sdk-spec/scripts/init_config.sh +0 -97
  64. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-0to1/SKILL.md +0 -113
  65. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-0to1/templates/STATE.md +0 -56
  66. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-dev-qa/SKILL.md +0 -117
  67. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-market-analysis/SKILL.md +0 -92
  68. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prd-coarse/SKILL.md +0 -72
  69. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prd-coarse/templates/prd-coarse.md +0 -61
  70. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prd-detailed/SKILL.md +0 -76
  71. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prd-detailed/templates/prd-detailed.md +0 -119
  72. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prototype/SKILL.md +0 -104
  73. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-publish/SKILL.md +0 -50
  74. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-publish/references/application-release.md +0 -106
  75. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-publish/references/sdk-release.md +0 -93
  76. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-spike/SKILL.md +0 -81
  77. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-tdd-dev/SKILL.md +0 -212
  78. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-tdd-dev/templates/impl-plan.md +0 -115
  79. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-tech-feasibility/SKILL.md +0 -105
  80. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-version-plan/SKILL.md +0 -64
  81. package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-version-plan/templates/version-plan.md +0 -72
  82. package/templates/ai-tools/skills//350/277/220/347/273/264/345/217/221/345/270/203/dwy-cibuildwheel/SKILL.md +0 -356
  83. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/assets/files-whitelist-snippet.json" +0 -0
  84. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/assets/js-commercial.npmignore" +0 -0
  85. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/assets/python-commercial-MANIFEST.in" +0 -0
  86. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/assets/python-commercial.gitignore" +0 -0
  87. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/references/js-commercial-guide.md" +0 -0
  88. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/references/publish-blacklist.md" +0 -0
  89. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/scripts/check_comments.py" +0 -0
  90. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/scripts/check_js_publish.sh" +0 -0
  91. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/scripts/check_python_publish.sh" +0 -0
  92. /package/templates/ai-tools/skills//345/{256/211/345/205/250 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-sdk-spec/scripts/detect_sdk.sh" +0 -0
  93. /package/templates/ai-tools/skills//345/{274/200/345/217/221/346/265/201/347/250/213 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-semver/SKILL.md" +0 -0
  94. /package/templates/ai-tools/skills//345/{274/200/345/217/221/346/265/201/347/250/213 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-semver/references/semver-spec.md" +0 -0
  95. /package/templates/ai-tools/skills//345/{274/200/345/217/221/346/265/201/347/250/213 → 217/221/345/270/203/345/217/221/347/211/210}/dwy-semver/scripts/bump.py" +0 -0
@@ -1,105 +0,0 @@
1
- ---
2
- name: dwy-tech-feasibility
3
- description: 技术可行性与选型调研:为产品核心能力找 1-3 个成熟开源方案做对比,给推荐 + 是否需要实测建议,绝不手撸已有轮子。涉及以下场景使用此 skill(即使没点名 'dwy-tech-feasibility'):用户说『这个功能用什么技术实现』『帮我做技术选型/可行性分析』『有没有现成的库做 X』『这个能力技术上可行吗』。WebSearch 找方案 + 四项对比表(能力覆盖/成熟度/适配度/坑)+ 敢下判断的推荐。区分:本 skill 是选型可行性调研(纸面对比);要真写代码跑通用 dwy-spike;要推荐整套项目技术栈用 dwy-tech-stack;完整 0→1 流水线用 dwy-0to1。
4
- ---
5
-
6
- # dwy-tech-feasibility · 技术可行性
7
-
8
- 找 1-3 个成熟方案实现产品核心能力,**绝不手撸**。选对省半年,选错返工到死。同时判断要不要先写代码实测核心风险。
9
-
10
- ## 运行模式
11
-
12
- 上下文自适应,两种调用方式:
13
-
14
- - **单独调用(默认)**:用户直接问某能力怎么实现 / 选什么技术。从用户描述的能力起步;产物落 `./tech-feasibility.md` 或用户指定位置;**不读写 STATE.md、不依赖 `docs/0to1/`**。做完跑下方「门」即结束。
15
- - **流水线调用**:`dwy-0to1` 调用,指令含「流水线模式」+ 前序产物路径(市场分析)+ 落盘路径(如 `docs/0to1/02-tech-feasibility.md`)。按指令读前序、写指定路径;**STATE 记账由 dwy-0to1 负责,本 skill 不碰 STATE.md**。
16
-
17
- ## 输入(核心能力从哪来)
18
-
19
- - 单独模式:从用户描述里拎出要实现的核心能力;不清楚就先问一句产品要做什么。
20
- - 流水线模式:读编排器给的市场分析产物,拿到**核心能力 / 最大技术风险假设**和**硬约束**(合规/PII/实时性/规模水位)——硬约束直接决定哪些方案能选。
21
-
22
- 技术调研只围绕**核心能力**转,别给还没定的边角功能选型。
23
-
24
- ## 怎么做
25
-
26
- 铁律:**先搜后造**,优先成熟开源方案,禁止手写已有主流方案的功能。
27
-
28
- ### 一、WebSearch 找方案(1-3 个)
29
-
30
- 1. 拆出产品的**核心技术能力**(如「实时语音转文字」「PDF 解析」「本地向量检索」),逐个搜主流实现。
31
- 2. 搜的标准(沿用 dwy「优先成熟开源方案」):
32
- - npm / PyPI / GitHub **stars > 1k**
33
- - **近期有维护**(近半年有 commit / release)
34
- - 社区主流,不是冷门小众
35
- 3. 每个能力列 **1-3 个**候选方案,别只列一个(没对比说不清推荐)。
36
-
37
- ### 二、目标技术栈没有合适库 → 跨语言参考
38
-
39
- 目标语言/栈里搜不到合适方案,但**别的语言有成熟库** → 推荐那个库**供参考实现**,讲清两件事:
40
- - 怎么参考:照它的核心算法/数据结构思路自己实现,还是直接调(子进程 / FFI / 服务化)。
41
- - 怎么移植:关键逻辑在哪、移植难点是什么。
42
-
43
- - ❌ 目标是 Python 但只有 Rust 有成熟库 → 直接说「没方案,自己写」
44
- - ✅ 「核心算法 Rust 的 `xxx`(stars 8k)最成熟。两条路:① 用 PyO3 包成 Python 扩展直接调;② 照它的 `core/` 算法思路用 Python 重写,难点在 SIMD 那段。推荐 ①,省事且不丢性能。」
45
-
46
- ### 三、每个方案给四项 + 推荐
47
-
48
- 每个候选方案列:
49
-
50
- | 项 | 说什么 |
51
- |----|--------|
52
- | 能力覆盖 | 核心能力它能做到几成,缺什么 |
53
- | 成熟度 | stars / 维护活跃度 / 生产案例 |
54
- | 适配度 | 跟产品技术栈、部署形态合不合、**能否满足硬约束**(合规/实时性/规模) |
55
- | 坑 | 已知限制、license、性能/体积代价 |
56
-
57
- 最后给 **推荐方案 + 理由**(敢下判断,别全列让用户猜),并说明推荐方案**如何满足硬约束**;若某硬约束无方案可满足,明确标红为风险。
58
-
59
- ### 四、判断要不要写代码实测
60
-
61
- | 判断 | 信号 | 建议 |
62
- |------|------|------|
63
- | **建议实测** | 有技术风险/不确定:新算法、硬件集成、性能未知、第三方 API 行为不明、跨语言移植没把握 | 接 dwy-spike 先写丢弃式 POC 验核心流程 |
64
- | **跳过实测** | 技术成熟无悬念、方案有大量生产案例、就是常规 CRUD/调 API | 直接进开发,不必 spike |
65
-
66
- 把建议写进产物,给用户拍板。
67
-
68
- ## 产物
69
-
70
- 落盘技术可行性文档(单独默认 `./tech-feasibility.md`;流水线按编排器给的路径)。frontmatter:
71
-
72
- ```markdown
73
- ---
74
- status: done # 落盘且过门后才填 done;过门前 awaiting-approval
75
- updated: <date +%Y-%m-%d>
76
- ---
77
- ```
78
-
79
- 正文必含:
80
-
81
- | 块 | 内容 |
82
- |----|------|
83
- | 核心能力清单 | 产品要实现哪几项关键技术能力 |
84
- | 方案对比表 | 每个能力 1-3 个候选,列 能力覆盖/成熟度/适配度/坑 |
85
- | 跨语言参考 | 如有:推荐别的语言的库 + 怎么参考/移植 |
86
- | 推荐方案 | 选哪个 + 理由(敢下判断)+ 如何满足硬约束 |
87
- | 是否实测建议 | 建议实测(说清验什么风险)/ 跳过(说清为什么无悬念) |
88
-
89
- ## 门(过门确认)
90
-
91
- 落盘后先**自己核一遍**(先验证再声称):每个核心能力都有候选吗、对比表四项填全了吗、推荐有理由吗、实测建议明确吗。
92
-
93
- 然后 `AskUserQuestion` 摆**方案对比 + 推荐**,问:
94
-
95
- > 选哪个方案?要不要先写代码实测核心流程再往下走?
96
-
97
- 让用户同时定下「技术方案」和「是否实测」两件事。
98
-
99
- ## 边界 / 禁止
100
-
101
- - **绝不手撸已有主流方案**——搜得到成熟库就用/参考,搜不到才自己写,且要在产物里写清「调研了哪些、为何都不用」。
102
- - **每个核心能力至少给候选,不能空着说「自己实现」**——除非确认无任何开源方案。
103
- - **推荐必须带理由,不和稀泥**——不「都可以,看你」。
104
- - **目标栈无库时别直接放弃**——先看跨语言有没有成熟方案可参考/移植。
105
- - 这步**只调研和选型,不写实现代码**。要验证可行性是 dwy-spike 干的事。
@@ -1,64 +0,0 @@
1
- ---
2
- name: dwy-version-plan
3
- description: 产品版本规划:基于细 PRD 把产品切成可交付版本(v1 最小闭环 → v2 → v3…),每版写包含功能、依赖、可验证的验收标准,按价值增量切不按技术层切。涉及以下场景使用此 skill(即使没点名 'dwy-version-plan'):用户说『帮我规划版本/迭代』『这个产品先做哪些功能、怎么分版本』『切个 v1 最小可用版本』『排个版本路线』。区分:本 skill 切版本+定验收;具体某版本的 TDD 实现用 dwy-tdd-dev;完整 0→1 流水线用 dwy-0to1。
4
- ---
5
-
6
- # dwy-version-plan · 版本规划
7
-
8
- 基于细 PRD 把产品切成若干可交付版本:v1 最小可用闭环 → v2 → v3…,每个版本是一个能独立交付的增量。
9
-
10
- ## 运行模式
11
-
12
- 上下文自适应,两种调用方式:
13
-
14
- - **单独调用(默认)**:用户直接让你规划版本。从用户给的 PRD/功能清单或描述起步;产物落 `./version-plan.md` 或用户指定位置;**不读写 STATE.md、不依赖 `docs/0to1/`**。做完跑下方「门」即结束。
15
- - **流水线调用**:`dwy-0to1` 调用,指令含「流水线模式」+ 前序产物路径(细 PRD)+ 落盘路径(如 `docs/0to1/06-version-plan.md`)。**STATE 记账(含选定版本、版本进度表)由 dwy-0to1 负责,本 skill 不碰 STATE.md**。
16
-
17
- ## 输入(切版本的依据)
18
-
19
- - **细 PRD 是切版本的唯一依据**:每个版本包含哪些功能,必须能映射回 PRD 的具体页面 / 功能,不能凭空加。
20
- - 看目标端和产品定位,版本节奏按端和定位定。
21
- - 单独模式:用户没给细 PRD 就先问清有哪些功能/页面、核心价值是什么,再切。
22
-
23
- ## 怎么做(具体步骤)
24
-
25
- 套 `templates/version-plan.md`,按下面思路切:
26
-
27
- 0. **先勾勒全局数据模型 + 架构骨架(跨版本一次性)** — 切版本前先定核心实体、实体间关系、2-3 句架构方向(分层 / 存储 / 关键边界)。这是所有版本共用的地基,先定好才能避免 v1 把表结构 / 架构画死、v2 被迫 DB 迁移。轻量草图即可,不下到字段类型级(那是 Step9 实施计划的事)。
28
- 1. **找 v1 最小闭环** — 从 PRD 里挑出「能跑通核心价值的最小一条路径」。用户能完整走完一次主流程、拿到核心价值,就是 v1。砍掉一切锦上添花。
29
- - ✅ 笔记 App v1 = 新建 / 编辑 / 列表 / 删除,一条闭环
30
- - ❌ v1 塞进多端同步、协作、AI 摘要、主题皮肤——这些进 v2+
31
- 2. **后续版本按价值增量切** — v2、v3 每个加一组**能独立交付**的功能。不要按技术层切(「v1 做后端、v2 做前端」是错的,那不是可交付增量)。
32
- 3. **大胆切大版本** — AI 写代码效率高,单版本可以比传统排期装更多。判据是「这一版能不能独立交付、独立验收」,不是「工时够不够一个 sprint」。能合并成一个能交付的闭环就别拆碎。
33
- 4. **写清依赖** — 哪个版本依赖前序版本的产物 / 数据结构。一般 v2 依赖 v1,但要显式写出来依赖的是什么(如「v2 的搜索依赖 v1 已落地的笔记表结构」)。
34
- 5. **每版写验收标准** — 这一版做完,怎么算「真的做完了」。要可验证:列出用户能完成的动作 + 可观测的结果,开发的完成前验证就照这个核对。
35
-
36
- 每个版本一节,写全:**目标(一句话)/ 包含功能(对应 PRD 哪些页面 / 功能)/ 依赖前序版本 / 验收标准**。
37
-
38
- ## 产物
39
-
40
- 落盘版本规划(单独默认 `./version-plan.md`;流水线按编排器给的路径)。套 `templates/version-plan.md`(含版本总览 + 每版本一节 + 一个填好的示例)。frontmatter:
41
-
42
- ```
43
- ---
44
- status: done
45
- updated: <date +%Y-%m-%d>
46
- ---
47
- ```
48
-
49
- 成稿要件:全局数据模型 / 架构骨架已勾勒;每个版本的「包含功能」都能映射回细 PRD 的具体页面 / 功能;v1 是最小可用闭环;依赖关系写清;每版有可验证的验收标准。落盘后核对:把版本里列的功能逐条回查细 PRD,确认没有 PRD 里没有的功能、也没把核心闭环拆散到多个版本,再声称完成(先验证再声称)。
50
-
51
- ## 门(过门确认)
52
-
53
- 用 `AskUserQuestion` 把版本建议摆给用户:
54
- - 摆什么:各版本一句话目标 + 包含的主要功能 + 依赖关系(建议方案)。
55
- - 问什么:「**这次做哪几个版本?(可多选)**」选项给 v1 / v2 / v3… 让用户勾选要一起做的版本,外加「调整切法」。
56
-
57
- 用户选定后,要改切法就改,直到确认。
58
-
59
- ## 边界 / 禁止
60
-
61
- - **禁止脱离细 PRD 凭空加功能**——版本里每个功能都要能指回 PRD 某页 / 某功能。
62
- - **禁止按技术层切版本**(后端版 / 前端版)——每个版本必须是能独立交付、独立验收的增量。
63
- - **禁止把核心闭环拆碎**——v1 必须自己就能跑通核心价值,不能「v1 只有界面没逻辑」。
64
- - **禁止漏依赖和验收标准**——每版都要写清依赖什么、怎么算做完。
@@ -1,72 +0,0 @@
1
- ---
2
- status: draft # draft | done
3
- updated: <YYYY-MM-DD>
4
- ---
5
-
6
- # <产品名> · 版本规划
7
-
8
- > 基于细 PRD 把产品切成可交付版本。v1 = 最小可用闭环,往后每版是能独立交付、独立验收的增量。每个版本的功能都要能映射回细 PRD 的具体页面 / 功能。
9
-
10
- ## 全局数据模型 / 架构骨架
11
-
12
- > 跨版本一次性定的地基,避免 v1 把结构画死、v2 被迫迁移。轻量草图,不下到字段类型级。
13
-
14
- - **核心实体**:<实体 A、实体 B…,各一句话职责>
15
- - **实体关系**:<A 1:N B、B M:N C… 关键关系>
16
- - **架构方向**:<2-3 句:分层 / 存储选型 / 关键边界,如「前端 SPA + REST 后端 + Postgres;鉴权走 JWT;文件走对象存储」>
17
-
18
- ## 版本总览
19
-
20
- | 版本 | 一句话目标 | 依赖 |
21
- |------|-----------|------|
22
- | v1 | <最小可用闭环目标> | 无 |
23
- | v2 | <在 v1 上加的价值增量> | v1 |
24
- | v3 | <下一个增量> | v2 |
25
-
26
- ---
27
-
28
- ## 示例(填好的样板,照这个颗粒度写每一版)
29
-
30
- ### v1:能写能看的笔记闭环
31
-
32
- - **目标**:用户能新建、编辑、查看、删除笔记,一条完整可用闭环。
33
- - **包含功能**(对应细 PRD 页面 / 功能):
34
- - 笔记列表页(PRD 页面 1):列表展示、空态、下拉刷新
35
- - 新建 / 编辑页(PRD 页面 2):标题 + 正文输入(含前后端长度上限)、保存
36
- - 删除(PRD 页面 1 的滑动删除 + 二次确认)
37
- - **依赖前序版本**:无(首版)。
38
- - **验收标准**:
39
- - [ ] 新建一条笔记 → 列表出现该笔记
40
- - [ ] 编辑后 → 列表与详情内容同步更新
41
- - [ ] 删除 + 确认 → 列表移除该笔记
42
- - [ ] 正文超 5000 字 → 前端截断 + 提示,后端拒绝返回 422
43
- - [ ] 全量测试通过、构建 exit 0
44
-
45
- ### v2:搜索 + 标签
46
-
47
- - **目标**:笔记多起来后能快速找到。
48
- - **包含功能**(对应细 PRD 页面 / 功能):
49
- - 搜索页(PRD 页面 3):关键词搜索、结果高亮、零结果态
50
- - 标签(PRD 页面 2 的标签选择 + 页面 1 的标签筛选)
51
- - **依赖前序版本**:v1(依赖 v1 已落地的笔记表结构与列表页)。
52
- - **验收标准**:
53
- - [ ] 输入关键词 → 匹配的笔记按相关度返回,命中词高亮
54
- - [ ] 无匹配 → 显示零结果态文案
55
- - [ ] 给笔记打标签 → 列表可按标签筛选
56
- - [ ] 全量测试通过、构建 exit 0
57
-
58
- ---
59
-
60
- ## 空白版本模板(每个真实版本复制一份填)
61
-
62
- ### vN:<版本名>
63
-
64
- - **目标**:<一句话,这一版让用户能完成什么>
65
- - **包含功能**(对应细 PRD 页面 / 功能):
66
- - <功能 A>(PRD 页面 X)
67
- - <功能 B>(PRD 页面 Y)
68
- - **依赖前序版本**:<无 / vM,依赖 vM 的什么产物或数据结构>
69
- - **验收标准**(可验证、对得上「用户能完成的动作 + 可观测结果」):
70
- - [ ] <动作 → 可观测结果>
71
- - [ ] <用户输入的长度上限边界 → 预期行为>
72
- - [ ] 全量测试通过、构建 exit 0
@@ -1,356 +0,0 @@
1
- ---
2
- name: dwy-cibuildwheel
3
- description: "用 GitHub Actions + cibuildwheel 把【含 C 扩展 / Cython / .so 编译产物】的 Python 包跨平台 build wheel(linux/macos/windows × x86_64/arm64)并通过 PyPI Trusted Publisher (OIDC) 发布到 PyPI 的避坑指南。仅适用于需要编译 .so 的包;纯 Python 包发 PyPI 不需要本 skill(走 dwy-publish + dwy-sdk-spec)。涵盖 PEP 639 license / cibuildwheel 版本 tag / YAML 冒号转义 / {package} 占位符 / 跨平台 shell 引号 / manylinux 镜像 / 测试阶段 binary 强制 / GitHub runner image 退役(macos-13 已死)等 8 类高频坑。触发条件:编辑或新建含 cibuildwheel 的 .github/workflows/*.yml、pyproject.toml 含 Cython / ext_modules、用户说 'cibuildwheel' / 'build wheel' / '跨平台 wheel' / '.so 跨平台打包' / 'wheel build 失败' / 'macos runner 一直 queued',或要把含 C 扩展的 Python 包发 PyPI 时。"
4
- ---
5
-
6
- # dwy-cibuildwheel — Python Cython SDK 跨平台 PyPI 发布避坑
7
-
8
- 适用场景:含 Cython 编译扩展的 Python 包、跨平台 wheel 分发(linux x86_64/aarch64 + macos x86_64/arm64 + windows AMD64)、GitHub Actions + cibuildwheel + PyPI Trusted Publisher OIDC 发版。
9
-
10
- > 定位:本 skill 只解决「含 C 扩展的包怎么用 GitHub Actions 跨平台打 wheel 发 PyPI」的 CI 避坑。通用发版流程(测试 / bump / changelog / tag)走 `dwy-publish`;发布前接口脱敏 / 源码泄露 / 产物审计走 `dwy-sdk-spec`;纯 Python 包不需要本 skill。
11
-
12
- **实战来源**:quant-sdk (quantzone) 0.4.0 首发到 PyPI 过程中暴露的 8 类坑,全部沉淀于此。
13
-
14
- ---
15
-
16
- ## 8 个高频坑
17
-
18
- ### 坑 1:PEP 639 license expression 触发 build env 依赖冲突
19
-
20
- **症状**(任意平台 build 阶段):
21
- ```
22
- ImportError: Cannot import `packaging.licenses`.
23
- Setuptools>=77.0.0 requires "packaging>=24.2" to work properly.
24
- ```
25
-
26
- **根因**:`pyproject.toml` 用了 PEP 639 字符串形式 `license = "MIT"`。setuptools 77+ 校验 license expression 时强依赖 `packaging>=24.2`,但跨平台 cibuildwheel 临时 build env 装到老 packaging 时直接撞死。
27
-
28
- **修复**:在 `[build-system].requires` 显式锁两个下限:
29
- ```toml
30
- [build-system]
31
- requires = [
32
- "setuptools>=77",
33
- "packaging>=24.2",
34
- "wheel",
35
- "Cython>=3.0.10",
36
- ]
37
- build-backend = "setuptools.build_meta"
38
- ```
39
-
40
- **例外**:还在用老语法 `license = {text = "MIT"}` / `license = {file = "LICENSE"}` 的项目不触发。但 PEP 639 是趋势,建议主动对齐 + 提前锁依赖。
41
-
42
- ---
43
-
44
- ### 坑 2:cibuildwheel action 必须用 minor 级或精确 tag
45
-
46
- **症状**(workflow 启动几秒就 fail,错误页面提示):
47
- ```
48
- Unable to resolve action `pypa/cibuildwheel@v3`, unable to find version `v3`
49
- ```
50
-
51
- **根因**:不像 `actions/checkout@v4` 那种 major moving alias,`pypa/cibuildwheel` **只维护 minor 级 moving tag**(`v3.4`)和精确 patch tag(`v3.4.1`),**没有 `v3` 这种 major alias**。
52
-
53
- **修复**:
54
- ```yaml
55
- - uses: pypa/cibuildwheel@v3.4 # minor moving,自动跟 v3.4.x patch(推荐)
56
- # 或精确锁
57
- - uses: pypa/cibuildwheel@v3.4.1
58
- ```
59
-
60
- **自检**:改 action 版本前先查实际存在的 tag:
61
- ```bash
62
- curl -sL https://api.github.com/repos/pypa/cibuildwheel/git/refs/tags \
63
- | python3 -c "import sys,json; tags=[r['ref'].replace('refs/tags/','') for r in json.load(sys.stdin)]; print([t for t in tags if t.startswith('v3')][-10:])"
64
- ```
65
-
66
- 通用教训:**不要假设任何 GitHub Action 都有 `v<N>` major alias**,必须先查仓库 tag 列表。
67
-
68
- ---
69
-
70
- ### 坑 3:YAML 字符串含冒号必须加引号(静默杀手)
71
-
72
- **症状**:workflow 触发后几秒 conclusion=failure,但 `gh run view <id> --json jobs` 显示 **jobs 数组为空**——一个 job 都没启动。
73
-
74
- **根因**:GitHub Actions 在 yaml 解析失败时直接拒绝 workflow,不启动任何 job。最常见触发:
75
- ```yaml
76
- CIBW_BEFORE_TEST: pip install --only-binary=:all: pyarrow # 错!
77
- ```
78
- `:all:` 第二个冒号被 YAML 解析为 mapping value delimiter,整个文件解析失败。
79
-
80
- **修复**:整行加引号:
81
- ```yaml
82
- CIBW_BEFORE_TEST: "pip install --only-binary=:all: pyarrow pandas"
83
- ```
84
-
85
- **强制自检**(改完任何 workflow 后必跑):
86
- ```bash
87
- python3 -c "import yaml; yaml.safe_load(open('.github/workflows/release.yml'))"
88
- ```
89
- 本地报错就修,不要 push 后等 GitHub 告诉你(GitHub 不给具体 yaml 错误行号,得自己查)。
90
-
91
- **调试线索**:run conclusion=failure + jobs 为空 → 99% yaml 解析问题。
92
-
93
- ---
94
-
95
- ### 坑 4:CIBW_TEST_COMMAND 用 `{package}` 不要用 `{project}`
96
-
97
- **症状**(monorepo + SDK 在子目录):
98
- ```
99
- ERROR: file or directory not found: /runner/work/<repo>/<repo>/tests
100
- collected 0 items
101
- ============================ no tests ran in 0.00s =============================
102
- ```
103
-
104
- **根因**:`{project}` 占位符替换为 cibuildwheel 调用的工作目录(**repo 根**),不是 `package-dir`。如果 SDK 在 `quant-sdk/` 子目录,测试在 `quant-sdk/tests/`,但 `{project}/tests` 会找 `<repo-root>/tests`,找不到。
105
-
106
- **修复**:用 `{package}` 占位符:
107
- ```yaml
108
- - uses: pypa/cibuildwheel@v3.4
109
- with:
110
- package-dir: quant-sdk
111
- env:
112
- CIBW_TEST_COMMAND: 'pytest {package}/tests -v -k "not requires_server"'
113
- ```
114
-
115
- **占位符对照表**:
116
-
117
- | 占位符 | 替换为 |
118
- |---|---|
119
- | `{project}` | cibuildwheel 调用的工作目录(repo 根) |
120
- | `{package}` | `package-dir` 的绝对路径 |
121
-
122
- **适用场景**:monorepo 必须用 `{package}`;单包仓库 `{project}` `{package}` 等价。习惯用 `{package}` 不会错。
123
-
124
- ---
125
-
126
- ### 坑 5:跨平台 shell 引号必须外单内双
127
-
128
- **症状**(仅 Windows,linux/macos 正常):
129
- ```
130
- + pytest D:\a\repo\repo\quant-sdk/tests -v -k 'not requires_server'
131
- ERROR: file or directory not found: requires_server'
132
- collecting ... collected 0 items
133
- ```
134
-
135
- **根因**:Windows cmd **不解析单引号字符串**。`-k 'not requires_server'` 在 cmd 里被拆成两个独立参数 `'not` 和 `requires_server'`,pytest 把第二个当成目录路径。
136
-
137
- **修复**:YAML value 外层用**单引号**,里面 shell 命令用**双引号**(双引号在 sh + cmd 都正常):
138
- ```yaml
139
- CIBW_TEST_COMMAND: 'pytest {package}/tests -v -k "not requires_server"'
140
- ```
141
-
142
- **反例**(外双内单 = Windows 必坏):
143
- ```yaml
144
- CIBW_TEST_COMMAND: "pytest {package}/tests -v -k 'not requires_server'" # 错!
145
- ```
146
-
147
- **通用原则**:跨平台跑的命令字符串里,shell 引号统一用双引号;YAML 引号统一用单引号。**永远不要在跨平台命令里用单引号包参数**。
148
-
149
- ---
150
-
151
- ### 坑 6:manylinux 镜像必须升到 `_2_28`
152
-
153
- **症状**(仅 linux 容器内 pip install 阶段):
154
- ```
155
- ERROR: Could not find a version that satisfies the requirement pyarrow (from versions: none)
156
- ERROR: No matching distribution found for pyarrow
157
- ```
158
-
159
- **根因**:`pyarrow` / `pandas` / `numpy` 等大型 C 扩展库**早已只发 `manylinux_2_28` wheel**(要求 glibc 2.28+,CentOS 8+ / Ubuntu 18.04+ / Debian 10+),**不再支持 `manylinux2014`**(glibc 2.17)。cibuildwheel 老配置默认起 `manylinux2014` 容器,容器内 pip 找不到任何匹配 wheel。
160
-
161
- **修复**:
162
- ```yaml
163
- env:
164
- CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28
165
- CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28
166
- # musllinux 通常不用动
167
- CIBW_MUSLLINUX_X86_64_IMAGE: musllinux_1_2
168
- CIBW_MUSLLINUX_AARCH64_IMAGE: musllinux_1_2
169
- ```
170
-
171
- **风险评估**:升 manylinux_2_28 提高了用户机器的 glibc 要求,但你的 SDK 既然依赖 pyarrow,用户本来就受这个约束,**所以不增加额外限制**。
172
-
173
- **判断标准**:你的运行时依赖里有 pyarrow / pandas / numpy / scipy / lxml 等 → 必须 `manylinux_2_28`。
174
-
175
- ---
176
-
177
- ### 坑 7:测试阶段三方依赖必须强制 binary
178
-
179
- **症状**(任意平台、最容易在 aarch64 触发):
180
- ```
181
- ERROR: Failed building wheel for libcst
182
- error: can't find Rust compiler
183
- ERROR: Failed to build 'pyarrow' when installing build dependencies for pyarrow
184
- ```
185
-
186
- **根因**:cibuildwheel 在 test 阶段 `pip install <built-wheel>` 时自动装 SDK 的 runtime deps。pip 默认 prefer binary 但**允许源码 fallback**——某些版本/架构组合下 pip 找不到合适 binary,回退源码 build pyarrow → pyarrow build dep 拉 libcst → libcst 需要 Rust → 容器内没装 → 整个链 fail。
187
-
188
- **修复**:在 test 前预装大依赖,**强制只用 binary**:
189
- ```yaml
190
- env:
191
- CIBW_TEST_REQUIRES: pytest pytest-asyncio respx
192
- CIBW_BEFORE_TEST: "pip install --only-binary=:all: pyarrow pandas"
193
- CIBW_TEST_COMMAND: 'pytest {package}/tests -v -k "not requires_server"'
194
- ```
195
-
196
- `--only-binary=:all:` 表示对**所有包**拒绝任何源码 build。找不到合适 wheel 直接 fail(快速明确),不会拉长得离谱的 build chain。
197
-
198
- **关键**:必须搭配坑 6 的 `manylinux_2_28`,否则 pip 找不到 binary 直接报"No matching distribution"(参见坑 6 现象)。
199
-
200
- ---
201
-
202
- ### 坑 8:macos-13 runner 已退休(2025-12 起死等)
203
-
204
- **症状**:workflow 长期卡在
205
- ```
206
- Requested labels: macos-13
207
- Waiting for a runner to pick up this job...
208
- ```
209
- 小时级 queued,runner 永远不分配。其他 job 都成功,publish 因 `needs: build_wheels` 一直不启动。
210
-
211
- **根因**:GitHub 已于 **2025-12-04** 正式退役 `macos-13` runner image。配 `runs-on: macos-13` 的 job 不是排队,是 **runner pool 已被删空**——永远等不到。GitHub 没有为这种 case 抛错,只让你 queued 着。
212
-
213
- Apple 完全停 Intel + GitHub 计划 **2027 秋停所有 x86_64 macOS runner**,整个 Intel Mac runner 时代在落幕。
214
-
215
- **修复**:根据是否需要 macOS x86_64 wheel 选一:
216
-
217
- ```yaml
218
- matrix:
219
- include:
220
- - { os: ubuntu-latest, archs: x86_64 }
221
- - { os: ubuntu-24.04-arm, archs: aarch64 }
222
- # 选项 A: 仍需 x86_64 wheel(开发者自己是 Intel Mac / 重要用户群有 Intel Mac)
223
- - { os: macos-15-intel, archs: x86_64 } # ✅ 替代死掉的 macos-13(真 Intel runner)
224
- # 选项 B: 不需要 x86_64,删掉上一行,Intel Mac 用户走 Rosetta 跑 arm64 wheel
225
- - { os: macos-14, archs: arm64 }
226
- - { os: windows-latest, archs: AMD64 }
227
- ```
228
-
229
- **其他可选替代 label**:
230
-
231
- | label | 说明 |
232
- |---|---|
233
- | `macos-15-intel` | 真 Intel Mac runner(新引入,推荐) |
234
- | `macos-14-large` / `macos-15-large` | Apple Silicon 上虚拟化跑 x86_64,贵且慢 |
235
-
236
- **通用教训**:GitHub runner image 会按计划退役(macos-11/12/13 已退,macos-14 在用,macos-15 是新主力)。改 workflow 前去 https://github.com/actions/runner-images 看当前 supported labels;不要假设 stackoverflow 上的老 yaml 还能跑。
237
-
238
- **自检**: 看 `Waiting for a runner` 卡超过 30 分钟,基本 100% 是 label 已死(而不是真排队)。
239
-
240
- ---
241
-
242
- ## 完整 workflow 模板
243
-
244
- 直接复制 `references/release-workflow-template.yml` 到项目 `.github/workflows/release.yml`,只改两处:
245
-
246
- 1. `package-dir: <PACKAGE_DIR>` → 实际 SDK 子目录(monorepo 必填)
247
- 2. `CIBW_BUILD` 行的 Python 版本枚举(按需调整)
248
-
249
- 模板已内置全部 7 项修复,开箱即用。
250
-
251
- ---
252
-
253
- ## Pre-flight checklist(发版前必跑)
254
-
255
- ```bash
256
- # 1. 工作树干净
257
- git status
258
-
259
- # 2. tag 必须 = pyproject 版本(避开 workflow version_check 失败)
260
- grep '^version = ' <PACKAGE_DIR>/pyproject.toml
261
- git tag -l 'v*'
262
-
263
- # 3. PyPI 上无该版本(PyPI 版本号永久不可重用!)
264
- curl -s https://pypi.org/pypi/<your-package>/json \
265
- | python3 -c "import sys,json; print(list(json.load(sys.stdin).get('releases',{}).keys()))"
266
-
267
- # 4. CHANGELOG 有新版本条目
268
- head -20 <PACKAGE_DIR>/CHANGELOG.md
269
-
270
- # 5. Trusted Publisher 已配(PyPI 网页 https://pypi.org/manage/account/publishing/ 确认)
271
- # owner = GitHub org,repo = GitHub repo 名(仓库改过名要同步改 PyPI!)
272
- # workflow = release.yml,environment = pypi
273
-
274
- # 6. GitHub Environment "pypi" 存在
275
- gh api repos/<owner>/<repo>/environments --jq '.environments[].name'
276
-
277
- # 7. workflow yml 本地解析通过
278
- python3 -c "import yaml; yaml.safe_load(open('.github/workflows/release.yml'))"
279
- ```
280
-
281
- ---
282
-
283
- ## Build 失败后的安全重发流程
284
-
285
- **前提**:PyPI 上还**没有 publish 成功**该版本号(PyPI 一旦 publish 成功,号码永久占用,必须 bump 下一个版本)。
286
-
287
- ```bash
288
- # 1. cancel 失败 run,节省 CI 额度
289
- gh run cancel <run-id>
290
-
291
- # 2. 修代码 + commit + push
292
- git add <修改文件>
293
- git commit -m "ci(sdk): 修复 xxx"
294
- git push origin main
295
-
296
- # 3. 删本地 + 远端 tag,重打指向新 commit
297
- git push origin :refs/tags/v0.4.0
298
- git tag -d v0.4.0
299
- git tag v0.4.0
300
- git push origin v0.4.0
301
-
302
- # 4. 监控新 run
303
- run_id=$(gh run list --workflow=release.yml --limit=1 --json databaseId --jq '.[0].databaseId')
304
- gh run watch "$run_id" --exit-status
305
- ```
306
-
307
- ⚠️ **commit 前隔离 staging**:如果你边修边并行有其他文件改动,用 `git commit -- <specific-file>` 只 commit 指定文件,避免把不相关改动一起打包到"修复 commit"里污染历史。
308
-
309
- ---
310
-
311
- ## 调试技巧
312
-
313
- | 场景 | 命令 |
314
- |---|---|
315
- | 看**进行中** job 的日志(`gh run view --log` 不让看 in-progress) | `gh api repos/<owner>/<repo>/actions/jobs/<job-id>/logs` |
316
- | 拿失败 job ID 列表 | `gh run view <run-id> --json jobs --jq '.jobs[] \| select(.conclusion=="failure") \| "\(.databaseId) \| \(.name)"'` |
317
- | 阻塞等待 run 完成(后台跑) | `gh run watch <run-id> --exit-status` |
318
- | run 几秒 fail + jobs 为空 | 99% yaml 解析错误,本地跑 `python3 -c "import yaml; yaml.safe_load(...)"` |
319
- | Filter 失败 job 关键错误 | `gh api .../jobs/<id>/logs \| grep -iE "error\|importerror\|cython\|setuptools\|packaging\|fatal\|not found"` |
320
-
321
- ---
322
-
323
- ## 仓库改名 / 迁移注意
324
-
325
- GitHub repo 改名后:
326
-
327
- - ✅ `Settings → Environments`(含 `pypi`)跟着 repo 保留,**不丢**
328
- - ✅ Trusted Publisher 是绑 `owner/repo` 的,repo 改名后**必须**去 PyPI 改 publisher 配置(`https://pypi.org/manage/account/publishing/` → 找到 publisher → 改 repo 名),否则下次 publish 被 PyPI 拒绝
329
- - ✅ 旧 repo URL 自动 301 redirect 一段时间,但建议立刻更新本地 `git remote set-url origin <新地址>`
330
-
331
- ---
332
-
333
- ## 不要做
334
-
335
- - ❌ **不要在本地跑 `python -m build && twine upload`** —— 本地无法 build 跨平台 wheel,且容易绕过 Trusted Publisher 引入凭证管理风险
336
- - ❌ **不要发 sdist 到 PyPI**(`pypa/gh-action-pypi-publish` 默认只发 wheel,保持这个行为)—— Cython 编译模块的 `.py` 源码会通过 sdist 完整泄漏,破坏混淆意义
337
- - ❌ **不要假设 GitHub Action 的 `v<N>` major moving tag 一定存在**,先查仓库实际 tag 列表
338
- - ❌ **workflow 改完不要直接 push**,先 `python3 -c "import yaml; yaml.safe_load(...)"` 本地验证
339
- - ❌ **不要在 publish 前先发同版本号 sdist 占位** —— PyPI 同版本号占了就废,下次 publish 被拒
340
- - ❌ **不要在 manylinux2014 容器里期望装上 pyarrow 24+ wheel** —— 必须 manylinux_2_28
341
- - ❌ **跨平台命令里不要用单引号包参数** —— Windows cmd 不识别
342
-
343
- ---
344
-
345
- ## 违规检测清单
346
-
347
- | 检查项 | 违规模式 | 严重程度 |
348
- |--------|---------|---------|
349
- | build-system 缺 packaging 锁 | 用 PEP 639 license 但 `[build-system].requires` 没列 `packaging>=24.2` | **致命 → 必坏** |
350
- | YAML 含 `:` 未加引号 | env 值有 `=:all:` / `port:8080` 等冒号但整行未加引号 | **致命 → 必坏** |
351
- | cibuildwheel 用 major alias | `pypa/cibuildwheel@v3`(不存在)/ `@v2`(不存在) | **致命 → 必坏** |
352
- | TEST_COMMAND 用 `{project}` | monorepo 子目录 SDK 用 `{project}/tests` | 高 |
353
- | TEST_COMMAND 外双内单 | `"... -k 'not xxx'"` Windows 必坏 | 高 |
354
- | manylinux2014 + 大库依赖 | 依赖含 pyarrow/pandas/numpy 但 manylinux 镜像还是 2014 | 高 |
355
- | 缺 CIBW_BEFORE_TEST binary 锁 | 大型 C 库依赖未预装 binary,源码 build 链失败 | 中 |
356
- | 用了已退役 runner image | matrix 含 `macos-13` / `macos-12` / `macos-11` / `ubuntu-20.04` 等已下线 label | **致命 → 死等不报错** |