@ranger1/dx 0.1.105 → 0.1.107

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 (36) hide show
  1. package/lib/cli/commands/core.js +46 -1
  2. package/lib/cli/dx-cli.js +1 -0
  3. package/lib/codex-initial.js +79 -5
  4. package/lib/env.js +7 -3
  5. package/lib/exec.js +4 -1
  6. package/package.json +1 -1
  7. package/skills/backend-audit-fixer/SKILL.md +98 -0
  8. package/skills/backend-audit-fixer/references/backend-layering.md +103 -0
  9. package/skills/backend-audit-fixer/references/e2e.md +60 -0
  10. package/skills/backend-audit-fixer/references/env-accessor.md +73 -0
  11. package/skills/backend-audit-fixer/references/error-handling.md +77 -0
  12. package/skills/{naming-audit-fixer/references/fix-guide.md → backend-audit-fixer/references/naming-fix-guide.md} +8 -3
  13. package/skills/backend-audit-fixer/references/naming.md +139 -0
  14. package/skills/backend-audit-fixer/references/pagination-dto.md +52 -0
  15. package/skills/create-issue/SKILL.md +90 -0
  16. package/skills/issues-batch-deliver/SKILL.md +193 -84
  17. package/skills/pr-train-ship/SKILL.md +202 -49
  18. package/skills/backend-layering-audit-fixer/SKILL.md +0 -180
  19. package/skills/e2e-audit-fixer/SKILL.md +0 -76
  20. package/skills/e2e-audit-fixer/agents/openai.yaml +0 -4
  21. package/skills/env-accessor-audit-fixer/SKILL.md +0 -149
  22. package/skills/env-accessor-audit-fixer/agents/openai.yaml +0 -7
  23. package/skills/error-handling-audit-fixer/SKILL.md +0 -187
  24. package/skills/error-handling-audit-fixer/agents/openai.yaml +0 -7
  25. package/skills/naming-audit-fixer/SKILL.md +0 -149
  26. package/skills/pagination-dto-audit-fixer/SKILL.md +0 -69
  27. package/skills/pagination-dto-audit-fixer/agents/openai.yaml +0 -7
  28. /package/skills/{env-accessor-audit-fixer → backend-audit-fixer}/references/bootstrap-env-foundation.md +0 -0
  29. /package/skills/{error-handling-audit-fixer/references/foundation-bootstrap.md → backend-audit-fixer/references/error-handling-foundation-bootstrap.md} +0 -0
  30. /package/skills/{error-handling-audit-fixer → backend-audit-fixer}/references/error-handling-standard.md +0 -0
  31. /package/skills/{pagination-dto-audit-fixer → backend-audit-fixer}/references/pagination-standard.md +0 -0
  32. /package/skills/{e2e-audit-fixer/scripts/e2e_e2e_audit.py → backend-audit-fixer/scripts/e2e_audit.py} +0 -0
  33. /package/skills/{env-accessor-audit-fixer → backend-audit-fixer}/scripts/env_accessor_audit.py +0 -0
  34. /package/skills/{error-handling-audit-fixer → backend-audit-fixer}/scripts/error_handling_audit.py +0 -0
  35. /package/skills/{naming-audit-fixer/scripts/audit_naming.py → backend-audit-fixer/scripts/naming_audit.py} +0 -0
  36. /package/skills/{pagination-dto-audit-fixer → backend-audit-fixer}/scripts/pagination_dto_audit.py +0 -0
@@ -0,0 +1,77 @@
1
+ # 维度:错误处理(error-handling)
2
+
3
+ 脚本:`scripts/error_handling_audit.py`。规则来源:`ruler/conventions.md` §9 统一错误码。
4
+
5
+ 先判断是否已具备统一错误处理基础设施,再扫业务代码是否绕过 `DomainException` / `ErrorCode`。默认只输出审计+建议,用户明确要求才自动修复。
6
+
7
+ ## 扫描范围
8
+
9
+ 脚本不预设路径,需 `--src-dir` / `--e2e-dir` 显式传入。以下始终排除:
10
+ 单测 `*.spec.ts`/`*.test.ts`/`*.e2e-spec.ts`;测试辅助 `*.mock.ts`/`*.stub.ts`/`*.fixture.ts`/`fixtures/`/`test-utils/`/`testing/`/`__tests__/`;基础设施 `*/filters/`/`prisma/`/`scripts/`;异常定义 `*.exception.ts`;入口 `main.ts`。
11
+
12
+ 仅用户**明确要求**评估测试债务时才传 `--e2e-dir` + `--scope e2e`。
13
+
14
+ ## 运行
15
+
16
+ 步骤 0 先探索项目(识别生产代码与测试目录,monorepo 多服务各传一个 `--src-dir`)。
17
+
18
+ ```bash
19
+ SKILL_HOME="${SKILL_HOME:-$HOME/.claude/skills}"
20
+ python "$SKILL_HOME/backend-audit-fixer/scripts/error_handling_audit.py" \
21
+ --workspace "$PWD" \
22
+ --src-dir apps/backend/src \
23
+ --output-json /tmp/audit-error.json
24
+ ```
25
+
26
+ 仅在用户要求时审计测试代码:`--e2e-dir apps/backend/e2e --scope e2e`。
27
+
28
+ ## 识别四类问题
29
+
30
+ 1. 直接实例化 Nest 标准异常(`BadRequestException`、`HttpException` 等)。
31
+ 2. `throw new Error(...)` 或 `Promise.reject(new Error(...))`。
32
+ 3. 直接 `new DomainException(...)` 但 payload 未显式带 `code`。
33
+ 4. `DomainException` 直接返回中文 message。
34
+
35
+ ## 合法 raw-error 判定(强制复核,别原样转发脚本结果)
36
+
37
+ 脚本 `raw-error` 规则误报率极高(实测一次 18 命中,复核后 17 个是误报)。**每条 `raw-error` 命中必须打开源码定位,按下表判定 `real` 还是 `false-positive`,禁止把脚本命中直接当 violation 报、禁止给误报写"建议改 XXX"。** 下列模式属合法 raw-error,不算违规:
38
+
39
+ | 合法模式 | 识别特征 | 实例 |
40
+ |---------|---------|------|
41
+ | 本地 catch 控制流 | `try` 内 `throw new Error` 紧接着被**同函数本地 `catch`** 捕获(吞掉 / 返回 null / 重试下一候选),不向 HTTP 上抛 | metadata 解析校验后 `catch { return null }`;候选循环 `lastError` 重试 |
42
+ | 内部不变量断言 | programmer invariant / 生命周期断言,触发即代码 bug,非用户可达业务错误 | `called before onModuleInit`、`Character missing in RequestContext`、`rows must match delete window`、启动期常量自检 |
43
+ | 运维脚本/非 HTTP 路径 | backfill、dry-run、CLI、Cron 等非 HTTP 业务请求路径的参数/SOP 校验 | `backfill window exceeds max`、`refuse to overwrite missing row` |
44
+ | 控制流信号 | `Promise.race` 超时、迭代终止等把 Error 当信号用,非异常上抛 | `setTimeout(() => reject(new Error('timeout')))` |
45
+
46
+ 真违规特征:**走 HTTP 业务请求路径(Controller→Service→Repository)、资源不存在 / 参数非法 / 状态冲突等用户可达错误、错误会冒泡到响应**。这类才报 `real` 并建议领域异常。
47
+
48
+ `domain-exception-missing-code` 同样要复核:若 `code` 是变量(如 `classify400()` 返回值)赋给 payload,脚本静态匹配不到但实际带了 code,属误报。
49
+
50
+ ## 修复准则(优先级固定)
51
+
52
+ 1. **优先复用现有领域异常**:模块 `exceptions/` 已有语义匹配类直接复用。
53
+ 2. **缺少则新增领域异常类**:在模块 `exceptions/` 下继承 `DomainException`,构造函数显式指定 `ErrorCode`,上下文放 `args`(不写死文案到 message),补最小单测。
54
+ 3. **临时直接用 DomainException**:仅在未抽专用类但必须推进时;payload 必含 `code`,`args` 保留排障上下文。
55
+ 4. **基础设施缺失判断**:无 `DomainException`/`ErrorCode` → 先补基础设施,别发散新增几十个本地异常;有 `DomainException` 无统一 `ErrorCode` → 先统一错误码源;有类有码缺结构化输出链路 → 先补过滤器/输出映射,保证 `code`/`args`/`requestId` 稳定透出。
56
+
57
+ 详见 [error-handling-standard.md](./error-handling-standard.md) 与 [error-handling-foundation-bootstrap.md](./error-handling-foundation-bootstrap.md)。
58
+
59
+ ## 注意
60
+
61
+ - 明确区分 `src` 与 `e2e` 命中数量,别让测试噪音淹没生产风险。
62
+ - 脚本结果与实际不一致时,抽样打开命中文件复核,别当绝对真相。
63
+ - **每条命中必带 `verdict`**:`real`(已开源码确认走 HTTP 业务路径、用户可达错误)或 `false-positive`(命中"合法 raw-error 判定"表任一模式,`note` 写明哪类)。未开源码确认不准报 `real`。
64
+
65
+ ## 返回给主 agent 的 findings
66
+
67
+ `total` 是脚本原始命中数;`real_total` 是复核后真违规数。两者都要给,让主 agent 看到误报比例。
68
+
69
+ ```json
70
+ {
71
+ "dimension": "error-handling",
72
+ "infra_status": {"DomainException":false,"ErrorCode":false,"filter":false},
73
+ "src": {"total":0,"real_total":0,"by_rule":{}},
74
+ "e2e": {"total":0,"real_total":0,"by_rule":{}},
75
+ "violations": [{"file":"","scope":"src","rule":"","line":0,"verdict":"real|false-positive","note":"real 写建议领域异常;false-positive 写命中哪类合法模式"}]
76
+ }
77
+ ```
@@ -78,14 +78,19 @@ dx build admin --dev
78
78
  | Hook .ts | camelCase | `useChat.ts` |
79
79
  | 路由文件 | 小写 | `page.tsx`, `layout.tsx` |
80
80
  | 目录 | kebab-case | `character/`(单数) |
81
- | ui/ | kebab-case | `button.tsx` |
81
+ | ui/ | kebab-case(shadcn 原生,**豁免 PascalCase**) | `button.tsx` |
82
+ | 点号描述符 | 保留,仅 base 段 kebab | `announcement-popup.storage.ts` ✅ |
82
83
 
83
- ### Vite + React
84
+ ### Vite + React(admin-front)
84
85
 
85
- Next.js 相同,但无路由文件约束。
86
+ 组件/工具命名同 Next.js。但 **`pages/**` 走 vite-plugin-pages 文件路由**:文件名即 URL,`.tsx` 改名属破坏性,默认不动(见高风险注意)。
86
87
 
87
88
  ## 高风险操作注意
88
89
 
90
+ - **vite-plugin-pages 文件路由(admin-front 最高危)**:`pages/**` 文件名即 URL。改名前 `rg "vite-plugin-pages|react-pages"`;命中则 `pages/**/*.tsx` 默认不改(改名 = 改 URL,且常无 import 纯靠路由存活,改完直接失联)。确需改:同步改 Pages `exclude` 或确认 URL 可变更并手测路由可达。
91
+ - **点号是描述符不是违规**:§10 认可 `.storage`/`.toggle`/`.core` 等描述符点号。改名**只动 base 段大小写**,保留点号(`CharactersPane.sub-normalize.ts`→`characters-pane.sub-normalize.ts`,不要拍平成 `characters-pane-sub-normalize.ts`)。
92
+ - **macOS 大小写不敏感**:`git mv MessageCenter message-center` 仅改大小写可能失败,需中间名过渡(`MessageCenter`→`message-center-tmp`→`message-center`)。
93
+ - **深引用 vs barrel**:改目录名前先 `rg` 确认外部走深路径还是 barrel——别假设走 index.ts,本仓实测外部全是 `Dir/Component` 深引用、barrel 零外部消费。
89
94
  - **barrel export (index.ts)**:重命名后检查是否有 `export * from './old-name'`
90
95
  - **动态 import**:`import()` 表达式中的路径也需要更新
91
96
  - **tsconfig paths**:如果 tsconfig 中配置了路径别名指向具体文件,也需更新
@@ -0,0 +1,139 @@
1
+ # 维度:文件/文件夹命名规范(naming)
2
+
3
+ 脚本:`scripts/naming_audit.py`。规则来源:`ruler/conventions.md` §10 前端目录与命名。
4
+
5
+ **特例**:此维度脚本不裸跑,需 model 先分析项目拼 JSON config 经 stdin 喂脚本。模型决策(判框架/范围/项目约定),脚本执行(遍历匹配输出)。
6
+
7
+ > ⚠️ **脚本只给候选,定性靠 model**。本仓实测脚本原始命中 95 → 真违规仅 21(误报率 78%)。脚本不懂「项目真源说哪条算合规」,所有命中**必须**逐条对照 §10 复核后再报。下方「§10 命中复核」是硬门槛,跳过即产出错误 issue。
8
+
9
+ ## Step 1:分析项目(subagent 先做)
10
+
11
+ 读以下判定技术栈与目录结构:
12
+ 1. `package.json`(根+各 app)— 识别框架
13
+ 2. `pnpm-workspace.yaml` / `workspaces` — monorepo 结构
14
+ 3. `tsconfig.json` — 源码目录(`rootDir`/`include`)
15
+ 4. `CLAUDE.md` / `AGENTS.md` — 项目自定义命名约定(优先级最高)
16
+ 5. `ls` 浏览实际源码位置
17
+
18
+ 确定:每个 app 框架、源码根目录、是否有 Next.js app 目录(路由豁免)、额外跳过目录(`generated/`)、额外豁免文件。
19
+
20
+ ### 范围裁剪(本仓实测,先裁再扫)
21
+
22
+ `ruler/conventions.md` §10 标题即「**前端**目录与命名规范」,全部条款/示例均为前端风格、**无后端条款**。据此:
23
+
24
+ | 目录 | 是否扫 | 原因 |
25
+ |------|--------|------|
26
+ | `apps/backend/src` `apps/backend/e2e` | **不扫** | §10 不约束后端。`x.service.spec.ts` 等点号是 NestJS 官方惯例,全是误报(本仓 33 条全假)。除非项目另有后端命名真源,否则别把 backend 塞进 config |
27
+ | `apps/front/src` | 扫 `nextjs-react` | §10 主战场 |
28
+ | `apps/admin-front/src` | **谨慎/默认不改** | 见下「vite-plugin-pages 路由陷阱」。可审计出报告,但 `pages/**` 的 `.tsx` 改名属破坏性,默认排除、单独评估 |
29
+ | `packages/shared/src` `packages/api-contracts/src` | 扫 `generic-ts`(api-contracts 加 `extra_skip_dirs:["generated"]`) | codegen 产物豁免 |
30
+
31
+ > 没有后端命名真源就别扫后端。脚本能扫不代表该扫——真源边界决定范围。
32
+
33
+ ### vite-plugin-pages 路由陷阱(admin-front 高危)
34
+
35
+ admin-front 用 `vite-plugin-pages`(`~react-pages`),`pages/**` **按文件名生成路由 URL**。把 `pages/comment/reports.tsx` 改成 `Reports.tsx` 会把 URL 从 `/comment/reports` 变成 `/comment/Reports`,且这类文件常**无任何 import**(纯靠文件路由存活),改名即路由失联。
36
+
37
+ → 扫到 admin-front 前先 `rg "vite-plugin-pages|react-pages" apps/admin-front`。命中则 `pages/**/*.tsx` 默认**不纳入改名**(写进 issue out-of-scope),需治理时必须同步处理 Pages 的 `exclude` 或确认 URL 可变更并加路由可达回归。`pages/` 外的组件/工具文件不受此限。
38
+
39
+ ## Step 2:拼 config 喂脚本
40
+
41
+ > config **必须**与上方「范围裁剪表」一致:**不要**把 `apps/backend` 写进 scans(§10 不约束后端,扫了全是误报)。admin-front 可扫出报告但 `pages/**` 改名走 out-of-scope。
42
+
43
+ ```bash
44
+ SKILL_HOME="${SKILL_HOME:-$HOME/.claude/skills}"
45
+ echo '{
46
+ "scans": [
47
+ {"root": "apps/front/src", "framework": "nextjs-react", "app_dir": "app"},
48
+ {"root": "apps/admin-front/src", "framework": "react"},
49
+ {"root": "packages/shared/src", "framework": "generic-ts"},
50
+ {"root": "packages/api-contracts/src", "framework": "generic-ts", "extra_skip_dirs": ["generated"]}
51
+ ]
52
+ }' | python "$SKILL_HOME/backend-audit-fixer/scripts/naming_audit.py"
53
+ ```
54
+
55
+ > 上面是本仓(无后端命名真源)的正确 config 形态。其他仓若确有后端命名真源,再按真源加 backend scan。
56
+
57
+ config 字段:
58
+
59
+ | 字段 | 必填 | 说明 |
60
+ |------|------|------|
61
+ | `root` | 是 | 扫描目录(相对项目根) |
62
+ | `framework` | 是 | 规则集,见下 |
63
+ | `app_dir` | 否 | Next.js app 目录名(默认 `app`),仅 `nextjs-react` 需要 |
64
+ | `extra_skip_dirs` | 否 | 额外跳过目录名 |
65
+ | `extra_ok_files` | 否 | 额外豁免文件名 |
66
+
67
+ 支持 framework:`nestjs` / `nextjs-react` / `react` / `vue` / `angular` / `generic-ts`。
68
+
69
+ ## Step 2.5:§10 命中复核(硬门槛,逐条过)
70
+
71
+ 脚本命中后,**每条**按下表判定,剔除误报与脏建议名再报。本仓实测命中 95→真违规 21,全栽在这几类:
72
+
73
+ | 复核项 | 规则(§10 真源) | 处理 |
74
+ |--------|------------------|------|
75
+ | **点号 ≠ 违规** | §10 把 `announcement-popup.storage.ts` 列为**合规**示例 → 描述性点号(`.storage`/`.toggle`/`.sub-normalize`/`.core`/`.middleware`/`.slice` 等)是认可的。违规的**只是 base 段大小写** | base 已 kebab 的点号文件(`share-story.toggle.test.ts`/`unified-error-handler.core.ts`)→ **不报**。只报 base 段是 camelCase/PascalCase 的(`CharactersPane.sub-normalize.ts`→`characters-pane.sub-normalize.ts`,保留点号) |
76
+ | **ui/ 豁免** | §10:「`ui/` 仅存放 shadcn 原生组件,保持 kebab-case」 | `components/ui/*.tsx` 的 kebab 命中**全部剔除**(本仓 26 条误报) |
77
+ | **hook 文件** | §10:hooks `.ts`/`.tsx` 用 camelCase | `useXxx.tsx`/`useXxx.ts` 被脚本判 PascalCase 的→剔除 |
78
+ | **多导出模块文件** | 文件导出 Provider+hook+类型+常量混合(非单一组件)→ 非「组件文件」,PascalCase 改名语义存疑 | 标 out-of-scope,不强改(如 theme 模块 `yuzu.tsx`) |
79
+ | **纯多组件文件**(区别于上行) | 文件只导出多个组件、无 hook/类型/Provider(如 `skeletons.tsx` 5 个 skeleton、`v7-sections.tsx` 组件+常量) | **算真违规**(仍是组件文件),按 PascalCase 报;建议名取主导出或文件语义(`Skeletons.tsx`),标注「多导出、命名取语义」 |
80
+ | **spec/test 文件名** | 测试文件名跟随**被测对象**命名,不独立判定 | 被测是组件(`ThemeProvider.tsx` PascalCase 合规)→ 其 `ThemeProvider.spec.ts` 跟随 PascalCase,**剔除**;被测是 kebab 文件 → spec 也 kebab |
81
+ | **工具函数文件** | 导出纯函数(非组件非 hook)的 `.tsx`/`.ts` | 按工具文件走 kebab(`focusOnMount.ts`→`focus-on-mount.ts`),**不要**按 .tsx 后缀套 PascalCase |
82
+ | **建议名脏数据** | 脚本对 camelCase 源生成的 `suggested` 可能是乱码(`renderWithYuzu.tsx`→`Renderwithyuzu.tsx`) | 建议名一律人工核,勿照搬脚本 `suggested` |
83
+ | **文件名 vs 导出名** | 单组件文件名应对齐其默认导出 | `page-router.tsx` 默认导出 `CharacterPageRouter`→建议 `CharacterPageRouter.tsx` 而非 `PageRouter.tsx` |
84
+
85
+ 复核产出:把脚本原始 N 条标注为「真违规 / 误报(原因) / out-of-scope(原因)」三类,findings 只含真违规。
86
+
87
+ ## Step 3:解读报告
88
+
89
+ 脚本输出 JSON:`total_violations` / `summary_by_rule` / `violations[]`(path/rule/current/suggested)/ `fix_plan[]`(`git mv` 命令)。
90
+
91
+ 展示:按规则汇总表 + 按目录分组列表(当前名→建议名)+ 询问是否修复。**审计阶段不自动改码。**
92
+
93
+ ## Step 4:修复(用户确认后)
94
+
95
+ 详见 [naming-fix-guide.md](./naming-fix-guide.md)。要点:
96
+ 1. 目录优先 `git mv`
97
+ 2. 按模块分批
98
+ 3. 每次重命名后 Grep 找所有 import/require 引用,Edit 更新
99
+ 4. 检查 barrel `index.ts` re-export
100
+ 5. 增量验证 lint + build
101
+ 6. 全部完成跑受影响测试
102
+
103
+ ## 命名规则速查
104
+
105
+ | framework | 核心规则 |
106
+ |----|---------|
107
+ | `nestjs` | `kebab-name.type.ts`(name 部分连字符),目录 kebab-case |
108
+ | `nextjs-react` | .tsx PascalCase,.ts kebab-case,hook camelCase,路由文件(`page.tsx`/`layout.tsx`)豁免,目录 kebab-case |
109
+ | `react` | .tsx PascalCase,.ts kebab-case,hook camelCase |
110
+ | `vue` | .vue PascalCase 或 kebab-case,.ts kebab-case |
111
+ | `angular` | `kebab-name.type.ts` |
112
+ | `generic-ts` | 全 kebab-case |
113
+
114
+ ## 注意
115
+
116
+ - 项目约定优先(CLAUDE.md/AGENTS.md 定义则以项目为准)。
117
+ - 脚本结果可能误报,展示前抽查。
118
+ - 目录重命名影响大,建议单独 commit。
119
+ - 入口文件、声明文件、动态路由自动豁免;`node_modules/`/`dist/`/`migrations/` 自动跳过。
120
+
121
+ ## 返回给主 agent 的 findings
122
+
123
+ `total` / `violations` 只含 **Step 2.5 复核后的真违规**;脚本原始数与剔除情况放 `triage`,让主 agent 知道范围怎么裁的。
124
+
125
+ ```json
126
+ {
127
+ "dimension": "naming",
128
+ "raw_hits": 0,
129
+ "total": 0,
130
+ "by_rule": {},
131
+ "violations": [{"file":"","rule":"","current":"","suggested":""}],
132
+ "triage": {
133
+ "excluded_false_positive": [{"file":"","reason":"ui/ shadcn 保留 kebab"}],
134
+ "excluded_out_of_scope": [{"file":"","reason":"vite-plugin-pages 路由 / 多导出模块 / 后端非 §10 范围"}]
135
+ }
136
+ }
137
+ ```
138
+
139
+ > `suggested` 必经人工核(脚本可能给乱码名);单组件文件名对齐默认导出名。
@@ -0,0 +1,52 @@
1
+ # 维度:分页 DTO(pagination-dto)
2
+
3
+ 脚本:`scripts/pagination_dto_audit.py`。规则来源:`ruler/conventions.md` §12 分页响应约定。
4
+
5
+ 先识别非标准分页 DTO 和手工分页返回,再按统一基类改造。脚本输出为问题清单真值源。
6
+
7
+ ## 运行
8
+
9
+ ```bash
10
+ SKILL_HOME="${SKILL_HOME:-$HOME/.claude/skills}"
11
+ python "$SKILL_HOME/backend-audit-fixer/scripts/pagination_dto_audit.py" \
12
+ --workspace /Users/a1/work/ai-monorepo \
13
+ --output-json /tmp/audit-pagination.json
14
+ ```
15
+
16
+ ## 执行流程
17
+
18
+ 1. 扫 `apps/backend/src/**/*.ts`,必要时 `--include-glob` 扩范围。
19
+ 2. 识别三类:
20
+ - 请求 DTO 声明 `page/limit/pageSize/currentPage` 但未继承 `BasePaginationRequestDto`
21
+ - 响应 DTO 命中 `items/data/total/page/limit/pageSize/currentPage` 但未继承 `BasePaginationResponseDto`
22
+ - Controller/Service/UseCase 直接 `return { ... }` 手工拼装分页结构
23
+ 3. 对照 [pagination-standard.md](./pagination-standard.md) 修复。
24
+ 4. 保持接口兼容;历史非标准字段名显式说明保留/转换策略。
25
+ 5. 复扫确认。
26
+
27
+ ## 修复准则
28
+
29
+ - 请求 DTO:继承 `BasePaginationRequestDto`,仅保留额外查询参数。
30
+ - 响应 DTO:改 `extends BasePaginationResponseDto<ItemResponseDto>`。
31
+ - 返回构造:在 **Controller 层** `new BasePaginationResponseDto(total, page, limit, items)`;Service/Repository 只返回 `{ total, items }` 等原始对象。
32
+ - 装饰器:用 `@ApiOkResponsePaginated(ItemDto)`,禁止手动 `@ApiExtraModels(BasePaginationResponseDto, ...)`。
33
+ - 兼容:线上依赖 `data/currentPage/pageSize` 时过渡期显式映射,不静默删字段。
34
+
35
+ > 注意:`ruler/conventions.md` §12 已禁用 `createPaginationResponseDto` 动态工厂与 `*PaginationResponseDto` 子类。修复一律走 `new BasePaginationResponseDto(...)` + `@ApiOkResponsePaginated`。
36
+
37
+ ## 判断原则
38
+
39
+ - 同时出现 `total` 且 `items`/`data`,再叠加 `page/limit/pageSize/currentPage` 任一 → 强分页信号。
40
+ - 类名/变量名含 `Pagination`/`Paginated`/`ListResponse`/`PageResult` → 优先人工复核。
41
+ - 只是普通列表无总数/页码 → 不归入本维度。
42
+
43
+ ## 返回给主 agent 的 findings
44
+
45
+ ```json
46
+ {
47
+ "dimension": "pagination-dto",
48
+ "total": 0,
49
+ "by_rule": {"request-dto":0,"response-dto":0,"manual-return":0},
50
+ "violations": [{"file":"","rule":"","line":0,"note":""}]
51
+ }
52
+ ```
@@ -0,0 +1,90 @@
1
+ ---
2
+ name: create-issue
3
+ description: 仅在用户显式调用 /create-issue 或明确要求使用 create-issue 技能时使用;不要通过关键词自动触发。用于把已收敛的设计对照 / 缺陷调查 / 需求讨论落成开发者可快速定位、可客观验收的 GitHub issue。
4
+ ---
5
+
6
+ # Create Issue
7
+
8
+ ## Overview
9
+
10
+ Turn a converged discussion into issue(s) that read like **an architect handing a spec to a programmer**: the programmer can locate the work, understand the plan without asking back, and verify done objectively — without the user re-issuing instructions each time.
11
+
12
+ **Core principle — write it as a task dispatch, not a bug note.** Every issue must let a programmer execute end-to-end on first read. That means three things per finding:
13
+ 1. **Stable location** — anchor to a durable identifier (`file` + function/class/symbol/section name, or a short quoted snippet). Line numbers are a *navigation hint only*, always approximate, never the anchor — code shifts and a hard line pin rots immediately and over-constrains the fix.
14
+ 2. **An unambiguous plan** — what to change and why, with no decision left dangling that forces the programmer to come back and ask.
15
+ 3. **An objective acceptance check** — verifiable by behavior/text/data-state plus a runnable command where applicable.
16
+
17
+ An issue that says "the button is wrong" forces the developer to re-investigate what you already know. An issue pinned to `Button.tsx:42` sends them to the wrong line after one edit. Anchor by symbol, plan the work, define done.
18
+
19
+ **Manual-only:** this skill NEVER auto-triggers on keywords (提issue / file an issue / etc.). Run it only when the user explicitly invokes `/create-issue` or names the skill.
20
+
21
+ ## When to Use
22
+
23
+ Only on explicit invocation. Appropriate when a review/investigation has converged — you've already located code and compared against a source of truth, and actionable items emerged.
24
+
25
+ **Not for:** still-exploring discussions, trivial one-line fixes the user is about to do themselves, or vague ideas with no verifiable outcome.
26
+
27
+ ## Workflow
28
+
29
+ 1. **Probe the repo's issue conventions first.** Read `CONTRIBUTING`, issue templates (`.github/`), or any `git-workflow`/ruler docs; skim a recent `gh issue list`. Match their template, labels, title style. Never hardcode another repo's format.
30
+ 2. **Group issues:**
31
+ - **3+ issues → always auto-create one parent/umbrella tracking issue + child issues. Do NOT ask, do NOT discuss.** Children link back with `Refs: #<parent>`; the parent lists children as a checklist and holds the cross-issue map.
32
+ - **Fewer than 3 → apply the Merge vs. Split table.** Confirm via AskUserQuestion only when genuinely ambiguous; otherwise state the default and proceed.
33
+ 3. **Anchor every finding to a stable location.** Anchor by `file` + durable identifier (function/class/method/symbol name, or a short quoted snippet), NOT by a hard line number. A line number may ride along as an approximate hint (`Button.tsx · onSubmit() (~L42)`), but the symbol is the anchor — it survives edits, a line pin doesn't. Pair each with its source-of-truth location (design section, spec criterion). Present as a table: `维度 | 期望(真源) | 现状(代码) | 位置(符号/锚点)`.
34
+ 4. **Plan the work like an architect.** State the intended approach so a programmer can execute without coming back to ask. Resolve the decisions you can already resolve; for genuinely open ones, say so explicitly and give the constraint/tradeoff rather than leaving a silent gap. Name the shared root cause once. Avoid ambiguity: if a phrasing could be read two ways, rewrite it.
35
+ 5. **Draw the boundary.** Explicitly list what's OUT of scope, what stays unchanged, and any knock-on effects on other files/modules — so the developer doesn't "fix" intentional things or miss a ripple. Call out adjacent code the change must NOT break.
36
+ 6. **Make acceptance criteria objective.** Each checkbox judges ONE thing, verifiable by behavior/text/data-state PLUS a runnable command (lint/build/test) where applicable. No "code is cleaner" subjective items.
37
+ 7. **Create via heredoc**, not `-m`/`--body` single-line (literal `\n` won't become newlines). Title in Conventional Commits style. For plain ordinals use `A1`/`第1项`/`` `#1` `` — never bare `#1`/`#2` (GitHub resolves them to issue links).
38
+ 8. **Review created issues — both plan AND code (MANDATORY).** After ALL issues are created, dispatch a subagent to audit them (see section below). The audit has TWO jobs: (a) verify claims match the codebase, and (b) read each issue as the programmer who'll execute it and flag any plan-level defect — ambiguity, missing decision, wrong/risky approach, undefined scope. Fix EVERY problem it reports via `gh issue edit` before reporting done.
39
+ 9. **Report back** the created URL(s) + one-line grouping/boundary summary + what the review found and fixed.
40
+
41
+ ## Post-Creation Review (mandatory)
42
+
43
+ After creating every issue, dispatch a subagent (Explore or general-purpose). Hand it the issue numbers/URLs and have it run BOTH passes below per issue. Reading code consistency alone is not enough — a factually-correct issue can still be unexecutable.
44
+
45
+ **Pass A — Code consistency (does it match reality?):**
46
+ - Every location anchor (file + symbol) actually exists and points at the claimed code. (Don't fail an issue over a stale line-number hint — anchors are symbols; line numbers are approximate by design.)
47
+ - Each acceptance criterion is objectively verifiable (a real command / path / behavior), not aspirational.
48
+ - Claims about current state (bugs, missing permissions/config, signatures) are true in the code TODAY.
49
+ - No finding contradicts the codebase or describes work already done.
50
+
51
+ **Pass B — Plan soundness (read it as the assigned programmer):** Ask "could I execute this start-to-finish without coming back to ask a question?"
52
+ - **Ambiguity:** any sentence open to two readings; vague pronouns; "fix the handling" with no defined target behavior.
53
+ - **Missing decision:** the issue defers a choice it should have made (which API, which file, which pattern) and leaves the programmer guessing.
54
+ - **Wrong/risky approach:** the proposed plan would break adjacent code, fight an existing convention (check ruler/CLAUDE.md), or pick a clearly worse path.
55
+ - **Undefined scope/boundary:** no out-of-scope statement, or knock-on effects on other modules not called out.
56
+ - **Acceptance ≠ goal:** the checkboxes, even if objective, don't actually prove the stated goal is met.
57
+ - **Structural:** `Refs:`/parent links correct; no bare `#n` ordinal mis-links; 3+ issues have an umbrella.
58
+
59
+ The subagent returns a per-issue defect list spanning both passes. **You MUST fix ALL reported problems** via `gh issue edit` (heredoc), then re-verify. Do not report the task complete while any reported problem stands unfixed.
60
+
61
+ ## Merge vs. Split (only when <3 issues)
62
+
63
+ | Signal | Action |
64
+ |--------|--------|
65
+ | Same component / source-of-truth target / change cycle, mutually non-blocking | One issue, internal groups (A/B/C) |
66
+ | Different host (e.g. web vs. mobile/Flutter), independent tracking/rollback, one item far heavier | Split, link with `Refs:` |
67
+ | User explicitly asks to split/merge | Follow user, link related ones |
68
+
69
+ ## Common Mistakes
70
+
71
+ - **Pinning to a hard line number** → after one edit the anchor points at the wrong code and over-constrains the fix. Anchor by file + symbol; line numbers are an approximate hint only.
72
+ - **Filename with no symbol anchor at all** → developer re-hunts. Always name the function/class/section.
73
+ - **Writing a bug note, not a task spec** → "X is wrong" with no plan leaves the programmer to redesign. State the intended approach.
74
+ - **Leaving a decision dangling** → "handle this better" forces a round-trip question. Resolve it, or state the constraint explicitly if genuinely open.
75
+ - **Acceptance criteria all subjective/visual** → not verifiable. Attach a command or observable behavior.
76
+ - **Acceptance that doesn't prove the goal** → objective but checks the wrong thing. Tie each checkbox to the stated goal.
77
+ - **Asking about grouping for 3+ issues** → don't. Auto-create umbrella + children.
78
+ - **Post-creation review only checks code, not the plan** → ships factually-correct but unexecutable/ambiguous issues. Run BOTH passes (code consistency + plan soundness).
79
+ - **No out-of-scope section** → developer changes intentional things or misses a ripple. Always state the boundary and knock-on effects.
80
+ - **`-m "...\n..."`** → literal `\n` in the issue body. Use heredoc `--body-file -`.
81
+ - **Bare `#1`/`#2` for ordinals** → GitHub mis-links them. Use `A1` / backticks.
82
+
83
+ ## Red Flags — stop and fix before reporting done
84
+
85
+ - About to anchor a finding to a bare line number, or with no symbol/source-of-truth reference at all.
86
+ - The issue describes what's wrong but not what to do about it — a programmer would have to design the fix from scratch.
87
+ - A sentence in the issue could be read two ways, or defers a decision the issue should have made.
88
+ - An acceptance checkbox you can't verify by running something or observing a concrete state — or that doesn't actually prove the goal.
89
+ - 3+ issues created without an umbrella, or related issues without `Refs:`.
90
+ - Reported done without running BOTH review passes (code + plan) and fixing every finding.