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
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# create-dwy
|
|
2
2
|
|
|
3
|
+
## 0.16.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- `dwy` 开头自动检测更新全局外部 skill:未装 / 清单变更(cli 加了 skill 或改了 tag)才联网重装,已装且清单一致零开销;失败不阻塞 sync。用户无需再另记 `dwy skills install`。
|
|
8
|
+
- 新增 `dwy-commercial` 商业分析 skill(立项阶段 validate 之后、poc 之前):商业模式 / 变现路径 / 定价 / 单位经济(CAC/LTV/毛利/回本)/ GTM 获客 + 商业可行性结论;startup 模式为硬闸门、builder 模式跳过。包装 pm-skills 的 `business-model` / `monetization-strategy` / `pricing-strategy` / `startup-canvas` / `porters-five-forces` + `gtm-strategy`。
|
|
9
|
+
- `dwy skills install` 降级为隐藏的强制刷新兜底(向后兼容保留,日常无需手动);`printHelp` 只露 `dwy` 主入口,`dwy sync` 为别名。
|
|
10
|
+
|
|
11
|
+
## 0.15.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- 新增「产品 0→1」三层 skill 体系(总控 `dwy-product-launcher` + 5 个可独立触发的阶段 skill + 13 个产出物级原子 skill):从模糊想法渐进式推进到上线产品,立项阶段三道闸门(需求市场验证为总闸门 → 技术 POC → MVP≤7),廉价验证在前、昂贵投入在后。
|
|
16
|
+
- 新增 `dwy skills install` 命令:把 pm-skills / superpowers 的外部 skill 安装到全局 `~/.dwy/skills/`(一台机一份、全项目共享),含完整 `scripts/` 与 LICENSE;再次运行即覆盖更新。`dwy claude sync` 选中相关 skill 时自动自检安装。
|
|
17
|
+
- 外部 skill 进全局纯数据目录而非 `.claude/skills/`,避免被工具当 skill 加载、与 `dwy-*` 触发冲突。
|
|
18
|
+
- 改造 `dwy-whiteboard-prototype`:配色按产品定位推荐(保留 `:root` 语义变量结构)、尺寸按目标端推荐、图标不再用 emoji。
|
|
19
|
+
|
|
3
20
|
## 0.14.7
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
package/bin/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { readFileSync } from 'fs'
|
|
|
4
4
|
import { fileURLToPath } from 'url'
|
|
5
5
|
import { dirname, resolve } from 'path'
|
|
6
6
|
import { syncAll } from '../src/sync-all.js'
|
|
7
|
+
import { installSkills } from '../src/skills-install.js'
|
|
7
8
|
|
|
8
9
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
9
10
|
const pkg = JSON.parse(readFileSync(resolve(__dirname, '..', 'package.json'), 'utf-8'))
|
|
@@ -14,13 +15,16 @@ function printHelp() {
|
|
|
14
15
|
`dwy ${pkg.version}`,
|
|
15
16
|
'',
|
|
16
17
|
'Usage:',
|
|
17
|
-
' dwy
|
|
18
|
-
' dwy sync 运行交互式同步',
|
|
18
|
+
' dwy 运行交互式同步(自动更新全局外部 skill)',
|
|
19
19
|
' dwy --help 显示本说明',
|
|
20
20
|
' dwy -h 显示本说明',
|
|
21
21
|
' dwy --version 显示当前版本',
|
|
22
22
|
' dwy -V 显示当前版本',
|
|
23
23
|
'',
|
|
24
|
+
'以下为隐藏命令(向后兼容保留,日常无需手动调用):',
|
|
25
|
+
' dwy sync 同上的别名',
|
|
26
|
+
' dwy skills install 强制刷新全局外部 skill',
|
|
27
|
+
'',
|
|
24
28
|
]
|
|
25
29
|
console.log(lines.join('\n'))
|
|
26
30
|
}
|
|
@@ -29,6 +33,8 @@ if (argv.includes('--help') || argv.includes('-h') || argv[0] === 'help') {
|
|
|
29
33
|
printHelp()
|
|
30
34
|
} else if (argv.includes('--version') || argv.includes('-V')) {
|
|
31
35
|
console.log(pkg.version)
|
|
36
|
+
} else if (argv[0] === 'skills' && argv[1] === 'install') {
|
|
37
|
+
await installSkills()
|
|
32
38
|
} else if (argv.length === 0 || argv[0] === 'sync') {
|
|
33
39
|
await syncAll()
|
|
34
40
|
} else {
|
package/package.json
CHANGED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import fs from 'fs-extra'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import os from 'node:os'
|
|
4
|
+
import { createHash } from 'node:crypto'
|
|
5
|
+
import { getDwyHomeDir, runGit, chalk } from './utils.js'
|
|
6
|
+
|
|
7
|
+
function logAction(label) {
|
|
8
|
+
console.log(chalk.green(` ✓ ${label}`))
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// 产品 0→1 流程依赖的外部 skill 清单。
|
|
12
|
+
// 每项:缓存目录名(= 原子 skill 引用的 ~/.dwy/skills/<name>)→ 来源 repo / stable tag / repo 内目录。
|
|
13
|
+
// 只用正式 release tag,不用 main HEAD(定版可复现)。更新版本时改这里的 tag。
|
|
14
|
+
const SKILL_SOURCES = {
|
|
15
|
+
'pm-skills': {
|
|
16
|
+
repo: 'https://github.com/phuryn/pm-skills.git',
|
|
17
|
+
tag: 'v2.0.0',
|
|
18
|
+
licenseFile: 'LICENSE',
|
|
19
|
+
licenseDest: 'LICENSE-pm-skills',
|
|
20
|
+
skills: {
|
|
21
|
+
'competitor-analysis': 'pm-market-research/skills/competitor-analysis',
|
|
22
|
+
'market-sizing': 'pm-market-research/skills/market-sizing',
|
|
23
|
+
'sentiment-analysis': 'pm-market-research/skills/sentiment-analysis',
|
|
24
|
+
'interview-script': 'pm-product-discovery/skills/interview-script',
|
|
25
|
+
'prioritize-features': 'pm-product-discovery/skills/prioritize-features',
|
|
26
|
+
'opportunity-solution-tree': 'pm-product-discovery/skills/opportunity-solution-tree',
|
|
27
|
+
'metrics-dashboard': 'pm-product-discovery/skills/metrics-dashboard',
|
|
28
|
+
'create-prd': 'pm-execution/skills/create-prd',
|
|
29
|
+
'outcome-roadmap': 'pm-execution/skills/outcome-roadmap',
|
|
30
|
+
'test-scenarios': 'pm-execution/skills/test-scenarios',
|
|
31
|
+
'release-notes': 'pm-execution/skills/release-notes',
|
|
32
|
+
'gtm-strategy': 'pm-go-to-market/skills/gtm-strategy',
|
|
33
|
+
// 商业分析(dwy-commercial 依赖):商业模式 / 变现 / 定价 / 创业画布 / 赛道五力
|
|
34
|
+
'business-model': 'pm-product-strategy/skills/business-model',
|
|
35
|
+
'monetization-strategy': 'pm-product-strategy/skills/monetization-strategy',
|
|
36
|
+
'pricing-strategy': 'pm-product-strategy/skills/pricing-strategy',
|
|
37
|
+
'startup-canvas': 'pm-product-strategy/skills/startup-canvas',
|
|
38
|
+
'porters-five-forces': 'pm-product-strategy/skills/porters-five-forces',
|
|
39
|
+
'intended-vs-implemented': 'pm-ai-shipping/skills/intended-vs-implemented',
|
|
40
|
+
'north-star-metric': 'pm-marketing-growth/skills/north-star-metric',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
superpowers: {
|
|
44
|
+
repo: 'https://github.com/obra/superpowers.git',
|
|
45
|
+
tag: 'v6.0.3',
|
|
46
|
+
licenseFile: 'LICENSE',
|
|
47
|
+
licenseDest: 'LICENSE-superpowers',
|
|
48
|
+
skills: {
|
|
49
|
+
brainstorming: 'skills/brainstorming',
|
|
50
|
+
'writing-plans': 'skills/writing-plans',
|
|
51
|
+
'test-driven-development': 'skills/test-driven-development',
|
|
52
|
+
'systematic-debugging': 'skills/systematic-debugging',
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 计算 SKILL_SOURCES 清单的内容指纹,用于检测「cli 加了 skill / 改了 tag」→ 需重装。
|
|
58
|
+
// SKILL_SOURCES 是源码内固定字面量,JSON.stringify 稳定(插入顺序固定)。
|
|
59
|
+
// 取 sha256 前 12 位,足以区分任意清单变更,无碰撞风险。
|
|
60
|
+
function computeManifestHash() {
|
|
61
|
+
return createHash('sha256').update(JSON.stringify(SKILL_SOURCES)).digest('hex').slice(0, 12)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 全局外部 skill 安装目录:~/.dwy/skills/
|
|
65
|
+
function getGlobalSkillsDir() {
|
|
66
|
+
return path.join(getDwyHomeDir(), 'skills')
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 浅克隆指定 tag 到临时目录(--depth 1 + --branch <tag> 只取定版,省带宽)。
|
|
70
|
+
async function shallowCloneTag(repoUrl, tag, destDir) {
|
|
71
|
+
await runGit(['clone', '--depth', '1', '--branch', tag, repoUrl, destDir])
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// 安装/更新全部外部 skill 到 ~/.dwy/skills/。再次运行即覆盖式更新。
|
|
75
|
+
export async function installSkills() {
|
|
76
|
+
const targetDir = getGlobalSkillsDir()
|
|
77
|
+
await fs.ensureDir(targetDir)
|
|
78
|
+
|
|
79
|
+
const tmpRoot = path.join(os.tmpdir(), `dwy-skills-${process.pid}`)
|
|
80
|
+
await fs.ensureDir(tmpRoot)
|
|
81
|
+
|
|
82
|
+
const versions = {}
|
|
83
|
+
try {
|
|
84
|
+
for (const [sourceName, src] of Object.entries(SKILL_SOURCES)) {
|
|
85
|
+
console.log(chalk.gray(`拉取 ${sourceName} @ ${src.tag} ...`))
|
|
86
|
+
const repoDir = path.join(tmpRoot, sourceName)
|
|
87
|
+
await shallowCloneTag(src.repo, src.tag, repoDir)
|
|
88
|
+
|
|
89
|
+
// 搬 LICENSE(MIT 要求保留原版权声明)
|
|
90
|
+
const licenseSrc = path.join(repoDir, src.licenseFile)
|
|
91
|
+
if (await fs.pathExists(licenseSrc)) {
|
|
92
|
+
await fs.copy(licenseSrc, path.join(targetDir, src.licenseDest), { overwrite: true })
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 搬每个 skill 整目录(含 scripts/、配套 .md)
|
|
96
|
+
for (const [skillName, repoPath] of Object.entries(src.skills)) {
|
|
97
|
+
const from = path.join(repoDir, repoPath)
|
|
98
|
+
const to = path.join(targetDir, skillName)
|
|
99
|
+
if (!await fs.pathExists(from)) {
|
|
100
|
+
throw new Error(`${sourceName} @ ${src.tag} 内未找到 ${repoPath}(仓库结构可能变了)`)
|
|
101
|
+
}
|
|
102
|
+
await fs.remove(to)
|
|
103
|
+
await fs.copy(from, to, { overwrite: true })
|
|
104
|
+
logAction(`skills/${skillName}`)
|
|
105
|
+
versions[skillName] = { repo: src.repo, tag: src.tag }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 写版本清单 + 清单指纹,供查看与后续更新比对。
|
|
110
|
+
// manifest_hash 变化(cli 加了 skill / 改了 tag)→ 下次 ensureSkillsInstalled 触发重装。
|
|
111
|
+
await fs.writeJson(
|
|
112
|
+
path.join(targetDir, 'VERSIONS.json'),
|
|
113
|
+
{ manifest_hash: computeManifestHash(), versions },
|
|
114
|
+
{ spaces: 2 },
|
|
115
|
+
)
|
|
116
|
+
console.log(chalk.green(`\n✓ 外部 skill 已安装到 ${targetDir}`))
|
|
117
|
+
} finally {
|
|
118
|
+
await fs.remove(tmpRoot)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 全局 skill 是否已就绪(VERSIONS.json 存在)。
|
|
123
|
+
export async function skillsInstalled() {
|
|
124
|
+
return fs.pathExists(path.join(getGlobalSkillsDir(), 'VERSIONS.json'))
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 确保 ~/.dwy/skills/ 与 cli 当前 SKILL_SOURCES 清单一致:未装 / 清单变更 → 自动重装。
|
|
128
|
+
// hash 一致 → 零开销跳过;失败 → warn 一行不阻塞主流程(离线/网络故障不挡 sync)。
|
|
129
|
+
// 返回 true = 本次执行了安装,false = 跳过。
|
|
130
|
+
export async function ensureSkillsInstalled() {
|
|
131
|
+
const versionsFile = path.join(getGlobalSkillsDir(), 'VERSIONS.json')
|
|
132
|
+
// 已装:读 manifest_hash 比对,一致即跳过,不联网
|
|
133
|
+
if (await fs.pathExists(versionsFile)) {
|
|
134
|
+
let stored
|
|
135
|
+
try {
|
|
136
|
+
stored = await fs.readJson(versionsFile)
|
|
137
|
+
} catch {
|
|
138
|
+
stored = {}
|
|
139
|
+
}
|
|
140
|
+
// 兼容老格式(无 manifest_hash)→ 视为不一致,触发一次重装补上指纹
|
|
141
|
+
if (stored.manifest_hash === computeManifestHash()) return false
|
|
142
|
+
console.log(chalk.gray('全局外部 skill 清单已更新,重新拉取...'))
|
|
143
|
+
} else {
|
|
144
|
+
console.log(chalk.gray('未检测到全局外部 skill,自动安装...'))
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
await installSkills()
|
|
148
|
+
return true
|
|
149
|
+
} catch (error) {
|
|
150
|
+
// 离线/网络故障:不阻塞主流程,下次再来
|
|
151
|
+
console.log(chalk.yellow(`外部 skill 自动更新失败:${error.message}`))
|
|
152
|
+
return false
|
|
153
|
+
}
|
|
154
|
+
}
|
package/src/sync-all.js
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
} from './sync-codex.js'
|
|
25
25
|
import { scanExistingCursorRules, syncCursor } from './sync-cursor.js'
|
|
26
26
|
import { syncOpenCode } from './sync-opencode.js'
|
|
27
|
+
import { ensureSkillsInstalled } from './skills-install.js'
|
|
27
28
|
|
|
28
29
|
const PLATFORM_OPTIONS = [
|
|
29
30
|
{ value: 'claude', label: 'Claude Code', hint: '支持 rules / skills / commands / hooks' },
|
|
@@ -559,6 +560,12 @@ export async function syncAll({
|
|
|
559
560
|
|
|
560
561
|
const projectDir = projectDirOverride || process.cwd()
|
|
561
562
|
|
|
563
|
+
// 开头无条件自检全局外部 skill:未装 / 清单变更(cli 加了 skill 或改了 tag)则自动更新,
|
|
564
|
+
// 已装且清单一致则零开销跳过。失败不阻塞 sync(离线/网络故障,下次再来)。
|
|
565
|
+
// 这样用户跑一次 `dwy` 就把 skill 更新到位,无需另记 `dwy skills install`。
|
|
566
|
+
console.log(chalk.gray('检查全局外部 skill 更新...'))
|
|
567
|
+
await ensureSkillsInstalled()
|
|
568
|
+
|
|
562
569
|
console.log(chalk.blue('\nScanning available Claude Code/Codex configuration...\n'))
|
|
563
570
|
const scans = {
|
|
564
571
|
skills: await scanSkills(sourceDir),
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
## 团队执行任务
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
任务执行前必须先分析 block;无 block 的任务使用多 Agent 并行执行以提高效率。
|
|
12
12
|
|
|
13
13
|
## 代码注释
|
|
14
14
|
|
|
@@ -54,6 +54,21 @@
|
|
|
54
54
|
- 如果你写了 200 行但可以写成 50 行,重写它。
|
|
55
55
|
- 问自己:"一个资深工程师会说这过于复杂吗?"如果是,简化。
|
|
56
56
|
|
|
57
|
+
### 写代码前走决策阶梯
|
|
58
|
+
|
|
59
|
+
写任何新代码前,从上往下逐级问,命中即停:
|
|
60
|
+
|
|
61
|
+
1. 这任务真需要存在吗?(YAGNI——能不做就不做)
|
|
62
|
+
2. 代码库里已有现成的吗?
|
|
63
|
+
3. 标准库覆盖吗?
|
|
64
|
+
4. 平台 / 框架原生特性有吗?
|
|
65
|
+
5. 已安装的依赖能做吗?
|
|
66
|
+
6. 能一行解决吗?
|
|
67
|
+
7. 以上都不行 → 才写最小代码。
|
|
68
|
+
|
|
69
|
+
刻意的简化用注释标注:跳过了什么、何时该加回。
|
|
70
|
+
红线——以下永不简化掉:输入校验、错误处理、安全、可访问性。先理解问题,再谈优化。
|
|
71
|
+
|
|
57
72
|
### 3. 精准改动
|
|
58
73
|
|
|
59
74
|
只动必须动的代码。只清理自己造成的混乱。
|
|
@@ -181,3 +196,15 @@
|
|
|
181
196
|
- 后端用 dict / map / any 接收 body
|
|
182
197
|
- 分页 `page_size` 无上限
|
|
183
198
|
- 图片只校验文件大小不校验像素
|
|
199
|
+
|
|
200
|
+
## 自成长项目规则(project-rules)
|
|
201
|
+
|
|
202
|
+
写项目要自成长:同一类问题反复踩坑,主动沉淀成可复用规则,下次自动生效,不靠人事后总结。
|
|
203
|
+
|
|
204
|
+
- **触发**:写代码 / 排查问题时,同一类问题踩坑 **≥2 次**(重复的报错根因、踩同一个坑、被反复纠正同一处写法)。
|
|
205
|
+
- **动作**:把教训沉淀成一条可复用规则(写清「现象 / 根因 / 怎么避免」),追加到 `project-rules.md`;已有同类规则补充进去,不重复立条。
|
|
206
|
+
- **落盘位置**(按当前工具自动选):
|
|
207
|
+
- **Claude Code** → 项目 `.claude/rules/project-rules.md`(放进去即自动加载,无需注册)。
|
|
208
|
+
- **Codex** → 项目根 `AGENTS.md`,写在 `<!-- DWY-RULES:START/END -->` 托管块**之外**的 `## [自成长] 项目规则` 节下。托管块内会被 `dwy codex sync` 整块覆盖,自成长内容**必落块外**。
|
|
209
|
+
- **方式**:自动沉淀,事后输出一行告知「已沉淀 <规则> 到 project-rules」,不打断当前任务、不逐条问用户。
|
|
210
|
+
- **边界**:只沉淀**可复用、跨任务**的教训;一次性 / 本任务特有的问题不立规则,避免噪音堆积。
|
|
@@ -37,8 +37,16 @@ PATTERNS=(
|
|
|
37
37
|
# 拼接为正则
|
|
38
38
|
REGEX=$(IFS='|'; echo "${PATTERNS[*]}")
|
|
39
39
|
|
|
40
|
-
#
|
|
41
|
-
|
|
40
|
+
# 只扫「新增行」(+ 开头,排除 +++ 文件头),删除的代码不可能是正在引入的凭证。
|
|
41
|
+
# 跳过文档/规则类文件(.md/.mdc/规则/hook 本身)——它们写的是「如何检测凭证」的模式说明,非真凭证。
|
|
42
|
+
SCAN_FILES=$(printf '%s\n' "$STAGED" | grep -viE '\.(md|mdc|txt)$|rules/|/hooks/|sensitive-check')
|
|
43
|
+
RESULT=""
|
|
44
|
+
for f in $SCAN_FILES; do
|
|
45
|
+
HIT=$(git diff --cached -U0 -- "$f" 2>/dev/null \
|
|
46
|
+
| grep -E '^\+' | grep -vE '^\+\+\+' \
|
|
47
|
+
| grep -inE "$REGEX" 2>/dev/null)
|
|
48
|
+
[ -n "$HIT" ] && RESULT="${RESULT}${f}:\n${HIT}\n"
|
|
49
|
+
done
|
|
42
50
|
|
|
43
51
|
if [ -n "$RESULT" ]; then
|
|
44
52
|
echo "========================================"
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Android 开发避坑清单(Gradle / 签名 / Compose / 生命周期 / 真机部署踩坑),按分类持续追加
|
|
3
|
+
paths:
|
|
4
|
+
- "**/*.java"
|
|
5
|
+
- "**/*.kt"
|
|
6
|
+
- "**/*.kts"
|
|
7
|
+
- "**/*.gradle"
|
|
8
|
+
- "**/AndroidManifest.xml"
|
|
9
|
+
- "**/res/**/*.xml"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Android 开发坑清单
|
|
13
|
+
|
|
14
|
+
> 动手前先对照本清单避开已知坑;踩到新坑随手按四栏格式(现象 / 根因 / 正确做法 / 适用)追加到对应分类,没有合适分类就新建一个。
|
|
15
|
+
>
|
|
16
|
+
> 通用开发规范见 `dwy-android-core` rule,本文件只记**非显而易见的实战坑**。
|
|
17
|
+
|
|
18
|
+
## 分类索引
|
|
19
|
+
|
|
20
|
+
- 工程与构建(Gradle / AGP / 依赖冲突)
|
|
21
|
+
- 签名与真机部署
|
|
22
|
+
- Compose / UI(重组、状态、生命周期)
|
|
23
|
+
- 生命周期 / 并发(协程、ViewModel、内存泄漏)
|
|
24
|
+
- 权限 / Manifest / Capability
|
|
25
|
+
- 排查方法论
|
|
26
|
+
- 其他分类遇到再加
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 工程与构建
|
|
31
|
+
|
|
32
|
+
<!-- 待填:踩到坑按四栏格式追加 -->
|
|
33
|
+
|
|
34
|
+
## 签名与真机部署
|
|
35
|
+
|
|
36
|
+
<!-- 待填 -->
|
|
37
|
+
|
|
38
|
+
## Compose / UI
|
|
39
|
+
|
|
40
|
+
<!-- 待填 -->
|
|
41
|
+
|
|
42
|
+
## 生命周期 / 并发
|
|
43
|
+
|
|
44
|
+
<!-- 待填 -->
|
|
45
|
+
|
|
46
|
+
## 权限 / Manifest / Capability
|
|
47
|
+
|
|
48
|
+
<!-- 待填 -->
|
|
49
|
+
|
|
50
|
+
## 排查方法论
|
|
51
|
+
|
|
52
|
+
<!-- 待填 -->
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: HarmonyOS ArkTS 严格性避坑(相对 TS/JS 的禁用语法,编译期 arkts-no-* 报错)
|
|
3
|
+
paths:
|
|
4
|
+
- "**/*.ets"
|
|
5
|
+
- "**/*.ts"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# ArkTS 严格性避坑
|
|
9
|
+
|
|
10
|
+
ArkTS 是 TypeScript 的**受限子集**,禁掉大量 TS/JS 动态写法以换取性能与静态可分析性。
|
|
11
|
+
从 TS/JS(尤其 iOS/前端转鸿蒙)照搬代码必触发 `arkts-no-*` 编译错误。
|
|
12
|
+
**写 `.ets` 前先过一遍本清单**,别用下面列出的禁用写法。每条配真实报错码 + 错误/正确写法。
|
|
13
|
+
|
|
14
|
+
## 1. 禁止解构声明与解构赋值(arkts-no-destruct-decls / arkts-no-destruct-assignment)
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
// 错:解构声明
|
|
18
|
+
let [oldR, r] = [a % m, m];
|
|
19
|
+
// 错:解构赋值
|
|
20
|
+
[oldR, r] = [r, oldR - q * r];
|
|
21
|
+
const { value, next } = readVarint(bytes, i);
|
|
22
|
+
|
|
23
|
+
// 对:拆成单变量 + 临时变量交换
|
|
24
|
+
let oldR = a % m;
|
|
25
|
+
let r = m;
|
|
26
|
+
const tmpR = oldR - q * r;
|
|
27
|
+
oldR = r;
|
|
28
|
+
r = tmpR;
|
|
29
|
+
const res = readVarint(bytes, i);
|
|
30
|
+
const value = res.value;
|
|
31
|
+
const next = res.next;
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 2. 对象字面量必须对应显式 class/interface(arkts-no-untyped-obj-literals / arkts-no-obj-literals-as-types)
|
|
35
|
+
|
|
36
|
+
ArkTS 不允许「匿名对象字面量当类型」,也不允许「无类型标注的对象字面量」。
|
|
37
|
+
**两种触发场景都要先声明 interface**:
|
|
38
|
+
|
|
39
|
+
### 2.1 函数返回类型不能写匿名对象
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
// 错:返回类型是匿名对象字面量
|
|
43
|
+
private static readVarint(bytes: Uint8Array, i: number): { value: number; next: number } { ... }
|
|
44
|
+
|
|
45
|
+
// 对:先声明 interface
|
|
46
|
+
interface VarintResult {
|
|
47
|
+
value: number;
|
|
48
|
+
next: number;
|
|
49
|
+
}
|
|
50
|
+
private static readVarint(bytes: Uint8Array, i: number): VarintResult { ... }
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 2.2 返回 / 赋值的对象字面量必须有类型来源
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// 错:裸对象字面量(编译器无法对应到具体类型)
|
|
57
|
+
return { command: c, arg0: a, arg1: b, dataLength: d };
|
|
58
|
+
const out = { header, payload: payload.slice() };
|
|
59
|
+
|
|
60
|
+
// 对:显式标注类型(interface 已声明)
|
|
61
|
+
const header: AdbHeader = { command: c, arg0: a, arg1: b, dataLength: d };
|
|
62
|
+
return header;
|
|
63
|
+
const out: AdbMessageResult = { header, payload: payload.slice() };
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 2.3 给 SDK API 传对象参数也要带类型
|
|
67
|
+
|
|
68
|
+
SDK(@ohos.net.socket / cryptoFramework 等)的参数即使是已声明类型,裸字面量仍报错,
|
|
69
|
+
必须用「声明类型的变量」传入:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
// 错:裸字面量传参
|
|
73
|
+
await tcp.connect({ address: { address: host, port: 5555, family: 1 }, timeout: 15000 });
|
|
74
|
+
await tcp.send({ data: buf });
|
|
75
|
+
const out = await signer.sign({ data: token });
|
|
76
|
+
|
|
77
|
+
// 对:拆成带 SDK 类型标注的变量
|
|
78
|
+
const netAddr: socket.NetAddress = { address: host, port: 5555, family: 1 };
|
|
79
|
+
const opts: socket.TCPConnectOptions = { address: netAddr, timeout: 15000 };
|
|
80
|
+
await tcp.connect(opts);
|
|
81
|
+
|
|
82
|
+
const sendOpts: socket.TCPSendOptions = { data: buf };
|
|
83
|
+
await tcp.send(sendOpts);
|
|
84
|
+
|
|
85
|
+
const input: cryptoFramework.DataBlob = { data: token };
|
|
86
|
+
const out = await signer.sign(input);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## 3. 禁止用下标访问 string 取字符(arkts-no-props-by-index)
|
|
90
|
+
|
|
91
|
+
string 不能 `s[i]` 取字符(被判为「字段索引访问」)。用 `charAt`:
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
// 错
|
|
95
|
+
const table = 'ABCD...';
|
|
96
|
+
out += table[(n >> 18) & 63];
|
|
97
|
+
|
|
98
|
+
// 对
|
|
99
|
+
out += table.charAt((n >> 18) & 63);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
> 注意:`Uint8Array[i]` / `Array[i]` 下标访问是允许的,只有 **string 下标取字符** 被禁。
|
|
103
|
+
|
|
104
|
+
## 4. 禁止 String() / Number() / Boolean() 当转换函数调用
|
|
105
|
+
|
|
106
|
+
ArkTS 禁止把内置构造器当函数转换值。catch 错误转文案、数字转字符串都要换写法:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
// 错
|
|
110
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
111
|
+
const s = String(num);
|
|
112
|
+
|
|
113
|
+
// 对:catch 变量在 ArkTS 里就是 Error(含 BusinessError extends Error),直接取 message
|
|
114
|
+
function errMsg(e: Error): string {
|
|
115
|
+
return e.message;
|
|
116
|
+
}
|
|
117
|
+
// 数字转字符串用 .toString() 或模板串
|
|
118
|
+
const s = num.toString();
|
|
119
|
+
const s2 = `${num}`;
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## 5. Promise executor / 回调形参类型:简单形参标,executor 的 resolve/reject 不标
|
|
123
|
+
|
|
124
|
+
箭头函数当回调,形参不能省类型;executor 里别把函数直接当回调透传:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// 错:resolve 无类型 + 直接把 resolve 透传给 setTimeout
|
|
128
|
+
return new Promise<void>((resolve) => setTimeout(resolve, ms));
|
|
129
|
+
|
|
130
|
+
// 对:形参标类型 + 包一层箭头
|
|
131
|
+
return new Promise<void>((resolve: () => void) => {
|
|
132
|
+
setTimeout(() => {
|
|
133
|
+
resolve();
|
|
134
|
+
}, ms);
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**⚠️ 例外(实测踩坑):给 `Promise` executor 的 resolve/reject 标注「函数类型」反而触发
|
|
139
|
+
`arkts-no-structural-typing`**。executor 的两个形参类型由 `Promise<T>` 自身约束,显式标
|
|
140
|
+
`(reject: (e: Error) => void)` 会与 SDK 内置的 reject 签名做结构比对而报错。这种情况**去掉
|
|
141
|
+
executor 形参的类型注解,让 ArkTS 推断**(reject 内部传 `Error` 子类实例完全正常):
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
// 错:executor 形参标函数类型 → arkts-no-structural-typing
|
|
145
|
+
return new Promise<Uint8Array>(
|
|
146
|
+
(resolve: (v: Uint8Array) => void, reject: (e: Error) => void) => { ... });
|
|
147
|
+
|
|
148
|
+
// 对:executor 形参不标,推断
|
|
149
|
+
return new Promise<Uint8Array>((resolve, reject) => {
|
|
150
|
+
reject(new MyError(...)); // MyError extends Error,正常
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
判据:**普通回调(如自己定义的 `onError: (e: Error) => void`)形参要标;`new Promise(...)`
|
|
155
|
+
的 executor 形参不标**。另:跨文件传回调时,形参类型用基类(`Error`)而非具体子类
|
|
156
|
+
(`MyGrpcError`),避免「子类型 lambda 赋给基类形参」触发同一规则。
|
|
157
|
+
|
|
158
|
+
## 6. 页面路由路径不带 `ets/` 前缀
|
|
159
|
+
|
|
160
|
+
`main_pages.json` 的 `src` 与 `windowStage.loadContent(...)` 的路径都相对 `src/main/ets/` 根,
|
|
161
|
+
**不要带 `ets/` 前缀**,否则编译报 `Page '.../ets/ets/xxx' does not exist`:
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
// 错:resources/base/profile/main_pages.json
|
|
165
|
+
{ "src": ["ets/spike/SpikePage"] }
|
|
166
|
+
// 对
|
|
167
|
+
{ "src": ["spike/SpikePage"] }
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
// 错
|
|
172
|
+
windowStage.loadContent('ets/spike/SpikePage', cb);
|
|
173
|
+
// 对
|
|
174
|
+
windowStage.loadContent('spike/SpikePage', cb);
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## 7. 大整数运算用原生 bigint(无需第三方库)
|
|
178
|
+
|
|
179
|
+
ArkTS 原生支持 ES11 `bigint`(`10n` / `BigInt(x)` / `<< >> % & | ** /`)。
|
|
180
|
+
但无 `.inverse(m)` / `.power(_,modulus:)` / `.serialize()` 这类方法(那是 Swift BigInt 库的),
|
|
181
|
+
模逆/模幂/序列化要**手写**:
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// 模幂(快速幂)
|
|
185
|
+
function modPow(base: bigint, exp: bigint, m: bigint): bigint {
|
|
186
|
+
let result = 1n;
|
|
187
|
+
let b = base % m;
|
|
188
|
+
let e = exp;
|
|
189
|
+
while (e > 0n) {
|
|
190
|
+
if ((e & 1n) === 1n) { result = (result * b) % m; }
|
|
191
|
+
e >>= 1n;
|
|
192
|
+
b = (b * b) % m;
|
|
193
|
+
}
|
|
194
|
+
return result;
|
|
195
|
+
}
|
|
196
|
+
// 模逆(扩展欧几里得,见本仓鸿蒙工程 AndroidPubkey.ets)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## 8. 自检清单(写完 .ets 提交前 grep 一遍)
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
grep -rn 'let \[\|const \[' . # 解构声明
|
|
203
|
+
grep -rn '): {' . # 匿名对象当返回类型
|
|
204
|
+
grep -rn 'return {' . # 裸对象字面量返回(确认有类型标注)
|
|
205
|
+
grep -rn 'String(\|Number(\|Boolean(' . # 构造器当转换函数(排除 String.fromCharCode)
|
|
206
|
+
grep -rn 'new Promise<.*>((.*:.*=>' . # executor 形参标了函数类型(见 §5 例外,应去注解)
|
|
207
|
+
# string 下标取字符需人工核对(table[i] 形式)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## 9. 仍需真机/真实 SDK 确认的(编译期过不代表运行对)
|
|
211
|
+
|
|
212
|
+
ArkTS 编译通过只保证语法合规;以下 SDK 行为编译期无法验证,需真机/模拟器实测:
|
|
213
|
+
- cryptoFramework 的 `createSign(规格串)` 是否支持目标算法组合(如 `RSA2048|PKCS1|NoHash`)
|
|
214
|
+
- `getEncoded()` 返回的公钥 DER 是 PKCS#1 还是 X.509 SPKI(影响解析)
|
|
215
|
+
- `@ohos.net.socket.TCPSocket` 局域网连通性(需 `ohos.permission.INTERNET`,normal 级安装即授予)
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
> 本文件只管**语言语法层**。ArkUI 组件、V2 状态管理、图标资源、工程构建、运行时容错的坑
|
|
220
|
+
> 见同目录 **`dwy-arkts-ui-build.md`**(图标名映射 / 自定义组件链属性 / @BuilderParam 默认值 /
|
|
221
|
+
> @Param 外部初始化 / async 状态快照 / bootstrap 分步容错 / DevEco 命令行构建)。
|