AI 写我的双端项目,只认鸿蒙不认小程序:祸根是注册表里的排列顺序

发布时间:2026/9/3 5:32:26
AI 写我的双端项目,只认鸿蒙不认小程序:祸根是注册表里的排列顺序 结论先说tri-coding 拿哪套编码规范写你的代码不取决于它多聪明而取决于tech-skills/registry.md那张 25 行表格的排列顺序。我一个鸿蒙加微信小程序双端的项目两端特征文件都命中了它只加载了排在第 67 行的arkts把wechat按互斥规则跳过。最终 design.md 的「编码规范」那一节从头到尾没出现过一次wxml。起因design.md 里一个 wxml 都没有雷达鸭是我自己在做的 App收录中国一人公司和超级个体的真实赚钱案例技术栈是 Uni-app 配 arkTS 插件加 UniCloud微信小程序和鸿蒙版本同步在跑。日常就是靠 tri-xxx 这一票 skill 帮着打理开发流程。那天要给它加一个「案例收藏夹」双端都要。按 tri-coding 的流程走门①需求审批过了到门②拿到 design.md我扫「编码规范」那一节越看越不对劲Component、State、build()、Prop是单数别写成复数……全是 ArkTS 那一套。小程序侧的app.json分包、setData批量更新、wxml里不能写复杂表达式一条都没有。我头一个念头是需求写漏了。回头翻 requirements.md双端写得清清楚楚。顺着链路往上翻卡点在氛围校准tri-coding 的技术栈不写死在 SKILL.md 里。它在产出 design.md 的「氛围校准」步骤做一次匹配链路是这样读tech-skills/registry.md→ 扫项目特征文件 → 按注册表的触发规则逐条匹配 → 命中的技术栈规范注入 design.md 的「技术选型」与「编码规范」两个环节。执行阶段编码时遵循的就是这批已加载的规范。我那项目的特征文件是齐的按注册表的触发规则一条条对我项目里的特征文件该命中的 tech_id分类实际加载了吗tsconfig.json、*.tstypescriptlanguage是*.ets、oh-package.json5、module.json5arktsplatform是project.config.json、*.wxmlwechatplatform没有.git/、.gitignoregittool是始终加载generalbase是四个该命中的三个到位wechat凭空少了。注册表里那条我之前没细读的规则翻到 registry.md 的「加载规则」往下有一段标题写着互斥规则同类互斥仅加载首个命中项框架层互斥组react↔vuejs框架层互斥组django↔fastapi↔flask平台层互斥组arkts↔wechat↔h5互斥组内多个命中时优先加载注册表中靠前的条目其余跳过并记录告警平台层那条后面还跟了句解释「同一项目通常面向单一平台」。这个假设对大多数项目成立对跨端项目不成立。Uni-app 整个存在的意义就是一套代码编译到多端arkts和wechat同时命中是它的常态而不是异常输入。再看「优先加载注册表中靠前的条目」——这句话的意思是表格行序本身就是优先级。我去数了 platform 分类那几行在注册表里的位置注册表行号tech_id分类互斥组内结果67arktsplatform命中且靠前 →加载68electronplatform未命中69h5platform未命中70wechatplatform命中但靠后 →跳过arkts在第 67 行wechat在第 70 行。arkts 赢了赢的理由只是它在表里写得更早。我个人挺不喜欢这种设计。把优先级藏在表格行序里而不写成显式的priority字段读的人不去数行号根本发现不了。三个解法前两个我都否了方案做法结果一把wechat那行剪到arkts前面小程序规范上来了鸿蒙侧没了方向掉个头而已二删掉平台层那条互斥组让两个叠加两端语法混进同一份「编码规范」执行阶段分不清哪条管哪端三新增一个跨端 tech_id 显式注册采用方案一我真试了把wechat提到arkts上面重跑氛围校准这回 design.md 里全是小程序那套鸿蒙侧的build()和状态装饰器又没了。互斥组只放一个进来这件事没变。方案二更糟。ArkTS 的build()链式调用和小程序的wxml模板语法混在同一节里执行阶段 AI 分不清哪条约束管哪一端我真怕它给我写出wxml里套Column()的东西。方案三是我最后用的加一个新的 tech_id把「跨端」这件事显式注册进去。registry.md 自己写了它是「唯一扩展入口」新增技术栈无需改 tri-coding/SKILL.md那就用它给的路子走。在注册表追加一行| uniapp-multiend | Uni-app 跨端(小程序鸿蒙) | platform | package.json 含 dcloudio/uni-app 且同时存在 *.ets 与 project.config.json | uniapp-multiend.md |再在tech-skills/uniapp-multiend.md里把两端约束按目录分区写清楚而不是混成一锅哪些规范管src/pages/小程序侧哪些管harmony/下的.ets鸿蒙侧。分区这一步是关键不分区就退回方案二的问题了。落到代码上差别在这加载对了之后鸿蒙侧给的还是那套 ArkTS 写法这部分本来就没错Componentexportstruct FavoriteCard{PropcaseTitle:string;PropmonthlyRevenue:number0;Linkstarred:boolean;build(){Row(){Column(){Text(this.caseTitle).fontSize(16).fontWeight(FontWeight.Medium);Text(月流水 ¥${this.monthlyRevenue}).fontSize(13).fontColor(#8A8A8E);}.alignItems(HorizontalAlign.Start).layoutWeight(1);Image(this.starred?$r(app.media.star_on):$r(app.media.star_off)).width(24).height(24).onClick((){this.starred!this.starred;});}.width(100%).padding(12);}}小程序侧的规范补回来之后多出来的是这类约束也正是之前 design.md 里完全缺失的那部分// 小程序侧收藏状态变更必须合并 setData逐条调用会触发多次渲染Page({data:{list:[]},toggleStar(e){constidxe.currentTarget.dataset.index;constlistthis.data.list;// 只推送变更路径不整包重设 listthis.setData({[list[${idx}].starred]:!list[idx].starred,[list[${idx}].starredAt]:Date.now()});}});wxml里不写复杂表达式、setData走变更路径而不是整包重设这些条目 ArkTS 那份规范里一个字都不会提。顺手写了个脚本别再靠肉眼数行号数行号这活儿干一次就够了。写了个小脚本扫注册表加项目特征把命中的和被互斥吃掉的都打出来importjson,re,sysfrompathlibimportPath MUTEX_GROUPS[{react,vuejs},{django,fastapi,flask},{arkts,wechat,h5},]# tech_id - 用于判定的特征文件 glob简化版够用即可FEATURES{typescript:[tsconfig.json,**/*.ts],arkts:[**/*.ets,**/oh-package.json5,**/module.json5],wechat:[**/project.config.json,**/*.wxml],h5:[**/*.html],git:[.gitignore],}defparse_registry(md:Path):按注册表出现顺序取出 (行号, tech_id, 分类)rows[]forlineno,lineinenumerate(md.read_text(encodingutf-8).splitlines(),1):mre.match(r^\|\s*([a-z0-9\-])\s*\|[^|]*\|\s*(base|language|framework|platform|tool)\s*\|,line)ifm:rows.append((lineno,m.group(1),m.group(2)))returnrowsdefhits(project:Path,tech_id:str)-bool:forpatinFEATURES.get(tech_id,[]):ifnext(project.glob(pat),None):returnTruereturnFalsedefresolve(project:Path,registry:Path):loaded,skipped[general],[]claimedset()forlineno,tech_id,categoryinparse_registry(registry):iftech_idgeneralornothits(project,tech_id):continuegroupnext((gforginMUTEX_GROUPSiftech_iding),None)ifgroupandgroupclaimed:winner(groupclaimed).pop()skipped.append((tech_id,lineno,winner))continueifgroup:claimed.add(tech_id)loaded.append(tech_id)returnloaded,skippedif__name____main__:projPath(sys.argv[1]iflen(sys.argv)1else.)regPath(sys.argv[2]iflen(sys.argv)2elsetri-coding/tech-skills/registry.md)loaded,skippedresolve(proj,reg)print(已加载:, .join(loaded))fortech_id,lineno,winnerinskipped:print(f[告警]{tech_id}(第{lineno}行) 被互斥跳过让位给更靠前的{winner})在我那项目根目录跑一下已加载: general typescript arkts git [告警] wechat(第70行) 被互斥跳过让位给更靠前的 arkts那句「其余跳过并记录告警」注册表里是写了的但告警得落到我看得见的地方才算数。现在这行[告警]我在门②之前就能看到不用等 design.md 交上来才发现少了半套。一句话registry 驱动这套设计的可扩展性是真的加一行就能扩SKILL.md 一个字不用改。但可扩展不等于会自动判断对它的平台层互斥规则里压着一个「同一项目通常面向单一平台」的假设跨端项目撞上去AI 会安安静静地少给你半套规范design.md 照样交得漂漂亮亮格式齐全、章节完整、一处不缺。门②那关别只看格式先数一下技术栈加载对没对。我是老三10 年软件开发经验软件设计师、人工智能应用工程师主要做鸿蒙应用ArkTS北向开发和 Web 前端也在折腾 AI 自动化不定期在 CSDN 写点鸿蒙和 AI 方向的东西。本文遵循 MIT 协议转载请注明出处即可。这个系列的文章都来自开源的 tri 技能库。整套 tri-xxx 技能都能在 skillhub 找到并安装一条命令装完即用比如skillhub install tri-coding。装完每个技能都有 README想摸清它到底能干嘛读那个就够了。