@h-ai/cli 0.1.0-alpha.56 → 0.1.0-alpha.57

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 (69) hide show
  1. package/README.en.md +205 -0
  2. package/README.ja.md +205 -0
  3. package/README.md +16 -0
  4. package/dist/chunk-MJGUBOAV.js +391 -0
  5. package/dist/chunk-MJGUBOAV.js.map +1 -0
  6. package/dist/{cli-skill-templates-ZIWYMS4Y.js → cli-skill-templates-ZYXES3NT.js} +3 -3
  7. package/dist/{cli-skill-templates-ZIWYMS4Y.js.map → cli-skill-templates-ZYXES3NT.js.map} +1 -1
  8. package/dist/index.js +32 -69
  9. package/dist/index.js.map +1 -1
  10. package/package.json +7 -7
  11. package/templates/apps/api/.gitignore.hbs +13 -0
  12. package/templates/apps/api/.npmrc.hbs +2 -0
  13. package/templates/apps/api/e2e/api-service.spec.ts.hbs +1 -1
  14. package/templates/apps/api/{eslint.config.js → eslint.config.js.hbs} +6 -8
  15. package/templates/apps/api/package.json.hbs +1 -1
  16. package/templates/apps/fullstack/.gitignore.hbs +16 -0
  17. package/templates/apps/fullstack/.npmrc.hbs +2 -0
  18. package/templates/apps/fullstack/apps/{{projectName}}-app/eslint.config.js.hbs +5 -8
  19. package/templates/apps/fullstack/apps/{{projectName}}-desktop/eslint.config.js.hbs +5 -8
  20. package/templates/apps/fullstack/apps/{{projectName}}-web/eslint.config.js.hbs +5 -8
  21. package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +1 -1
  22. package/templates/apps/fullstack/{eslint.config.js → eslint.config.js.hbs} +6 -8
  23. package/templates/apps/fullstack/package.json.hbs +1 -1
  24. package/templates/base/.npmrc.hbs +15 -0
  25. package/templates/base/eslint-rules.js +45 -0
  26. package/templates/base/eslint.config.js.hbs +6 -8
  27. package/templates/base/package.json.hbs +1 -1
  28. package/templates/skills/AGENTS.md +9 -8
  29. package/templates/skills/CLAUDE.md +4 -0
  30. package/templates/skills/bridges/admin/AGENTS.md +8 -0
  31. package/templates/skills/bridges/admin/CLAUDE.md +4 -0
  32. package/templates/skills/bridges/admin/copilot-instructions.md +2 -0
  33. package/templates/skills/bridges/api/AGENTS.md +8 -1
  34. package/templates/skills/bridges/api/CLAUDE.md +4 -0
  35. package/templates/skills/bridges/api/copilot-instructions.md +2 -0
  36. package/templates/skills/bridges/fullstack/AGENTS.md.hbs +8 -2
  37. package/templates/skills/bridges/fullstack/CLAUDE.md.hbs +4 -0
  38. package/templates/skills/bridges/fullstack/copilot-instructions.md.hbs +2 -0
  39. package/templates/skills/bridges/h5/AGENTS.md +8 -0
  40. package/templates/skills/bridges/h5/CLAUDE.md +4 -0
  41. package/templates/skills/bridges/h5/copilot-instructions.md +2 -0
  42. package/templates/skills/bridges/mobile-app/AGENTS.md +8 -0
  43. package/templates/skills/bridges/mobile-app/CLAUDE.md +4 -0
  44. package/templates/skills/bridges/mobile-app/copilot-instructions.md +2 -0
  45. package/templates/skills/bridges/website/AGENTS.md +8 -0
  46. package/templates/skills/bridges/website/CLAUDE.md +4 -0
  47. package/templates/skills/bridges/website/copilot-instructions.md +2 -0
  48. package/templates/skills/claude-skill.md.hbs +7 -0
  49. package/templates/skills/copilot-instructions.md +2 -0
  50. package/templates/skills/hai-api-client/SKILL.md +2 -0
  51. package/templates/skills/hai-app-create/SKILL.md +9 -7
  52. package/templates/skills/hai-app-create/development.md +66 -0
  53. package/templates/skills/hai-app-create/reference.md +44 -32
  54. package/templates/skills/hai-app-review/SKILL.md +50 -144
  55. package/templates/skills/hai-app-tests/SKILL.md +3 -1
  56. package/templates/skills/hai-app-tests/reference.md +47 -27
  57. package/templates/skills/hai-build/SKILL.md +5 -4
  58. package/templates/skills/hai-build/reference.md +52 -32
  59. package/templates/skills/hai-ci/SKILL.md +8 -15
  60. package/templates/skills/hai-framework-sync/SKILL.md +8 -1
  61. package/templates/skills/hai-pr-review/SKILL.md +5 -4
  62. package/templates/skills/hai-reldb/SKILL.md +1 -0
  63. package/templates/skills/hai-reldb/reference.md +3 -0
  64. package/templates/skills/hai-scheduler/SKILL.md +3 -0
  65. package/templates/skills/hai-serv/SKILL.md +1 -0
  66. package/templates/skills/hai-serv/reference.md +16 -2
  67. package/templates/skills/hai-storage/SKILL.md +3 -1
  68. package/dist/chunk-WUYLYCW2.js +0 -237
  69. package/dist/chunk-WUYLYCW2.js.map +0 -1
@@ -7,3 +7,5 @@
7
7
  ## 质量门禁
8
8
 
9
9
  按 AGENTS.md 和实际 package.json 选择 typecheck、lint、build、test、test:e2e;最终说明已执行结果、未运行原因及同步文档/依赖方。
10
+
11
+ 普通新增、修改、修复任务先读 [应用开发 Skill](../.agents/skills/hai-app-create/SKILL.md) 和 [开发规范与框架能力路由](../.agents/skills/hai-app-create/development.md),依照 AGENTS.md 的默认规则复用框架并完成安全与质量验证。
@@ -0,0 +1,7 @@
1
+ {{frontmatter}}
2
+
3
+ # {{skillName}}
4
+
5
+ 执行本技能前,先读取 [共享技能正文](../../../.agents/skills/{{skillName}}/SKILL.md),按正文的使用路径执行;相对参考链接以共享技能目录为基准按需读取。
6
+
7
+ 项目约束见 [AGENTS.md](../../../AGENTS.md)。本文件只提供 Claude Code 原生发现入口,通用规则与参考资源维护在 `.agents/skills/`,不要在此重复维护另一份正文。
@@ -7,3 +7,5 @@
7
7
  ## 质量门禁
8
8
 
9
9
  按 AGENTS.md 和实际 package.json 选择 typecheck、lint、build、test、test:e2e;最终说明已执行结果、未运行原因及同步文档/依赖方。
10
+
11
+ 普通新增、修改、修复任务先读 [应用开发 Skill](../.agents/skills/hai-app-create/SKILL.md) 和 [开发规范与框架能力路由](../.agents/skills/hai-app-create/development.md),依照 AGENTS.md 的默认规则复用框架并完成安全与质量验证。
@@ -126,6 +126,8 @@ Access token 存在内存中,refresh token 由服务端通过 `HttpOnly` cooki
126
126
 
127
127
  启用 `transport` 时,登录、业务请求以及 401 后的自动刷新都会复用同一个加密 fetch 链路;不要在业务代码中手写明文 `/auth/refresh` 请求。
128
128
 
129
+ 自动刷新仅检查真实 HTTP 401(`Response.status`)。serv 普通 procedure 默认通过 HTTP 200 返回失败 HaiResult,其中 `error.httpStatus=401` 不会触发自动刷新;调用方仍须检查 `success` 与 `error.code` 并处理登录失效。
130
+
129
131
  ```ts
130
132
  import { apiClient } from '@h-ai/api-client'
131
133
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: hai-app-create
3
- description: "在 hai 应用中新增页面、路由、API、服务、模型或组件。"
3
+ description: "在 hai 应用中新增、修改或修复功能,按需求复用框架能力并验证安全、质量与风格。"
4
4
  ---
5
5
 
6
6
  # hai-app-create
@@ -9,23 +9,25 @@ description: "在 hai 应用中新增页面、路由、API、服务、模型或
9
9
 
10
10
  | 项目 | 契约 |
11
11
  | --- | --- |
12
- | 能力 | 在 hai 应用中新增页面、路由、API、服务、模型或组件 |
13
- | 适用场景 | 已确定需求的应用功能实现 |
12
+ | 能力 | 在 hai 应用中新增、修改或修复页面、API、服务、模型与组件 |
13
+ | 适用场景 | 日常应用功能开发与已授权修复 |
14
14
  | 输入 | 功能需求、现有路由/contract、数据模型和验收场景 |
15
- | 输出 | 最小实现、必要测试、i18n 与同步文档 |
15
+ | 输出 | 能力选择依据、最小实现、行为验证、i18n 与受影响文档 |
16
16
  | 限制 | 优先复用;TDD 仅让新增目标用例先失败,已有回归保持通过。API workspace 不生成 SvelteKit 路由。 |
17
17
 
18
18
  ## 使用路径
19
19
 
20
- - 从真实路由/contract、UI 组件和服务层扩展;API workspace、SvelteKit 和 SPA 的文件结构不能混用。
21
- - 对新增行为先写有意义的目标用例,已有回归保持通过;同步 i18n、README 和调用方。
20
+ 1. 读取 [development.md](development.md):先按真实需求匹配框架能力、已安装版本与应用架构,再确定改动。适用能力包括同一模块已有 feature、配置和扩展点,不以导入包作为复用完成的证据。
21
+ 2. 读取所选模块的 skill 与实际公开类型,复用现有服务和组件。新增依赖或直接使用第三方 SDK 前说明已有能力的具体缺口;无需安装无关模块。
22
+ 3. 新增或改变行为时用有意义的目标用例验证,已有回归保持通过;按下方参考实现,使用 [hai-app-review](../hai-app-review/SKILL.md) 检查改动涉及的安全与质量边界。
23
+ 4. 运行当前项目已定义的门禁,报告行为证据、能力选择及未验证项。纯文案、格式和文档变化按影响验证,不强制新增测试。
22
24
 
23
25
  ## 按需参考
24
26
 
25
27
  详细配置、API 签名、错误码和范本在 [reference.md](reference.md)。按下列标题定位所需小节,不默认通读;用例中的业务变量需结合当前应用补齐。
26
28
 
27
29
  - 适用场景
28
- - TDD 开发流程(强制)
30
+ - 行为开发与验证
29
31
  - 目录结构约定
30
32
  - 创建页面
31
33
  - 创建 API 端点
@@ -0,0 +1,66 @@
1
+ # hai 应用开发决策
2
+
3
+ 日常新增、修改和修复功能时读取本文件;专项模块 API 只读取下表匹配的 skill。这里的“应用尽用”是让每项真实需求优先使用适用框架能力,并检查已有 feature、配置和扩展点;不要求所有项目安装或启用全部模块。
4
+
5
+ ## 先确认应用与版本
6
+
7
+ - 读取当前 `AGENTS.md`、README、`package.json`、lockfile、初始化入口和已有相似功能;用 `rg` 查实现、引用、测试。保留已有改动,沿用项目分层、命名、ESLint、i18n 与测试入口。
8
+ - 确认架构:SvelteKit 使用 `kit` 和文件路由;API workspace 使用 contract/service;fullstack 使用 contract/serv/shared 与所选前端;Vite SPA/原生端通过 typed API 客户端调用服务。不要把服务端目录、DB、密钥或 Node 初始化复制到浏览器。
9
+ - 从所属 workspace 的依赖与 lockfile 确认 `@h-ai/*` 实际解析版本和 npm/local 模式。模板 skill 提供导航,**当前安装包的 `package.json.exports`、公开 `.d.ts` 与随包文档决定可用 API**;本地框架源码只在版本匹配或显式联调时作实现证据。
10
+ - 若 skill 与安装版本不符,以公开类型和实际行为核验。先使用已支持能力;任务确需新版本时列明版本变更、调用方与验证范围。不能直接复制未发布源码的 API,也不能为绕过差异添加虚构兼容层。
11
+
12
+ ## 将需求映射到现有能力
13
+
14
+ 开发前,对本次涉及的需求简述“需求 → 现有应用实现/框架能力 → 版本与契约依据 → 修改位置与验收”。简单任务可用几句话;跨模块任务用表格。查找顺序:已有应用实现 → 框架公开能力和配置 → 最小业务补充。
15
+
16
+ 下表技能名用于能力导航;先确认 `.agents/skills/<name>/SKILL.md` 存在再读取。CLI 按应用类型/已选模块交付技能,缺目录不代表框架没有该能力:继续查已安装包的公开 exports/types;确需补充模块/技能时按当前 CLI 帮助和项目依赖策略处理,不能跳过需求匹配或猜测不存在的 API。
17
+
18
+ | 需求 | 优先检查的能力与 skill | 使用边界 |
19
+ | --- | --- | --- |
20
+ | 配置、日志、ID、结果/错误、i18n | `hai-core` | getter、logger、ID 是直接值;ID 不作为密钥 |
21
+ | 数据库查询、CRUD、事务、分页 | `hai-reldb` | 先检查现有 CRUD/Repository 与事务支持,不另建 DB 连接层 |
22
+ | 缓存、TTL、共享锁 | `hai-cache` | 区分 memory 与共享后端;单进程状态不能承担跨节点防重 |
23
+ | 注册、登录、会话、角色/权限 | `hai-iam` | 优先配置内置认证能力;业务资源/租户授权仍由应用检查 |
24
+ | SvelteKit Hook、守卫、校验、响应 | `hai-kit` | 只用于 SvelteKit;沿用已有认证/transport 管道 |
25
+ | 共享输入输出和 HTTP contract | `hai-api-contract` | 扩展已有 contract 与 schema,不维护第二份业务路径 |
26
+ | API 运行时、内置 feature、route guard | `hai-serv` | 先检查内置 procedures/features 与 route auth/permission;不另写平行服务器 |
27
+ | 浏览器/原生 API、刷新会话 | `hai-api-client` | 已支持接口复用 typed client、认证与 transport;额外 fetch/刷新封装需有缺口依据 |
28
+ | 页面、表单、表格、弹窗、移动 UI | `hai-ui` | 按实际导出选择场景/组合/原子组件;应用补业务交互 |
29
+ | 文件上传、下载、元数据、预签名 URL | `hai-storage` | 检查已有 storage feature;资源授权、大小/类型/路径限制不可省略 |
30
+ | 加密、签名、哈希 | `hai-crypto` | 复用公开 API 与密钥配置,不自创加密或硬编码密钥 |
31
+ | LLM、流式、Embedding、RAG、Agent/MCP | `hai-ai` | 先检查内置能力与 provider 配置,再补应用编排 |
32
+ | 文本清洗、分块、管线 | `hai-datapipe` | 纯函数无生命周期;分块不代表已经生成向量 |
33
+ | 向量集合与检索 | `hai-vecdb` | 后端、维度与过滤条件使用实际契约 |
34
+ | 邮件/短信/通知触达 | `hai-reach` | 复用已有 provider;投递状态不等于 HTTP 成功 |
35
+ | 支付、订单、订阅、回调 | `hai-payment` | 验签、金额/订单绑定、幂等与状态迁移仍需业务验收 |
36
+ | 操作审计 | `hai-audit` | 复用审计记录/查询;应用决定脱敏、保留期及失败策略 |
37
+ | cron、持久任务、重试、手工触发 | `hai-scheduler` | 复用任务模型;明确取消、幂等、共享锁及可信代码边界 |
38
+ | 原生设备与安全 token 存储 | `hai-capacitor` | 仅在适用平台启用;桌面/小程序依当前项目适配 |
39
+
40
+ 已有能力满足需求时使用它;已导入模块但仍手写其已有认证、缓存、上传、分页或 UI 功能,需要修正。确有缺口时记录缺失的具体能力、当前版本和最小补充方案,按需求增加依赖或应用代码;不为凑模块覆盖率增加服务和抽象。
41
+
42
+ ## 落实契约与安全边界
43
+
44
+ 按本次真实输入、资源和副作用选取下面检查,并把适用项变成可观察验收。不能用“已遵循安全规范”或 lint 通过替代行为证据。
45
+
46
+ | 边界 | 实现要求 | 验收证据 |
47
+ | --- | --- | --- |
48
+ | 输入与输出 | 外部输入在请求/contract 边界 schema 校验,限制长度、分页、大小与合法枚举;从公开类型推导共享结构 | 非法/超限输入被拒绝,未触发写入或外部副作用;输出符合 contract |
49
+ | 身份与资源 | 使用对应架构守卫;另查资源所有者、租户、角色/权限;不能信任客户端传来的 userId/tenantId | 未登录、缺权限、跨用户/租户访问失败;正常路径可用 |
50
+ | SQL、文件、URL、内容 | SQL 值参数化,动态标识符白名单;文件防路径逃逸;用户控制的服务端请求 URL 限制目的地;HTML/AI 内容按不可信输入处理 | 相关注入/逃逸/越界目的地被拒绝;正常输入仍可用 |
51
+ | 凭据与会话 | 密钥仅服务端配置/环境,`.env.example` 只放占位;PUBLIC/VITE 配置不含密钥。沿用 Cookie/内存 token,原生用安全 TokenStorage;检查 CORS、Cookie、CSRF 与现有管道 | 浏览器产物/日志无敏感内容;登录/退出/刷新及适用的跨域攻击失败路径可验证 |
52
+ | HaiResult 与错误 | HaiResult 型业务 API 先判断 `success`,服务层保留错误;HTTP 边界沿实际包络/状态契约并隐藏内部敏感细节。显式抛错、流迭代与 SvelteKit 控制流按各自契约 | 依赖失败不回退为空列表/成功消息;流失败与业务状态失败有反馈,用户输入得到保留 |
53
+ | 初始化与清理 | 只对有生命周期的模块按依赖 init → use → close;检查每次结果,关键依赖失败停止启动,清理已创建资源,关闭反序 | 初始化失败不能继续执行业务;关闭/取消后连接、监听器与任务退出 |
54
+ | 写入与重试 | 多步一致性用事务或明确补偿;重试/回调/任务定义幂等;跨节点业务状态使用共享存储 | 中途失败无不一致写入;重复请求/回调不产生重复副作用 |
55
+ | 风格与可维护性 | 禁止 `any`、无说明的 `as unknown as T`、`console.log`、硬编码密钥;注释中文、日志英文且脱敏;文案使用现有 i18n 并同步中英文;遵循项目实际 lint 配置 | typecheck/lint 通过;人工核对脱敏、文本、分层与不受 lint 覆盖的规则 |
56
+
57
+ 不把所有函数改成 HaiResult:纯工具、getter、工厂、客户端/流及控制流按实际签名。不把所有模块加上 init/close。应用服务根据已有业务契约返回 HaiResult,HTTP/UI 层做适当转换。
58
+
59
+ serv/oRPC 普通 procedure 返回的失败 HaiResult 可以位于 HTTP 200 包络,`error.httpStatus` 是错误元数据,不等于响应状态;输入 schema 校验、传输错误、路由中间件及 kit 的 Response 各有状态契约。验收同时检查响应体 `success/error.code` 和真实 HTTP 状态,不照搬另一架构的 401/500 断言,也不以 HTTP 200 判为业务成功。
60
+
61
+ ## 验证与交付
62
+
63
+ - 对新增/改变行为按 [hai-app-tests](../hai-app-tests/SKILL.md) 写有意义的测试;目标用例先因行为缺失失败,既有回归保持通过。UI/路由改动覆盖真实流程、异步失败与权限路径;纯文案/文档按影响验证。
64
+ - 从当前 `package.json` 选择实际脚本,优先 workspace filter;按 `typecheck → lint → build(构建/配置/跨包变更)→ test → 相关 E2E` 验证,PowerShell 使用 `pnpm.cmd`。不能调用框架仓库私有命令替代应用检查。
65
+ - typecheck/lint 只覆盖部分质量规则;权限、事务、降级、真实 provider、浏览器、容器和原生交付各自需要适用行为证据。缺环境或密钥时报告未验证,不能用 mock 冒充真实集成。
66
+ - 完成说明:实际复用能力与自定义缺口、修改路径、已执行命令/行为结果、同步的 contract/调用方/配置/i18n/文档、未验证项及原因。无需无关模块的“覆盖率”清单。
@@ -2,8 +2,7 @@
2
2
 
3
3
  从 [SKILL.md](SKILL.md) 选择主题后读取对应小节。代码片段展示 API 用法;省略的业务变量、schema、依赖与 return 上下文需由应用补齐。
4
4
 
5
- > 面向 AI 助手的应用功能创建指南。**必须遵循 TDD**:先写测试(Red)→ 再实现(Green)→ 再重构(Refactor)。
6
- > 若目标是纯 API service workspace,优先围绕 `apps/*-contract`、`apps/*-service` 与测试组织改动,而不是套用页面/路由脚手架。
5
+ 新增、修改和修复功能前先读 [development.md](development.md),确认适用框架能力、当前安装版本与安全边界。这里的路由/页面示例适用于 SvelteKit;API workspace 围绕已有 contract/service 扩展,fullstack 使用现有 contract/serv/shared 和所选前端,不套用 SvelteKit 目录。
7
6
 
8
7
  ## 适用场景
9
8
 
@@ -12,22 +11,23 @@
12
11
  - 新增服务层模块(`$lib/server/services/`)
13
12
  - 新增数据库表 / 数据模型
14
13
  - 新增业务组件
14
+ - 修改或修复已有功能、接口和交互
15
15
 
16
- ## TDD 开发流程(强制)
16
+ ## 行为开发与验证
17
17
 
18
- 创建任何新功能时,必须按以下顺序执行:
18
+ 新增/改变行为时采用下列流程;纯文案、格式或文档变化按影响验证,不为流程补无意义测试。
19
19
 
20
20
  ### Step 1:需求分析与测试设计
21
21
 
22
22
  1. 明确功能的输入、输出、边界条件、错误场景
23
- 2. 确定需要创建的文件(服务、路由、Schema、组件等)
24
- 3. 设计测试用例清单(参照 `hai-app-tests` 技能的覆盖范围要求)
23
+ 2. 按 development.md 匹配现有应用实现、框架模块及其 feature/配置;查公开类型与安装版本,再确定修改文件(服务、路由、Schema、组件等)
24
+ 3. 设计正常、错误和适用安全边界的可观察验收(参照 `hai-app-tests`);已有行为优先扩展现有用例
25
25
 
26
26
  ### Step 2:编写测试(Red 阶段)
27
27
 
28
- 1. **创建单元测试**:在 `tests/` 下为服务层、Schema 编写 Vitest 测试
29
- 2. **创建 E2E 测试**:在 `e2e/` 下为 API 端点、页面交互编写 Playwright 测试
30
- 3. **创建空的实现文件**:仅包含函数签名和类型定义,不写实际逻辑(确保 import 不报错)
28
+ 1. **编写目标用例**:按当前项目测试结构为改变的服务行为、Schema、接口或交互选择单元/集成/E2E 测试,不要求每次创建两套测试
29
+ 2. **保留既有回归**:新增目标用例不得依赖破坏现有实现才能失败
30
+ 3. 新文件可先提供最小签名,但不能为制造 Red 把现有功能替换成空实现
31
31
  4. **运行测试确认新增目标用例因预期行为缺失而失败(既有回归保持通过)**:
32
32
  ```bash
33
33
  pnpm --filter <app-name> test # 新增目标用例应 FAIL,既有回归应 PASS
@@ -40,11 +40,13 @@
40
40
  ### Step 4:重构与验证(Refactor 阶段)
41
41
 
42
42
  1. 参照 `hai-app-review` 审查代码规范
43
- 2. 运行质量门禁:`pnpm typecheck && pnpm lint && pnpm test`
44
- 3. 运行 E2E:`pnpm --filter <app-name> test:e2e`
43
+ 2. 依当前 scripts 顺序执行 `typecheck → lint → build(构建/配置/跨包变更)→ test`,优先 workspace filter,PowerShell 使用 `pnpm.cmd`
44
+ 3. UI/路由/端到端改动执行相应 E2E;报告失败路径与安全验收结果,未运行的边界说明原因
45
45
 
46
46
  ## 目录结构约定
47
47
 
48
+ 以下为 SvelteKit 示例;其它架构沿当前项目目录,不生成这些文件。
49
+
48
50
  ```
49
51
  src/
50
52
  hooks.server.ts # `handle` hook 入口
@@ -129,23 +131,27 @@ src/
129
131
  import type { PageServerLoad } from './$types'
130
132
  import { error, redirect } from '@sveltejs/kit'
131
133
 
134
+ // someService 与 safeLoadErrorMessage 由应用已有服务与请求 locale 的 i18n 提供。
132
135
  export const load: PageServerLoad = async ({ locals }) => {
133
136
  if (!locals.session)
134
137
  redirect(303, '/auth/login')
135
138
  const result = await someService.list()
136
139
  if (!result.success)
137
- error(500, result.error.message)
140
+ error(503, safeLoadErrorMessage)
138
141
  return { items: result.data }
139
142
  }
140
143
  ```
141
144
 
142
145
  ## 创建 API 端点
143
146
 
144
- ### RESTful 端点模板
147
+ API workspace/fullstack 先检查 [hai-api-contract](../hai-api-contract/SKILL.md) 的内置领域 contract 与 [hai-serv](../hai-serv/SKILL.md) 的 feature procedures;应用私有接口通过现有 contract → procedure → typed client 扩展。身份/权限守卫用 serv route 的 auth/permission/role,业务资源归属在服务层检查;不添加 `+server.ts` 或 kit.validate。
148
+
149
+ ### SvelteKit RESTful 端点模板
150
+
151
+ 本例依赖应用提供 `service`;`toHttpError(result.error)` 是应用已有或需实现的错误边界:保留安全错误码、映射 HTTP 状态,对内部失败使用当前 locale 的安全文案且不暴露 SQL/路径/凭据。不能不分类便直接透传内部错误消息。
145
152
 
146
153
  ```typescript
147
154
  // src/routes/api/[resource]/+server.ts
148
- import type { RequestHandler } from './$types'
149
155
  import { kit } from '@h-ai/kit'
150
156
  import { z } from 'zod'
151
157
 
@@ -160,7 +166,7 @@ export const GET = kit.handler(async ({ locals }) => {
160
166
 
161
167
  const result = await service.list()
162
168
  if (!result.success)
163
- return kit.response.error(result.error.code, result.error.message)
169
+ return toHttpError(result.error)
164
170
  return kit.response.ok(result.data)
165
171
  })
166
172
 
@@ -172,18 +178,18 @@ export const POST = kit.handler(async ({ request, locals }) => {
172
178
 
173
179
  const result = await service.create(data)
174
180
  if (!result.success)
175
- return kit.response.error(result.error.code, result.error.message)
181
+ return toHttpError(result.error)
176
182
  return kit.response.created(result.data)
177
183
  })
178
184
  ```
179
185
 
180
186
  ### 要点
181
187
 
182
- - 所有端点**必须**用 `kit.handler(async ({ locals, request, ... }) => { ... })` 包裹,由 handler 统一处理 throw 的 Response
183
- - 权限守卫使用 `kit.guard.require(locals.session, 'xxx:yyy')`,它本身就是 throw 模式(未通过时 throw 403 Response),**无需**检查返回值
188
+ - 使用 kit.guard.require / kit.validate.body 的 SvelteKit 端点用 `kit.handler(async ({ locals, request, ... }) => { ... })` 包裹,由 handler 统一处理 throw 的 Response;其它架构用对应运行时
189
+ - 权限守卫使用 `kit.guard.require(locals.session, 'xxx:yyy')`,它本身就是 throw 模式(未登录 throw 401、无权限 throw 403 Response),**无需**检查返回值
184
190
  - 输入校验使用 `await kit.validate.body(request, Schema)`,校验失败时 throw 400 Response,**无需**手动判断 valid
185
191
  - 返回统一使用 `kit.response.*`
186
- - HaiResult 错误直接透传,不重新包装
192
+ - 服务层保留上游 HaiResult 错误;本例 SvelteKit HTTP 边界按安全消息和状态转换,不能把数据库失败作为 400 或空列表成功。serv/oRPC 普通 procedure 按真实 HaiResult 包络契约验收,不照搬本例状态映射
187
193
  - HaiResult 型业务操作先检查 result.success;流和显式抛错 API 按各自契约处理
188
194
 
189
195
  ## 创建服务层
@@ -218,7 +224,7 @@ export async function listArticles(params: ListParams): Promise<HaiResult<Pagina
218
224
 
219
225
  ### 服务层规则
220
226
 
221
- - 统一返回 `HaiResult<T>`
227
+ - 应用领域操作沿现有契约返回 `HaiResult<T>`;纯 getter、工具、工厂与流按实际签名,不统一改造
222
228
  - 写操作需 `debug`(进入)+ `info`(成功)日志
223
229
  - 读操作仅 `debug` 日志
224
230
  - 禁止 `console.log`,使用 `core.logger`
@@ -228,7 +234,7 @@ export async function listArticles(params: ListParams): Promise<HaiResult<Pagina
228
234
 
229
235
  ### Schema 定义(SQL DDL)
230
236
 
231
- 数据库表 Schema 定义在 `$lib/server/init.ts` 中:
237
+ 沿用当前应用的迁移/建表入口;仅开发初始化用的简单 SvelteKit 示例可在 `$lib/server/init.ts` 建表。不要把本例 SQLite DDL 无修改复制到 PostgreSQL/MySQL,迁移与索引需匹配实际数据库。
232
238
 
233
239
  ```typescript
234
240
  const BUSINESS_SCHEMA = `
@@ -275,7 +281,8 @@ interface CreateArticleInput {
275
281
  ```svelte
276
282
  <!-- src/lib/components/ArticleCard.svelte -->
277
283
  <script lang="ts">
278
- import type { Article } from '$lib/server/services/article'
284
+ import type { Article } from '$lib/types/article'
285
+ import * as m from '$lib/paraglide/messages.js'
279
286
 
280
287
  let { article, onEdit }: { article: Article, onEdit?: () => void } = $props()
281
288
  </script>
@@ -286,13 +293,15 @@ interface CreateArticleInput {
286
293
  <p>{article.content ?? ''}</p>
287
294
  {#if onEdit}
288
295
  <div class="card-actions justify-end">
289
- <button class="btn btn-primary" onclick={onEdit}>编辑</button>
296
+ <button class="btn btn-primary" onclick={onEdit}>{m.article_edit()}</button>
290
297
  </div>
291
298
  {/if}
292
299
  </div>
293
300
  </div>
294
301
  ```
295
302
 
303
+ `Article` 放在客户端可用的共享类型位置,`article_edit` 在中英文 messages 中新增后由项目生成;实际已安装 `@h-ai/ui` 有适用 Card/Button 时使用其公开组件和 Props,本例只展示业务 props、事件与文案边界。
304
+
296
305
  ### 组件规则
297
306
 
298
307
  - 使用 Svelte 5 Runes 语法(`$props()`、`$state()`、`$derived()`、`$effect()`)
@@ -303,16 +312,18 @@ interface CreateArticleInput {
303
312
 
304
313
  ## 初始化顺序
305
314
 
306
- 在 `$lib/server/init.ts` 中管理模块初始化顺序:
315
+ 复用当前应用服务端启动/关闭入口;SvelteKit 通常为 `$lib/server/init.ts`,API/fullstack 使用已有 service/serv 初始化文件。下列是启用 IAM 时的常见依赖关系,不要求无关应用安装这些模块:
307
316
 
308
317
  ```
309
- core.init() → reldb.init() → cache.init() → iam.init() → createBusinessTables()
318
+ core.init() → crypto.init() → reldb.init() → cache.init() → iam.init() → createBusinessTables()
310
319
  ```
311
320
 
312
- 新增模块时需在此文件中按依赖顺序添加初始化调用。
321
+ 新增生命周期模块时按实际配置/依赖添加初始化、检查结果并反序关闭;关键依赖失败停止启动并清理已创建资源。core 无 close、datapipe 为纯函数、serv/kit/contract 为工厂或适配器,不能虚构 init/close。
313
322
 
314
323
  ## 容器交付
315
324
 
325
+ 仅涉及容器构建/部署变更时使用本节;普通功能开发无需每次启动镜像。
326
+
316
327
  - 保持脚手架根目录 `Dockerfile`、`.dockerignore` 与 `package.json` 中 `docker:build*` / `podman:build*` 命令同步。
317
328
  - Podman 多阶段构建保持 `--format docker --jobs=1`;前者保留 `HEALTHCHECK`,后者避免部分 Podman 5.8/Buildah 组合在并行 stage 构建时触发内部 semaphore panic。
318
329
  - 先复制 lockfile 与 workspace 配置执行 `pnpm fetch`,再复制源码并离线安装、构建;避免源码变化重复下载依赖,同时兼容新增 workspace。
@@ -325,19 +336,20 @@ core.init() → reldb.init() → cache.init() → iam.init() → createBusinessT
325
336
 
326
337
  ## 检查清单
327
338
 
328
- - [ ] **TDD 流程已执行**:先写测试 → 确认失败 → 再实现 → 确认通过
329
- - [ ] 单元测试已编写(服务层、Schema)
330
- - [ ] E2E 测试已编写(API 端点、页面交互)
339
+ - [ ] 需求已匹配框架现有能力/feature/配置,版本与契约已核验,自定义缺口有依据
340
+ - [ ] 新增/改变行为有意义的目标用例先失败、后通过;既有回归保持通过
341
+ - [ ] 适用安全边界已验证:非法输入、越权/租户隔离、失败结果及相关事务/幂等/清理
342
+ - [ ] 相关 API/页面改动已执行适用集成/E2E 流程
331
343
  - [ ] 页面使用 Svelte 5 Runes 语法
332
344
  - [ ] API 端点有权限守卫与输入校验
333
- - [ ] 服务层统一返回 `HaiResult<T>`
345
+ - [ ] 服务层和调用方遵循实际返回/抛错/流契约,不能以 HTTP 成功替代业务状态成功
334
346
  - [ ] 日志级别正确(读 debug / 写 debug+info / 失败 warn|error)
335
347
  - [ ] 禁止 `console.log`、`any`、硬编码密钥
336
348
  - [ ] 用户可见文本走 i18n
337
- - [ ] Docker / Podman 镜像可启动,配置/环境变量/数据目录行为已验证
349
+ - [ ] 涉及容器交付时,镜像启动及配置/环境变量/数据目录行为已验证
338
350
  - [ ] 新增表有索引定义
339
351
  - [ ] 组件优先使用 `@h-ai/ui`
340
- - [ ] `pnpm typecheck && pnpm lint && pnpm test` 通过
352
+ - [ ] 按当前 scripts 运行适用 typecheck/lint/build/test/E2E 并报告未验证项
341
353
 
342
354
  ## 相关 Skills
343
355
 
@@ -1,173 +1,79 @@
1
1
  ---
2
2
  name: hai-app-review
3
- description: "审查 hai 应用的路由、权限、i18n、服务层与交互体验。"
3
+ description: "审查 hai 应用的框架复用、安全边界、返回契约、代码风格与真实交互,支持开发后的自查。"
4
4
  ---
5
5
 
6
- # hai-app-review — 应用代码审查规范
6
+ # hai-app-review
7
7
 
8
8
  ## 能力契约
9
9
 
10
10
  | 项目 | 契约 |
11
11
  | --- | --- |
12
- | 能力 | 审查 hai 应用的路由、权限、i18n、服务层与交互体验 |
13
- | 适用场景 | 用户要求应用代码/体验审查或修复评估 |
14
- | 输入 | 用户指定范围、代码/差异、运行证据与验收要求 |
15
- | 输出 | 按优先级列出的证据、影响和修正建议 |
16
- | 限制 | 只读审查不自动改代码;未读取的实现不下结论,不把偏好当缺陷。实现修复需用户已授权。 |
12
+ | 能力 | 审查应用的框架复用、安全、质量、风格与交互 |
13
+ | 适用场景 | 用户要求审查/规范化,或完成功能开发后的自查 |
14
+ | 输入 | 指定范围、需求/验收、代码差异、当前依赖与运行证据 |
15
+ | 输出 | 有路径、影响、依据、验收方法的问题及验证结果 |
16
+ | 限制 | 只读审查不自动改代码;已有实现/修复授权时可修正本次范围内的问题。未读实现不下结论,不把偏好当缺陷。 |
17
17
 
18
- > 面向 AI 助手的应用代码审查指南。用于审查使用 hai-framework 构建的 SvelteKit 应用、纯 Svelte/Vite 客户端与 API service workspace。本技能也是 TDD Refactor 阶段的执行入口。
18
+ ## 审查路径
19
19
 
20
- ## 适用场景
20
+ 1. 读取当前项目入口规则、package scripts、lockfile 与差异,确认 SvelteKit、API workspace、fullstack 或 Vite/原生架构。
21
+ 2. 按 [development.md](../hai-app-create/development.md) 对需求核对实际框架能力、当前安装版本及适用安全边界;只读所涉及模块 skill、公开类型和相关调用方。
22
+ 3. 沿真实路径检查输入 → 身份/资源权限 → 服务/副作用 → 结果 → UI。先报告能导致安全或行为错误的问题,再检查风格与维护性。
23
+ 4. 对已授权修复做最小改动并验证。修正真实缺陷不以“已有测试未发现”为前提;保留用户已有改动与业务目标。
21
24
 
22
- - 审查应用代码是否符合 hai-framework 规范
23
- - TDD Refactor 阶段:在测试通过后进行代码重构与规范化
24
- - 规范化现有代码(分层、命名、日志、i18n)
25
- - 安全审查(权限、输入校验、密钥管理)
25
+ ## 框架复用与架构
26
26
 
27
- ## 工作准则
27
+ - 本次需求是否已经由应用已有服务、框架 feature/配置/扩展点实现?查实际 API 与版本,不能只计算导入包数量。
28
+ - 登录/刷新、数据库连接/CRUD/事务、缓存、上传、AI provider、任务调度及通用 UI 若已有适用能力,应复用。自定义代码或新依赖应有具体缺口证据,不能为覆盖率安装无关模块。
29
+ - SvelteKit 的 hooks 仅编排初始化/中间件,load/端点守卫 → 校验 → 服务 → 响应;API workspace/fullstack 在现有 contract/procedure/serv 扩展,不生成 kit 路由。
30
+ - UI 负责显示与交互;数据库、密钥与服务端模块留在服务端。浏览器共享类型从客户端可用的 contract/types/shared 引入,不从 server services 引入。
31
+ - 从 `package.json.exports` 公开入口导入;复用真实类型,拒绝内部源码路径、本地仿造类型和无用途转发层。公共 contract/配置变化同步服务、客户端、测试和文档。
28
32
 
29
- 1. **先搜索再改动**:用全局检索确认引用关系,避免遗漏更新。
30
- 2. **最小变更**:除非测试暴露缺陷,不改业务行为。
31
- 3. **成套更新**:代码 / 测试 / 文档同步。
32
- 4. **重构后测试必须仍通过**:任何重构都不能破坏已有测试。
33
+ ## 返回、失败与生命周期
33
34
 
34
- ## 审查清单
35
+ - 返回 HaiResult 的调用先检查 `success` 再读 `data`,服务层保留上游错误;纯函数、getter、工厂、流式 API 与显式抛错按实际签名。
36
+ - SvelteKit 控制流及 kit.guard.require/kit.validate.body 抛出的响应按 kit/SvelteKit 契约处理,不吞掉 redirect/error。服务端 SDK/流迭代异常不能因“框架不抛业务异常”而遗漏。
37
+ - HTTP 边界沿实际状态/包络与安全 i18n 契约,不暴露 SQL、路径、凭据和堆栈。serv/oRPC 普通 procedure 的失败 HaiResult 可位于 HTTP 200,error.httpStatus 不等于传输状态;不能照搬 kit 的 Response 断言。不能将依赖失败回退为空列表、零统计或空权限;权限读取失败不得继续写入。
38
+ - 投递、支付、调度等需要继续判断业务状态字段;HTTP/HaiResult 成功不能替代送达、完成或提交。失败反馈保留用户输入,重试明确幂等。
39
+ - 初始化复用当前入口;只对有生命周期的模块按真实依赖顺序 init → use → close,检查每个结果。关键依赖失败停止启动、清理已创建资源;关闭反序释放,覆盖并发初始化与失败路径。
35
40
 
36
- ### TDD 合规性
41
+ ## 安全验收
37
42
 
38
- - [ ] 每个功能都有对应的单元测试(`tests/` 目录)
39
- - [ ] 关键流程有对应的 E2E 测试(`e2e/` 目录)
40
- - [ ] 单元测试覆盖四种路径:正常、边界、权限、错误
41
- - [ ] E2E 测试覆盖 API 端点的未认证/认证场景
42
- - [ ] 测试先于实现编写(TDD 流程已遵循)
43
- - [ ] `pnpm test` 单元测试全部通过
44
- - [ ] `pnpm test:e2e` E2E 测试全部通过
43
+ 按 development.md 的安全表选本次适用项,并检查可观察行为:
45
44
 
46
- ## 审查清单
45
+ - 非法/超限输入被 schema 拒绝且没有写入/外部副作用。SvelteKit 用对应 kit 校验,API service 在 contract/procedure 边界校验,不给其它架构强加 kit.validate。
46
+ - 未登录、缺权限、跨资源/用户/租户访问被拒绝;客户端身份字段不能替代服务端会话。公开接口有明确匿名策略。
47
+ - SQL 值参数化;动态标识符白名单;文件路径/类型/大小与目的地 URL 限制匹配真实入口;不可信 HTML/AI 内容不能执行。
48
+ - 日志、响应、客户端构建产物与公共环境变量无密钥/密码/token。会话沿现有 Cookie/内存或原生安全 TokenStorage;相关 CORS、Cookie、CSRF、刷新与退出路径得到验证。
49
+ - 适用的事务、幂等、并发/重复请求、回调验签、金额与订单绑定、任务重试/取消得到验证。共享业务状态不放单进程 memory。
47
50
 
48
- ### 架构分层
51
+ typecheck/lint 不能证明越权、租户隔离、事务、错误状态或资源清理正确;需要适用的失败/攻击用例、运行检查或明确未验证说明。
49
52
 
50
- - [ ] `hooks.server.ts` 仅做中间件编排(初始化、i18n、`handle` hook),无业务逻辑
51
- - [ ] `+page.server.ts` / `+server.ts` 仅做请求处理(守卫 → 校验 → 调用服务 → 响应)
52
- - [ ] 业务逻辑集中在 `$lib/server/services/`
53
- - [ ] 客户端组件不直接调用数据库或服务端模块
54
- - [ ] 依赖方向:路由 → 服务 → 框架模块,不反向
53
+ ## 代码风格与质量
55
54
 
56
- ### HaiResult 处理
55
+ - 禁止 `any`、无说明的 `as unknown as T`、`console.log`、硬编码密钥;外部 `unknown` 先校验/缩窄。必要第三方断言有真实依据。
56
+ - 遵循当前 ESLint、TypeScript、目录与命名规则,函数返回类型按真实契约标注;不把所有返回类型都强制成 HaiResult。
57
+ - 注释中文,结构化日志英文并脱敏。读操作用 debug,写操作成功用 info,失败按业务/系统性质用 warn/error;避免记录整份请求、凭据或未经脱敏的 error/context。
58
+ - 用户可见文案沿现有 i18n 入口,同步中英文;包括错误、空态、降级、校验和状态文案。禁止手改 Paraglide 生成文件;框架组件内置翻译沿公开 Props 使用。
59
+ - 业务逻辑不塞入 UI/hook;优先 early return、按职责拆分复杂函数。遵守实际 lint 的复杂度/长度限制,不为了数字拆出无意义转发链。
60
+ - 循环串行/并发按依赖、事务、限流与资源限制选择;列表分页/流式处理,避免热路径同步 I/O、重复连接和无界并发。
57
61
 
58
- - [ ] 投递等业务状态按 `sent` 等字段判断,失败保留用户输入;HTTP/HaiResult 成功不代替业务完成
62
+ ## 交互与行为验证
59
63
 
60
- - [ ] 返回 HaiResult 的调用先检查 `result.success`
61
- - [ ] 上游 HaiResult 错误直接透传,不重新包装
62
- - [ ] 不使用 `try/catch` 来处理框架模块返回的错误(HaiResult 型 API 的业务错误在结果中;流/显式抛错 API 另按契约处理)
64
+ 涉及 UI 时沿真实用户路径走查,确认适用的:
63
65
 
64
- ```typescript
65
- // ❌ 重新包装
66
- const result = await reldb.sql.query(sql)
67
- if (!result.success) {
68
- return { success: false, error: { code: 'QUERY_FAILED', message: result.error.message } }
69
- }
66
+ - Svelte 5 Runes、props 事件、SSR/浏览器边界及项目样式系统;优先复用 `@h-ai/ui` 的公开组件。
67
+ - Loading/Empty/Error/Success 四态、表单校验/错误焦点、长任务进度、失败后输入恢复与重试。
68
+ - 桌面/移动布局、长文本与中英文展开、主题对比、键盘/触摸/IME、焦点与可访问性;危险操作有符合产品目标的确认/撤销。
69
+ - 并发操作、网络失败、权限变化与返回导航不导致假成功、丢失输入或死路。
70
70
 
71
- // ✅ 直接透传
72
- const result = await reldb.sql.query(sql)
73
- if (!result.success)
74
- return result
75
- ```
71
+ 新增/改变行为有对应的有效单元/集成/E2E 用例;关键接口覆盖正常、失败及适用权限/边界路径。已有代码是否遵循 TDD 不能仅从最终 diff 推断,需当时执行证据;测试数量与机械打勾不代替行为验证。
76
72
 
77
- ### 权限与安全
73
+ ## 门禁与输出
78
74
 
79
- - [ ] 受保护端点/load 有与实际框架匹配的守卫;公开路由显式允许匿名,不给 API service 强加 kit.guard
80
- - [ ] 所有用户输入通过 Zod Schema 校验(`kit.validate.*`)
81
- - [ ] 无硬编码 API Key / 密钥
82
- - [ ] 日志不输出密码、token 明文
75
+ 从当前 package.json 选择实际 scripts,优先 workspace filter;PowerShell 使用 `pnpm.cmd`。按 typecheck → lint → build(构建/配置/跨包变更)→ test → 相关 E2E 执行。浏览器、真实 provider、容器和原生交付各自报告实际结果。
83
76
 
84
- ### 日志规范
77
+ 交付说明需求/范围、带路径与影响的发现、已复用能力和必要缺口、已修正项、已执行门禁/行为证据、同步的 contract/调用方/i18n/配置/文档,以及未验证项和原因。只读审查报告问题与验证建议;不能凭审查清单宣称所有测试通过。
85
78
 
86
- - [ ] 禁止 `console.log`,统一使用 `core.logger`
87
- - [ ] 日志级别正确:
88
-
89
- | 场景 | 级别 |
90
- | --------------------- | ------------------------------ |
91
- | 读操作 / 查询 | `debug` |
92
- | 写操作进入 | `debug` |
93
- | 写操作成功 | `info` |
94
- | 校验失败 | `warn` |
95
- | 系统异常 | `error` |
96
- | 初始化完成 / 关闭 | `info` |
97
- | 安全操作(登录/登出) | `info`(成功)/ `warn`(失败) |
98
-
99
- - [ ] 日志消息英文、简洁动宾结构
100
- - [ ] 失败日志附带 `{ error }` 或 `{ reason }`
101
-
102
- ### 类型安全
103
-
104
- - [ ] 禁止 `any`,不确定用 `unknown` + 缩窄
105
- - [ ] 函数返回类型明确标注(`HaiResult<T>` / `Promise<HaiResult<T>>`)
106
-
107
- ### i18n
108
-
109
- - [ ] 所有用户可见文本走 i18n key(`$lib/paraglide/messages.js`)
110
- - [ ] 禁止直接修改 `src/lib/paraglide` 生成文件
111
- - [ ] `@h-ai/ui` 组件内置翻译,不传入翻译 props
112
-
113
- ### 代码质量
114
-
115
- - [ ] return 语句不包含复杂逻辑(条件判断、循环、多级调用链)
116
- - [ ] 无超过 2 层的 if 嵌套(使用 Early Return)
117
- - [ ] 单函数 ≤ 120 行(不含注释和空行)
118
- - [ ] 错误创建用错误码 + i18n 消息,无硬编码字符串
119
-
120
- ### Svelte 5 规范
121
-
122
- - [ ] 使用 Runes 语法(`$props()`、`$state()`、`$derived()`、`$effect()`)
123
- - [ ] 事件回调通过 props 传入(非 `createEventDispatcher`)
124
- - [ ] 样式使用 TailwindCSS 4 + DaisyUI 5
125
-
126
- ### 产品体验与交互审查(用户视角走查)
127
-
128
- - [ ] 页面层级与视觉重心清晰,主操作足够突出
129
- - [ ] 响应式断点(桌面 / 平板 / 移动)下无溢出、遮挡、错位
130
- - [ ] 暗色 / 亮色主题下文字对比度满足 WCAG AA
131
- - [ ] 关键路径步骤最短,无多余跳转或确认
132
- - [ ] 危险操作(删除、提交、不可逆变更)有二次确认或可撤销机制
133
- - [ ] 所有可点击区域 hit area ≥ 44px(移动端尤其)
134
- - [ ] 表单具备失焦校验、提交校验与首个错误项聚焦
135
- - [ ] 长任务有进度反馈(百分比 / 预计时间 / skeleton)
136
- - [ ] 四态反馈完整:Loading / Empty / Error / Success
137
- - [ ] 边界场景覆盖:空数据、超长文本、并发操作、权限不足、网络抖动
138
- - [ ] 导航无死路:用户在任意页面都能退出/返回
139
- - [ ] 国际化文本展开后不破坏布局
140
-
141
- ### 初始化
142
-
143
- - [ ] 模块初始化顺序正确:`core → db → cache → iam → ...`
144
- - [ ] 初始化在 `$lib/server/init.ts` 统一管理
145
- - [ ] 配置文件路径遵循 `config/_<module>.yml` 约定
146
-
147
- ## 质量门禁
148
-
149
- 审查完成后按顺序执行:
150
-
151
- 1. `pnpm typecheck`
152
- 2. `pnpm lint`
153
- 3. `pnpm test`(单元测试)
154
- 4. `pnpm --filter <app-name> test:e2e`(E2E 测试)
155
-
156
- 优先使用 `pnpm --filter <app-name>` 指定应用。
157
-
158
- ## 输出要求
159
-
160
- - 列出改动文件与原因
161
- - 说明是否修复了缺陷或仅做规范化
162
- - 明确测试(单元 + E2E)与 lint 结果
163
- - 确认重构后所有测试仍然通过
164
-
165
- ## 相关 Skills
166
-
167
- - `hai-build`:项目架构总览与 TDD 工作流导航
168
- - `hai-app-create`:TDD 驱动的应用功能创建规范
169
- - `hai-app-tests`:TDD 测试规范(Red 阶段详细指引)
170
-
171
- 管理端数据读取在 HTTP 应用边界保留失败:查询异常返回 503 和可刷新错误页,分页任一页或权限关联失败均中止加载,禁止回退为空列表、零统计或空权限。未知权限代码返回 400,权限读取失败时不得继续写入。底层模块仍使用 HaiResult。
172
-
173
- 失败与降级提示也必须国际化:官网 API 按请求 locale 生成 AI 降级/邮件送达状态;未送达不能称为已接收。CLI 部署状态使用 cliM,Gallery 加密能力限制使用双语消息。中文与英文分别验证未配置、失败和成功路径,无需调用付费服务。
79
+ 相关技能:[hai-app-create](../hai-app-create/SKILL.md)、[hai-app-tests](../hai-app-tests/SKILL.md)、[hai-build](../hai-build/SKILL.md)。
@@ -18,6 +18,8 @@ description: "编写或修复 hai 应用的 Vitest/Playwright 测试,验证业
18
18
  ## 使用路径
19
19
 
20
20
  - 先选单元/集成/浏览器层,复用测试 fixture,验证用户可观察结果。
21
+ - 按 [development.md](../hai-app-create/development.md) 的真实行为与安全边界选测试;新增/改变业务行为、缺陷修复有目标用例,纯文案/格式/文档及无行为变化的可逆低影响修改不补镜像测试。
22
+ - 不要求每个功能同时新增单元与 E2E;复用已有用例,选择能验证变化的最小适用层,关键跨层用户流程仍需端到端证据。
21
23
  - 新用例已通过时先检查是否已有能力;不能为达成 Red 人为破坏旧测试。
22
24
  - 外部服务未运行必须报告;mock/Testcontainers/浏览器/真实付费 Provider 的结果分开表述。
23
25
 
@@ -26,7 +28,7 @@ description: "编写或修复 hai 应用的 Vitest/Playwright 测试,验证业
26
28
  详细配置、API 签名、错误码和范本在 [reference.md](reference.md)。按下列标题定位所需小节,不默认通读;用例中的业务变量需结合当前应用补齐。
27
29
 
28
30
  - 适用场景
29
- - TDD 核心工作流(必须严格遵循)
31
+ - 行为验证与 TDD 工作流
30
32
  - 测试目录约定
31
33
  - 核心规则
32
34
  - 覆盖范围