@manohub/kit 0.10.4 → 1.0.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/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # @manohub/kit
2
2
 
3
3
  AIHub 子应用**入口编排层**:`createSubApp` 统一挂载、i18n 单实例,
4
- 外加随包分发的接入契约(`CONTRACT.md`:五层闭集条款 + §7 自检清单)与三个 AI 技能包(`skills/`)。
4
+ 外加随包分发的接入契约(`CONTRACT.md`:五层闭集条款 + §7 自检清单)与四个 AI 技能包(`skills/`)。
5
5
 
6
6
  **组件与命令式服务不在本包** —— 它们来自 [`@manohub/ui`](https://www.npmjs.com/package/@manohub/ui);
7
7
  **全局令牌(值)不在本包** —— 它来自 [`@manohub/theme`](https://www.npmjs.com/package/@manohub/theme);
@@ -10,8 +10,9 @@ AIHub 子应用**入口编排层**:`createSubApp` 统一挂载、i18n 单实
10
10
  > **0.6.0 是破坏性变更**(上一个已发布版本是 `@manohub/app-kit@0.4.3`):本包不再提供任何组件
11
11
  > (`App*` 前缀名与 `.ak-*` 类名全部退场、farris 依赖移除)、**主题层独立为 `@manohub/theme`**
12
12
  > (容器锚改名 `data-manohub-ui`)、**本包内的样式全部删除**(`reset.css` 与 `.app-markdown`
13
- > 富文本预设不再提供)、**消费侧机器规则整批下线**(原 `kit lint` 三条护栏不再发布,
14
- > 合规改为「契约条款 + §7 自检清单」)。
13
+ > 富文本预设不再提供)、**消费侧机器规则整批下线**(原 `kit lint` 三条护栏不再发布 ——
14
+ > **0.7.0 起以四组护栏的新立足点恢复**,见下方「5. 自检」;合规判据始终是
15
+ > 「契约条款 + §7 自检清单」)。
15
16
  > 这些是**同一次重构**,一次性做完 —— 迁移对照与步骤见 `CONTRACT.md` §12。
16
17
 
17
18
  ## 新项目接入(快速开始)
@@ -100,15 +101,18 @@ export default function SkillList() {
100
101
 
101
102
  三种页面模板、四种操作位、两级滚动归属、分页归属 —— 见 `CONTRACT.md` §5(L2 结构)。
102
103
 
103
- ### 5. 自检(0.6.0 起没有自动扫描)
104
+ ### 5. 自检(护栏 + 自检清单)
104
105
 
105
- 本包**不再发布消费侧机器规则**。合规靠契约条款 + 自检清单在写作与评审时把关:
106
+ 本包提供 `kit lint`(**四组**:`style` / `source` / `namespace` / `property`,`--help` 有全量用法),
107
+ 它覆盖**可机械判定的那一部分**;契约条款 + §7 自检清单仍是**完整**判据,两者不互相替代:
106
108
 
107
109
  1. 写代码前按契约 §0 权威源表去取值 / 查件名 / 查词表(不要抄一份会过期的副本);
108
- 2. 收工前人工过 `CONTRACT.md` §7 自检清单(24 问,五层各一组);
110
+ 2. 收工前跑一次护栏,**并**人工过 `CONTRACT.md` §7 自检清单(24 问,五层各一组)——
111
+ **结构类与语义类没有工具替你查**;
109
112
  3. 类型与构建照常跑:
110
113
 
111
114
  ```bash
115
+ pnpm exec kit lint --root <应用目录> --namespace <前缀>
112
116
  pnpm exec vue-tsc --noEmit
113
117
  pnpm build
114
118
  ```
@@ -119,7 +123,7 @@ pnpm build
119
123
  ### 6. 技能包落盘(AI 代理用)
120
124
 
121
125
  ```bash
122
- pnpm exec kit install # 把三个技能落到本工程的技能目录
126
+ pnpm exec kit install # 把四个技能落到本工程的技能目录
123
127
  pnpm exec kit install --dry-run # 先看会写什么
124
128
  ```
125
129
 
@@ -150,6 +154,7 @@ pnpm exec kit install --dry-run # 先看会写什么
150
154
  | `manohub-kit` | 不确定该用哪个子技能、问骨架层总体规范、要接入步骤与升级口径 |
151
155
  | `manohub-kit-dev` | 写/改页面:选模板、选组件与 prop、样式纪律、收工前自检 |
152
156
  | `manohub-kit-migrate` | 存量应用改造:按契约分层盘点、划批次、逐文件替换、逐层收口 |
157
+ | `manohub-kit-upgrade` | 四包**版本升级**:立基线、读判据来源、按件族分批改、每批过三道闸;含破坏性变更处置与陷阱清单 |
153
158
 
154
159
  技能目录名带包名前缀(旧名 `kit` / `kit-migrate` / `kit-dev` 已废弃):从带旧名的版本升级时,
155
160
  先手工删掉技能目录下的这三个旧目录再重跑 `kit install`,否则新旧两份技能会同时在场。
package/bin/kit.mjs CHANGED
@@ -40,7 +40,7 @@ const PKG_ROOT = dirname(dirname(fileURLToPath(import.meta.url)))
40
40
  export const COMMANDS = {
41
41
  install: {
42
42
  script: 'skills/install.mjs',
43
- summary: '把随包分发的三个 AI 技能落到本工程(--also-claude / --target <dir> / --dry-run)',
43
+ summary: '把随包分发的四个 AI 技能落到本工程(--also-claude / --target <dir> / --dry-run)',
44
44
  },
45
45
  lint: {
46
46
  script: 'skills/lint.mjs',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manohub/kit",
3
- "version": "0.10.4",
3
+ "version": "1.0.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "子应用入口编排层:createSubApp(作用域容器与宿主锚点、pinia/路由/vue-query 装配、宿主挂载协议)、i18n 单实例与语言探测,外加随包分发的接入契约(CONTRACT.md,五层闭集条款 + 自检清单)与三个 AI 技能包。本包**零样式产物**:设计令牌(值)在 @manohub/theme,组件(类与行为)在 @manohub/ui,两者由消费方直接引入。",
@@ -39,12 +39,6 @@
39
39
  "main": "./dist/index.js",
40
40
  "module": "./dist/index.js",
41
41
  "types": "./dist/index.d.ts",
42
- "scripts": {
43
- "build": "node ../../scripts/clean-dist.mjs && vue-tsc -p tsconfig.build.json && vite build",
44
- "type-check": "vue-tsc --noEmit -p tsconfig.json",
45
- "test:unit": "vitest run",
46
- "test:watch": "vitest"
47
- },
48
42
  "peerDependencies": {
49
43
  "@tanstack/vue-query": "^5.0.0",
50
44
  "pinia": "^4.0.0",
@@ -53,16 +47,22 @@
53
47
  "vue-router": "^4.6.0"
54
48
  },
55
49
  "devDependencies": {
56
- "@tanstack/vue-query": "catalog:",
57
- "@vitejs/plugin-vue-jsx": "catalog:",
50
+ "@tanstack/vue-query": "^5.64.0",
51
+ "@vitejs/plugin-vue-jsx": "^5.1.6",
58
52
  "jsdom": "^25.0.1",
59
- "pinia": "catalog:",
60
- "typescript": "catalog:",
61
- "vite": "catalog:",
53
+ "pinia": "^4.0.3",
54
+ "typescript": "^6.0.2",
55
+ "vite": "^7.3.6",
62
56
  "vitest": "^3.2.7",
63
- "vue": "catalog:",
64
- "vue-i18n": "catalog:",
65
- "vue-router": "catalog:",
66
- "vue-tsc": "catalog:"
57
+ "vue": "^3.5.40",
58
+ "vue-i18n": "^11.4.8",
59
+ "vue-router": "^4.6.3",
60
+ "vue-tsc": "^3.3.8"
61
+ },
62
+ "scripts": {
63
+ "build": "node ../../scripts/clean-dist.mjs && vue-tsc -p tsconfig.build.json && vite build",
64
+ "type-check": "vue-tsc --noEmit -p tsconfig.json",
65
+ "test:unit": "vitest run",
66
+ "test:watch": "vitest"
67
67
  }
68
- }
68
+ }
package/skills/README.md CHANGED
@@ -15,13 +15,14 @@
15
15
  所以技能里的**条款式描述一律算缺陷**:它必然与契约漂移,而契约才是唯一裁判。技能只写两件事 ——
16
16
  **「读契约第 X 节」** 与 **「过 §7 自检清单」**。
17
17
 
18
- ## 三个技能
18
+ ## 四个技能
19
19
 
20
20
  | 技能 | 职责 | 可独立调用 |
21
21
  |---|---|---|
22
- | `manohub-kit` | 入口编排:识别意图 → 调 `manohub-kit-migrate` 或 `manohub-kit-dev`(另有「从零建新应用」导到接入 SOP);承载跨场景硬约束 | 是(子技能也可直接调) |
22
+ | `manohub-kit` | 入口编排:识别意图 → 调 `manohub-kit-migrate` / `manohub-kit-dev` / `manohub-kit-upgrade`(另有「从零建新应用」导到接入 SOP);承载跨场景硬约束 | 是(子技能也可直接调) |
23
23
  | `manohub-kit-migrate` | 存量应用改造到「`@manohub/ui` 组件 + `@manohub/kit` 骨架」(清理 `App*` 旧组件名、`.ak-*` 样式、直连底层组件库的写法):按契约逐层盘点 → 划批次 → 逐文件替换 → 逐层收口 → 验收;支持**只迁一部分**(典型是「只迁页面骨架」) | 是 |
24
24
  | `manohub-kit-dev` | 按骨架层规范做日常页面开发:选模板 / 选组件与 prop / 守样式纪律 / 缺件处置 / 自检 | 是 |
25
+ | `manohub-kit-upgrade` | **版本升级**:已接入的应用把四包从一版升到另一版 —— 立基线 → 读判据来源 → 升依赖 → 按件族分批改 → 每批过三道闸 → 收尾登记;含破坏性变更(改名 / 删除 / 语义翻转)的处置与陷阱清单 | 是 |
25
26
 
26
27
  ## 安装到消费方技能目录
27
28
 
@@ -49,7 +50,7 @@ pnpm exec kit install --dry-run # 只预览不落盘
49
50
 
50
51
  安装器是幂等的:每次执行**先清理同名技能目录再整体复制**,所以包升级后重跑一次即刷新到新版内容。
51
52
  等价写法(老脚本/钩子里可用):`node node_modules/@manohub/kit/skills/install.mjs`。
52
- 它只管理 `manohub-kit` / `manohub-kit-migrate` / `manohub-kit-dev` 这三个目录,不触碰目标目录下的其它内容。
53
+ 它只管理 `manohub-kit` / `manohub-kit-migrate` / `manohub-kit-dev` / `manohub-kit-upgrade` 这四个目录,不触碰目标目录下的其它内容。
53
54
 
54
55
  > **技能目录名带包名前缀**:旧名 `kit` / `kit-migrate` / `kit-dev` 已废弃,安装器**不再管理**它们 ——
55
56
  > 从带旧名的版本升级时,须先手工删掉技能目录下的这三个旧目录再重跑 `kit install`,
@@ -64,14 +65,16 @@ pnpm exec kit install --dry-run # 只预览不落盘
64
65
  - **不复述条款**:不抄白名单、不抄件名清单、不抄 prop 词表、不抄值。
65
66
  需要时写「读契约 §x.y」或指向读取路径(见契约 §0 权威源表)。凡本目录内出现判据式描述,视为缺陷。
66
67
  - `SKILL.md` 只放流程与硬约束(控制在 5k 词内);查表内容(替换映射、场景配方)放各自的 `references/`,按需加载。
67
- - 三个技能的 `description` 触发条件互不重叠,否则代理会命中错的那个
68
- (`kit` 只在「意图还没落到具体任务」时命中,具体任务交给两个子技能)。
68
+ - 四个技能的 `description` 触发条件互不重叠,否则代理会命中错的那个
69
+ (`kit` 只在「意图还没落到具体任务」时命中,具体任务交给三个子技能;三个子技能按
70
+ **形态改造 / 版本升级 / 日常开发** 分工)。
69
71
  - 技能引用的 `references/` 文件必须真实存在,文件名改动要同步 `SKILL.md`
70
72
  (已由 `verify-pack` 的 `checkSkillPack` 机械校验,跨技能引用 `../<skill>/references/…` 同样校验)。
71
73
  - 技能目录下的每个文件都必须真进 tarball(`references/` 漏发时「查表」会整体失效,也已机械校验)。
72
74
  - 技能引用的契约章节必须真实存在(改契约标题即需同步本目录,`verify-pack` 会校验章节号可解析)。
73
75
  - 技能与文档里的命令一律写**消费方命令** `pnpm exec kit install`(npm 注一句 `npx`)。
74
- - 本包**只有 `install` 一个子命令**(0.6.0 起 `kit lint` 及其四个校验子命令已下线)。
76
+ - 本包有**两个子命令**:`install`(技能落盘)与 `lint`(接入护栏,**四组**:
77
+ `style` / `source` / `namespace` / `property`;用法见技能 `manohub-kit-upgrade`)。
75
78
  `bin/` 是工具脚本、没有自测,改后手工跑一次确认参数透传(如 `--dry-run`),
76
79
  `verify-pack` 校验 `bin/kit.mjs` 随包分发。
77
80
  - 改动后跑门禁与打包校验(在仓库根):
@@ -25,7 +25,7 @@ import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:pat
25
25
  import { fileURLToPath, pathToFileURL } from 'node:url'
26
26
 
27
27
  /** 本技能包管理的技能目录名(白名单:只有这些名字允许被创建或清理) */
28
- export const SKILL_NAMES = ['manohub-kit', 'manohub-kit-migrate', 'manohub-kit-dev']
28
+ export const SKILL_NAMES = ['manohub-kit', 'manohub-kit-migrate', 'manohub-kit-dev', 'manohub-kit-upgrade']
29
29
 
30
30
  /** 缺省的技能目录(相对消费方工程根) */
31
31
  export const TARGET_CODEXBUDDY = ['.codebuddy', 'skills']
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: manohub-kit
3
3
  version: 1.0.0
4
- description: 子应用骨架层 @manohub/kit 的入口技能:识别意图并编排到 manohub-kit-migrate(存量应用改造)或 manohub-kit-dev(日常页面开发),并承载两个子技能共用的全局硬约束。触发条件:用户提到 kit / manohub-kit / 骨架层 / 接入契约本身、询问该怎么接入或改造但尚未落到具体页面或文件、不确定该用哪个 manohub-kit 技能、或需要接入步骤/升级口径等跨场景事项时使用;一旦意图明确落到「迁移存量应用」或「写/改页面」,由对应子技能承接。
4
+ description: 子应用骨架层 @manohub/kit 的入口技能:识别意图并编排到 manohub-kit-migrate(存量应用形态改造)、manohub-kit-upgrade(四包版本升级)或 manohub-kit-dev(日常页面开发),并承载三个子技能共用的全局硬约束。触发条件:用户提到 kit / manohub-kit / 骨架层 / 接入契约本身、询问该怎么接入或改造但尚未落到具体页面或文件、不确定该用哪个 manohub-kit 技能、或需要接入步骤/升级口径等跨场景事项时使用;一旦意图明确落到「迁移存量应用」「升级四包版本」或「写/改页面」,由对应子技能承接。
5
5
  ---
6
6
 
7
7
  # manohub-kit:骨架层入口编排
@@ -14,8 +14,9 @@ description: 子应用骨架层 @manohub/kit 的入口技能:识别意图并
14
14
  | 用户意图信号 | 走向 |
15
15
  |---|---|
16
16
  | 应用还没接本包;或页面里还有 `App*` 组件名 / `.ak-*` 样式 / 直连底层组件库;或出现「迁移」「改造」「接入」「违规盘点」「收口」 | `Skill('manohub-kit-migrate')` |
17
+ | 应用**已接入**,要把它装着的四包版本抬上去;或出现「升级」「升到 X 版」「破坏性变更」,以及升级后编译不过 / 件找不到 / 样式与行为对不上 | `Skill('manohub-kit-upgrade')` |
17
18
  | 应用已接入,要新增或修改页面、组件;或要求「按规范写」「用 Page / Panel / Table…」 | `Skill('manohub-kit-dev')` |
18
- | 两者交织(边接入边改页面) | 先跑 `manohub-kit-migrate` 的接入阶段(契约已落到应用文档),再进 `manohub-kit-dev` |
19
+ | 形态改造与版本升级叠在一起(跨过一次重构型跃迁) | 先按 `manohub-kit-migrate` 做形态改造并装到目标版本,再按 `manohub-kit-upgrade` 收口与验收 |
19
20
  | 应用还不存在,要从零建一个子应用 | 按 `references/adoption.md` «9. 新应用从零搭建» 走,建成后按上面的表继续 |
20
21
  | 问的是组件本身的 prop / 用法(不是页面结构) | 读 `node_modules/@manohub/ui/README.md` 与类型声明;本包的契约只管**页面怎么搭** |
21
22
  | 与骨架层无关(纯后端问题、非 Vue 前端工程) | 不使用本技能 |
@@ -43,8 +44,9 @@ description: 子应用骨架层 @manohub/kit 的入口技能:识别意图并
43
44
  **冲突时的优先级**:包内 `CONTRACT.md` > `@manohub/ui` 的 README 与类型声明里的 `@example`
44
45
  > 消费仓 `AGENTS.md` > 其它文档。发现 `@example` 与契约冲突,按契约写,并把该 `@example` 当缺陷处理。
45
46
 
46
- > 本包 **0.6.0 起不再发布消费侧机器规则**(原先的三条护栏已下线)。合规靠
47
- > 「契约条款 + §7 自检清单」在写作与评审时把关,不再有自动拦断。
47
+ > **机器规则在 0.6.0 曾整批下线,0.7.0 起以新的立足点恢复** —— 现为 `kit lint` 的四组护栏
48
+ > (`style` / `source` / `namespace` / `property`,用法见 `manohub-kit-upgrade`)。
49
+ > 它覆盖**可机械判定的那一部分**;契约条款 + §7 自检清单仍是完整判据,两者不互相替代。
48
50
 
49
51
  ## 三、固定命令(在应用包根执行)
50
52
 
@@ -55,7 +57,7 @@ pnpm build # 生产构建
55
57
  ```
56
58
 
57
59
  - `kit` 是本包的命令入口(`package.json` 的 `bin`);npm 消费方把 `pnpm exec` 换成 `npx`。
58
- 本包**只有 `install` 一个子命令**。
60
+ 子命令有两个:`install`(技能落盘)与 `lint`(四组接入护栏,用法见 `manohub-kit-upgrade`)。
59
61
  - 技能包内容更新后重新落盘(幂等,包升级后重跑即刷新):
60
62
 
61
63
  ```bash
@@ -73,7 +75,7 @@ pnpm exec kit install # 等价:node node_modules/@manohub/kit/skills/i
73
75
  | 调子技能报「技能不存在」 | 技能未安装或未刷新,跑上面的 `pnpm exec kit install` |
74
76
  | 终端里敲 `kit` 报 command not found | 用 `pnpm exec kit …`(或 npm 的 `npx kit …`) |
75
77
  | 类型检查报「无法解析 `*.css`」 | 消费方 tsconfig 的 `types` 需包含 `vite/client`,见 `references/adoption.md` |
76
- | 想找「某个写法合不合规」的机器判据 | 没有了 —— 读 `CONTRACT.md` 对应层 + §7 自检清单;确需全仓盘点时按 `manohub-kit-migrate` 的条款级盘点流程人工过 |
78
+ | 想找「某个写法合不合规」的机器判据 | 跑 `pnpm exec kit lint --root <应用目录> --namespace <前缀>`(四组,用法见 `manohub-kit-upgrade`)—— 它覆盖可机械判定的部分;其余读 `CONTRACT.md` 对应层 + §7 自检清单 |
77
79
 
78
80
  ## 五、参考
79
81
 
@@ -87,8 +87,8 @@ pinia / vue-router / vue-query 装配、宿主挂载协议(`window.mount/unmou
87
87
 
88
88
  ## 4. 命名空间表(本仓自建)
89
89
 
90
- 自 0.6.0 起 `kit lint` 下线,**类名前缀不再由配置文件登记**,改为本仓自己维护一张命名空间表:
91
- `docs/kit-namespaces.md`(哪个应用占哪个类名前缀)。格式见
90
+ **类名前缀不再由配置文件登记**(0.6.0 起),改为本仓自己维护一张命名空间表:
91
+ `docs/kit-namespaces.md`(哪个应用占哪个类名前缀)—— 它同时是 `kit lint --namespace` 的入参。格式见
92
92
  `../../manohub-kit-migrate/references/migration-playbook.md` 的模板。
93
93
 
94
94
  - 库锚 `[data-manohub-ui]` 与类名 `.app-container` 恒允许、不必登记(但 `app-container` 不是跨包契约)。
@@ -115,7 +115,8 @@ pnpm exec kit install --dry-run # 只预览
115
115
 
116
116
  - [ ] `pnpm exec vue-tsc --noEmit` 0 错
117
117
  - [ ] `pnpm build` 成功
118
- - [ ] **人工过一遍契约 §7 自检清单**(24 问;0.6.0 起没有自动扫描兜底)
118
+ - [ ] `pnpm exec kit lint --root <应用目录> --namespace <前缀>` **无违规**(退出码 0)
119
+ - [ ] **人工过一遍契约 §7 自检清单**(24 问;结构类 / 语义类没有工具替你查)
119
120
  - [ ] 应用能挂载:非 micro-app 下自动挂载;micro-app 下宿主能 `mount/unmount` 重挂
120
121
  - [ ] 容器带 `data-manohub-ui` 属性(`createSubApp` 无条件写;自建容器要自己写)
121
122
  - [ ] `toast('success', 'ok')` 后 DOM 里 `[data-manohub-ui]` 内有 `.mh-toast`(否则样式会丢)
@@ -164,7 +165,8 @@ my-app/
164
165
  - **`0.6.0` 是破坏性变更**(上一个是 `@manohub/app-kit@0.4.3`),三个方面**一次做完**:
165
166
  ① 本包不再提供组件 —— `App*` 名与 `.ak-*` 样式全部退场、farris 退场;
166
167
  ② 主题层独立成 `@manohub/theme`、容器锚改名 `data-app-container` → `data-manohub-ui`、
167
- kit 不再发布任何样式;③ 消费侧机器规则(`kit lint` 三条护栏)整批下线,合规改为
168
+ kit 不再发布任何样式;③ 消费侧机器规则(`kit lint` 三条护栏)整批下线
169
+ (**0.7.0 起以四组护栏的新立足点恢复**,见技能 `manohub-kit-upgrade`),合规改为
168
170
  「契约条款 + §7 自检清单」,契约整体重写为五层(L0 / L1 / L1.5 / L2 / L3)。
169
171
  `appkit-guardrails.config.json` 不再被读取 —— 类名前缀迁到本仓 `docs/kit-namespaces.md`。
170
172
  - 升级后**务必重建产物再联调**(消费侧装的是 `dist`);联调流程见包根 `AGENTS.md`。
@@ -43,13 +43,16 @@
43
43
  | 组件有哪些、每个件的 prop 是什么 | `node_modules/@manohub/ui/README.md` + `dist/index.d.ts` |
44
44
  | 本仓的类名命名空间归谁 | 本仓 `docs/kit-namespaces.md`(per-app 文件,不在契约里) |
45
45
 
46
- ## 注意:0.6.0 起没有自动扫描了
46
+ ## 注意:机器规则 0.6.0 整批下线、0.7.0 起以新立足点恢复
47
47
 
48
- `kit lint` 与三条护栏(style / component / structure)**已下线**,本包不再发布消费侧机器规则。
49
- 合规判据全在 `CONTRACT.md`:每条都是闭集,配合 §7 自检清单在**写作与评审时**把关。
48
+ 现为 `kit lint` 的**四组**:`style` / `source` / `namespace` / `property`
49
+ (用法见技能 `manohub-kit-upgrade`)。它查的是**可机械判定的那一部分** ——
50
+ 样式红线、外观来源、业务类名前缀、视觉属性闭集;契约条款 + §7 自检清单仍是**完整**判据,
51
+ 两者不互相替代。
50
52
 
51
- - 别再找「跑一条命令看有多少违规」——没有了。
52
- - 要全仓盘点时,按 `../../manohub-kit-migrate/references/migration-playbook.md` 的**条款级盘点口径**人工过。
53
+ - 「还剩多少违规」用 `pnpm exec kit lint --root <应用目录> --namespace <前缀>` 拿(有退出码)。
54
+ - **结构类与语义类没有任何工具替你查** —— 要全仓盘点时,
55
+ 按 `../../manohub-kit-migrate/references/migration-playbook.md` 的**条款级盘点口径**人工过。
53
56
  - **库侧**的机械校验(`@manohub/ui` 与 `@manohub/theme` 包内的契约测试)**仍然在跑**,
54
57
  那是库自己的守卫,与消费方无关。
55
58
 
@@ -44,4 +44,5 @@
44
44
  ## 三、收工前
45
45
 
46
46
  契约 §7 自检清单的 L1 组(属性白名单 / 令牌引用 / 自定义属性 / 工具类形态)逐条答一遍。
47
- 0.6.0 起没有自动扫描,**答不上来就等于没检查**。
47
+ 其中**可机械判定的部分先交给 `pnpm exec kit lint`**(`style` / `property` 两组最相关,
48
+ 用法见技能 `manohub-kit-upgrade`);清单里剩下那些**答不上来就等于没检查**。
@@ -12,10 +12,12 @@ description: 把存量子应用改造到 @manohub/ui + @manohub/kit 骨架层(
12
12
  分六阶段,每阶段都有可核对的产出。
13
13
  **替换对照表见 `references/migration-map.md`**;阶段细则、盘点登记格式与验收清单见 `references/migration-playbook.md`。
14
14
 
15
- > **0.6.0 起本包不再发布消费侧机器规则**(`kit lint` 三条护栏已下线)。
16
- > 改造的判据变成「契约条款 + §7 自检清单」,违规的**盘点与归零由人/代理按契约逐条过**,
17
- > 不再有自动拦断。这决定了两件事:① 阶段 1 的基线靠人工按层盘;② 阶段 3/4 的「归零」
18
- > 以**人工过 §7 清单**为证据,而不是一张 lint 退出码。
15
+ > **机器规则在 0.6.0 曾整批下线,0.7.0 起以新的立足点恢复** —— 现为 `kit lint` 的四组护栏
16
+ > (`style` / `source` / `namespace` / `property`,用法见 `manohub-kit-upgrade`)。
17
+ > 它查的是**可机械判定的那一部分**:样式红线、外观来源、业务类名前缀、视觉属性闭集;
18
+ > **结构类与语义类没有工具替你查**,只能人工过 §7。契约条款 + §7 自检清单仍是**完整**判据,
19
+ > 两者不互相替代。这决定了两件事:① 阶段 1 的基线 = `kit lint` 的数字 **+** 人工补盘结构 / 语义类;
20
+ > ② 阶段 3/4 的「归零」以「`kit lint` 相关组归零 **+** 人工过 §7」**双证据**落文档。
19
21
 
20
22
  ## 阶段 0 · 摸清现状
21
23
 
@@ -30,7 +32,7 @@ description: 把存量子应用改造到 @manohub/ui + @manohub/kit 骨架层(
30
32
 
31
33
  ## 阶段 1 · 按契约分层盘点违规
32
34
 
33
- 没有自动扫描了,所以这一步是**人工按层过**:打开 `CONTRACT.md`,逐层逐条对着代码盘。
35
+ 这一步分两半:**能机械判定的先交给 `kit lint`**,剩下的(结构类 / 语义类)人工按层过。
34
36
 
35
37
  1. 装依赖:
36
38
 
@@ -40,8 +42,17 @@ description: 把存量子应用改造到 @manohub/ui + @manohub/kit 骨架层(
40
42
  ```
41
43
 
42
44
  2. 建本仓的**命名空间表** `docs/kit-namespaces.md`(哪个应用占哪个类名前缀),
43
- 格式见 `references/migration-playbook.md`。这张表取代了旧配置里的 `prefixes`。
44
- 3. 按契约的五层盘一遍,把命中记成条款级清单(`L0-3 / L1-5 / L2-12 …` 这个样子),
45
+ 格式见 `references/migration-playbook.md`。这张表取代了旧配置里的 `prefixes`,
46
+ 同时也是下面 `--namespace` 的入参。
47
+ 3. 跑一次护栏,把**可机械判定**的部分拿成数字(这一步顺带产出阶段 0 的基线):
48
+
49
+ ```bash
50
+ pnpm exec kit lint --root <应用目录> --namespace <本应用前缀> --json
51
+ ```
52
+
53
+ 四组分开记(`style` / `source` / `namespace` / `property`)—— 改造过程中它就是进度指标。
54
+ 4. 打开 `CONTRACT.md` 把五层**逐条人工过**(结构类与语义类没有工具替你查),
55
+ 把命中记成条款级清单(`L0-3 / L1-5 / L2-12 …` 这个样子),
45
56
  登记格式见 `references/migration-playbook.md`。**盘点是「改造前的事实」,不是「要修掉的清单」**。
46
57
 
47
58
  > 首次盘必然很多命中(`App*` 名字、`.ak-*` 样式、缺 `data-manohub-ui` 都会中),这是预期的。
@@ -79,11 +90,13 @@ description: 把存量子应用改造到 @manohub/ui + @manohub/kit 骨架层(
79
90
  |---|---|
80
91
  | 已承诺的层 | 该层条款**逐条**对照代码过一遍,无命中(证据:清单里该层打勾,附文件清单) |
81
92
  | 未承诺的层 | 照常记录、数量不高于阶段 1 的盘点(写进应用文档) |
93
+ | 护栏 | `pnpm exec kit lint --root <应用目录> --namespace <前缀>` 的**相关组归零**(退出码 0) |
82
94
  | 类型 | `pnpm exec vue-tsc --noEmit` 0 错 |
83
95
  | 构建 | `pnpm build` 成功;产物大小与阶段 0 记录值量级一致(差异要能解释) |
84
96
 
85
- - **归零没有退出码了**,所以证据必须落在文档上:**每条打勾的条款都要能指出「哪些文件里没有它」**。
86
- 做不到就说明没真过一遍。
97
+ - **归零是双证据**:① `kit lint` 相关组归零(有退出码,可直接引用);② 人工过 §7 清单 ——
98
+ **结构类与语义类的条款没有任何工具替你查**,这部分打勾时要能指出「哪些文件里没有它」,
99
+ 做不到就说明没真过一遍。两条都落文档。
87
100
  - 下一批的起点 = 本轮未承诺层的盘点结果;收口顺序 = 层序(L0 → L1 → L1.5 → L2 → L3)。
88
101
 
89
102
  ## 阶段 5 · 验收(缺一不可)
@@ -114,7 +127,7 @@ description: 把存量子应用改造到 @manohub/ui + @manohub/kit 骨架层(
114
127
  | 类型出现「两种同名类型不兼容」 | 检查是否装了两份 vue / 依赖重复;按 `../manohub-kit/references/adoption.md` 的单例收敛处理 |
115
128
  | 命令式提示样式全丢 | 提示没落回应用容器:确认入口走的是 `createSubApp`(写 `data-manohub-ui`),或显式 `configureHost(el)` |
116
129
  | 分页页码整体差 1 | 旧 `page` 是 0 基、新 `Pagination.modelValue` 是 1 基(`migration-map.md` 的 Pagination 一节) |
117
- | 想找「跑一条命令看还剩多少违规」 | 没有了 —— 按阶段 4 的分层盘点口径人工过,成果记在应用文档 |
130
+ | 想找「跑一条命令看还剩多少违规」 | 用 `pnpm exec kit lint --root <应用目录> --namespace <前缀>`(四组,用法见 `manohub-kit-upgrade`)—— 它覆盖可机械判定的部分;结构类 / 语义类仍需人工过 §7,成果记在应用文档 |
118
131
 
119
132
  ## 参考
120
133
 
@@ -3,9 +3,11 @@
3
3
  `SKILL.md` 是流程骨架,本文件是**阶段细则 + 可直接抄的登记模板**。
4
4
  替换对照表见 `migration-map.md`;契约条款见 `node_modules/@manohub/kit/CONTRACT.md`。
5
5
 
6
- > **0.6.0 起没有自动扫描了**:`kit lint` 与三条护栏已下线。本文件里原先「装护栏 → 跑出基线 →
7
- > 逐文件归零 → 撤销豁免」的机械流程,改为**按契约条款人工盘点与收口** —— 判据仍是闭集,
8
- > 但执行从「跑命令」变成「过清单」,成果必须落在应用文档上。
6
+ > **机器规则 0.6.0 整批下线、0.7.0 起以新立足点恢复**:现为 `kit lint` 四组
7
+ > (`style` / `source` / `namespace` / `property`,用法见技能 `manohub-kit-upgrade`)。
8
+ > 本文件里原先「装护栏 → 跑出基线 → 逐文件归零 → 撤销豁免」的机械流程,
9
+ > 现在**一半能跑命令**(上面四组),另一半(结构类 / 语义类)仍是**按契约条款人工盘点与收口** ——
10
+ > 判据始终是闭集,但机械覆盖不全,成果必须落在应用文档上。
9
11
 
10
12
  ---
11
13
 
@@ -105,7 +107,7 @@
105
107
  | 构建 | `pnpm build` 成功;产物大小与阶段 0 记录值量级一致(差异要能解释) |
106
108
 
107
109
  **「无命中」要能举证**:说某层已收口,就得说得出「哪几(十)个文件里没有它」。
108
- 说不出就说明没真过一遍 —— 0.6.0 没有退出码帮你确认。
110
+ 说不出就说明没真过一遍 —— 结构类 / 语义类没有退出码帮你确认(机械那半走上面的 `kit lint`)。
109
111
 
110
112
  定版例外(**不是通行证**,登记也只放行契约 §11 允许的范围):
111
113
 
@@ -0,0 +1,96 @@
1
+ ---
2
+ name: manohub-kit-upgrade
3
+ version: 1.0.0
4
+ description: 把**已接入**骨架层的子应用从一版 @manohub/* 四包升到另一版:立基线、按判据来源盘点要动的东西、按件族分批改、每批过三道闸、最后收尾登记。触发条件:用户要求「升级/更新四包版本」「升到 X 版」「处理破坏性变更」,或升级后出现编译不过 / 件与成员找不到 / 页面样式或行为与升级前不一致等需要定位的回归时使用。不负责把尚未接入的应用改造过来(那是 manohub-kit-migrate),也不负责已是最新版时的日常页面开发(那是 manohub-kit-dev)。
5
+ ---
6
+
7
+ # manohub-kit-upgrade:四包版本升级
8
+
9
+ ## 一、先分清三件事
10
+
11
+ | 眼前的事 | 走哪 |
12
+ |---|---|
13
+ | 应用还带着旧组件名 / 旧样式前缀 / 直连底层组件库的写法 | `manohub-kit-migrate`(**形态改造**) |
14
+ | 形态已合规,只是**包的版本要被抬上去** | **本技能**(**版本跃迁**) |
15
+ | 应用已是最新版,要写/改页面 | `manohub-kit-dev` |
16
+
17
+ 两者可以叠在同一个任务里(跨过那一次四包重构就是):**先按 migrate 做形态改造并装到目标版本,
18
+ 再按本技能收口与验收**。不要为了「先升一半」把同一段代码改两遍 —— 重构型的跃迁不存在中间版本。
19
+
20
+ ## 二、升级的判据从哪来(先接受一个现实)
21
+
22
+ **发布物里没有一份按版本列全的变更清单。** 能读到的只有这几处:
23
+
24
+ | 去哪读 | 覆盖什么 |
25
+ |---|---|
26
+ | `node_modules/@manohub/kit/CONTRACT.md` §12 | 升级与破坏性变更。⚠️ **只覆盖到它写成时的版本**,更晚的版本不在其中 |
27
+ | `node_modules/@manohub/ui/README.md` | 组件清单 / 服务层 / 主题层;个别破坏性提示写在这里 |
28
+ | `node_modules/@manohub/icon/README.md` | 字形改名对照(**不给别名**,改名即编译期红) |
29
+ | `node_modules/@manohub/theme/README.md` | 令牌的分片与边界 |
30
+ | `node_modules/@manohub/kit/README.md` | 接入步骤、样式链顺序、技能包落盘 |
31
+
32
+ > ⚠️ 四个包的 `files` 只发布 `dist` + `README.md`(`kit` 另有 `CONTRACT.md`)—— 仓库内部的
33
+ > `docs/guide/migration-*.md` **不在发布物里**。不要引用它,也不要指望消费方能读到。
34
+
35
+ 因此**实际判据是三样东西的交叉**:① 上面这些随包文档;② `kit lint` 的四组护栏;
36
+ ③ 类型检查与构建(改名与删除会直接编译期红,这是最省事的导航)。
37
+
38
+ ## 三、护栏:`kit lint`
39
+
40
+ ```bash
41
+ pnpm exec kit lint --root <应用目录> --namespace <本仓业务类名前缀> [--group <组>] [--json]
42
+ ```
43
+
44
+ | 组 | 查什么 |
45
+ |---|---|
46
+ | `style` | 红线条(`!important` / 覆写组件内部类 / 裸元素与 `*` / `rem` / 原子化样式框架残留) |
47
+ | `source` | 外观来源白名单(第三方组件库 / CSS 框架 / 图标库 / 深引子路径 / 旧包名) |
48
+ | `namespace` | 业务类名前缀(需 `--namespace`,不给则跳过该组) |
49
+ | `property` | 视觉属性闭集(越界的属性) |
50
+
51
+ 缺省四组全跑;有违规退出码 1,`--json` 出结构化结果。`--namespace` 可多次(一个仓多个子应用时各给一个)。
52
+
53
+ **用法**:升级**前后各跑一次**,把各组违规数记进应用文档 —— 它就是这次的进度指标与最终验收口径之一。
54
+
55
+ ## 四、五个阶段
56
+
57
+ | 阶段 | 产出 |
58
+ |---|---|
59
+ | **0 立基线** | 升级前的四个事实:四包版本、构建产物体积、`kit lint` 各组违规数、关键页面/弹窗的实测值 |
60
+ | **1 读判据** | 按目标版本把第 §二 节那几张文档读一遍,列出「要动的件 / 令牌 / 写法」清单 |
61
+ | **2 升依赖** | 四包一并升降(版本必须一致)→ 重装 → 先跑一次类型检查与构建,看哪些是 API 变更 |
62
+ | **3 分批改** | 按**件族**切批(表格 / 弹窗 / 表单 / 图标 / 服务层…),每批改完立刻过闸,不攒到最后 |
63
+ | **4 收尾** | 违规数回零或落到可解释的残留;重建产物;把结论与残留写进应用文档 |
64
+
65
+ 阶段细则、依赖与 lock 的处置、批次怎么切,见 `references/upgrade-playbook.md`。
66
+
67
+ ## 五、硬约束
68
+
69
+ 1. **判据只认契约与随包文档** —— 不复述条款、不凭记忆;要判据时读 `CONTRACT.md`,收工前过 §7 自检清单。
70
+ 2. **四包版本必须一致**(同一条版本线),不一致会出现「装了两份同名类型」。
71
+ 3. **改完必须重建产物再联调** —— 消费侧装的是 `dist`。
72
+ 4. **每批都过完整三道闸**(类型+构建 / 护栏 / 运行时),不要等全部改完才验。
73
+ 5. **换了件就要验「件本身的渲染」**,不能只验自己写的样式 —— 只验后者会漏掉用法错误(方向反了、
74
+ 值没进去、件压根没生效)。细则与陷阱见 `references/verification.md`。
75
+
76
+ ## 六、失败处理
77
+
78
+ | 现象 | 处理 |
79
+ |---|---|
80
+ | 件 / 成员「不存在」或类型不兼容 | 读 `@manohub/ui/README.md` 的组件清单与 `dist` 的类型声明;**改名不提供别名**,老名字一律改掉 |
81
+ | 图标名报错 | 读 `@manohub/icon/README.md` 的改名对照;字形名**按用途不按形状**,取值以**运行时清单**为准,别按上游图标库的名字猜 |
82
+ | 样式全丢 / 颜色是浏览器默认 | 容器缺锚属性,或样式链顺序不对 —— 读 `CONTRACT.md` §2(入口与作用域,**不可豁免**) |
83
+ | 自定义属性取不到值 | 令牌锚在**容器属性**上,容器**之上**的节点取不到 —— 不要在 `html` / `body` / 挂载根上写 `var(--ui-*)` |
84
+ | 装了两份同名类型 | 依赖重复(四包版本不一致或 peer 冲突),按 `../manohub-kit/references/adoption.md` 的单例收敛处理 |
85
+ | 违规数不降 | 先看是不是只改了写法没改**外观来源** —— `source` 组查的是 import 源,改样式不解决 |
86
+ | 升级后行为变了(点遮罩关不关、尺寸档变大变小…) | 属破坏性变更:逐条对照 §12 与各 README 确认,确认后**写进应用文档**,不要按旧行为「改回去」 |
87
+ | 想知道某写法合不合规 | 读 `CONTRACT.md` 对应层 + §7 自检清单;需要全仓数字时用 §三 的 `kit lint` |
88
+
89
+ ## 七、参考
90
+
91
+ - `references/upgrade-playbook.md`:阶段细则、判据来源详解、依赖与 lock 处置、批次划分、收尾登记
92
+ - `references/verification.md`:三道闸(类型+构建 / 护栏 / 运行时)与**升级期高频陷阱清单**
93
+ - `../manohub-kit/references/adoption.md`:接入 SOP(安装、样式链、入口、类型配置、单例收敛)
94
+ - `../manohub-kit/references/contract-index.md`:契约速查索引(按主题定位章节)
95
+ - `../manohub-kit-dev/references/style-rules.md`:样式纪律(动手改样式前读)
96
+ - `node_modules/@manohub/kit/CONTRACT.md`:规范唯一事实源(§7 自检清单、§12 升级)
@@ -0,0 +1,131 @@
1
+ # 升级 playbook:阶段细则
2
+
3
+ 本文件是 `manohub-kit-upgrade` 的阶段展开。**判据不在这里** —— 判据在契约与随包文档里,
4
+ 本文件只讲「怎么组织一次升级」。
5
+
6
+ ---
7
+
8
+ ## 阶段 0 · 立基线
9
+
10
+ 升级前把四个事实记进应用文档(后面每一步都要拿它对照):
11
+
12
+ | 记录项 | 怎么取 | 为什么要它 |
13
+ |---|---|---|
14
+ | **四包版本** | 读 `node_modules/@manohub/{kit,ui,theme,icon}/package.json` 的 `version` | 四者必须一致;不一致本身就是一条待修的问题 |
15
+ | **构建产物体积** | 跑一次生产构建,记 `dist` 产物大小量级 | 升级后体积突然翻倍往往意味着依赖重复或某件被整包引进来了 |
16
+ | **护栏违规数** | `kit lint` 按组各记一个数 | 这次的进度指标与验收口径 |
17
+ | **关键页面实测值** | 挑若干代表页/弹窗,记下可量化的计算样式或尺寸 | 升级后用来判断「视觉变了」是不是意外 |
18
+
19
+ > 后两项要**在升级前**取。升级后再回头取基线是不可能的(状态已经变了)。
20
+
21
+ ---
22
+
23
+ ## 阶段 1 · 读判据,列清单
24
+
25
+ 按顺序读,一次读完再动手:
26
+
27
+ 1. `node_modules/@manohub/kit/CONTRACT.md` 的 **§12 升级(破坏性)** —— 注意它的覆盖范围,
28
+ 比它更晚的版本不在这里。
29
+ 2. `node_modules/@manohub/ui/README.md` —— 组件清单(件名与成员的权威来源是 `dist` 的 `.d.ts`,
30
+ README 只是索引)、服务层、主题层。
31
+ 3. `node_modules/@manohub/icon/README.md` —— 字形改名对照。
32
+ 4. `node_modules/@manohub/theme/README.md` —— 令牌分片与边界。
33
+ 5. `node_modules/@manohub/kit/README.md` —— 样式链顺序与入口要求。
34
+
35
+ 产出一张**要动的清单**,按性质分三类(它们的处置手法完全不同):
36
+
37
+ | 类别 | 例子 | 怎么改 |
38
+ |---|---|---|
39
+ | **改名类** | 件名 / 成员名 / 字形名 | 编译器会告诉你全部落点,逐个换;**没有别名**,不存在「先用旧的顶一下」 |
40
+ | **删除类** | 某档 prop / 某个导出被撤 | 先找等价能力(新 prop、新成员,或组合写法);找不到走契约 §8 缺件流程,**不要自绘** |
41
+ | **语义翻转类** | 缺省值变了、尺寸档变了、换行口径翻面 | 编译器**不会**报错,只能靠读文档 + 运行时实测抓 —— 这类最危险,清单里单独标出来 |
42
+
43
+ > ⚠️ 仓库内部的 `docs/guide/migration-*.md` 不在发布物里,读不到;别把希望寄托在它上面。
44
+
45
+ ---
46
+
47
+ ## 阶段 2 · 升依赖
48
+
49
+ ### 四包同线
50
+
51
+ 四个包按同一条版本线发布,**一并升降,版本必须一致**:
52
+
53
+ ```bash
54
+ pnpm add @manohub/kit@<v> @manohub/ui@<v> @manohub/theme@<v> @manohub/icon@<v>
55
+ ```
56
+
57
+ monorepo 里如果四包走 `catalog:` 协议,就改 `catalog` 一处(各子包写 `catalog:`),
58
+ 不要在每个子包的 `package.json` 里各写一个版本号 —— 那必然漂开。
59
+
60
+ > 只看某一个包是不是最新不够:四包版本不一致会出现「同名类型不兼容」,这种报错很难归因。
61
+
62
+ ### 依赖与 lock
63
+
64
+ - 装完 **lockfile 一定会变**,把它和源码一起提交;漏提交会让别人的 `install` 结果与你不同。
65
+ - 消费方若开了**最小发布年龄**一类的策略(pnpm 11 起内建默认 24 小时),刚发布的版本可能被
66
+ 解析阶段拒绝或校验阶段硬失败。按消费仓既有做法登记豁免 —— **别为了绕过它去装旧版本**,
67
+ 那会破坏四包同线。清单口径以消费仓自己的 `pnpm-workspace.yaml` 为准。
68
+ - 装完先跑一次类型检查与构建:**这一步的报错就是升级导航**(改名与删除全在这里现形)。
69
+ 此时**不要急着改**,先把报错归类到阶段 1 的三类清单里,再按批改。
70
+
71
+ ### 重建产物再联调
72
+
73
+ 消费侧装的是 `dist`。改了依赖或包产物之后,**必须重建后再起本地服务**,
74
+ 且要清掉构建缓存(清缓存用移动而不是删除,避免被沙箱策略拦)。
75
+
76
+ ---
77
+
78
+ ## 阶段 3 · 分批改
79
+
80
+ ### 按件族切批,不按文件数
81
+
82
+ 一批 = 一个**能被独立验证的语义单元**。建议顺序(先做影响面大、验证方式明确的):
83
+
84
+ 1. **入口与样式链** —— 锚属性、样式引入顺序。这层错了下面全错,且症状明显(颜色全是浏览器默认)。
85
+ 2. **骨架件**(页 / 面板 / 布局)—— 收益最大、风险最低。
86
+ 3. **高密度件**(表格 / 表单 / 弹窗 / 分页)—— prop 差异最大,改完能解掉大部分页面阻塞。
87
+ 4. **图标与图形** —— 改名集中,机械但量大。
88
+ 5. **服务层**(命令式反馈:提示 / 确认 / 加载)—— API 是重新设计的,**逐处改调用点**,不是批量改名。
89
+ 6. **样式收口** —— 删掉为旧版件写的覆盖;残留的视觉意图翻成令牌。
90
+
91
+ ### 每批的固定动作
92
+
93
+ 1. 改这一批涉及的文件;
94
+ 2. 跑**类型检查 + 构建**;
95
+ 3. 跑 `kit lint`(至少 `namespace` 与 `source` 两组),记下本批降了多少;
96
+ 4. **对改到的页面/弹窗做一次运行时验证**(见 `references/verification.md`);
97
+ 5. 记一句结论到应用文档(改了什么、验证证据、遗留)。
98
+
99
+ > 不要攒到最后一起验:升级期的错误会互相掩盖,一次改 50 个文件后你无法判断是哪一处引入的。
100
+
101
+ ### 处理「不确定」的姿势
102
+
103
+ - 拿不准某个写法是否还有效 → **读契约对应层**,不要靠试;
104
+ - 件的能力不够 → 走契约 §8 缺件流程(记录 + 提件),**不要在应用侧自绘**、也不要回去直连底层组件库;
105
+ - 视觉与升级前不一致 → 先判断是不是「旧写法本来就在覆写组件内部类」(那种删掉即可),
106
+ 确属缺能力则记录待建件,**不要把它改回旧的外观**。
107
+
108
+ ---
109
+
110
+ ## 阶段 4 · 收尾
111
+
112
+ | 事项 | 口径 |
113
+ |---|---|
114
+ | 护栏 | `kit lint` 各组违规数从基线降到**零**,或落到能逐条解释的残留(写进文档) |
115
+ | 构建 | 成功;产物体积与基线同量级(差异要能解释,例如某件被新引进来了) |
116
+ | 产物 | **重建一次**,确认联调用的是新产物 |
117
+ | 文档 | 应用文档里更新:四包新版本、本次处置的破坏性变更逐条、验收证据、遗留项 |
118
+ | 技能 | 包升级后重跑一次技能落盘命令刷新本地技能副本(安装器幂等);**跨过技能目录改名的版本时**,要手工删掉旧目录名再重跑,否则新旧两份技能同时在场 |
119
+
120
+ ---
121
+
122
+ ## 附:判断「要不要一次升到位」
123
+
124
+ | 情形 | 做法 |
125
+ |---|---|
126
+ | 中间隔着一次**重构型**跃迁(组件换库 / 主题层独立 / 契约重写) | **一次做完**。拆轮只会把同一段代码改两遍 |
127
+ | 中间是若干次**修复与补齐** | 可以按件族分批,但四包版本一次升到目标值,不要「先升一个小版本试试」 |
128
+ | 目标版本里有**语义翻转类**变更 | 无论怎么分批,这类都要**单独一批**、单独验证、单独记录 |
129
+
130
+ 升级不是「把版本号改大」,而是「把旧版的行为假设逐条换成新版的」。判断一次升级做完了没有,
131
+ 标准只有一个:**基线里每一项都有了对照值,且差异都解释得出来。**
@@ -0,0 +1,137 @@
1
+ # 验证:三道闸与升级期陷阱
2
+
3
+ 升级期最贵的错误不是「改错了」,而是「**以为改对了**」。本文件给三样东西:
4
+ 三道闸分别验什么、每个陷阱怎么用最小代价抓到、以及哪些场景不能省运行时验证。
5
+
6
+ ---
7
+
8
+ ## 闸 1 · 类型 + 构建
9
+
10
+ ```bash
11
+ pnpm exec vue-tsc --noEmit # 或工程引用型 tsconfig 下:vue-tsc -b
12
+ pnpm build
13
+ ```
14
+
15
+ - ⚠️ **工程引用型 tsconfig 下必须带 `-b`**:不带时不编译任何文件、直接成功 —— 那是**假绿**,
16
+ 比报错更危险。以消费仓既有的构建脚本为准(`build` 里应当已经包含它)。
17
+ - 类型报错在升级期**优先当导航用**:改名与删除的落点全在这里,比读文档找得更全。
18
+ - 构建成功后**记体积**,与基线对照。
19
+
20
+ ## 闸 2 · 护栏
21
+
22
+ ```bash
23
+ pnpm exec kit lint --root <应用目录> --namespace <前缀> --json
24
+ ```
25
+
26
+ - 四组分头记数(`style` / `source` / `namespace` / `property`),一次只盯一组地降,别混着看。
27
+ - `--json` 出结构化结果,便于按文件分组、排优先级。
28
+ - 违规数**只降不涨**:某一批改完发现总数涨了,说明这批引入了新的外观来源或新的裸元素写法。
29
+
30
+ ## 闸 3 · 运行时
31
+
32
+ **必须用真实浏览器加载真实应用**(对构建产物或 dev server),不是读源码推断。
33
+
34
+ | 验什么 | 怎么取证据 |
35
+ |---|---|
36
+ | 样式生效 | 读**计算样式**(`getComputedStyle`)与自定义属性的解析值;不要只看源码写了没有 |
37
+ | 尺寸与布局 | 读 `getBoundingClientRect`(边框盒)**与**内容盒,两者差多少就是内距/边框 |
38
+ | 组件行为 | 读件渲染出来的 DOM 结构、属性(如 `disabled`)、以及交互后的状态变化 |
39
+ | 交互 | 用**真实指针事件**(浏览器协议的鼠标/键盘事件),而不是直接调元素的 `click()` —— 后者会绕过指针事件与命中测试 |
40
+ | 视觉 | 改前/改后各截一张,同尺寸同缩放,逐处对照 |
41
+
42
+ **无后端 / 数据拿不到时的做法**:起一个**探测入口**(临时页面挂真实业务组件),
43
+ 把**数据源模块**换成假数据(模块别名替换,只换那一个模块),业务逻辑仍跑真实实现。
44
+ 用完立即删除探测文件,不要让它进版本库。
45
+
46
+ ---
47
+
48
+ ## 升级期高频陷阱(每条都给「怎么抓」)
49
+
50
+ ### 1. 自定义属性静默失效
51
+
52
+ 令牌锚在**容器属性**上 ⇒ 容器**之上**的节点(`html` / `body` / 挂载根)取不到值,
53
+ 且**不报错**,只是落空。
54
+
55
+ **抓法**:在读到的元素上取 `getComputedStyle(el).getPropertyValue('--ui-…')`,
56
+ **空串就是没生效**。修复方向是把样式落到容器**之内**的节点上,而不是去改根节点。
57
+
58
+ ### 2. 组件 prop 的大小写
59
+
60
+ 件的 prop 名以 `dist` 的 `.d.ts` 为准。**写错大小写不会报错** —— 它会作为普通属性落进 `attrs`,
61
+ 有时"看着像生效",有时**静默失效**(被件内以同名 prop 渲染的属性覆盖掉)。
62
+
63
+ **抓法**:读**原生元素**上的 DOM property 与 attribute,并做一次真实输入验证,
64
+ 不要只看"能不能输进去"。
65
+
66
+ ### 3. CSS 特异性
67
+
68
+ 覆写组件内部样式前先数特异性。库的规则常写成 `父类 > 子元素`(0-1-1),
69
+ 一个单纯的应用类(0-1-0)**压不过**,而"压不过"看起来就像"样式没写对"。
70
+
71
+ **抓法**:用浏览器的「匹配规则」接口看**哪条规则赢了**,不要靠调属性试。
72
+ 需要覆盖时,按「元素+类」(0-1-1,靠引入顺序)或「父类 > 子类」(0-2-0)来提权。
73
+
74
+ ### 4. `box-sizing` 吃掉内距
75
+
76
+ 容器内元素若继承 `border-box`,给它加 `padding` 会**从 `width` 里扣掉** ⇒ 内容区变小。
77
+ 图标类元素的症状特别明显(看着"小了一半")。
78
+
79
+ **抓法**:同时量 `getBoundingClientRect`(边框盒)与内容盒;两者相等而内容显得小,就是这条。
80
+ 热区(内距)应当交给**外层包裹元素**,不要写在内容元素自己身上。
81
+
82
+ ### 5. 换了件,只验了自己的样式
83
+
84
+ 最常见的漏验:改完 CSS 看"样式都在",却没验**件本身有没有按预期工作**
85
+ (值没进去、方向反了、件根本没渲染成你想的那个结构)。
86
+
87
+ **抓法**:把件的**实际渲染结果**读出来 —— DOM 结构、关键属性、计算值,
88
+ 并与"它应该是什么样"逐项对照。
89
+
90
+ ### 6. 受控组件的值键不同源 ⇒ 静默显示为空
91
+
92
+ 列表型受控件(下拉 / 树选)按**选项键**精确比较。若传入的值与选项的键**不是同一套标识**
93
+ (一边是 id、一边是 code),件**不报错、不提示**,就是空白 —— 与"没选"看起来一模一样。
94
+
95
+ **抓法**:把要回显的值与选项列表的键**并排打印**比对。数据源侧应当让映射同时登记两套键、
96
+ 并提供「任意标识 → 选项键」的归一化,回显前统一过一遍。
97
+
98
+ ### 7. 探测受控容器要先关后开
99
+
100
+ 组件若在「打开状态」的 `watch` 里做初始化(填表单、重置状态),
101
+ 探测时**直接以「打开」状态挂载会跳过初始化** —— 所有字段停在空值,
102
+ 会被误判成"数据源为空 / 接口失败"。
103
+
104
+ **抓法**:先以关闭状态挂载,稍后再置为打开,并回写状态变化。真实使用路径本来就是"先关后开"。
105
+
106
+ ### 8. 断言写死了随环境变化的值
107
+
108
+ 响应式的数值(随视口折算的尺寸、`min()` / `calc()` 的结果)写死会把"断言错"报成"代码错"。
109
+
110
+ **抓法**:断言里保留算式(用实际视口推导期望值),或断言"关系"而不是"绝对值"。
111
+
112
+ ### 9. 改了依赖 / 包产物却没清缓存
113
+
114
+ 会读到旧的预构建产物,症状是"**改了没生效**"或"报的是上一版才有的错"。
115
+
116
+ **抓法**:改依赖或包产物后,停服务 →(**移动**而不是删除)构建缓存目录 → 重启。
117
+ 不要在运行中的服务上比对。
118
+
119
+ ### 10. 把「无报错」当「已生效」
120
+
121
+ 升级期大量失败是静默的:值落空、属性被忽略、键不同源、初始化被跳过。
122
+ 它们共同的检验方式只有一条:**去读运行时的实际值**,而不是确认"代码写对了"。
123
+
124
+ ---
125
+
126
+ ## 哪些场景不能省运行时验证
127
+
128
+ | 场景 | 为什么 |
129
+ |---|---|
130
+ | 换了件(组件级替换) | 件的用法、默认值、DOM 结构都可能不同 |
131
+ | 改了样式链 / 锚属性 | 错了会整片失效,且症状是"颜色不对"这种容易被忽略的表现 |
132
+ | 改了令牌或用自定义属性 | 静默失效,编译器不管 |
133
+ | 破坏性变更涉及**行为**(缺省值、尺寸档、开关方向) | 编译器完全不管,只有跑起来才看得见 |
134
+ | 改了受控组件的值来源 | 键不同源会静默显示为空 |
135
+
136
+ 反之,纯改名类(件名 / 字形名)有类型检查和护栏兜底,可以不必每处都跑运行时 ——
137
+ 但**每批至少挑一个代表页面**过一遍闸 3。