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.
- package/CHANGELOG.md +17 -0
- package/bin/index.js +8 -2
- package/package.json +1 -1
- package/src/skills-install.js +154 -0
- package/src/sync-all.js +7 -0
- package/templates/ai-tools/CLAUDE.md +28 -1
- package/templates/ai-tools/hooks/Git/pre-git-commit-sensitive-check.sh +10 -2
- package/templates/ai-tools/rules/Android/dwy-android-pitfalls.md +52 -0
- package/templates/ai-tools/rules/HarmonyOS/dwy-arkts-strict.md +221 -0
- package/templates/ai-tools/rules/HarmonyOS/dwy-arkts-ui-build.md +193 -0
- package/templates/ai-tools/rules/Python/dwy-python-backend.md +16 -63
- package/templates/ai-tools/rules/Python/dwy-python-base-lib.md +89 -0
- package/templates/ai-tools/rules/Python/dwy-python-pitfalls.md +49 -0
- package/templates/ai-tools/rules/Vue/dwy-vue-base-lib.md +127 -0
- package/templates/ai-tools/rules/Vue/dwy-vue-core.md +22 -86
- package/templates/ai-tools/rules/Vue/dwy-vue-pitfalls.md +66 -0
- package/templates/ai-tools/rules/iOS/dwy-ios-pitfalls.md +159 -0
- package/templates/ai-tools/rules/iOS/dwy-swift-core.md +35 -0
- package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-dependency-freshness.md +59 -0
- package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-tdd-development.md +47 -2
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-acceptance/SKILL.md +24 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-architecture/SKILL.md +70 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-commercial/SKILL.md +58 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-competitor/SKILL.md +23 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-explore/SKILL.md +83 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-mvp/SKILL.md +24 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-poc/SKILL.md +24 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-prd/SKILL.md +23 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-product-launcher/SKILL.md +73 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-product-launcher/references/state-and-contract.md +155 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-prototype/SKILL.md +42 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-release/SKILL.md +27 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-design/SKILL.md +30 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-dev/SKILL.md +54 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-launch/SKILL.md +37 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-prd/SKILL.md +31 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-stage-ship/SKILL.md +30 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-tasks/SKILL.md +32 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-tdd-dev/SKILL.md +34 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-validate/SKILL.md +29 -0
- package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-version/SKILL.md +24 -0
- 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
- 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
- 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
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/SKILL.md +31 -0
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/android.md +31 -0
- 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
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/changelog.md +37 -0
- 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
- 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
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/harmony.md +25 -0
- package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/ios.md +32 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-whiteboard-prototype/SKILL.md +70 -0
- 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
- package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-sdk-spec/scripts/init_config.sh +0 -97
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-0to1/SKILL.md +0 -113
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-0to1/templates/STATE.md +0 -56
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-dev-qa/SKILL.md +0 -117
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-market-analysis/SKILL.md +0 -92
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prd-coarse/SKILL.md +0 -72
- 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
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prd-detailed/SKILL.md +0 -76
- 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
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prototype/SKILL.md +0 -104
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-publish/SKILL.md +0 -50
- 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
- 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
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-spike/SKILL.md +0 -81
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-tdd-dev/SKILL.md +0 -212
- 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
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-tech-feasibility/SKILL.md +0 -105
- package/templates/ai-tools/skills//345/274/200/345/217/221/346/265/201/347/250/213/dwy-version-plan/SKILL.md +0 -64
- 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
- package/templates/ai-tools/skills//350/277/220/347/273/264/345/217/221/345/270/203/dwy-cibuildwheel/SKILL.md +0 -356
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
- /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
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# 鸿蒙发布流程
|
|
2
|
+
|
|
3
|
+
适用:HarmonyOS ArkTS 产物——**应用包(har app / hap)** 或 **SDK(har→ohpm)**。
|
|
4
|
+
|
|
5
|
+
## 版本(通用步,固化)
|
|
6
|
+
|
|
7
|
+
- `oh-package.json5` 的 `version` = 语义版本号,走 `../dwy-semver` 决策 + bump.py。
|
|
8
|
+
- 多文件同步见 `version-sync.md`。
|
|
9
|
+
|
|
10
|
+
## build / publish(项目步,不写死命令)
|
|
11
|
+
|
|
12
|
+
命令来自缓存(build_cmd/publish_cmd),缓存缺则按 `publish-config.md` 探测:
|
|
13
|
+
- 探测线索:`build-profile.json5`、ohpm 脚本、DevEco 构建配置、CI workflow
|
|
14
|
+
- 探测不到→问用户→缓存
|
|
15
|
+
|
|
16
|
+
按缓存 method 分流:
|
|
17
|
+
- `ohpm` → 用项目实际的 ohpm 发布命令(中心仓 / 私有源)
|
|
18
|
+
- `github-action` → 引 `../dwy-github-action-publish`(先过通用检查)
|
|
19
|
+
- `local` → 缓存的本地构建/发布命令
|
|
20
|
+
|
|
21
|
+
## changelog / 安全检查 / 监控
|
|
22
|
+
|
|
23
|
+
- changelog → `changelog.md`(写 `harmony/CHANGELOG.md`)
|
|
24
|
+
- 安全检查 → `../dwy-sdk-spec`
|
|
25
|
+
- 监控 + 结果 → `monitor-notify.md`
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# iOS 发布流程
|
|
2
|
+
|
|
3
|
+
适用:iOS 产物——**应用包(ipa→TestFlight/App Store)** 或 **SDK(framework/xcframework→CocoaPods/SPM)**。
|
|
4
|
+
|
|
5
|
+
## 先判产物形态
|
|
6
|
+
|
|
7
|
+
- 应用包:有 app target、`fastlane/` beta/release lane、TestFlight 上传 → 走 app 路径
|
|
8
|
+
- SDK:产出 framework/xcframework、有 podspec / `Package.swift` → 走 SDK 路径
|
|
9
|
+
|
|
10
|
+
## 版本(通用步,固化)
|
|
11
|
+
|
|
12
|
+
- 语义版本号 `CFBundleShortVersionString`,走 `../dwy-semver` 决策 + bump.py。
|
|
13
|
+
- **build 号 `CFBundleVersion` = 时间戳 `yyyyMMddHHmm` 12 位**(如 `202606231430`,`date +%Y%m%d%H%M`),每次发布重新生成,单调递增。app 和 SDK 都适用。
|
|
14
|
+
- 多文件同步见 `version-sync.md`。
|
|
15
|
+
|
|
16
|
+
## build / publish(项目步,不写死命令)
|
|
17
|
+
|
|
18
|
+
命令来自缓存(`release_config.sh` 的 build_cmd/publish_cmd),缓存缺则按 `publish-config.md` 探测:
|
|
19
|
+
- 探测线索:`fastlane/Fastfile`、`*.xcodeproj`/`*.xcworkspace`、`Makefile`、CI workflow、`package.json` scripts
|
|
20
|
+
- 探测不到→问用户→缓存
|
|
21
|
+
|
|
22
|
+
按缓存 method 分流:
|
|
23
|
+
- `testflight` → 用项目实际的 TestFlight 上传命令(fastlane lane / Transporter / altool)
|
|
24
|
+
- `cocoapods` / `spm` → 用项目实际的 pod 发布 / git tag 命令(SPM 以 tag 为版本,tag 须等于 `CFBundleShortVersionString`)
|
|
25
|
+
- `github-action` → 引 `../dwy-github-action-publish`(先过其通用检查)
|
|
26
|
+
- `local` → 缓存的本地命令
|
|
27
|
+
|
|
28
|
+
## changelog / 安全检查 / 监控
|
|
29
|
+
|
|
30
|
+
- changelog → `changelog.md`(写 `ios/CHANGELOG.md`)
|
|
31
|
+
- 安全检查 → `../dwy-sdk-spec`(SDK 发布尤其要查泄露)
|
|
32
|
+
- 监控 + 结果 → `monitor-notify.md`
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# 监控发布进程 + 通知结果
|
|
2
|
+
|
|
3
|
+
发布触发后监控进程直到终态,再输出结果文本。监控方式因 CI / 本地而异(项目步)。
|
|
4
|
+
|
|
5
|
+
## 监控
|
|
6
|
+
|
|
7
|
+
发布方式来自缓存 method:
|
|
8
|
+
|
|
9
|
+
- **CI(github-action / github-action-oidc)**:
|
|
10
|
+
```bash
|
|
11
|
+
gh run watch "$(gh run list --workflow=<release.yml> --limit=1 --json databaseId --jq '.[0].databaseId')" --exit-status
|
|
12
|
+
```
|
|
13
|
+
观察到失败时拉日志定位失败 job:`gh run view <run-id> --json jobs,conclusion`。
|
|
14
|
+
- **本地(local / testflight / maven / cocoapods / ohpm)**:用缓存的 `publish_cmd` 退出码判断,再做产物 / 渠道检查。
|
|
15
|
+
|
|
16
|
+
## verify
|
|
17
|
+
|
|
18
|
+
用缓存 `verify_cmd`,或按渠道验证新版本可见:
|
|
19
|
+
|
|
20
|
+
- npm:`npm view <pkg> version`
|
|
21
|
+
- PyPI:`pip index versions <pkg>`
|
|
22
|
+
- maven / ohpm / cocoapods:对应渠道版本查询
|
|
23
|
+
- TestFlight:App Store Connect 构建状态
|
|
24
|
+
- GitHub Release:`gh release view <tag>`
|
|
25
|
+
- 前端 / 后端:页面访问 / 版本接口 / 健康检查
|
|
26
|
+
|
|
27
|
+
verify 失败,发布不算完成。
|
|
28
|
+
|
|
29
|
+
## 通知结果(输出结果文本)
|
|
30
|
+
|
|
31
|
+
发布终态后在对话里输出结果摘要,不接外部通知:
|
|
32
|
+
|
|
33
|
+
- **成功**:平台 / 应用目录、版本号、产物、渠道、verify 结果
|
|
34
|
+
- **失败**:失败阶段、关键报错、下一步建议(重发 / bump / 修配置)
|
|
35
|
+
|
|
36
|
+
涉及删除远端 release / tag 的重发,必须先确认用户允许。
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# 发布方式缓存 + 命令探测
|
|
2
|
+
|
|
3
|
+
发布方式与 build/publish 命令**因项目而异,不写死**。按应用目录探测 → 问 → 缓存复用。
|
|
4
|
+
|
|
5
|
+
## 缓存机制
|
|
6
|
+
|
|
7
|
+
- 缓存文件:`<project_root>/.dwy/publish/config.json`,读写走 `scripts/release_config.sh`。
|
|
8
|
+
- key = **相对项目根的相对目录**(如 `ios`、`apps/electron`,根用 `.`)。
|
|
9
|
+
- `.dwy/` 是本机判断缓存,**提醒用户加进 `.gitignore`**,不入版本库。
|
|
10
|
+
|
|
11
|
+
## 读写流程
|
|
12
|
+
|
|
13
|
+
1. 确定本次要发的**应用目录**(相对路径)。
|
|
14
|
+
2. `release_config.sh get <root> <rel_dir>`:
|
|
15
|
+
- 命中且 `configured=true` → 用缓存的 method + build_cmd/publish_cmd/verify_cmd
|
|
16
|
+
- 比对 `cmd_source`:若项目里对应命令源(package.json scripts / Fastfile / workflow 等)已变 → 重新探测+问用户+更新缓存
|
|
17
|
+
- 未命中(首次进入该目录)→ 走第 3 步
|
|
18
|
+
3. 首次配置:
|
|
19
|
+
- 探测真实命令(见下方探测线索)
|
|
20
|
+
- AskUserQuestion 问发布方式(见下方各平台候选)
|
|
21
|
+
- 检查对应配置就绪(GA workflow 是否存在 / TestFlight 凭据线索 / maven·pod publish 配置)
|
|
22
|
+
- `release_config.sh set <root> <rel_dir> <platform> <method> <channel> <configured> [build_cmd] [publish_cmd] [verify_cmd] [cmd_source]`
|
|
23
|
+
- 提醒把 `.dwy/` 加进 `.gitignore`
|
|
24
|
+
4. 目录与缓存对不上(仓库结构变了):先 AI 自助判断目录是否仍正确,判不准再问用户,必要时 `reset` 重建。
|
|
25
|
+
|
|
26
|
+
全程 AI 自动跑,仅探测不到 / 命令歧义 / 配置缺失时才问用户。
|
|
27
|
+
|
|
28
|
+
## build/publish 命令探测线索(不写死,按项目找)
|
|
29
|
+
|
|
30
|
+
| 平台 | 去哪找真实命令 |
|
|
31
|
+
|------|---------------|
|
|
32
|
+
| 前端 | `package.json` scripts(build/deploy)、`vite.config.*`、`.github/workflows/`、`Makefile` |
|
|
33
|
+
| 后端 | `Dockerfile`、`docker-compose`、部署脚本、`Makefile`、`pyproject.toml`、`.github/workflows/` |
|
|
34
|
+
| iOS | `fastlane/Fastfile`、`*.xcodeproj` / `*.xcworkspace`、`Makefile`、CI workflow、`package.json` scripts |
|
|
35
|
+
| Android | `build.gradle(.kts)` task、`gradlew`、`fastlane/`、CI workflow |
|
|
36
|
+
| 鸿蒙 | `build-profile.json5`、ohpm 脚本、DevEco 构建配置、CI workflow |
|
|
37
|
+
| 通用包 | `package.json` scripts、`pyproject.toml`、`Makefile`、发布脚本、`.github/workflows/` |
|
|
38
|
+
|
|
39
|
+
探测到多个候选时问用户选;探测不到时问用户给命令。命令存进缓存的 `build_cmd`/`publish_cmd`/`verify_cmd`。
|
|
40
|
+
|
|
41
|
+
## 各平台发布方式候选(AskUserQuestion)
|
|
42
|
+
|
|
43
|
+
先按平台 + 产物形态(应用包 vs SDK)裁剪候选,推荐项标注:
|
|
44
|
+
|
|
45
|
+
| platform / 产物 | method 候选 |
|
|
46
|
+
|------|------|
|
|
47
|
+
| ios 应用包(ipa) | `testflight`(推荐) / `github-action` / `local` / `manual` |
|
|
48
|
+
| ios SDK(framework/xcframework) | `cocoapods` / `spm` / `github-action` / `local` |
|
|
49
|
+
| android 应用包(apk/aab) | `github-action`(推荐) / `local` |
|
|
50
|
+
| android SDK(aar) | `maven`(推荐) / `github-action` / `local` |
|
|
51
|
+
| harmony(har / har app) | `ohpm`(推荐) / `github-action` / `local` |
|
|
52
|
+
| frontend | `github-action`(CI,推荐 OIDC) / `local` |
|
|
53
|
+
| backend | `github-action`(CI,推荐 OIDC) / `local` |
|
|
54
|
+
| generic — PyPI/npm | `github-action-oidc`(**推荐**,无静态凭据、符合团队准则) / `local` |
|
|
55
|
+
| generic — Cython wheel | `github-action`(cibuildwheel) / `local` |
|
|
56
|
+
| generic — Electron | `github-action`(多平台 runner) / `local` |
|
|
57
|
+
| generic — Docker/二进制 | `github-action` / `local` |
|
|
58
|
+
|
|
59
|
+
## PyPI / npm 首次配置:主动推荐 GitHub Action OIDC
|
|
60
|
+
|
|
61
|
+
PyPI / npm 且未配置 GA 时,**主动推荐 `github-action-oidc`**(OIDC Trusted Publishing,无长期静态凭据):
|
|
62
|
+
|
|
63
|
+
- 给 workflow 模板:见 `../dwy-github-action-publish`(Python wheel / 纯包 OIDC)。
|
|
64
|
+
- 给 Trusted Publisher 网页配置步骤:PyPI/npmjs 后台绑定 repo + workflow 文件名 + environment。
|
|
65
|
+
- 用户仍可选 `local`(`uv publish` / `pnpm publish` 等),按其选择缓存。
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# 版本号多文件同步
|
|
2
|
+
|
|
3
|
+
版本号定好后,**同一次发布的所有版本来源文件必须改到完全一致**。一个技术栈往往有多处版本声明,漏改一处就会导致包内版本不一致、构建产物版本错乱。
|
|
4
|
+
|
|
5
|
+
## 各技术栈版本来源清单
|
|
6
|
+
|
|
7
|
+
| 技术栈 | 版本来源文件 | 字段 |
|
|
8
|
+
|------|------|------|
|
|
9
|
+
| Python | `pyproject.toml` + 包 `__init__.py` | `version` / `__version__` |
|
|
10
|
+
| Node/Vue | `package.json` | `version` |
|
|
11
|
+
| Android | `build.gradle(.kts)` | `versionName`(语义号)+ `versionCode`(整数,每次发布递增) |
|
|
12
|
+
| iOS | `Info.plist` 或 `project.pbxproj` | `CFBundleShortVersionString`(语义号)+ `CFBundleVersion`(build 号,见 `sdk-ios.md`) |
|
|
13
|
+
| 鸿蒙 | `oh-package.json5` | `version` |
|
|
14
|
+
|
|
15
|
+
## 规则
|
|
16
|
+
|
|
17
|
+
- **Python**:`pyproject.toml` 的 `version` 与包 `__init__.py` 的 `__version__` 两处必须一致。
|
|
18
|
+
- **Android**:`versionName` 用语义版本号;`versionCode` 是单调递增整数,与语义号无关,每次发布 +1。
|
|
19
|
+
- **iOS**:`CFBundleShortVersionString` 用语义版本号;`CFBundleVersion`(build 号)用时间戳,规则见 `sdk-ios.md`。
|
|
20
|
+
- 改完后用 grep 全仓库扫一遍旧版本号,确认无遗漏:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
grep -rn "<旧版本号>" --include=pyproject.toml --include=package.json --include="*.gradle*" --include="*.plist" --include="oh-package.json5" .
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 禁止
|
|
27
|
+
|
|
28
|
+
- 禁止只改一处版本来源就发布(如只改 `pyproject.toml` 漏改 `__init__.py`)
|
|
29
|
+
- 禁止用会自动 commit 的版本命令(`npm version` / `bumpversion` 等),直接编辑文件,保持提交边界可控
|
|
30
|
+
- 禁止 `versionCode` / `CFBundleVersion` 不递增就重发(应用商店会拒)
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# dwy-publish 发布方式缓存读写
|
|
3
|
+
# 缓存写项目内 <project_root>/.dwy/publish/config.json,key 用相对项目根的相对目录
|
|
4
|
+
# 用法:
|
|
5
|
+
# release_config.sh get <project_root> <rel_dir>
|
|
6
|
+
# release_config.sh set <project_root> <rel_dir> <platform> <method> <channel> <configured> [build_cmd] [publish_cmd] [verify_cmd] [cmd_source]
|
|
7
|
+
# release_config.sh reset <project_root> <rel_dir>
|
|
8
|
+
# release_config.sh list <project_root>
|
|
9
|
+
#
|
|
10
|
+
# 设计要点(与发布编排配套):
|
|
11
|
+
# - 通用步(定版本/changelog/安全检查)不进缓存,走固化流程
|
|
12
|
+
# - 项目步(build/publish/verify)命令因项目而异,探测/确认后存这里复用
|
|
13
|
+
# - cmd_source 是命令来源指纹,编排器 get 后比对,变更则重新问用户更新
|
|
14
|
+
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
config_file() {
|
|
18
|
+
echo "${1%/}/.dwy/publish/config.json"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
ensure_config() {
|
|
22
|
+
local root="$1"
|
|
23
|
+
local dir="${root%/}/.dwy/publish"
|
|
24
|
+
local file
|
|
25
|
+
file="$(config_file "$root")"
|
|
26
|
+
mkdir -p "$dir"
|
|
27
|
+
if [[ ! -f "$file" ]]; then
|
|
28
|
+
echo '{"version":"1","apps":{}}' > "$file"
|
|
29
|
+
fi
|
|
30
|
+
# 检测损坏
|
|
31
|
+
if ! jq empty "$file" 2>/dev/null; then
|
|
32
|
+
echo "ERROR: $file is corrupted. Back it up and delete to reset." >&2
|
|
33
|
+
exit 2
|
|
34
|
+
fi
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
cmd_get() {
|
|
38
|
+
local root="$1" rel="$2"
|
|
39
|
+
ensure_config "$root"
|
|
40
|
+
jq --arg p "$rel" '.apps[$p] // null' "$(config_file "$root")"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
cmd_set() {
|
|
44
|
+
local root="$1" rel="$2" platform="$3" method="$4" channel="$5" configured="$6"
|
|
45
|
+
local build_cmd="${7:-}" publish_cmd="${8:-}" verify_cmd="${9:-}" cmd_source="${10:-}"
|
|
46
|
+
|
|
47
|
+
case "$platform" in
|
|
48
|
+
frontend|backend|ios|android|harmony|generic) ;;
|
|
49
|
+
*) echo "ERROR: platform must be one of frontend|backend|ios|android|harmony|generic, got: $platform" >&2; exit 2 ;;
|
|
50
|
+
esac
|
|
51
|
+
case "$configured" in
|
|
52
|
+
true|false) ;;
|
|
53
|
+
*) echo "ERROR: configured must be 'true' or 'false', got: $configured" >&2; exit 2 ;;
|
|
54
|
+
esac
|
|
55
|
+
if [[ -z "$method" ]]; then
|
|
56
|
+
echo "ERROR: method must not be empty" >&2; exit 2
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
ensure_config "$root"
|
|
60
|
+
local now file tmp
|
|
61
|
+
now=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
62
|
+
file="$(config_file "$root")"
|
|
63
|
+
tmp=$(mktemp)
|
|
64
|
+
jq \
|
|
65
|
+
--arg p "$rel" \
|
|
66
|
+
--arg pl "$platform" \
|
|
67
|
+
--arg m "$method" \
|
|
68
|
+
--arg c "$channel" \
|
|
69
|
+
--arg b "$build_cmd" \
|
|
70
|
+
--arg pub "$publish_cmd" \
|
|
71
|
+
--arg v "$verify_cmd" \
|
|
72
|
+
--arg cs "$cmd_source" \
|
|
73
|
+
--argjson cfg "$configured" \
|
|
74
|
+
--arg t "$now" \
|
|
75
|
+
'.apps[$p] = {platform:$pl, method:$m, channel:$c, build_cmd:$b, publish_cmd:$pub, verify_cmd:$v, cmd_source:$cs, configured:$cfg, configured_at:$t}' \
|
|
76
|
+
"$file" > "$tmp"
|
|
77
|
+
mv "$tmp" "$file"
|
|
78
|
+
|
|
79
|
+
echo "OK: cached $rel -> $platform/$method"
|
|
80
|
+
echo "Remember to add .dwy/ to .gitignore (本机判断缓存,不入版本库)"
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
cmd_reset() {
|
|
84
|
+
local root="$1" rel="$2"
|
|
85
|
+
ensure_config "$root"
|
|
86
|
+
local file tmp
|
|
87
|
+
file="$(config_file "$root")"
|
|
88
|
+
tmp=$(mktemp)
|
|
89
|
+
jq --arg p "$rel" 'del(.apps[$p])' "$file" > "$tmp"
|
|
90
|
+
mv "$tmp" "$file"
|
|
91
|
+
echo "OK: removed $rel from cache"
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
cmd_list() {
|
|
95
|
+
local root="$1"
|
|
96
|
+
ensure_config "$root"
|
|
97
|
+
jq '.apps | to_entries | map({dir: .key, platform: .value.platform, method: .value.method, configured: .value.configured})' "$(config_file "$root")"
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
main() {
|
|
101
|
+
if [[ $# -lt 1 ]]; then
|
|
102
|
+
echo "Usage: $0 {get|set|reset|list} <project_root> [args...]" >&2
|
|
103
|
+
exit 2
|
|
104
|
+
fi
|
|
105
|
+
local action="$1"; shift
|
|
106
|
+
case "$action" in
|
|
107
|
+
get) cmd_get "$@" ;;
|
|
108
|
+
set) cmd_set "$@" ;;
|
|
109
|
+
reset) cmd_reset "$@" ;;
|
|
110
|
+
list) cmd_list "$@" ;;
|
|
111
|
+
*) echo "ERROR: unknown action: $action" >&2; exit 2 ;;
|
|
112
|
+
esac
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
main "$@"
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: dwy-sdk-spec
|
|
3
|
-
description: "通用 SDK 发布前安全检查——任何 SDK 对外发布(PyPI / npm / 私有源 / 直接交付,渠道不限)前都应先过这一关。查三类风险:①接口注释是否泄露后端实现(内网域名、数据库表名、Redis key、内部服务名、员工邮箱、JIRA 链接、SQL 语句);②商业版 SDK 源码是否被保护(Python 用 Cython 编译 .so、JS 用 tsup/rollup minify + files 白名单);③发布产物是否夹带隐藏敏感文件(.py 源码 / .map source map / .env / .npmrc / tsbuildinfo / __pycache__ 等)。跨项目复用:首次进入新项目用 AskUserQuestion 问商业版还是开源版,缓存到
|
|
3
|
+
description: "通用 SDK 发布前安全检查——任何 SDK 对外发布(PyPI / npm / 私有源 / 直接交付,渠道不限)前都应先过这一关。查三类风险:①接口注释是否泄露后端实现(内网域名、数据库表名、Redis key、内部服务名、员工邮箱、JIRA 链接、SQL 语句);②商业版 SDK 源码是否被保护(Python 用 Cython 编译 .so、JS 用 tsup/rollup minify + files 白名单);③发布产物是否夹带隐藏敏感文件(.py 源码 / .map source map / .env / .npmrc / tsbuildinfo / __pycache__ 等)。跨项目复用:首次进入新项目用 AskUserQuestion 问商业版还是开源版,缓存到 <project_root>/.dwy/sdk-spec/config.json,下次自动按规则检查。涉及以下任何场景必须使用此 skill:用户说「检查 SDK」「SDK 发版前检查」「SDK 注释脱敏」「SDK 接口规范」「发布前安全检查」「SDK 源码泄露检查」「商业版 SDK 打包」「Cython 编译 .so」「打包前体检」「.gitignore 漏了什么」「npm pack 看看包里有什么」「重设 SDK 版本类型」时。注:本 skill 只做发布前安全检查闸门,不执行发版流程(发版编排走 dwy-publish,会在发布前主动调用本检查)。"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# dwy-sdk-spec — SDK 接口规范与发布安全检查
|
|
7
7
|
|
|
8
8
|
防三类风险:接口注释泄露后端实现 / 商业版 SDK 源码被还原 / 发布产物夹带隐藏敏感文件。
|
|
9
9
|
|
|
10
|
-
**适用范围**:任何 SDK 对外发布前的通用安全闸门,与发布渠道无关——PyPI / npm / 私有源 / 直接打包交付都先过这一关。发 PyPI 只是其中一种渠道,不是触发前提。检查通过后,通用发版流程(测试 / bump / changelog / tag / publish)走 `dwy-publish`;含 C 扩展需跨平台 wheel 的走 `dwy-
|
|
10
|
+
**适用范围**:任何 SDK 对外发布前的通用安全闸门,与发布渠道无关——PyPI / npm / 私有源 / 直接打包交付都先过这一关。发 PyPI 只是其中一种渠道,不是触发前提。检查通过后,通用发版流程(测试 / bump / changelog / tag / publish)走 `dwy-publish`;含 C 扩展需跨平台 wheel 的走 `dwy-github-action-publish`。
|
|
11
11
|
|
|
12
12
|
## 何时触发
|
|
13
13
|
|
|
@@ -26,28 +26,24 @@ skill 跨项目复用。每次执行流程 A/B/C 前先确保当前项目的配
|
|
|
26
26
|
|
|
27
27
|
### 缓存文件格式
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
路径:`<project_root>/.dwy/sdk-spec/config.json`(写项目内,扁平结构,不存绝对路径)
|
|
30
30
|
|
|
31
31
|
```json
|
|
32
32
|
{
|
|
33
33
|
"version": "1",
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
},
|
|
42
|
-
"configured_at": "2026-05-18T12:34:56Z"
|
|
43
|
-
}
|
|
44
|
-
}
|
|
34
|
+
"edition": "commercial",
|
|
35
|
+
"languages": ["python", "js"],
|
|
36
|
+
"sdk_paths": {
|
|
37
|
+
"python": ["backend"],
|
|
38
|
+
"js": ["frontend/eui", "frontend/ekit"]
|
|
39
|
+
},
|
|
40
|
+
"configured_at": "2026-05-18T12:34:56Z"
|
|
45
41
|
}
|
|
46
42
|
```
|
|
47
43
|
|
|
48
44
|
- `edition` 必填,只能是 `commercial` 或 `opensource`
|
|
49
|
-
- `languages` / `sdk_paths`
|
|
50
|
-
-
|
|
45
|
+
- `languages` / `sdk_paths` 自动探测,`sdk_paths` 是**相对项目根的相对路径**
|
|
46
|
+
- 配置随项目走、不存绝对路径;`.dwy/` 是本机判断缓存,提醒用户加进 `.gitignore`
|
|
51
47
|
|
|
52
48
|
### 读取流程
|
|
53
49
|
|
|
@@ -57,9 +53,22 @@ PROJECT_PATH=$(pwd)
|
|
|
57
53
|
CONFIG=$(bash "$SKILL_DIR/scripts/init_config.sh" get "$PROJECT_PATH")
|
|
58
54
|
```
|
|
59
55
|
|
|
60
|
-
- 输出非 `null` → 已配置,提取 `edition` / `languages` / `sdk_paths
|
|
56
|
+
- 输出非 `null` → 已配置,提取 `edition` / `languages` / `sdk_paths`,先做**路径校验**(见下),再跳到对应流程
|
|
61
57
|
- 输出 `null` → 走「首次配置」
|
|
62
58
|
|
|
59
|
+
### 路径校验(应对 SDK 目录改名)
|
|
60
|
+
|
|
61
|
+
`sdk_paths` 存相对路径,SDK 子目录改名(如 `backend`→`core`)后缓存会指向已不存在的目录。get 返回非 `null` 后,逐个检查 `sdk_paths` 里的相对目录在 `$PROJECT_PATH` 下是否存在:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
for d in $(jq -r '.sdk_paths[][]' <<< "$CONFIG"); do
|
|
65
|
+
[[ -d "$PROJECT_PATH/$d" ]] || echo "MISSING: $d"
|
|
66
|
+
done
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
- 全部存在 → 直接用缓存
|
|
70
|
+
- 有 `MISSING` → 警告用户「缓存的 SDK 路径已失效」,跑 `detect_sdk.sh` 重新探测,再用 `init_config.sh set` 覆盖更新(`edition` 沿用旧值),然后继续
|
|
71
|
+
|
|
63
72
|
### 首次配置流程
|
|
64
73
|
|
|
65
74
|
1. 跑 `bash scripts/detect_sdk.sh "$PROJECT_PATH"` 探测语言:
|
|
@@ -207,12 +216,13 @@ bash "$SKILL_DIR/scripts/check_js_publish.sh" "$PROJECT_PATH/<js_sdk_path>" --ed
|
|
|
207
216
|
| 情况 | 处理 |
|
|
208
217
|
|---|---|
|
|
209
218
|
| 脚本说命中敏感词但是误报 | 该行后加 `# sdk-spec: ignore`(Python)或 `// sdk-spec: ignore`(JS/TS)行内豁免 |
|
|
210
|
-
| 商业版但项目特殊不用 Cython(如纯接口包) | 跟用户确认;要长期跳过 Python 商业打包检查 → `bash scripts/init_config.sh reset` 重选「开源版」,或单次跳过流程 B |
|
|
219
|
+
| 商业版但项目特殊不用 Cython(如纯接口包) | 跟用户确认;要长期跳过 Python 商业打包检查 → `bash scripts/init_config.sh reset "$(pwd)"` 重选「开源版」,或单次跳过流程 B |
|
|
211
220
|
| 想换商业 / 开源版本 | `bash scripts/init_config.sh reset "$(pwd)"` 然后重触发 skill 重问 |
|
|
212
221
|
| `detect_sdk.sh` 没找到 SDK 但项目确实是 | 让用户手动指定 `--sdk-paths '{"python":["src/mypkg"]}'`,跳过自动探测 |
|
|
213
222
|
| `python -m build` 失败 | 报告原因给用户,建议先 `pip install build`;不强制执行流程 C,可仅做流程 A+B |
|
|
214
223
|
| `npm pack --dry-run` 失败 | 多半是 `npm install` 没跑或 `package.json` 缺字段,让用户先修复,重跑 |
|
|
215
|
-
| 缓存文件损坏(jq 解析失败) | 提示用户备份原文件后删除
|
|
224
|
+
| 缓存文件损坏(jq 解析失败) | 提示用户备份原文件后删除 `<project_root>/.dwy/sdk-spec/config.json`,重新走首次配置 |
|
|
225
|
+
| 缓存的 SDK 路径失效(目录改名/删除) | 走「路径校验」:警告后跑 `detect_sdk.sh` 重探测 + `set` 覆盖更新 |
|
|
216
226
|
|
|
217
227
|
## 跨项目约束
|
|
218
228
|
|
|
@@ -222,13 +232,13 @@ skill 文件**零绝对路径**。装到任何机器上首次用时自动走流
|
|
|
222
232
|
1. 装了 `jq`(解析缓存 JSON)
|
|
223
233
|
2. Python 项目:装了 `python` 与 `build` 包(流程 C 用)
|
|
224
234
|
3. JS 项目:装了 `npm` 与 `node`(流程 C 用)
|
|
225
|
-
4.
|
|
235
|
+
4. 缓存文件写项目内 `<project_root>/.dwy/sdk-spec/config.json`,是本机判断缓存,提醒用户加进 `.gitignore`,不入版本库
|
|
226
236
|
|
|
227
237
|
## 安全约束
|
|
228
238
|
|
|
229
239
|
- skill 不存任何 token / 凭证 / 私钥
|
|
230
240
|
- skill 不动 `~/.pypirc` / `~/.npmrc`
|
|
231
|
-
- 脚本只做本地读 + 本地写
|
|
241
|
+
- 脚本只做本地读 + 本地写 `<project_root>/.dwy/sdk-spec/`
|
|
232
242
|
- 不静默修改任何源文件 / 配置文件,所有改动建议输出给用户决策
|
|
233
243
|
- 不实际发布到 PyPI / npm,流程 C 全部使用 `--dry-run` 或临时目录
|
|
234
244
|
- 检查通过 ≠ 安全保证,最终发布前用户必须人工 review `npm pack --dry-run` 输出
|
|
@@ -136,7 +136,7 @@ unzip -l dist/*.whl | grep -E '_.*\.py$' && echo "FAIL: source leaked" || echo "
|
|
|
136
136
|
| wheel 里有 `.py` 源 | `exclude-package-data` 没匹配到 / MANIFEST.in 缺 global-exclude | 同时配 setup 配置 + MANIFEST.in |
|
|
137
137
|
| 装完后 `ImportError: cannot import name '_engine'` | `__init__.py` 用了 `from . import _engine` 但 .so 命名空间不对 | 确保 `.so` 文件在包内,名字与 import 路径一致 |
|
|
138
138
|
| `pip install -e .` 后 import 慢 | 开发模式没编译 .so,跑了 .py | 开发用 `python setup.py build_ext --inplace` 触发编译 |
|
|
139
|
-
| 跨平台 wheel(manylinux / macOS) | 单平台编译产物只能装到对应平台 | 用 `cibuildwheel`(项目已有 dwy-
|
|
139
|
+
| 跨平台 wheel(manylinux / macOS) | 单平台编译产物只能装到对应平台 | 用 `cibuildwheel`(项目已有 dwy-github-action-publish skill) |
|
|
140
140
|
|
|
141
141
|
## 参考 dwy-shared 内已有 SDK
|
|
142
142
|
|
|
@@ -109,4 +109,4 @@ export async function fetchUser(id: string): Promise<UserProfile> { ... }
|
|
|
109
109
|
- Python:`# sdk-spec: ignore`
|
|
110
110
|
- TS/JS:`// sdk-spec: ignore`
|
|
111
111
|
|
|
112
|
-
豁免**单行**,不豁免整段。要长期豁免某文件 → 在
|
|
112
|
+
豁免**单行**,不豁免整段。要长期豁免某文件 → 在 `<project_root>/.dwy/sdk-spec/config.json` 加 `ignore_files: ["path/to/file.py"]`(未来支持,当前手动用行内豁免)。
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# dwy-sdk-spec 配置缓存读写
|
|
3
|
+
# 缓存写项目内 <project_root>/.dwy/sdk-spec/config.json,扁平结构、不存绝对路径
|
|
4
|
+
# 用法:
|
|
5
|
+
# init_config.sh get <project_root>
|
|
6
|
+
# init_config.sh set <project_root> <edition> <languages_json> <sdk_paths_json>
|
|
7
|
+
# init_config.sh reset <project_root>
|
|
8
|
+
|
|
9
|
+
set -euo pipefail
|
|
10
|
+
|
|
11
|
+
config_file() {
|
|
12
|
+
echo "${1%/}/.dwy/sdk-spec/config.json"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
ensure_config() {
|
|
16
|
+
local root="$1"
|
|
17
|
+
local dir="${root%/}/.dwy/sdk-spec"
|
|
18
|
+
local file
|
|
19
|
+
file="$(config_file "$root")"
|
|
20
|
+
mkdir -p "$dir"
|
|
21
|
+
if [[ ! -f "$file" ]]; then
|
|
22
|
+
echo '{"version":"1"}' > "$file"
|
|
23
|
+
fi
|
|
24
|
+
# 检测损坏
|
|
25
|
+
if ! jq empty "$file" 2>/dev/null; then
|
|
26
|
+
echo "ERROR: $file is corrupted. Back it up and delete to reset." >&2
|
|
27
|
+
exit 2
|
|
28
|
+
fi
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
cmd_get() {
|
|
32
|
+
local root="$1"
|
|
33
|
+
ensure_config "$root"
|
|
34
|
+
# 无 edition 视为未配置,返回 null
|
|
35
|
+
jq 'if has("edition") then . else null end' "$(config_file "$root")"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
cmd_set() {
|
|
39
|
+
local root="$1" edition="$2" languages_json="$3" sdk_paths_json="$4"
|
|
40
|
+
|
|
41
|
+
if [[ "$edition" != "commercial" && "$edition" != "opensource" ]]; then
|
|
42
|
+
echo "ERROR: edition must be 'commercial' or 'opensource', got: $edition" >&2
|
|
43
|
+
exit 2
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
ensure_config "$root"
|
|
47
|
+
local now file tmp
|
|
48
|
+
now=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
49
|
+
file="$(config_file "$root")"
|
|
50
|
+
tmp=$(mktemp)
|
|
51
|
+
jq -n \
|
|
52
|
+
--arg e "$edition" \
|
|
53
|
+
--argjson l "$languages_json" \
|
|
54
|
+
--argjson s "$sdk_paths_json" \
|
|
55
|
+
--arg t "$now" \
|
|
56
|
+
'{version:"1", edition:$e, languages:$l, sdk_paths:$s, configured_at:$t}' \
|
|
57
|
+
> "$tmp"
|
|
58
|
+
mv "$tmp" "$file"
|
|
59
|
+
|
|
60
|
+
echo "OK: cached $root -> $edition"
|
|
61
|
+
echo "Remember to add .dwy/ to .gitignore (本机判断缓存,不入版本库)"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
cmd_reset() {
|
|
65
|
+
local root="$1"
|
|
66
|
+
local file
|
|
67
|
+
file="$(config_file "$root")"
|
|
68
|
+
rm -f "$file"
|
|
69
|
+
echo "OK: removed $file"
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
main() {
|
|
73
|
+
if [[ $# -lt 1 ]]; then
|
|
74
|
+
echo "Usage: $0 {get|set|reset} <project_root> [args...]" >&2
|
|
75
|
+
exit 2
|
|
76
|
+
fi
|
|
77
|
+
local action="$1"
|
|
78
|
+
shift
|
|
79
|
+
|
|
80
|
+
case "$action" in
|
|
81
|
+
get) cmd_get "$@" ;;
|
|
82
|
+
set) cmd_set "$@" ;;
|
|
83
|
+
reset) cmd_reset "$@" ;;
|
|
84
|
+
*)
|
|
85
|
+
echo "ERROR: unknown action: $action" >&2
|
|
86
|
+
exit 2
|
|
87
|
+
;;
|
|
88
|
+
esac
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
main "$@"
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dwy-whiteboard-prototype
|
|
3
|
+
description: "用 HTML 白板(FigJam/draw.io 风格)画可交互 UI 原型。触发场景:用户说『画原型 / 出原型 / 画白板 / 原型图 / 做个原型 / prototype / 把某页面的各种状态画出来 / 把这几个页面的跳转画清楚』,或要在动手写 UI 代码前先验证页面与交互流程时。产出:每个页面一个 HTML 白板文件,画布二维摆放、SVG 连线表达跳转、左侧导航在白板间切换、右侧标注写交互与边界。这是项目原型的标准做法,画 iOS/移动端页面原型时务必用本 skill,别另起炉灶手搓样式与交互引擎。"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 白板原型(HTML 可交互)
|
|
7
|
+
|
|
8
|
+
把页面与交互流程画成「白板」:每个页面一个 HTML 文件,文件内把该页面的**所有状态**(默认/空态/加载/错误/禁用…)摆成二维画布,用 SVG 连线表达状态间跳转,左侧固定导航在不同页面白板间切换。
|
|
9
|
+
|
|
10
|
+
**这套原型是雏形/脚手架**——目的是先把页面齐、状态全、跳转流程理清、交互无 bug,给后续 UI 设计打底。所以重点在覆盖与流程正确,**不必纠结像素级视觉**。图标用稳定图标库(SF Symbols 风格的字符/内联 SVG)占位,**不用 emoji 作功能性图标**。
|
|
11
|
+
|
|
12
|
+
## 起步:复制模板,别手搓引擎
|
|
13
|
+
|
|
14
|
+
`assets/template.html` 已含整套白板引擎(平移缩放、SVG 连线、选中高亮、复位展示、左侧导航、拖拽防误触)。**画新原型时复制它,只改三处**:
|
|
15
|
+
|
|
16
|
+
1. **画布区**(`.stage` 列表)——每个状态一个画布
|
|
17
|
+
2. **`EDGES`**(脚本顶部)——声明白板内状态跳转,决定画哪些连线
|
|
18
|
+
3. **左侧 `.sidenav`**——把当前页设 `.on`,其余指向对应白板 html
|
|
19
|
+
|
|
20
|
+
引擎部分(`drawWires`/`select`/`focusOn`/拖拽缩放/`fitAll`)**不要改、不要重写**——这些是反复调试过的,重写极易引入下面「交互铁律」里踩过的坑。
|
|
21
|
+
|
|
22
|
+
## 组织:按「页面」划分白板
|
|
23
|
+
|
|
24
|
+
- **一个页面 = 一个 HTML 文件**(如 `connect-spec.html` `home-spec.html`)。文件内放该页面的**全部状态变体**,每个状态一个画布。
|
|
25
|
+
- 不要把多个并列功能塞一个白板——页面多了会糊成网格图、画布爆炸。模块间的关系交给左侧导航和跨白板跳转。
|
|
26
|
+
- **左侧导航按用户旅程顺序排页面**(例:引导页 → 首页 → 连接页 → 功能页),不是按技术依赖。每个白板的导航内容一致,只有「当前页」标记不同。
|
|
27
|
+
- 一个**总览页** `index-spec.html` 串各页入口(卡片 + 链接下钻到各白板)。
|
|
28
|
+
- 文件统一放 `docs/prototypes/`,命名 `<页面>-spec.html`。
|
|
29
|
+
|
|
30
|
+
## 每个画布的结构
|
|
31
|
+
|
|
32
|
+
左 `.phone`(设备框,内 `.screen` 放 UI)+ 右 `.spec` 标注栏。`.stage` 用 `data-id`(唯一)、`data-x`/`data-y`(白板坐标,列距约 760、行距约 820);`.canvas-no` 的 `id` 必须 = `data-id`(选中靠它)。
|
|
33
|
+
|
|
34
|
+
**设备尺寸按目标端定**(不写死):模板 `.phone` 默认 320×680,复制后**按产品目标端改 `.phone` 的 `width`/`height`**——iOS 用 iPhone 逻辑尺寸(如 390×844)、鸿蒙用对应 vp 尺寸、iPad/平板/Web 用各自真实比例。列距/行距随之放宽以免画布重叠。
|
|
35
|
+
|
|
36
|
+
**标注栏三段式**(这是原型的核心价值,别省):
|
|
37
|
+
|
|
38
|
+
- **用途**:一句话讲清这个页面/状态的职责。
|
|
39
|
+
- **交互跳转**:点哪 → 去哪。白板内跳转用 `<a class="jump" data-go="目标id">`;跨白板跳转用 `<a class="xjump" href="目标-spec.html">`(绿色 ↗ 标识)。
|
|
40
|
+
- **边界处理**:雏形阶段最该写全的部分——单行文字截断、空态、加载态、禁用态、错误态、超时兜底等,按该状态适用项列。
|
|
41
|
+
|
|
42
|
+
付费/受限操作:按钮旁加 `<span class="pill lock">PRO</span>`,标注栏加「付费」段(`.gt.pay`),按需。
|
|
43
|
+
|
|
44
|
+
## 交互铁律(踩过的坑,务必遵守)
|
|
45
|
+
|
|
46
|
+
这些是反复迭代修出来的,模板已实现;自己改引擎或写新交互时不要违背:
|
|
47
|
+
|
|
48
|
+
- **编号 = 选中入口,画框不选中**。只有点 `.canvas-no`(编号标题)才选中并「复位展示」。画框本身不响应选中——否则点画框空白、点画框内按钮都容易误触出 bug。
|
|
49
|
+
- **按钮 = 跳转**。画框内可点元素用 `data-go="目标id"` 做白板内跳转(点了 select + 复位展示);跨白板跳转用 `<a href>`。
|
|
50
|
+
- **可点元素不启动拖拽**。`pointerdown` 里 `if(e.target.closest('input,a,[data-go],.canvas-no'))return`。原因:真实鼠标点击带几像素抖动,若任意位置都进入拖拽判定,点击会被 `moved` 判成拖拽而吞掉——曾导致「点编号不高亮、点按钮不跳转」。这是最隐蔽的坑,务必保留。
|
|
51
|
+
- **复位展示让目标看清**。跳转/选中后调 `focusOn(id)`:缩放到单画布刚好填满视口 + 居中,不管之前缩放多小都清晰。别只 `centerOn`(保持原缩放会看不清)。
|
|
52
|
+
- **连线从画框边缘进出**,不从中心(否则被框体盖住像断的)。`edgeAnchor` 已实现选最近边 + 贝塞尔曲线 + 箭头 + 中点标签。
|
|
53
|
+
- **禁文本选中**:`body{user-select:none}` + `input{user-select:text}`,拖拽不选中画框文字。
|
|
54
|
+
- **单行截断**:`white-space:nowrap;overflow:hidden;text-overflow:ellipsis` + 父级 `min-width:0`(省略号生效前提)。列表项必带。
|
|
55
|
+
|
|
56
|
+
## 视觉 token
|
|
57
|
+
|
|
58
|
+
**配色按产品定位推荐,只换色板、不动结构。** 模板 `:root` 是一套**语义变量架构**(`--gold` 主色 / `--device` 背景 / `--surface*` 分层 / `--red`/`--green`/`--pro` 等),默认填的是深色蓝调一套可跑值。复制后**按产品定位重填这些变量的色值 + 明/暗调**:金融稳重、社交活泼、工具中性——AI 自行判断给配色方案。
|
|
59
|
+
|
|
60
|
+
只换**色值**,`:root` 的变量名、圆角、阴影、间距、质感等**结构不动**(引擎和样式都引用这些变量名,改名会断)。纯系统字体 `-apple-system,"PingFang SC"`,**零外部字体依赖**(符合本地纯客户端定位,也避免离线打不开)。
|
|
61
|
+
|
|
62
|
+
## 产出后自检
|
|
63
|
+
|
|
64
|
+
用本地 http 服务打开(`python3 -m http.server`,注意 `?v=` 破缓存),确认:
|
|
65
|
+
- 各画布定位正确、连线带箭头无坐标错误(`NaN`);
|
|
66
|
+
- 点编号 → 高亮 + 复位展示;点画框内按钮/标注 jump → 白板内跳转;点跨白板链接 → 切文件;
|
|
67
|
+
- 拖拽空白处平移、滚轮缩放正常;点画框空白处不误选中;
|
|
68
|
+
- 列表超长文字省略号截断不撑破。
|
|
69
|
+
|
|
70
|
+
新增页面白板后,记得在 `index-spec.html` 和各白板左侧导航里补上入口。
|