@captain_z/zsk-skills 0.1.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 +263 -0
- package/bundles.yaml +104 -0
- package/design-handoff/.gitkeep +0 -0
- package/design-handoff/figma-to-code/SKILL.md +265 -0
- package/design-handoff/ue-mcp/SKILL.md +184 -0
- package/frontend/.gitkeep +0 -0
- package/frontend/a11y-web/SKILL.md +169 -0
- package/frontend/api-contract-ts/SKILL.md +275 -0
- package/frontend/css-bem/SKILL.md +268 -0
- package/frontend/design-frontend/SKILL.md +163 -0
- package/frontend/dor-dod-frontend/SKILL.md +114 -0
- package/frontend/feature-tasks-frontend/SKILL.md +246 -0
- package/frontend/i18n/SKILL.md +296 -0
- package/frontend/nfr-web/SKILL.md +258 -0
- package/frontend/performance-web/SKILL.md +299 -0
- package/frontend/react-components/SKILL.md +211 -0
- package/frontend/react-naming/SKILL.md +224 -0
- package/frontend/review-frontend/SKILL.md +126 -0
- package/frontend/security-web/SKILL.md +286 -0
- package/frontend/spec-frontend/SKILL.md +141 -0
- package/frontend/testing-web/SKILL.md +252 -0
- package/frontend/typescript/SKILL.md +219 -0
- package/meta/.gitkeep +0 -0
- package/meta/philosophy/SKILL.md +221 -0
- package/package.json +24 -0
- package/quality/.gitkeep +0 -0
- package/quality/a11y-principles/SKILL.md +155 -0
- package/quality/code-hygiene/SKILL.md +126 -0
- package/quality/release/SKILL.md +209 -0
- package/quality/security-owasp/SKILL.md +157 -0
- package/quality/testing-pyramid/SKILL.md +173 -0
- package/sdlc/.gitkeep +0 -0
- package/sdlc/archive/SKILL.md +267 -0
- package/sdlc/bugfix/SKILL.md +181 -0
- package/sdlc/bugfix-tasks/SKILL.md +232 -0
- package/sdlc/coding/SKILL.md +177 -0
- package/sdlc/design/SKILL.md +299 -0
- package/sdlc/dor-dod/SKILL.md +120 -0
- package/sdlc/feature/SKILL.md +162 -0
- package/sdlc/proposal/SKILL.md +271 -0
- package/sdlc/refactor/SKILL.md +220 -0
- package/sdlc/refactor-tasks/SKILL.md +265 -0
- package/sdlc/reviewing/SKILL.md +197 -0
- package/sdlc/spec/SKILL.md +235 -0
- package/sdlc/task/SKILL.md +116 -0
- package/sdlc/task-evidence/SKILL.md +178 -0
- package/sdlc/task-structure/SKILL.md +153 -0
- package/sdlc/task-tracking/SKILL.md +192 -0
- package/sdlc/verify/SKILL.md +181 -0
- package/system/.gitkeep +0 -0
- package/system/adr/SKILL.md +169 -0
- package/system/architecture/SKILL.md +182 -0
- package/system/glossary/SKILL.md +141 -0
- package/system/nfr-baseline/SKILL.md +156 -0
- package/system/project-constraints-template/SKILL.md +241 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zsk:typescript
|
|
3
|
+
description: TypeScript in frontend codebases — red lines (no any / as any /
|
|
4
|
+
@ts-ignore / empty interface / Object type), must-do (explicit types for
|
|
5
|
+
public boundaries, union literals, strict + noUncheckedIndexedAccess), API
|
|
6
|
+
types from backend (not hand-written), type vs interface, generics discipline,
|
|
7
|
+
unknown over any. Complements quality/code-hygiene for cross-language hygiene.
|
|
8
|
+
category: standard
|
|
9
|
+
domain: frontend
|
|
10
|
+
tier: optional
|
|
11
|
+
related:
|
|
12
|
+
- ../react-components/SKILL.md
|
|
13
|
+
- ../api-contract-ts/SKILL.md
|
|
14
|
+
- ../../quality/code-hygiene/SKILL.md
|
|
15
|
+
triggers:
|
|
16
|
+
- TypeScript red lines
|
|
17
|
+
- no any
|
|
18
|
+
- strict mode
|
|
19
|
+
- noUncheckedIndexedAccess
|
|
20
|
+
- type vs interface
|
|
21
|
+
- generic constraints
|
|
22
|
+
- API type from backend
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# TypeScript · 类型纪律
|
|
26
|
+
|
|
27
|
+
> **范围**:TypeScript 的**红线 + 必做 + 风格** — 针对 React + Web 生态
|
|
28
|
+
> **前置**:`tsconfig.json` 必须 `strict: true`,否则本文件 70% 规则无法强制
|
|
29
|
+
|
|
30
|
+
## 红线(CI 必 fail)
|
|
31
|
+
|
|
32
|
+
### 禁用关键字
|
|
33
|
+
|
|
34
|
+
- ❌ `any`(除非经 ADR 豁免 + 该行 `// eslint-disable-next-line @typescript-eslint/no-explicit-any` + 理由)
|
|
35
|
+
- ❌ `as any` / `as unknown as X`(**双层断言禁用**:绕过了两层类型系统,等同于 `any`)
|
|
36
|
+
- ❌ `@ts-ignore` / `@ts-nocheck`(改用 `@ts-expect-error` 并注明理由)
|
|
37
|
+
- ❌ `Object` / `Function` 作为类型(用具体签名:`Record<string, unknown>` / `(x: T) => U`)
|
|
38
|
+
- ❌ 空 interface `interface Foo {}`(意图不清:若是占位用 `Record<string, never>`,若要继承请声明字段)
|
|
39
|
+
- ❌ 类型别名和原类型等价(`type Str = string` 没意义)
|
|
40
|
+
- ❌ `!` 非空断言除非紧邻一个刚验证非空的 if(多数场景用**类型收窄**)
|
|
41
|
+
|
|
42
|
+
### 禁用操作
|
|
43
|
+
|
|
44
|
+
- ❌ 手写 API 响应 / 请求类型(见"类型来自后端"一节)
|
|
45
|
+
- ❌ 在 `.ts` 里写 `any` 的推断源(比如 `JSON.parse` 结果不收窄就用)
|
|
46
|
+
- ❌ 绕过 strict:在文件顶端加 `// @ts-nocheck`
|
|
47
|
+
|
|
48
|
+
## 必做
|
|
49
|
+
|
|
50
|
+
### 公共边界显式类型
|
|
51
|
+
|
|
52
|
+
以下位置**必须**显式标注类型(不依赖推断):
|
|
53
|
+
|
|
54
|
+
| 位置 | 示例 |
|
|
55
|
+
| --- | --- |
|
|
56
|
+
| 导出函数入参 / 返回值 | `export function foo(x: string): User {}` |
|
|
57
|
+
| 组件 Props | `type BtnProps = { ... }` |
|
|
58
|
+
| Hook 入参 / 返回值 | `export function useX(id: string): UseXResult {}` |
|
|
59
|
+
| Event 回调签名 | `onChange: (value: string) => void` |
|
|
60
|
+
| Service 层方法 | `async function getUser(id: string): Promise<User>` |
|
|
61
|
+
| 模块级常量含复杂对象 | `const CONFIG: AppConfig = { ... }` |
|
|
62
|
+
|
|
63
|
+
**局部变量**可依赖推断(`const user = getUser()`),不用重复标注。
|
|
64
|
+
|
|
65
|
+
### strict 必开子项
|
|
66
|
+
|
|
67
|
+
`tsconfig.json`:
|
|
68
|
+
|
|
69
|
+
```jsonc
|
|
70
|
+
{
|
|
71
|
+
"compilerOptions": {
|
|
72
|
+
"strict": true, // 打开下面全部
|
|
73
|
+
"noUncheckedIndexedAccess": true, // arr[0] 推断为 T | undefined
|
|
74
|
+
"exactOptionalPropertyTypes": true, // 可选属性和 undefined 区分
|
|
75
|
+
"noImplicitOverride": true, // override 必须显式
|
|
76
|
+
"noFallthroughCasesInSwitch": true,
|
|
77
|
+
"forceConsistentCasingInFileNames": true
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 联合字面量优于字符串魔法
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
// ❌
|
|
86
|
+
const status = 'loading'; // 手写错了没人知道
|
|
87
|
+
|
|
88
|
+
// ✅
|
|
89
|
+
type Status = 'idle' | 'loading' | 'success' | 'error';
|
|
90
|
+
const status: Status = 'loading'; // 拼错 TS 报错
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### `unknown` 优于 `any`
|
|
94
|
+
|
|
95
|
+
接收不可信输入时用 `unknown`,强制消费处收窄:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
function parse(raw: unknown): User {
|
|
99
|
+
if (isUser(raw)) return raw; // 收窄
|
|
100
|
+
throw new Error('invalid user');
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 空值
|
|
105
|
+
|
|
106
|
+
- **默认用 `undefined`**(符合 JS 引擎语义 + 可选参数自然对齐)
|
|
107
|
+
- **对接后端 `null`** 时:service 层就地归一化为 `undefined` 或保持 `null`,**项目内保持一致**
|
|
108
|
+
- `exactOptionalPropertyTypes` 开启后:`{ x?: string }` 不等于 `{ x: string | undefined }`
|
|
109
|
+
|
|
110
|
+
## 类型来自后端
|
|
111
|
+
|
|
112
|
+
API 类型**不手写**。引用 `{{config.paths.api_contracts}}/{service}/types.ts`:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
import type { UserListResponse, UserCreateRequest } from '{{config.paths.api_contracts}}/user/types';
|
|
116
|
+
|
|
117
|
+
async function fetchUsers(): Promise<UserListResponse> {
|
|
118
|
+
const res = await request.get<UserListResponse>('/api/users');
|
|
119
|
+
return res.data;
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**理由**:后端变更时类型自动报错,而不是运行时才发现。详见 [`api-contract-ts`](../api-contract-ts/SKILL.md)。
|
|
124
|
+
|
|
125
|
+
## type vs interface
|
|
126
|
+
|
|
127
|
+
| 场景 | 选 type 还是 interface | 理由 |
|
|
128
|
+
| --- | --- | --- |
|
|
129
|
+
| 联合 / 交叉 / 元组 / mapped | `type` | interface 不支持 |
|
|
130
|
+
| Props / 数据模型 / 简单对象 | 两者皆可,**项目内保持一致** | 功能等价 |
|
|
131
|
+
| 需要 declaration merging(全局扩展第三方库) | `interface` | type 不支持 |
|
|
132
|
+
| 需要 extends 多个(复用) | 两者皆可,`type` 用 `&` | 可读性差异 |
|
|
133
|
+
|
|
134
|
+
**建议**:项目统一用 `type`(更一致,能表达更多结构),只有需要合并时用 `interface`。
|
|
135
|
+
|
|
136
|
+
## 泛型纪律
|
|
137
|
+
|
|
138
|
+
### 何时用泛型
|
|
139
|
+
|
|
140
|
+
- ✅ 参数类型决定返回类型(`function first<T>(arr: T[]): T | undefined`)
|
|
141
|
+
- ✅ 容器 / 高阶抽象(`type Result<T, E> = { ok: true; value: T } | { ok: false; error: E }`)
|
|
142
|
+
- ✅ 组件接受不同数据形态(`<Table<T> columns={...} data={...} />`)
|
|
143
|
+
|
|
144
|
+
### 泛型命名
|
|
145
|
+
|
|
146
|
+
- 单字母:`T` / `U` / `V`(简单占位)
|
|
147
|
+
- 描述性:`TData` / `TError` / `TResponse`(语义清晰)
|
|
148
|
+
- 约束:`T extends { id: string }`(别用空 `T`)
|
|
149
|
+
|
|
150
|
+
### 禁用
|
|
151
|
+
|
|
152
|
+
- ❌ 泛型没被使用(`function foo<T>(x: string): void` 的 `T` 是僵尸)
|
|
153
|
+
- ❌ 过度泛型化("以后可能要换类型" = YAGNI)
|
|
154
|
+
- ❌ 泛型默认值用 `any`(用 `unknown` 或具体类型)
|
|
155
|
+
|
|
156
|
+
## 窄化技巧(淘汰 `!` 和 `as`)
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
// ❌ 非空断言
|
|
160
|
+
const name = user!.name;
|
|
161
|
+
|
|
162
|
+
// ✅ 收窄
|
|
163
|
+
if (!user) return null;
|
|
164
|
+
const name = user.name;
|
|
165
|
+
|
|
166
|
+
// ❌ 断言
|
|
167
|
+
const el = document.getElementById('x') as HTMLInputElement;
|
|
168
|
+
|
|
169
|
+
// ✅ 运行时校验
|
|
170
|
+
const el = document.getElementById('x');
|
|
171
|
+
if (!(el instanceof HTMLInputElement)) throw new Error('x not an input');
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### 常见窄化
|
|
175
|
+
|
|
176
|
+
- `typeof x === 'string'`
|
|
177
|
+
- `Array.isArray(x)`
|
|
178
|
+
- `x instanceof SomeClass`
|
|
179
|
+
- 自定义 type guard:`function isUser(x: unknown): x is User { ... }`
|
|
180
|
+
- `in` 操作符:`'error' in result`
|
|
181
|
+
|
|
182
|
+
## `import type` 习惯
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
import type { User } from './types'; // 只做类型用途
|
|
186
|
+
import { createUser } from './service'; // 运行时值
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**好处**:bundler 可以完全剥离类型,不污染生产 bundle。
|
|
190
|
+
|
|
191
|
+
## `as const` 与常量对象
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
const PERMISSIONS = ['read', 'write', 'admin'] as const;
|
|
195
|
+
type Permission = typeof PERMISSIONS[number]; // 'read' | 'write' | 'admin'
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
比手写 `type Permission = 'read' | 'write' | 'admin'` 少一处维护。
|
|
199
|
+
|
|
200
|
+
## 反模式(禁止)
|
|
201
|
+
|
|
202
|
+
- ❌ `// @ts-nocheck` 顶在文件头
|
|
203
|
+
- ❌ `const data: any = ...` 然后一路传递
|
|
204
|
+
- ❌ `as unknown as X` 双层断言
|
|
205
|
+
- ❌ 空 interface 作占位符
|
|
206
|
+
- ❌ 手写与后端不同步的 API 类型
|
|
207
|
+
- ❌ 泛型没有使用 / 没有约束
|
|
208
|
+
- ❌ `I` 前缀 / `Type` 后缀(见 [`react-naming`](../react-naming/SKILL.md))
|
|
209
|
+
|
|
210
|
+
## 质量门禁
|
|
211
|
+
|
|
212
|
+
- [ ] `strict: true` + `noUncheckedIndexedAccess: true`
|
|
213
|
+
- [ ] 无新增 `any` / `as any` / `@ts-ignore` / `@ts-nocheck`
|
|
214
|
+
- [ ] 公共边界全部显式类型
|
|
215
|
+
- [ ] API 类型引自 `{{config.paths.api_contracts}}`
|
|
216
|
+
- [ ] 联合字面量替代字符串魔法值
|
|
217
|
+
- [ ] 无非空断言 `!`(或每处有 ADR 链接)
|
|
218
|
+
- [ ] type / interface 项目内一致
|
|
219
|
+
- [ ] `tsc --noEmit` 零 error
|
package/meta/.gitkeep
ADDED
|
File without changes
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zsk:philosophy
|
|
3
|
+
description: Design rationale of the zsk skill set — LLM Wiki × Superpowers ×
|
|
4
|
+
GSD × project-adaptation synthesis. For contributors needing to understand why
|
|
5
|
+
zsk is organized the way it is.
|
|
6
|
+
category: meta
|
|
7
|
+
domain: meta
|
|
8
|
+
tier: optional
|
|
9
|
+
related:
|
|
10
|
+
- ../../system/project-constraints-template/SKILL.md
|
|
11
|
+
triggers:
|
|
12
|
+
- zsk philosophy
|
|
13
|
+
- why is zsk organized this way
|
|
14
|
+
- design rationale
|
|
15
|
+
- LLM wiki vs superpowers
|
|
16
|
+
- skill set principles
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Philosophy:LLM Wiki × Superpowers × GSD × 项目适配
|
|
20
|
+
|
|
21
|
+
## TL;DR
|
|
22
|
+
|
|
23
|
+
本 skill set 是**四股思想的合成**,目标是产出**通用 + LLM 友好 + 可项目适配 + 有纪律**的软件开发工作流规范。
|
|
24
|
+
|
|
25
|
+
- **通用**:不绑定任何具体项目、技术栈、组件库
|
|
26
|
+
- **LLM 友好**:frontmatter + 小文件 + 交叉引用
|
|
27
|
+
- **可适配**:项目通过 `PROJECT-CONFIG.yaml` 挂接,不 fork skills
|
|
28
|
+
- **有纪律**:Superpowers 硬原则(证据先于断言、TDD、置信度质疑)
|
|
29
|
+
|
|
30
|
+
## 四股思想的贡献
|
|
31
|
+
|
|
32
|
+
### 1. LLM Wiki — 组织哲学
|
|
33
|
+
|
|
34
|
+
> 原始出处:Karpathy 的 LLM Wiki 模式(完整事实源保存在 zsk 仓库 `.raws/` 目录,不随 skill 分发)。
|
|
35
|
+
|
|
36
|
+
本 skill set **借鉴**以下组织哲学,不照搬原文的具体运营机制:
|
|
37
|
+
|
|
38
|
+
- 每份文档 YAML frontmatter(`name` / `description` / `related` / `triggers`)
|
|
39
|
+
- 小而聚焦(单文件 ≤ 300 行,匹配 LLM chunk 读取窗口)
|
|
40
|
+
- 显式交叉引用(`related:` + 编号锚,让引用关系成为一等公民)
|
|
41
|
+
- 确定性路径命名(LLM 能预测文件位置)
|
|
42
|
+
- `description` 字段用**直接陈述风格**告诉 LLM 本文件是什么(主题名词短语 — 关键要点),不以 "Use when…" 开头
|
|
43
|
+
|
|
44
|
+
#### 借鉴什么 × 有意不采纳什么
|
|
45
|
+
|
|
46
|
+
Karpathy 原文是**"LLM 持续自维护的活知识库"**;本 skill set 是**"LLM 友好的静态 SDLC 文档"**,两者目的不同,取舍也不同:
|
|
47
|
+
|
|
48
|
+
| Karpathy 原文要素 | 本 skill set 态度 | 理由 |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| 层(Raw / Wiki / Schema) | ✅ 借鉴:`_raws/` / `docs/{module}/` / `CLAUDE.md`+`SYSTEM-SPEC.md`+本目录 | 所有权与可变性模型与工程场景天然吻合 |
|
|
51
|
+
| 交叉引用纪律 | ✅ 借鉴并强化为 FR/NFR/US/AC **编号锚** | 工程化对追溯的要求比知识库更严,用编号替代纯 `related:` 链接 |
|
|
52
|
+
| 小文件 + frontmatter | ✅ 借鉴 | 便于 LLM 按需加载 + 人类快速定位 |
|
|
53
|
+
| **Ingest(LLM 批量改多页)** | ❌ 不采纳 | Spec 是**冻结契约**(DoR 明说),不能让 LLM 日常改写 |
|
|
54
|
+
| **Lint(矛盾 / 孤儿 / 过期审计)** | ❌ 不采纳 | 质量门禁 + Code Review + 编号矩阵兜住 |
|
|
55
|
+
| **index.md / log.md 模块级元文件** | ❌ 不采纳 | `docs/{module}/` 本身即聚合目录 |
|
|
56
|
+
| **LLM 独占 wiki 写入权** | ❌ 不采纳 | 工程场景下决策归责于人 |
|
|
57
|
+
|
|
58
|
+
**一句话**:LLM Wiki 贡献**组织哲学**,7 阶段工作流贡献**工程化纪律**——两者合成,不是任一方的替代或部分实现。
|
|
59
|
+
|
|
60
|
+
### 2. Superpowers — 工作流骨架
|
|
61
|
+
|
|
62
|
+
给"软件开发方法论"提供可 skill 化的组织:
|
|
63
|
+
|
|
64
|
+
- Skill-based orchestration:每个能力一个 skill
|
|
65
|
+
- 线性工作流 + 显式触发条件
|
|
66
|
+
- "Red flags" 反模式告警机制
|
|
67
|
+
- 决策流程图(Graphviz)表达分支
|
|
68
|
+
|
|
69
|
+
**从 Superpowers 吸收的硬原则(写入所有 stages / workflows)**:
|
|
70
|
+
|
|
71
|
+
| 原则 | 含义 |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| 证据先于断言 | 未跑过的命令不得声称"通过" |
|
|
74
|
+
| Red-Green-Refactor | Bugfix / Refactor 默认纪律 |
|
|
75
|
+
| Bug 置信度质疑 | 修 bug 前先问"bug 存在吗、原因对吗、修复有效吗" |
|
|
76
|
+
| 技术严谨 > 性能式同意 | Review 分歧先验证技术事实 |
|
|
77
|
+
|
|
78
|
+
### 3. GSD (Getting Stuff Done) — 心智模型
|
|
79
|
+
|
|
80
|
+
给"阶段推进"提供心智依据:
|
|
81
|
+
|
|
82
|
+
- **Capture** → 收集想法 / 需求 / 问题
|
|
83
|
+
- **Clarify** → 澄清:这是什么?做不做?怎么做?
|
|
84
|
+
- **Organize** → 组织到具体位置(清单、项目、日程)
|
|
85
|
+
- **Reflect** → 回顾 / 审视 / 斟酌
|
|
86
|
+
- **Engage** → 动手执行
|
|
87
|
+
|
|
88
|
+
映射到本 skill set 的 7 阶段:
|
|
89
|
+
|
|
90
|
+
| GSD 心智 | 本 skill set 阶段 | 负责什么 |
|
|
91
|
+
| --- | --- | --- |
|
|
92
|
+
| Capture + Clarify | `zsk:proposal` | 为什么做 / 不做什么 |
|
|
93
|
+
| Organize | `zsk:spec` | 做什么(契约 / 验收) |
|
|
94
|
+
| Reflect | `zsk:design` | 怎么做(设计 / ADR) |
|
|
95
|
+
| Engage | `zsk:coding` → `zsk:reviewing` → `zsk:verify` → `zsk:archive` | 动手执行 + 审代码 + 验收 + 沉淀 |
|
|
96
|
+
|
|
97
|
+
### 4. 项目 SYSTEM-SPEC — 适配层
|
|
98
|
+
|
|
99
|
+
项目总有定制需求(路径 / 技术栈 / 命名 / 环境)。适配层保证:
|
|
100
|
+
|
|
101
|
+
- **占位符系统**:`{{config.*}}` 在 skill 内作为抽象变量
|
|
102
|
+
- **优先级层级**:项目覆写 > 通用 skill
|
|
103
|
+
- **不 fork**:通过配置文件覆盖,而非修改 skill 本体
|
|
104
|
+
|
|
105
|
+
## 合成:5 条设计原则
|
|
106
|
+
|
|
107
|
+
### 原则 1:通用方法 × 项目配置
|
|
108
|
+
|
|
109
|
+
```text
|
|
110
|
+
方法论(WHAT / HOW 抽象) 配置(WHERE / WHICH 具体)
|
|
111
|
+
↓ ↓
|
|
112
|
+
.best-practices/ × PROJECT-CONFIG.yaml
|
|
113
|
+
↘ ↙
|
|
114
|
+
运行时解析 → 具体产物(模块 proposal.md / spec.md 等)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- **方法论** → zsk skills(跨项目通用,npm 包)
|
|
118
|
+
- **路径 / 工具 / 命名** → `PROJECT-CONFIG.yaml`(项目本地)
|
|
119
|
+
|
|
120
|
+
### 原则 2:LLM 优先的组织
|
|
121
|
+
|
|
122
|
+
- Frontmatter 必须有 `name` / `description` / `category` / `domain` / `related` / `triggers`
|
|
123
|
+
- `description` 用**直接陈述**风格(主题名词短语 — 关键要点),不以 "Use when…" 开头
|
|
124
|
+
- 单文件 ≤ 300 行
|
|
125
|
+
- 显式 `related:` 链接
|
|
126
|
+
- 避免跨文件隐式依赖
|
|
127
|
+
|
|
128
|
+
### 原则 3:阶段化 + 变更类型 + 领域分簇
|
|
129
|
+
|
|
130
|
+
- **基础**:7 阶段(Proposal → Spec → Design → Coding → Reviewing → Verify → Archive),**不可删**
|
|
131
|
+
- **分支**:Feature / Bugfix / Refactor(按变更类型差异化填充 7 阶段)
|
|
132
|
+
- **领域**:sdlc / frontend / quality / design-handoff / system / meta
|
|
133
|
+
- Skill 通过 frontmatter `domain:` + `category:` + `tier:` 标注
|
|
134
|
+
|
|
135
|
+
### 原则 4:基于证据的纪律
|
|
136
|
+
|
|
137
|
+
- "完成 / 通过 / 修复"必须有**可验证证据链接**
|
|
138
|
+
- TDD 是 Bugfix / Refactor 默认;Feature 视复杂度
|
|
139
|
+
- 修 bug 前必问三问(Superpowers 置信度质疑)
|
|
140
|
+
- Review 分歧时先验证技术,再讨论情感
|
|
141
|
+
|
|
142
|
+
### 原则 5:编号化交叉引用
|
|
143
|
+
|
|
144
|
+
> 灵感源头:Karpathy LLM Wiki 的 "cross-references are already there"——好的知识库里,引用关系是一等公民。
|
|
145
|
+
> 工程化强化:我们把纯 `related:` 链接升级为**强编号锚**。
|
|
146
|
+
|
|
147
|
+
7 阶段文档间建立**编号化追溯链**:
|
|
148
|
+
|
|
149
|
+
```text
|
|
150
|
+
Proposal G-{n} (SMART 目标)
|
|
151
|
+
↓
|
|
152
|
+
Spec US-{n} / FR-{n} / NFR-{n} / AC-{n} (可被下游锚定)
|
|
153
|
+
↓ ↑
|
|
154
|
+
Design FR-{n} → 入口文件 + ADR-{n} + 覆盖任务 (显式回链)
|
|
155
|
+
↓
|
|
156
|
+
Coding 每任务声明"覆盖 FR"
|
|
157
|
+
↓
|
|
158
|
+
Reviewing / Verify FR 覆盖矩阵 + AC 勾选兜底
|
|
159
|
+
↓
|
|
160
|
+
Archive Postmortem / ADR 引用原编号保留追溯
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**纪律要点**:
|
|
164
|
+
|
|
165
|
+
- Spec 是编号的**唯一发源地**,Design / Task 只引用不自创
|
|
166
|
+
- 编号只增不改(废弃标记代替删除,合并/拆分留追踪)
|
|
167
|
+
- Bugfix 的"受影响契约项"、Refactor 的"行为不变"都用同一套编号
|
|
168
|
+
- DoR/DoD/质量门禁把编号完整性作为硬性门禁
|
|
169
|
+
|
|
170
|
+
## 优先级层级(冲突时上位胜出)
|
|
171
|
+
|
|
172
|
+
1. **用户显式指令**(CLAUDE.md / 会话中的直接请求)
|
|
173
|
+
2. **项目 PROJECT-CONFIG.yaml**(本项目的配置覆写)
|
|
174
|
+
3. **项目 SYSTEM-SPEC.md**(本项目的系统规约)
|
|
175
|
+
4. **项目 docs/system/\***(本项目 ADR / architecture / NFR)
|
|
176
|
+
5. **zsk skills**(通用方法论,本目录)
|
|
177
|
+
6. **`~/.claude/skills/*` 平台级 skill**(如 Superpowers)
|
|
178
|
+
7. **工具默认行为**
|
|
179
|
+
|
|
180
|
+
## 占位符系统
|
|
181
|
+
|
|
182
|
+
Skill 文件引用项目特定内容时,一律用 `{{config.*}}` 占位符,由 `project-config.yaml`(CLI `zsk project-init` 产出)填充:
|
|
183
|
+
|
|
184
|
+
```text
|
|
185
|
+
{{config.paths.srs}} 原始需求文档
|
|
186
|
+
{{config.paths.figma_index}} 设计索引(如有)
|
|
187
|
+
{{config.stack.ui_lib}} UI 库
|
|
188
|
+
{{config.stack.state_async}} 异步状态库
|
|
189
|
+
{{config.stack.state_shared}} 共享状态
|
|
190
|
+
{{config.i18n.namespace}} i18n 命名空间
|
|
191
|
+
{{config.git.main_branch}} 主干分支
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## 为什么这样合成
|
|
195
|
+
|
|
196
|
+
- **单独用 Superpowers**:强在工作流骨架,但缺 LLM 组织约束 + 项目适配机制
|
|
197
|
+
- **单独用 GSD**:心智清晰,但没有 skill 化的产物
|
|
198
|
+
- **单独用 LLM Wiki**:结构清晰,但没有方法论灵魂
|
|
199
|
+
- **三者合一 + 项目适配层**:结构 + 方法论 + 心智 + 可复用
|
|
200
|
+
|
|
201
|
+
## 反模式(Red Flags)
|
|
202
|
+
|
|
203
|
+
以下情况立即停止并修正:
|
|
204
|
+
|
|
205
|
+
1. Skill 里出现硬编码项目路径(如 `.raws/SRS.md`)→ 必须改为 `{{config.*}}`
|
|
206
|
+
2. Skill 里推荐特定 UI 库名 → 改为 `{{config.stack.ui_lib}}`
|
|
207
|
+
3. 同一份 skill 做 3+ 件事 → 拆分
|
|
208
|
+
4. 单文件 > 300 行 → 拆分或精简
|
|
209
|
+
5. 文档没 frontmatter → 补齐
|
|
210
|
+
6. `description` 以 "Use when…" 开头 → 重写为直接陈述风格(主题名词短语 — 关键要点)
|
|
211
|
+
7. 引用其他 skill 但没写在 `related:` → 补齐
|
|
212
|
+
8. 模板用了未在 `project-config.yaml` 声明的变量 → 补齐配置模板
|
|
213
|
+
|
|
214
|
+
## 输出承诺
|
|
215
|
+
|
|
216
|
+
最终的 skill set 通过 `@captain_z/zsk` CLI 发布,允许:
|
|
217
|
+
|
|
218
|
+
- ✅ 任意新项目通过 `npx @captain_z/zsk project-init` 接入
|
|
219
|
+
- ✅ 不需要修改 skill 内容,只改 `project-config.yaml`
|
|
220
|
+
- ✅ 允许项目通过 `SYSTEM-SPEC.md` 本地覆写个别规则
|
|
221
|
+
- ✅ 上游 skill 更新不破坏项目(版本化 + config 向后兼容)
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@captain_z/zsk-skills",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "ZNorth Standard Kit — skill content package (SDLC + frontend + quality + design-handoff + system + meta)",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"files": [
|
|
7
|
+
"sdlc",
|
|
8
|
+
"frontend",
|
|
9
|
+
"quality",
|
|
10
|
+
"design-handoff",
|
|
11
|
+
"system",
|
|
12
|
+
"meta",
|
|
13
|
+
"bundles.yaml",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"exports": {
|
|
17
|
+
"./package.json": "./package.json",
|
|
18
|
+
"./bundles.yaml": "./bundles.yaml"
|
|
19
|
+
},
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {}
|
|
24
|
+
}
|
package/quality/.gitkeep
ADDED
|
File without changes
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zsk:a11y-principles
|
|
3
|
+
description: Accessibility principles at the concept level — WCAG 2.1 AA
|
|
4
|
+
baseline, POUR principles, keyboard operation matrix, focus management, aria
|
|
5
|
+
semantics, contrast ratios, don't-rely-on-color, reduced motion. For Web/JSX
|
|
6
|
+
implementation (axe-core, jsx-a11y, focus traps in Modal, etc.) see
|
|
7
|
+
frontend/a11y-web.md.
|
|
8
|
+
category: standard
|
|
9
|
+
domain: quality
|
|
10
|
+
tier: optional
|
|
11
|
+
related:
|
|
12
|
+
- ../../system/nfr-baseline/SKILL.md
|
|
13
|
+
- ../../frontend/a11y-web/SKILL.md
|
|
14
|
+
triggers:
|
|
15
|
+
- accessibility principles
|
|
16
|
+
- WCAG AA
|
|
17
|
+
- POUR
|
|
18
|
+
- keyboard matrix
|
|
19
|
+
- focus management
|
|
20
|
+
- aria semantics
|
|
21
|
+
- contrast ratio
|
|
22
|
+
- reduced motion
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# Quality: A11y Principles(可访问性原则 · 跨栈)
|
|
26
|
+
|
|
27
|
+
> **范围**:可访问性的**概念层** — WCAG、POUR、键盘、焦点、aria、对比度、色彩、Reduced Motion
|
|
28
|
+
> **不含**:具体实现(JSX label 关联 / axe-core 扫描 / Modal 焦点陷阱 等)— 见 [`frontend/a11y-web`](../../frontend/a11y-web/SKILL.md)
|
|
29
|
+
> **参考规范**:WCAG 2.1 AA、ARIA Authoring Practices Guide(APG)、Section 508
|
|
30
|
+
> **系统基线**:[`system/nfr-baseline`](../../system/nfr-baseline/SKILL.md) 的第 2 类继承本文件
|
|
31
|
+
|
|
32
|
+
## 基线:WCAG 2.1 AA
|
|
33
|
+
|
|
34
|
+
所有新增 / 修改界面必须达到 WCAG 2.1 Level AA。
|
|
35
|
+
|
|
36
|
+
### 四大原则(POUR)
|
|
37
|
+
|
|
38
|
+
| 原则 | 含义 | 关键要求 |
|
|
39
|
+
| --- | --- | --- |
|
|
40
|
+
| **Perceivable** | 可感知 | 文字替代、对比度、可缩放 |
|
|
41
|
+
| **Operable** | 可操作 | 键盘可达、焦点管理、无时间限制 |
|
|
42
|
+
| **Understandable** | 可理解 | 可读、可预测、输入辅助 |
|
|
43
|
+
| **Robust** | 健壮 | 兼容辅助技术 |
|
|
44
|
+
|
|
45
|
+
## 键盘操作矩阵(概念层)
|
|
46
|
+
|
|
47
|
+
所有交互元素必须满足以下键盘等价操作:
|
|
48
|
+
|
|
49
|
+
| 键位 | 行为 | 通用场景 |
|
|
50
|
+
| --- | --- | --- |
|
|
51
|
+
| `Tab` | 焦点前进 | 所有可交互元素 |
|
|
52
|
+
| `Shift + Tab` | 焦点后退 | 所有可交互元素 |
|
|
53
|
+
| `Enter` | 激活 / 确认 | 按钮、链接、表单提交 |
|
|
54
|
+
| `Space` | 激活 / 切换 | 按钮、复选框、单选 |
|
|
55
|
+
| `Esc` | 取消 / 关闭 | Modal、Popover、菜单 |
|
|
56
|
+
| `↑ ↓` | 列表 / 下拉项移动 | List、Select、Menu |
|
|
57
|
+
| `← →` | 树展开 / 折叠 | Tree、Tabs |
|
|
58
|
+
| `Home / End` | 跳首项 / 尾项 | 列表、树 |
|
|
59
|
+
|
|
60
|
+
组件特有键位在模块 `spec.md` 的 UE 状态矩阵声明。
|
|
61
|
+
|
|
62
|
+
## 焦点管理(概念层)
|
|
63
|
+
|
|
64
|
+
### 基线
|
|
65
|
+
|
|
66
|
+
- **焦点可见**:焦点态必须有视觉表现(轮廓 / 背景)
|
|
67
|
+
- **焦点顺序**:Tab 顺序符合视觉阅读顺序(不用正数 tabindex)
|
|
68
|
+
- **焦点陷阱**:Modal / Drawer 打开时焦点锁在内;关闭时回到触发元素
|
|
69
|
+
- **跳过链接**:长页面提供"跳到主内容"链接
|
|
70
|
+
|
|
71
|
+
### Modal / Overlay 规则
|
|
72
|
+
|
|
73
|
+
1. 打开时焦点移到第一个可交互元素
|
|
74
|
+
2. 循环 Tab 只在 Modal 内
|
|
75
|
+
3. `Esc` 关闭
|
|
76
|
+
4. 关闭时焦点回到触发 Modal 的元素
|
|
77
|
+
|
|
78
|
+
## aria 最佳实践(概念层)
|
|
79
|
+
|
|
80
|
+
### Role(语义角色)
|
|
81
|
+
|
|
82
|
+
- `button` / `link` / `navigation` / `main` / `dialog` / `tree` / `treeitem` / `list` / `listbox`
|
|
83
|
+
- **优先用语义 HTML / 等价平台原生控件**
|
|
84
|
+
- 用原生不行时才加 role
|
|
85
|
+
|
|
86
|
+
### State(状态属性)
|
|
87
|
+
|
|
88
|
+
| 属性 | 用途 |
|
|
89
|
+
| --- | --- |
|
|
90
|
+
| `aria-label` | 无可见文字时提供标签 |
|
|
91
|
+
| `aria-labelledby` | 引用已存在的标签元素 |
|
|
92
|
+
| `aria-describedby` | 引用描述(帮助文本 / 错误提示) |
|
|
93
|
+
| `aria-expanded` | 展开 / 折叠(树 / 下拉) |
|
|
94
|
+
| `aria-selected` | 选中态(列表 / 树 / Tab) |
|
|
95
|
+
| `aria-disabled` | 禁用(替代原生 `disabled` 属性时) |
|
|
96
|
+
| `aria-hidden="true"` | 对辅助技术隐藏装饰元素 |
|
|
97
|
+
| `aria-live` | 动态内容变化通知(`polite` / `assertive`) |
|
|
98
|
+
| `aria-invalid` | 表单校验失败 |
|
|
99
|
+
|
|
100
|
+
### aria 禁用
|
|
101
|
+
|
|
102
|
+
- ❌ 同时用 `aria-label` 和 `aria-labelledby`
|
|
103
|
+
- ❌ 给纯装饰元素加 role
|
|
104
|
+
- ❌ `aria-hidden="true"` 包住可交互元素
|
|
105
|
+
- ❌ 滥用 `aria-live="assertive"`(打扰读屏用户)
|
|
106
|
+
|
|
107
|
+
## 对比度与色彩
|
|
108
|
+
|
|
109
|
+
| 元素 | 最小对比度 |
|
|
110
|
+
| --- | --- |
|
|
111
|
+
| 正文(< 18pt 或 < 14pt 加粗) | **4.5:1** |
|
|
112
|
+
| 大字号(≥ 18pt 或 ≥ 14pt 加粗) | **3:1** |
|
|
113
|
+
| UI 组件边界(按钮、表单) | **3:1** |
|
|
114
|
+
| 焦点指示 | **3:1** |
|
|
115
|
+
|
|
116
|
+
### 不依赖颜色传递信息
|
|
117
|
+
|
|
118
|
+
错误态除了红色必须有图标 / 文字;必选字段除了红色 `*` 必须有文字声明。
|
|
119
|
+
|
|
120
|
+
## 动效(Reduced Motion)
|
|
121
|
+
|
|
122
|
+
尊重用户系统偏好 `prefers-reduced-motion: reduce`:
|
|
123
|
+
|
|
124
|
+
- 装饰性 / 过度动效必须在该偏好下关闭
|
|
125
|
+
- 视差效果、弹跳、旋转、自动播放动画必须可关闭
|
|
126
|
+
|
|
127
|
+
## 图片与媒体(概念层)
|
|
128
|
+
|
|
129
|
+
- 图片必须有替代文字(装饰图为空字符串,信息图写明含义)
|
|
130
|
+
- 图表 / 数据可视化需要可访问替代文本(data table / 描述)
|
|
131
|
+
- 视频需要字幕;无自动播放音频
|
|
132
|
+
|
|
133
|
+
## 测试原则
|
|
134
|
+
|
|
135
|
+
### 自动化
|
|
136
|
+
- Lint 层面的 a11y 规则(按栈选插件)
|
|
137
|
+
- 运行时 a11y 扫描器(按栈选工具,如 axe-core 系)
|
|
138
|
+
- CI 跑扫描关键页面,**零 critical violation** 才可合并
|
|
139
|
+
|
|
140
|
+
### 手工
|
|
141
|
+
- 键盘只操作一遍关键流程
|
|
142
|
+
- 读屏抽检(VoiceOver / NVDA / TalkBack)
|
|
143
|
+
- 浏览器 / 系统缩放 200% 检查
|
|
144
|
+
|
|
145
|
+
## 质量门禁
|
|
146
|
+
|
|
147
|
+
- [ ] 符合 WCAG 2.1 AA
|
|
148
|
+
- [ ] 键盘操作矩阵完整
|
|
149
|
+
- [ ] 焦点可见 + 陷阱 + 回归
|
|
150
|
+
- [ ] aria 属性按场景使用(不滥用)
|
|
151
|
+
- [ ] 对比度达标
|
|
152
|
+
- [ ] 不依赖颜色传递信息
|
|
153
|
+
- [ ] 支持 Reduced Motion
|
|
154
|
+
- [ ] 自动化扫描零 critical
|
|
155
|
+
- [ ] (Web 实现)见 `frontend/a11y-web` 的补充门禁
|