create-dwy 0.19.0 → 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 (117) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/package.json +1 -1
  3. package/src/cli-help.js +28 -2
  4. package/src/prompt-style.js +82 -0
  5. package/src/searchable-select.js +12 -29
  6. package/src/sync-all.js +95 -583
  7. package/src/sync-codex.js +14 -7
  8. package/src/sync-opencode.js +8 -22
  9. package/src/sync.js +60 -149
  10. package/src/tab-multiselect.js +21 -64
  11. package/templates/ai-tools/CHANGELOG.md +195 -0
  12. package/templates/ai-tools/CLAUDE.md +39 -58
  13. package/templates/ai-tools/VERSION +1 -1
  14. package/templates/ai-tools/hooks/Git/pre-git-commit-ai-signature-check.sh +5 -4
  15. package/templates/ai-tools/rules/Android/dwy-android-core.md +147 -13
  16. package/templates/ai-tools/rules/Android/dwy-android-layering.md +142 -0
  17. package/templates/ai-tools/rules/Android/dwy-android-mvp.md +55 -0
  18. package/templates/ai-tools/rules/Android/dwy-android-support-only.md +2 -0
  19. package/templates/ai-tools/rules/Docker/dwy-docker.md +23 -1
  20. package/templates/ai-tools/rules/Flutter/dwy-flutter-core.md +2 -0
  21. package/templates/ai-tools/rules/Flutter/dwy-flutter-testing.md +1 -1
  22. package/templates/ai-tools/rules/HarmonyOS/dwy-arkts-ui-build.md +12 -8
  23. package/templates/ai-tools/rules/Python/dwy-python-backend.md +4 -43
  24. package/templates/ai-tools/rules/Python/dwy-python-base-lib.md +1 -1
  25. package/templates/ai-tools/rules/Python/dwy-python-layering.md +169 -0
  26. package/templates/ai-tools/rules/Vue/dwy-vue-core.md +11 -49
  27. package/templates/ai-tools/rules/Vue/dwy-vue-layering.md +153 -0
  28. package/templates/ai-tools/rules/iOS/dwy-apple-layering.md +133 -0
  29. package/templates/ai-tools/rules/iOS/dwy-swift-core.md +2 -0
  30. package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-code-craft.md +83 -0
  31. package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-dependency-freshness.md +27 -66
  32. package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-git-commit.md +8 -219
  33. package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-oss-commercial-license.md +27 -123
  34. package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-prod-branch.md +31 -0
  35. package/templates/ai-tools/rules//346/225/260/346/215/256/345/272/223/dwy-postgres.md +17 -10
  36. package/templates/ai-tools/rules//346/225/260/346/215/256/345/272/223/dwy-redis.md +6 -3
  37. package/templates/ai-tools/skills/Docker/dwy-deploy-first/SKILL.md +14 -14
  38. package/templates/ai-tools/skills/Docker/dwy-deploy-first/references/chapter-01-mirrors.md +2 -2
  39. package/templates/ai-tools/skills/Docker/dwy-docker/SKILL.md +21 -13
  40. package/templates/ai-tools/skills/Docker/dwy-docker/references/ask-templates.md +13 -12
  41. package/templates/ai-tools/skills/Docker/dwy-docker/references/templates.md +3 -1
  42. package/templates/ai-tools/skills/Docker/dwy-docker/references/version-rules.md +10 -6
  43. package/templates/ai-tools/skills/Docker/dwy-docker/scripts/query_dockerhub.py +21 -6
  44. package/templates/ai-tools/skills/Docker/dwy-docker/scripts/scan_images.sh +2 -2
  45. package/templates/ai-tools/skills/Docker/dwy-mirror-source/SKILL.md +44 -30
  46. package/templates/ai-tools/skills/Docker/dwy-mirror-source/references/dockerfile-snippets.md +2 -0
  47. package/templates/ai-tools/skills/Docker/dwy-mirror-source/references/mirror-providers.md +8 -8
  48. package/templates/ai-tools/skills/Docker/dwy-mirror-source/scripts/apply_mirrors.py +14 -1
  49. package/templates/ai-tools/skills/Docker/dwy-mirror-source/scripts/check_mirrors.py +4 -0
  50. package/templates/ai-tools/skills/DolphinDB/dwy-dolphindb/SKILL.md +8 -6
  51. package/templates/ai-tools/skills/DolphinDB/dwy-dolphindb/references/digest/python-sdk.md +3 -3
  52. package/templates/ai-tools/skills/DolphinDB/dwy-dolphindb/references/digest/stream-engine.md +2 -2
  53. package/templates/ai-tools/skills/DolphinDB/dwy-dolphindb/references/review-rules/anti-patterns.md +3 -1
  54. package/templates/ai-tools/skills/DolphinDB/dwy-dolphindb/references/review-rules/change-checklist.md +4 -4
  55. package/templates/ai-tools/skills/DolphinDB/dwy-dolphindb/references/review-rules/lethal-violations.md +5 -5
  56. package/templates/ai-tools/skills/DolphinDB/dwy-dolphindb/references/review-rules/perf-baselines.md +5 -5
  57. package/templates/ai-tools/skills/Python/dwy-eapi/SKILL.md +59 -200
  58. package/templates/ai-tools/skills/Python/dwy-eapi/shared/anticorruption.md +13 -0
  59. package/templates/ai-tools/skills/Python/dwy-eapi/shared/layering.md +5 -0
  60. package/templates/ai-tools/skills/Python/dwy-eapi/shared/response-envelope.md +20 -0
  61. package/templates/ai-tools/skills/Python/dwy-eapi/shared/timezone.md +7 -0
  62. package/templates/ai-tools/skills/Python/dwy-eapi/v0/breaking.md +15 -0
  63. package/templates/ai-tools/skills/Python/dwy-eapi/v0/email-canonical.md +43 -0
  64. package/templates/ai-tools/skills/Python/dwy-eapi/v0/index.md +103 -0
  65. package/templates/ai-tools/skills/Python/dwy-eapi/v0/providers-email.md +49 -0
  66. package/templates/ai-tools/skills/Python/dwy-eapi/versions.yml +13 -0
  67. package/templates/ai-tools/skills/Vue/dwy-eui/SKILL.md +62 -306
  68. package/templates/ai-tools/skills/Vue/dwy-eui/references/eui-design-guide.md +8 -1
  69. package/templates/ai-tools/skills/Vue/dwy-eui/references/eui-integration-guide.md +0 -31
  70. package/templates/ai-tools/skills/Vue/dwy-eui/shared/config-theme.md +8 -0
  71. package/templates/ai-tools/skills/Vue/dwy-eui/shared/form.md +6 -0
  72. package/templates/ai-tools/skills/Vue/dwy-eui/shared/overlay.md +6 -0
  73. package/templates/ai-tools/skills/Vue/dwy-eui/shared/reka.md +5 -0
  74. package/templates/ai-tools/skills/Vue/dwy-eui/v1/index.md +8 -0
  75. package/templates/ai-tools/skills/Vue/dwy-eui/v2/breaking.md +14 -0
  76. package/templates/ai-tools/skills/Vue/dwy-eui/v2/index.md +55 -0
  77. package/templates/ai-tools/skills/Vue/dwy-eui/v2/lookup.md +29 -0
  78. package/templates/ai-tools/skills/Vue/dwy-eui/versions.yml +12 -0
  79. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-architecture/SKILL.md +11 -14
  80. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-product-launcher/references/state-and-contract.md +1 -1
  81. package/templates/ai-tools/skills//344/272/247/345/223/2010/345/210/2601/dwy-prototype/SKILL.md +1 -1
  82. 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
  83. 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
  84. 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
  85. 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
  86. 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
  87. 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
  88. 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
  89. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/SKILL.md +4 -3
  90. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/android.md +1 -1
  91. 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
  92. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/changelog.md +45 -27
  93. 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
  94. 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
  95. 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
  96. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/harmony.md +1 -1
  97. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-publish/references/ios.md +1 -1
  98. package/templates/ai-tools/skills//345/217/221/345/270/203/345/217/221/347/211/210/dwy-semver/SKILL.md +8 -0
  99. package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/SKILL.md +7 -7
  100. package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/references/checks-runtime.md +63 -59
  101. package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/scripts/check_base.sh +10 -1
  102. package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/scripts/check_capacity.sh +21 -23
  103. package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/scripts/check_db.sh +9 -1
  104. package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/scripts/check_docker.sh +20 -24
  105. package/templates/ai-tools/skills//345/256/211/345/205/250/dwy-deploy-audit/scripts/check_logs.sh +3 -3
  106. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/SKILL.md +4 -2
  107. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/references/api.md +1 -1
  108. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/dwy-doubao-tts/scripts/synthesize.py +1 -0
  109. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/media-platform-packaging/SKILL.md +7 -5
  110. package/templates/ai-tools/skills//350/207/252/345/252/222/344/275/223/media-platform-packaging/references/platform-copy-examples.md +5 -3
  111. package/templates/ai-tools/skills//351/200/232/347/224/250/dwy-dependency-choice/SKILL.md +140 -0
  112. package/templates/ai-tools/skills//351/200/232/347/224/250/dwy-git-commit/SKILL.md +113 -0
  113. package/templates/ai-tools/skills//351/200/232/347/224/250/dwy-shared/SKILL.md +16 -13
  114. package/templates/ai-tools/skills//351/200/232/347/224/250/dwy-whiteboard-prototype/SKILL.md +1 -1
  115. package/src/sync-packs.js +0 -223
  116. package/src/sync-scene.js +0 -178
  117. package/templates/ai-tools/rules//345/274/200/345/217/221/346/265/201/347/250/213/dwy-tdd-development.md +0 -115
@@ -2,7 +2,7 @@
2
2
 
3
3
  > **何时读这份:** 当 AI 即将运行 4.6 / 4.8 / 4.9 / 4.10 类检查或解读其输出时读取本文件。
4
4
 
5
- 本文件聚焦"运行时与韧性"维度的检查规则、严重度判定与输出格式。涵盖 Docker 安全、自愈与资源耗尽防护、日志大小与防爆、硬件识别与资源推荐。
5
+ 本文件聚焦"运行时与韧性"维度的检查规则、严重度判定与输出格式。涵盖 Docker 安全、自愈与资源耗尽防护、日志大小与防爆、硬件与容器资源。内存和日志的具体数字是冷启动先验,有实测就不用表。
6
6
 
7
7
  脚本目录简称 `{scripts}` = `../scripts/`。
8
8
 
@@ -11,8 +11,8 @@
11
11
  ## 4.6 Docker 安全 — `{scripts}/check_docker.sh`
12
12
 
13
13
  > **跨 skill 联动**:本节发现的镜像版本/镜像源问题,只**报告**不修复。具体修复路径:
14
- > - 镜像 tag 不固定 / `:latest` / 浮动 tag → 引导用户跑 `/dwy-docker`(走 query_dockerhub.py 选 N-1 minor)
15
- > - daemon 未配 registry-mirrors / 容器用境外 registry → 引导用户跑 `/dwy-mirror-source`(写阿里云/中科大/daocloud)
14
+ > - 镜像 tag 不固定 / `:latest` / 浮动 tag → 引导用户跑 `/dwy-docker`(当次列出 tag 再固定,N-1 只是偏好)
15
+ > - daemon 未配 registry-mirrors / 容器用境外 registry → 引导用户跑 `/dwy-mirror-source`(当次探测后取延迟最低的源)
16
16
 
17
17
  | 检查项 | 期望值 | 严重级 |
18
18
  |--------|--------|--------|
@@ -30,9 +30,9 @@
30
30
  | 容器 `RestartPolicy` | `always` 或 `unless-stopped`(**服务器重启后自动起来**) | **critical** |
31
31
  | 容器 `RestartPolicy=no` 但正在 running | 不允许(重启会丢) | **critical** |
32
32
  | 容器 `RestartPolicy=on-failure` | 不推荐(手动 stop / OOM 后不会重启) | high |
33
- | daemon 日志驱动 `log-opts.max-size` | 已配置(≤ 100m,防容器日志写满磁盘) | high |
34
- | **daemon `registry-mirrors`**(时区在 PRC 时) | 至少 1 个国内源(daocloud / aliyun / ustc / tsinghua) | high(PRC 无配置)/ info(境外) |
35
- | **运行容器使用境外 registry**(`gcr.io` `ghcr.io` `k8s.gcr.io` `quay.io` `mcr.microsoft.com` `nvcr.io` `docker.elastic.co`)且时区在 PRC | 改用 `<registry>.m.daocloud.io` 前缀(`registry-mirrors` **不**对它们生效) | high |
33
+ | daemon 日志驱动 `log-opts.max-size` | 已配置上限。数字按实测日志增速,不要求 ≤ 100m | high(未配置) |
34
+ | **daemon `registry-mirrors`** | 名单里有 daocloud / aliyun / ustc 不算通过。合格看当次对 Registry API 的延迟和内容。未配置时提示去探测,不因为没写某个国内源判失败。私有库或用户指定源不参加公网竞速 | info |
35
+ | **运行容器使用境外 registry**(`gcr.io` `ghcr.io` `k8s.gcr.io` `quay.io` `mcr.microsoft.com` `nvcr.io` `docker.elastic.co`)且时区在 PRC | 改用当次探测选出的国内前缀(`registry-mirrors` **不**对它们生效)。DaoCloud 前缀只是当前候选。私有库不改前缀 | high |
36
36
 
37
37
  **Docker 版本与暴露面判定补充:**
38
38
 
@@ -93,23 +93,40 @@
93
93
  |--------|--------|--------|
94
94
  | Docker 单容器 `*-json.log` 大小 | < 500 MB(daemon 配 log-opts max-size 时自动控) | high(>500 MB) / critical(>1 GB 且 daemon 无 log-opts) |
95
95
  | 容器自身 `LogConfig.Config` 覆盖 | 至少有 `max-size`,否则继承 daemon | high(容器 + daemon 都没配) |
96
- | Docker daemon `log-opts.max-size` | 已配置 ≤ 100m | high(同 check_docker.sh,本节关联展开) |
96
+ | Docker daemon `log-opts.max-size` | 已配置上限。数字按本节实测增速,不要求 ≤ 100m | high(未配置) |
97
97
  | Nginx access.log / error.log 单文件 | < 500 MB | high |
98
98
  | `/etc/logrotate.d/nginx` | 存在 | high |
99
99
  | `journalctl --disk-usage` | < 2 GB | medium / high(≥ 2 GB 且 SystemMaxUse 未配) |
100
100
  | `/etc/systemd/journald.conf` `SystemMaxUse` | 已显式配置 | low |
101
101
  | 应用日志目录(`/var/log/<svc>` / `/opt/*/logs` / `/home/*/logs` / `/srv/*/logs`) | 列出 Top 10 供人工核对 | info |
102
- | 日志按当前 docker 容器存活时长粗估的撑天数 | > 90 天 | high(<90) / critical(<30) |
102
+ | 日志按当前 docker 容器存活时长粗估的撑天数 | 按实测增速,写满根盘前有人处理。30 / 90 天是告警线,不是要配成的保留天数 | high(<90) / critical(<30) |
103
103
 
104
104
  **输出规约:** 脚本会汇总 `Docker json-log + Nginx + journal + 应用日志` 总占用,对照根盘可用空间,给出"按 docker 当前增速预计可撑 N 天"的粗估。粗估只算 docker json-log 增量,不含数据库/应用日志业务增量,因此**结论偏乐观**,作为下限警示使用。
105
105
 
106
106
  ---
107
107
 
108
- ## 4.10 硬件识别与资源推荐 — `{scripts}/check_capacity.sh`
108
+ ## 4.10 硬件识别与资源 — `{scripts}/check_capacity.sh`
109
109
 
110
- > 脚本只输出 raw(硬件规格 + 当前容器 mem_limit + Postgres/Redis 启动参数 + compose 资源声明);主 Claude 用下表生成 "推荐 vs 当前" 对比报告。详细推荐规则与配比公式参考 `dwy-docker` skill 第二部分。
110
+ 脚本输出宿主规格、容器硬限、`docker stats` 单帧占用、Postgres/Redis 参数、compose 声明、日志日增量能对上的根盘剩余。报告写「本次实测 vs 当前硬限」。**禁止**把下面的数字写成应改成的配额。
111
111
 
112
- **容器资源推荐分级表(按宿主总内存)**
112
+ 必须成立的只有这些:
113
+
114
+ - 每个容器有内存硬限。关键服务(redis / postgres / mysql / mongo / clickhouse / elasticsearch)没有就是 high
115
+ - Redis 设了 `maxmemory`,且容器 `mem_limit` 大于它。未设或为 0 是 **critical**
116
+ - Postgres `shared_buffers` 不超过宿主总内存的 50%。这是 OOM 天花板,不是目标比例
117
+ - 容器硬限合计不超过宿主总内存的 75%。超过则 OS 没有余量,是 high。不要求贴近 65%
118
+ - 日志有 `max-size` 和 `max-file`。两边都没有是 **critical**
119
+ - 按 `check_logs.sh` 的实测日增量,根盘会在短时间内写满,才收紧轮转。30 天 critical,90 天 high。这是告警线
120
+
121
+ 有 `docker stats` 或日志日增量时,用实测:
122
+
123
+ - 内存硬限低于这一帧占用(或已有的监控峰值)才要加。单帧不是峰值,报告里写明
124
+ - 硬限远高于占用,不是问题,不要为了贴近下表去改小
125
+ - 日志配额按日增量和根盘剩余算。`max-size × max-file × 容器数` 本身就能占掉根盘约 5% 以上,说明天花板太高,是 high。5% 是安全天花板,不是目标占用
126
+
127
+ 没有占用、也没有日志增量(服务刚起)时,才用下面的冷启动先验。服务跑起来之后以实测替换,不把先验写回本文件。
128
+
129
+ **冷启动先验:内存(没有实测时才用)**
113
130
 
114
131
  | 宿主总内存 | Backend mem_limit | Postgres mem_limit / shm_size / shared_buffers / effective_cache_size | Redis mem_limit / maxmemory |
115
132
  |-----------|-------------------|--------------------------------------------------------------------|----------------------------|
@@ -118,83 +135,70 @@
118
135
  | 8 GB | 2g | 2g / 512m / 512MB / 1536MB | 768m / 512mb |
119
136
  | 16 GB | 4g | 4g / 1g / 1GB / 3GB | 1g / 700mb |
120
137
 
121
- **配比原则**
138
+ 比例只解释这张先验怎么来的:硬限合计大约留出 OS 余量;Postgres `shared_buffers` 约容器硬限的 25%,`effective_cache_size` 约 75%;Redis `maxmemory` 约容器硬限的 70%,其余给 fork 时的写时复制。实测对不上就丢掉整行。
122
139
 
123
- - 容器 `mem_limit` 合计 ≤ 宿主总内存的 **65%**(预留 OS / 全局 nginx / 监控 agent / frpc 等)
124
- - Postgres `shared_buffers` = 容器 `mem_limit` 的 **25%**
125
- - Postgres `effective_cache_size` = 容器 `mem_limit` 的 **75%**
126
- - Redis `maxmemory` = 容器 `mem_limit` 的 **70%**(剩 30% 给 RDB/AOF fork 时 COW 留 buffer)
127
- - Redis `mem_limit` = `maxmemory ÷ 0.7` 向上取整
128
-
129
- **对比报告格式(主 Claude 在报告里生成)**
140
+ **对比报告格式**
130
141
 
131
142
  ```
132
- | 服务 | 配置项 | 推荐(基于 X GB 宿主) | 当前 | 状态 |
133
- |------|--------|--------------------|------|------|
134
- | backend | mem_limit | 1g | 无 | ❌ 缺失 |
135
- | db | mem_limit | 1g | 1g | ✅ |
136
- | db | shared_buffers | 256MB | 128MB(默认) | ⚠️ 偏低 |
137
- | db | shm_size | 256m | 64m(默认) | ⚠️ 偏低 |
138
- | redis | maxmemory | 256mb | 256mb | ✅ |
139
- | redis | mem_limit | 384m | 384m | ✅ |
140
- | redis | appendonly | yes | no | ⚠️ 重启丢数据 |
143
+ | 服务 | 配置项 | 本次实测 | 当前硬限 | 状态 |
144
+ |------|--------|----------|----------|------|
145
+ | backend | mem | stats 420MiB(单帧) | 无 | 缺上限 |
146
+ | db | mem | stats 300MiB(单帧) | 1g | 硬限高于实测 |
147
+ | db | shared_buffers | — | 超过宿主 50% | 撞上天花板 |
148
+ | redis | maxmemory | 当前占用 | 0 | 未设 |
141
149
  ```
142
150
 
143
- **严重等级标记规则**
151
+ 没有实测的新机器,在「本次实测」列写「无,用冷启动先验 &lt;数字&gt;」,并注明服务跑起来后要重测。
152
+
153
+ **严重等级**
144
154
 
145
155
  | 检查项 | 期望值 | 严重级 |
146
156
  |--------|--------|--------|
147
- | 关键服务(redis / postgres / mysql / mongo / clickhouse / elasticsearch)容器无 `mem_limit` | 已设置 | high |
148
- | Redis `--maxmemory` 未设置或 `0` | 已设置 | **critical** |
149
- | Postgres `shared_buffers` > 宿主总内存 50% | ≤ 宿主总内存 50% | high |
150
- | Postgres `shm_size` < 128m | ≥ 256m | medium |
151
- | Redis 未启用 AOF(`--appendonly yes`) | yes | medium |
152
- | 容器 `mem_limit` 合计 > 宿主总内存 75% | ≤ 65% | high |
153
- | `mem_limit` 偏离推荐表 ±50% 以上(主 Claude 判定) | 在分级表区间内 | medium |
157
+ | 关键服务容器无 `mem_limit` | 已设置 | high |
158
+ | 硬限低于本次 `docker stats` 占用 | 硬限高于实测 | high |
159
+ | Redis `--maxmemory` 未设置或 `0` | 已设置,且小于容器 `mem_limit` | **critical** |
160
+ | Postgres `shared_buffers` > 宿主总内存 50% | 不超过 | high |
161
+ | Redis 未启用 AOF(`--appendonly yes`) | 按持久化需求,不是配额 | medium |
162
+ | 容器 `mem_limit` 合计 > 宿主总内存 75% | 不超过。低于 75% 不要求再贴近某个比例 | high |
163
+
164
+ 偏离冷启动先验表 **不是** 违规。
154
165
 
155
166
  ---
156
167
 
157
- ### 日志大小推荐分级表(防容器日志无限增长撑爆磁盘)
168
+ ### 日志轮转
158
169
 
159
- 依据是 `<根盘容量>` × `<容器规模>`,**单容器最大日志占用 = `max-size` × `max-file`**;所有容器日志合计应 ≤ 根盘可用空间的 **5%**(留磁盘给数据/swap/OS)。
170
+ 有日增量时用增速和根盘剩余决定 `max-size` / `max-file`。没有增量时才看冷启动先验。
160
171
 
161
- **daemon 兜底配置(`/etc/docker/daemon.json` `log-opts`)**
172
+ **冷启动先验:daemon `log-opts`(没有日志增量时才用)**
162
173
 
163
174
  | 宿主规格 | 根盘 | 容器数(估) | `max-size` | `max-file` | 单容器 quota | 备注 |
164
175
  |---------|------|-----------|------------|-----------|-------------|------|
165
- | 入门 | < 50 GB | 任意 | `10m` | `3` | ~30 MB | 2-4 GB VM 入门款,日志少留磁盘 |
166
- | 标准 | 50-150 GB | ≤ 5 | `50m` | `5` | ~250 MB | 4-8 GB VM 通用 |
167
- | 标准 | 50-150 GB | > 5 | `20m` | `5` | ~100 MB | 容器多则降单容器 quota |
168
- | 大型 | > 150 GB | 任意 | `100m` | `5` | ~500 MB | 16+ GB 服务器,空间充裕 |
169
-
170
- **容器级覆盖(compose `logging.options`,优先于 daemon)**
176
+ | 入门 | < 50 GB | 任意 | `10m` | `3` | ~30 MB | 盘小,先验从紧 |
177
+ | 标准 | 50-150 GB | ≤ 5 | `50m` | `5` | ~250 MB | 无增速时的起点 |
178
+ | 标准 | 50-150 GB | > 5 | `20m` | `5` | ~100 MB | 容器多,先验收紧 |
179
+ | 大型 | > 150 GB | 任意 | `100m` | `5` | ~500 MB | 无增速时的起点 |
171
180
 
172
- | 容器类型 | `max-size` | `max-file` | 理由 |
173
- |---------|-----------|-----------|------|
174
- | 数据库 (postgres / mysql / mongo) | `20m` | `10` | 慢查询日志价值高,保留更多滚动 |
175
- | Web 反代 (nginx access log 走 stdout) | `50m` | `5` | 写入量大,单文件可放宽 |
176
- | 应用后端 (FastAPI / Node 等) | `10m` | `5` | 通用 |
177
- | Redis / 缓存类 | `10m` | `3` | 写入少,保留少 |
181
+ 容器级 `logging.options` 盖过 daemon。库、反代、应用的保留条数不一样,同样只在没有该容器增速时参考,不作为合格线。
178
182
 
179
- **daemon.json 模板**
183
+ 字段写法示例(数字不是目标配额):
180
184
 
181
185
  ```json
182
186
  {
183
187
  "log-driver": "json-file",
184
188
  "log-opts": {
185
- "max-size": "50m",
186
- "max-file": "5",
189
+ "max-size": "<当次算出的大小>",
190
+ "max-file": "<当次算出的个数>",
187
191
  "compress": "true"
188
192
  }
189
193
  }
190
194
  ```
191
195
 
192
- **严重等级标记(脚本侧 + 主 Claude 对照表)**
196
+ **严重等级**
193
197
 
194
198
  | 判定 | 严重级 |
195
199
  |------|--------|
196
200
  | daemon 无 `log-opts.max-size` 且容器也无 `LogConfig.Config` | **critical** |
197
- | daemon `max-size` > 推荐档 50% 以上(如根盘 < 50 GB 用 100m) | high |
198
- | 容器无 `LogConfig.Config` 但 daemon 有兜底 | OK(走 daemon) |
199
- | 容器 `LogConfig.Config` 设了但 max-size 偏离推荐档 ±50% | medium |
200
- | 估算所有容器日志合计 > 根盘可用 5% | high |
201
+ | 容器无单独 `LogConfig.Config`,daemon 已有上限 | 通过(走 daemon) |
202
+ | `max-size × max-file × 容器数` > 根盘约 5% | high(配额天花板太高) |
203
+ | 按实测日增量,不足 90 天写满根盘 | high;不足 30 天为 **critical** |
204
+ | 当前 `max-size` 与冷启动先验不同 | 不是问题 |
@@ -30,7 +30,16 @@ for cmd in nginx postgres psql redis-cli docker openssl ufw firewall-cmd iptable
30
30
  done
31
31
 
32
32
  echo "--- PUBLIC IP (best effort) ---"
33
- curl -fsS --max-time 5 https://api.ipify.org 2>/dev/null || hostname -I | awk '{print $1}'
33
+ # 回显地址是先验。一个失败换下一个。全部失败印 unknown。禁止用 hostname -I 的内网地址冒充公网 IP。
34
+ PUB_IP=""
35
+ for url in https://api.ipify.org https://ifconfig.me/ip https://icanhazip.com; do
36
+ PUB_IP=$(curl -fsS --max-time 5 "$url" 2>/dev/null | tr -d '[:space:]')
37
+ if printf '%s' "$PUB_IP" | grep -Eq '^[0-9]{1,3}(\.[0-9]{1,3}){3}$'; then
38
+ break
39
+ fi
40
+ PUB_IP=""
41
+ done
42
+ echo "${PUB_IP:-unknown}"
34
43
  echo
35
44
 
36
45
  echo "--- USER & SUDO ---"
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env bash
2
2
  # 硬件规格识别 + 当前服务资源配置盘点 (只读)
3
3
  #
4
- # 输出 raw data, 由主 Claude 对照 SKILL.md 4.10 的推荐分级表生成
5
- # "推荐 vs 当前" 对比报告。
4
+ # 输出实测:硬件、硬限、docker stats 单帧、日志配额。
5
+ # 分级数字只是没有实测时的冷启动先验,见 checks-runtime.md 4.10。
6
+ # 不要因为当前值没贴近先验就判失败。
6
7
  #
7
8
  # 检查范围:
8
9
  # - 宿主硬件: CPU 核数 / 总内存 / 根盘容量 / swap
@@ -26,7 +27,7 @@ MEM_TOTAL_MB=$(( ${MEM_TOTAL_KB:-0} / 1024 ))
26
27
  MEM_AVAIL_MB=$(( ${MEM_AVAIL_KB:-0} / 1024 ))
27
28
  SWAP_TOTAL_MB=$(( ${SWAP_TOTAL_KB:-0} / 1024 ))
28
29
 
29
- # 推荐分档(对齐 SKILL.md 4.10 的 2/4/8/16 GB 表)
30
+ # 冷启动分档。有 docker stats 时不用这档决定 mem_limit。
30
31
  if [[ $MEM_TOTAL_MB -ge 14000 ]]; then TIER="16GB"
31
32
  elif [[ $MEM_TOTAL_MB -ge 7000 ]]; then TIER="8GB"
32
33
  elif [[ $MEM_TOTAL_MB -ge 3500 ]]; then TIER="4GB"
@@ -39,7 +40,7 @@ echo "CPU 型号: ${CPU_MODEL:-unknown}"
39
40
  echo "总内存: ${MEM_TOTAL_MB} MB"
40
41
  echo "可用内存: ${MEM_AVAIL_MB} MB"
41
42
  echo "Swap: ${SWAP_TOTAL_MB} MB"
42
- echo "推荐分档: ${TIER} (主 Claude 据此查推荐表)"
43
+ echo "冷启动分档: ${TIER} (没有占用数据时才参考先验表)"
43
44
 
44
45
  echo ""
45
46
  echo "--- 根盘容量 ---"
@@ -90,6 +91,8 @@ echo "--- 容器实际内存占用 (docker stats 单帧) ---"
90
91
  timeout 8 docker stats --no-stream --format \
91
92
  'table {{.Name}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.CPUPerc}}' 2>/dev/null \
92
93
  || echo "[i] docker stats 超时或不可用"
94
+ # 单帧不是峰值。硬限低于这一帧才算不够;远高于这一帧不必改到先验表。
95
+ echo "[i] 单帧采样不是峰值。有监控历史用峰值。没有数据时才用冷启动先验,不要为贴近先验表改硬限。"
93
96
 
94
97
  echo ""
95
98
  echo "--- Postgres 启动参数 (从 docker inspect Args 提取) ---"
@@ -116,10 +119,10 @@ for c in $(docker ps -q 2>/dev/null); do
116
119
  # 从 docker inspect 取 shm_size (Postgres 关键)
117
120
  shm=$(docker inspect -f '{{.HostConfig.ShmSize}}' "$c" 2>/dev/null)
118
121
  shm_mb=$(( shm / 1024 / 1024 ))
119
- if [[ "$shm_mb" -lt 128 ]]; then
120
- echo " [!] MEDIUM: shm_size=${shm_mb}m 偏低 (大查询可能 'no space left on /dev/shm', 推荐 >=256m)"
121
- else
122
- echo " [OK] shm_size=${shm_mb}m"
122
+ # 64m 是 Docker 默认。没有 /dev/shm 写满的证据时,不把 256m 当合格线。
123
+ echo " shm_size=${shm_mb}m"
124
+ if [[ "$shm_mb" -lt 64 ]]; then
125
+ echo " [i] shm_size 低于 Docker 默认 64m。仅当日志出现 no space left on /dev/shm 时再加大,不预设 256m"
123
126
  fi
124
127
 
125
128
  # 校验 shared_buffers 是否过大
@@ -200,14 +203,14 @@ for f in $COMPOSE_FILES; do
200
203
  done
201
204
 
202
205
  echo ""
203
- echo "--- 日志兜底推荐档 (基于根盘 + 容器规模, 对照 SKILL.md 4.10) ---"
206
+ echo "--- 日志上限 (冷启动先验,不是目标配额) ---"
204
207
  ROOT_TOTAL_MB=$(df -BM --output=size / 2>/dev/null | tail -1 | tr -d ' M')
205
208
  ROOT_TOTAL_GB=$(( ${ROOT_TOTAL_MB:-0} / 1024 ))
206
209
  RUNNING_COUNT=$(docker ps -q 2>/dev/null | wc -l | tr -d ' ')
207
210
  echo "根盘容量: ${ROOT_TOTAL_GB} GB"
208
211
  echo "运行容器数: ${RUNNING_COUNT}"
209
212
 
210
- # 推荐档分级
213
+ # 没有日志日增量时的起点。有 check_logs 的增速就用增速,不要改成跟这里一致。
211
214
  if [[ $ROOT_TOTAL_GB -lt 50 ]]; then REC_TIER="入门"; REC_SIZE="10m"; REC_FILE="3"
212
215
  elif [[ $ROOT_TOTAL_GB -lt 150 ]]; then
213
216
  REC_TIER="标准"
@@ -215,8 +218,7 @@ elif [[ $ROOT_TOTAL_GB -lt 150 ]]; then
215
218
  else REC_SIZE="50m"; REC_FILE="5"; fi
216
219
  else REC_TIER="大型"; REC_SIZE="100m"; REC_FILE="5"
217
220
  fi
218
- echo "推荐档: ${REC_TIER}"
219
- echo "推荐 daemon log-opts: max-size=${REC_SIZE}, max-file=${REC_FILE}, compress=true"
221
+ echo "冷启动先验档: ${REC_TIER} (无日志增量时才参考 max-size=${REC_SIZE}, max-file=${REC_FILE})"
220
222
 
221
223
  # 拿当前 daemon.json log-opts (复用 check_docker.sh 的逻辑)
222
224
  DAEMON_JSON=$(sudo -n cat /etc/docker/daemon.json 2>/dev/null \
@@ -227,13 +229,11 @@ CUR_FILE=$(echo "$DAEMON_JSON" | grep -oE '"max-file"[[:space:]]*:[[:space:]]*"[
227
229
  | head -1 | grep -oE '"[^"]+"$' | tr -d '"')
228
230
  echo "当前 daemon.json: max-size=${CUR_SIZE:-(未配置)}, max-file=${CUR_FILE:-(未配置)}"
229
231
 
230
- # 简单对比标记
232
+ # 缺上限才是问题。和先验档相同或不同都不表示配额正确。
231
233
  if [[ -z "$CUR_SIZE" ]]; then
232
234
  echo "[!!!] CRITICAL: daemon 无 log-opts.max-size, 长跑容器日志会无限增长"
233
- elif [[ "$CUR_SIZE" == "$REC_SIZE" ]]; then
234
- echo "[OK] max-size 与推荐档一致"
235
235
  else
236
- echo "[i] 当前 max-size=${CUR_SIZE} 与推荐档 ${REC_SIZE} 不同 (主 Claude 据 SKILL.md 4.10 判定是否偏离 50%)"
236
+ echo "[i] 已有 max-size=${CUR_SIZE} max-file=${CUR_FILE:-(未配置)}。与冷启动先验不同不是问题,按日志增速判断。"
237
237
  fi
238
238
 
239
239
  # 估算所有容器日志合计 quota = max-size × max-file × 容器数, 看占根盘比
@@ -250,15 +250,15 @@ if [[ -n "$CUR_SIZE" ]]; then
250
250
  total_quota_mb=$(( ${size_mb:-0} * file_n * RUNNING_COUNT ))
251
251
  if [[ "$ROOT_TOTAL_MB" -gt 0 ]]; then
252
252
  pct=$(( total_quota_mb * 100 / ROOT_TOTAL_MB ))
253
- echo "所有容器最大日志 quota 合计: ${total_quota_mb} MB (占根盘 ${pct}%, 期望 < 5%)"
253
+ echo "所有容器最大日志 quota 合计: ${total_quota_mb} MB (占根盘 ${pct}%)"
254
254
  if [[ "$pct" -gt 5 ]]; then
255
- echo "[!!] HIGH: 日志 quota 合计 ${pct}% 已超根盘 5% 上限"
255
+ echo "[!!] HIGH: 配额天花板占根盘 ${pct}%。5% 是安全上限,超过说明 max-size/max-file 过大,不是叫你改成先验档的 10m/50m"
256
256
  fi
257
257
  fi
258
258
  fi
259
259
 
260
260
  echo ""
261
- echo "--- 资源占比汇总 (供 Claude 校验 65% 上限规则) ---"
261
+ echo "--- 内存硬限占宿主比 (75% 是安全天花板,不是目标利用率) ---"
262
262
  echo "宿主总内存: ${MEM_TOTAL_MB} MB"
263
263
  TOTAL_LIMIT_MB=$(docker ps -q 2>/dev/null \
264
264
  | xargs -I{} docker inspect -f '{{.HostConfig.Memory}}' {} 2>/dev/null \
@@ -268,11 +268,9 @@ if [[ "$MEM_TOTAL_MB" -gt 0 ]]; then
268
268
  pct=$(( TOTAL_LIMIT_MB * 100 / MEM_TOTAL_MB ))
269
269
  echo "占宿主总内存: ${pct}%"
270
270
  if [[ "$pct" -gt 75 ]]; then
271
- echo "[!!] HIGH: 容器硬限合计 > 75% 宿主内存, OS/nginx/监控 留 buffer 不足"
272
- elif [[ "$pct" -lt 30 ]]; then
273
- echo "[i] INFO: 容器硬限合计 < 30%, 可能资源利用不足"
271
+ echo "[!!] HIGH: 容器硬限合计 > 75% 宿主内存, OS 没有余量"
274
272
  else
275
- echo "[OK] 容器硬限合计在 30%-75% 区间"
273
+ echo "[i] 硬限合计 ${pct}%。不要求贴近 65%。硬限低于上面的 docker stats 才要加"
276
274
  fi
277
275
  fi
278
276
  REMOTE
@@ -139,7 +139,15 @@ fi
139
139
 
140
140
  echo ""
141
141
  echo "########## 公网可达性自测 ##########"
142
- PUB_IP=$(curl -fsS --max-time 5 https://api.ipify.org 2>/dev/null)
142
+ # 与 check_base.sh 同一原则:回显地址是先验,失败换下一个,禁止用内网地址顶上。
143
+ PUB_IP=""
144
+ for url in https://api.ipify.org https://ifconfig.me/ip https://icanhazip.com; do
145
+ PUB_IP=$(curl -fsS --max-time 5 "$url" 2>/dev/null | tr -d '[:space:]')
146
+ if printf '%s' "$PUB_IP" | grep -Eq '^[0-9]{1,3}(\.[0-9]{1,3}){3}$'; then
147
+ break
148
+ fi
149
+ PUB_IP=""
150
+ done
143
151
  echo "公网 IP (best effort): ${PUB_IP:-unknown}"
144
152
  if [[ -n "$PUB_IP" ]]; then
145
153
  echo "[i] 注意: 真实公网可达性需从外网测试,此处仅本机视角"
@@ -43,7 +43,7 @@ docker ps --format "{{.Names}}|{{.Ports}}" 2>/dev/null | while IFS='|' read -r n
43
43
  done
44
44
 
45
45
  echo ""
46
- echo "--- 镜像 tag 分级检查 (生产期望: 固定到具体 patch, 跑 /dwy-docker 选 N-1 minor) ---"
46
+ echo "--- 镜像 tag 分级检查 (生产期望: 固定到具体 patch, 跑 /dwy-docker 按当次 tag 列表选) ---"
47
47
  # 浮动 tag 黑名单 (无版本号或仅描述类的)
48
48
  FLOATING_TAGS='^(latest|stable|mainline|edge|current|alpine|slim|bookworm|bullseye|buster|jammy|focal|noble|nightly)$'
49
49
  docker ps --format "{{.Names}}|{{.Image}}" 2>/dev/null | while IFS='|' read -r name image; do
@@ -87,7 +87,7 @@ docker ps --format "{{.Names}}|{{.Image}}" 2>/dev/null | while IFS='|' read -r n
87
87
  fi
88
88
  done
89
89
  echo ""
90
- echo "[i] 修复:对每条 [!!!] / [!!] / [!] 的镜像,跑 /dwy-docker 用 query_dockerhub.py 拿 N-1 minor 推荐版本"
90
+ echo "[i] 修复:对每条 [!!!] / [!!] / [!] 的镜像,跑 /dwy-docker 按当次 tag 列表固定版本。query_dockerhub.py 只是 Hub 先验"
91
91
 
92
92
  echo ""
93
93
  echo "--- 容器是否以 root 运行 ---"
@@ -169,7 +169,7 @@ echo "max-size: ${LOG_MAX_SIZE:-(未配置, 单容器日志可无限增长)}"
169
169
  echo "max-file: ${LOG_MAX_FILE:-(未配置)}"
170
170
  if [[ -z "$LOG_MAX_SIZE" ]]; then
171
171
  echo "[!!] HIGH: 未限制单容器日志大小,长跑容器可能写满磁盘"
172
- echo " 建议: daemon.json 加 \"log-opts\": {\"max-size\": \"100m\", \"max-file\": \"3\"}"
172
+ echo " 建议: daemon.json 的 log-opts 写上 max-size 和 max-file。数字按 check_logs 的日增量和根盘剩余,没有增速才用冷启动先验,不要写死 100m"
173
173
  fi
174
174
 
175
175
  echo ""
@@ -177,39 +177,36 @@ echo "--- docker compose 文件位置 (用于人工核查) ---"
177
177
  sudo -n find /home /opt /srv /root -maxdepth 5 \( -name "docker-compose*.yml" -o -name "compose.yml" \) 2>/dev/null | head -10
178
178
 
179
179
  echo ""
180
- echo "--- 镜像源加速检查 (国内服务器拉境外镜像必装) ---"
181
- # a. 时区判定 (粗判境内)
180
+ echo "--- 镜像源 (候选名单不是合格线) ---"
181
+ # a. 时区只说明要不要考虑公网加速,不决定哪个源合格
182
182
  TZ_VAL=$(timedatectl show -p Timezone --value 2>/dev/null || readlink -f /etc/localtime 2>/dev/null | sed 's|.*/zoneinfo/||')
183
183
  echo "服务器时区: ${TZ_VAL:-unknown}"
184
184
  LIKELY_CN=0
185
185
  case "$TZ_VAL" in
186
186
  Asia/Shanghai|Asia/Chongqing|Asia/Urumqi|Asia/Harbin|Asia/Hong_Kong|PRC) LIKELY_CN=1 ;;
187
187
  esac
188
- [[ "$LIKELY_CN" == "1" ]] && echo "→ 时区在 PRC, 拉境外 registry 不加速会非常慢" \
189
- || echo "→ 时区非 PRC, 加速可选"
188
+ [[ "$LIKELY_CN" == "1" ]] && echo "→ 时区在 PRC。拉 docker.io 前先探测,私有库不参加公网竞速" \
189
+ || echo "→ 时区非 PRC。加速可选"
190
190
 
191
191
  # b. daemon.json registry-mirrors
192
+ # 主机名在候选名单里不等于通过。合格要看当次 Registry 请求的内容和延迟。
192
193
  echo ""
193
194
  MIRRORS=$(echo "$DAEMON_JSON" | grep -oE '"registry-mirrors"[[:space:]]*:[[:space:]]*\[[^]]*\]' | head -1)
194
195
  if [[ -n "$MIRRORS" ]]; then
195
196
  echo "daemon registry-mirrors:"
196
197
  echo " $MIRRORS"
197
- # 简单识别推荐源
198
198
  echo "$MIRRORS" | grep -oE 'https?://[a-zA-Z0-9.-]+' | while read u; do
199
199
  case "$u" in
200
200
  *daocloud*|*aliyun*|*aliyuncs*|*ustc*|*tsinghua*|*163*|*tencent*|*huaweicloud*)
201
- echo " [OK] $u (国内加速源)" ;;
201
+ echo " [i] $u (在候选名单里,未测延迟和内容)" ;;
202
202
  *)
203
- echo " [i] $u (非已知国内主流源, 确认是否仍可用)" ;;
203
+ echo " [i] $u (名单外。私有库或用户指定源保持不动;公网源要当次探测)" ;;
204
204
  esac
205
205
  done
206
206
  else
207
- if [[ "$LIKELY_CN" == "1" ]]; then
208
- echo "[!!] HIGH: daemon.json 未配 registry-mirrors, 国内服务器拉 docker.io 镜像会非常慢"
209
- else
210
- echo "[i] daemon.json 未配 registry-mirrors (境外服务器一般不需要)"
211
- fi
212
- echo " 修复: 跑 /dwy-mirror-source 自动写入阿里云/中科大/daocloud 镜像源"
207
+ echo "[i] daemon.json 未配 registry-mirrors"
208
+ echo " 拉的是 docker.io 公网时,跑 /dwy-mirror-source,当次探测后按延迟从低到高写入"
209
+ echo " 不要因为没写 daocloud 判失败。私有库或用户指定源不参加公网竞速"
213
210
  fi
214
211
 
215
212
  # c. 当前运行中容器使用的境外 registry (registry-mirrors 仅对 docker.io 生效)
@@ -231,21 +228,20 @@ docker ps --format "{{.Names}}|{{.Image}}" 2>/dev/null | while IFS='|' read -r n
231
228
 
232
229
  case "$registry" in
233
230
  docker.io)
234
- tag="OK 走 daemon registry-mirrors 加速"
235
- [[ -z "$MIRRORS" && "$LIKELY_CN" == "1" ]] && tag="[!!] 未配 mirror 国内拉取慢"
231
+ tag="[i] docker.io。加速是否最快看当次探测,不看名单里有没有源"
236
232
  ;;
237
233
  gcr.io|ghcr.io|k8s.gcr.io|registry.k8s.io|quay.io|mcr.microsoft.com|nvcr.io|docker.elastic.co)
238
234
  if [[ "$LIKELY_CN" == "1" ]]; then
239
- tag="[!!] HIGH 境外 registry, registry-mirrors 不生效, 必须把 image 名改 *.m.daocloud.io 前缀"
235
+ tag="[!!] HIGH 境外 registry, registry-mirrors 不生效, 跑 /dwy-mirror-source 选当次延迟最低且内容正确的前缀"
240
236
  else
241
237
  tag="[i] 境外 registry"
242
238
  fi
243
239
  ;;
244
240
  *daocloud*|*aliyun*|*aliyuncs*|*ustc*)
245
- tag="[OK] 已用国内镜像前缀"
241
+ tag="[i] 用了候选前缀,未测是否本次最快"
246
242
  ;;
247
243
  *)
248
- tag="[i] 自建/私有 registry"
244
+ tag="[i] 自建/私有 registry,不参加公网竞速"
249
245
  ;;
250
246
  esac
251
247
  printf " %-32s registry=%-32s %s\n" "$name" "$registry" "$tag"
@@ -253,7 +249,7 @@ done
253
249
 
254
250
  echo ""
255
251
  echo "[i] 修复路径:"
256
- echo " 1. docker.io 加速 → /dwy-mirror-source 自动配 daemon registry-mirrors"
257
- echo " 2. gcr/ghcr/k8s → 把 image 改 <registry>.m.daocloud.io 前缀, 见 dwy-mirror-source 镜像替换表"
258
- echo " 3. 镜像版本不固定 → /dwy-docker 选 N-1 minor 重新固定"
252
+ echo " 1. docker.io 加速 → /dwy-mirror-source 当次探测后按延迟排序写入 registry-mirrors"
253
+ echo " 2. gcr/ghcr/k8s → 把 image 改成当次延迟最低的前缀, 候选见 dwy-mirror-source"
254
+ echo " 3. 镜像版本不固定 → /dwy-docker 按当次 tag 列表固定,N-1 只是偏好"
259
255
  REMOTE
@@ -190,9 +190,9 @@ echo "估算 Docker 日志日均增量: ${GROWTH_MB} MB/day (基于容器存活
190
190
  if [[ "$GROWTH_MB" -gt 0 && "$ROOT_FREE_MB" -gt 0 ]]; then
191
191
  DAYS=$(( ROOT_FREE_MB / GROWTH_MB ))
192
192
  echo "按当前增速预计可撑: ${DAYS} 天 (粗估, 仅算 docker json-log)"
193
- if [[ "$DAYS" -lt 30 ]]; then echo "[!!!] CRITICAL: 不足 30 天, 必须立即配 log-opts 或扩盘"
194
- elif [[ "$DAYS" -lt 90 ]]; then echo "[!!] HIGH: 不足 90 天, 建议尽快补 log-opts max-size"
195
- else echo "[OK] 撑天数 >= 90 天"
193
+ if [[ "$DAYS" -lt 30 ]]; then echo "[!!!] CRITICAL: 按当前增速不足 30 天写满根盘。先确认已有 max-size;配额按这条增速收紧或扩盘,不要套用固定的 10m/50m/100m"
194
+ elif [[ "$DAYS" -lt 90 ]]; then echo "[!!] HIGH: 按当前增速不足 90 天写满根盘。30/90 天是告警线,不是要配成的保留天数"
195
+ else echo "[i] 按当前增速撑过 90 天。90 天是告警线,不是目标配额"
196
196
  fi
197
197
  else
198
198
  echo "[i] 无法估算日均增量 (容器刚起或无日志)"
@@ -18,8 +18,10 @@ description: >
18
18
  1. **私人配置唯一位置**:`~/.dwy/config.yaml`(权限 `600`),豆包段为顶层 key `doubao_tts`
19
19
  2. **禁止**把 `api_key`、音色 ID 写入 skill、项目、commit;禁止回显完整 Key
20
20
  3. 输出音频默认 `doubao_tts.output_dir`(默认 `~/Movies/doubao-tts`),不落到仓库内
21
- 4. 模型资源:`X-Api-Resource-Id: seed-icl-2.0`
22
- 5. 接口:`POST https://openspeech.bytedance.com/api/v3/tts/unidirectional`
21
+
22
+ ## 当前接口先验
23
+
24
+ 写作时可用的资源是 `seed-icl-2.0`,地址是 `POST https://openspeech.bytedance.com/api/v3/tts/unidirectional`。真正调用以 `~/.dwy/config.yaml` 的 `resource_id` 和 `endpoint` 为准。返回 4xx、模型下线或连不上时,查火山引擎控制台当前文档和账号已开通资源,换可用地址和资源 ID。不要把查到的新地址写回本 skill。结束码 `20000000`、`speech_rate` / `loudness_rate` 的 `[-50,100]` 只属于这条先验接口,换接口后以新文档为准。
23
25
 
24
26
  ## 全局配置约定(`~/.dwy/config.yaml`)
25
27
 
@@ -1,6 +1,6 @@
1
1
  # 豆包单向流式 TTS(HTTP Chunked)摘要
2
2
 
3
- 权威字段以火山引擎控制台文档为准。实现以 `scripts/synthesize.py` 为准。
3
+ 权威字段以火山引擎控制台文档为准。实现以 `scripts/synthesize.py` 为准。下面的地址、`seed-icl-2.0`、结束码和取值范围是当前先验。调用失败或模型下线就换控制台当前文档,不要把新地址写回本文件。
4
4
 
5
5
  ## 配置
6
6
 
@@ -206,6 +206,7 @@ def synthesize(
206
206
  timeout: int,
207
207
  ) -> dict[str, Any]:
208
208
  """发单向流式请求,拼接 base64 音频并落盘。"""
209
+ # 配置缺字段时才用当前先验。4xx 或模型下线不要死磕这两条,改查火山控制台文档。
209
210
  endpoint = cfg.get("endpoint") or "https://openspeech.bytedance.com/api/v3/tts/unidirectional"
210
211
  resource_id = cfg.get("resource_id") or "seed-icl-2.0"
211
212
  speaker = speaker_id(cfg, voice_key)
@@ -35,13 +35,15 @@ description: |
35
35
 
36
36
  ## 平台文案规则
37
37
 
38
+ 字数上限和标签分隔符是各平台当前发布页的先验。交付前以该平台此刻的输入限制为准。页面改了上限或分隔符,按页面改文案。不要用 20、16 或英文逗号把一份文案判失败,也不要把新上限写回本文件。
39
+
38
40
  | 平台 | 标题策略 | 简介与标签 |
39
41
  |---|---|---|
40
42
  | B站 | 主题 + 明确收益;长度不强行压缩 | 用开场问题、内容范围、一个边界或收获;4–7 个 `#标签` |
41
- | YouTube | 主题 + 明确收益;长度不强行压缩 | 用开场问题、内容范围、一个边界或收获;标签字段使用多个关键词,并以**英文逗号**分隔,例如 `AI education, large language models, Transformer` |
43
+ | YouTube | 主题 + 明确收益;长度不强行压缩 | 用开场问题、内容范围、一个边界或收获;标签字段当前先验是不用 `#`、多个关键词用英文逗号分隔,例如 `AI education, large language models, Transformer` |
42
44
  | 抖音 | 问题或反常识钩子优先 | 1–2 句,强调观看收益;3–6 个标签 |
43
- | 小红书 | **必须不超过 20 个汉字(标点计入)**;先写“小白也能懂”或直接收益 | 2–4 句,口语、可保存;5–8 个标签 |
44
- | 微信视频号 | **必须不超过 16 个字符(中文、英文、数字与标点均计入)**;优先“人群 + 主题/收益” | 1–2 句,直接说明看完能获得什么;3–5 个标签 |
45
+ | 小红书 | 当前上限先验:20 个汉字(标点计入)。先写“小白也能懂”或直接收益 | 2–4 句,口语、可保存;5–8 个标签 |
46
+ | 微信视频号 | 当前上限先验:16 个字符(中文、英文、数字与标点均计入)。优先“人群 + 主题/收益” | 1–2 句,直接说明看完能获得什么;3–5 个标签 |
45
47
 
46
48
  避免“保姆级”“秒变专家”“全网最全”等空泛承诺。标题、封面主字和简介可以分工,不能机械重复。
47
49
 
@@ -118,8 +120,8 @@ description: |
118
120
 
119
121
  ## 交付前检查
120
122
 
121
- - [ ] 小红书标题 ≤20 字。
122
- - [ ] 微信视频号标题 ≤16 字(标点计入)。
123
+ - [ ] 小红书标题不超过该平台当前标题上限。页面上读不到限制时,用先验 20 字(标点计入)。
124
+ - [ ] 微信视频号标题不超过该平台当前标题上限。页面上读不到限制时,用先验 16 字(标点计入)。
123
125
  - [ ] 每个封面只含一个主标题,且与缩略图尺寸匹配。
124
126
  - [ ] 16:9、4:3、3:4 是独立构图,不是同图硬裁。
125
127
  - [ ] 已核对并报告每张图片的像素比例与保存路径。
@@ -1,8 +1,10 @@
1
1
  # 平台文案示例
2
2
 
3
+ 字数和标签分隔符跟 `SKILL.md` 一样,是当前发布页的先验。页面限制变了,以页面为准。
4
+
3
5
  ## 小红书标题长度
4
6
 
5
- 计算 Unicode 字符数,标点也计入。上限 20。
7
+ 计算 Unicode 字符数,标点也计入。当前上限先验 20。
6
8
 
7
9
  | 合格示例 | 字符数 |
8
10
  |---|---:|
@@ -11,7 +13,7 @@
11
13
 
12
14
  ## 微信视频号标题长度
13
15
 
14
- 计算 Unicode 字符数,中文、英文、数字和标点均计入;上限 16。
16
+ 计算 Unicode 字符数,中文、英文、数字和标点均计入。当前上限先验 16。
15
17
 
16
18
  | 合格示例 | 字符数 |
17
19
  |---|---:|
@@ -20,7 +22,7 @@
20
22
 
21
23
  ## YouTube 标签格式
22
24
 
23
- YouTube 的标签字段不使用 `#`,多个标签必须用英文逗号分隔:
25
+ YouTube 标签字段的当前先验:不用 `#`,多个标签用英文逗号分隔。发布页改了分隔符就跟页面走:
24
26
 
25
27
  ```text
26
28
  AI education, large language models, Transformer, generative AI