@qnroa/qtype 0.0.1
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/CHANGELOG.md +97 -0
- package/CHANGELOG.zh.md +82 -0
- package/LICENSE +201 -0
- package/README.md +113 -0
- package/README.zh.md +114 -0
- package/dist/cli/bootstrap.js +190 -0
- package/dist/cli/commands/check/action.js +56 -0
- package/dist/cli/commands/check/i18n.js +26 -0
- package/dist/cli/commands/check/index.js +20 -0
- package/dist/cli/commands/config/action.js +236 -0
- package/dist/cli/commands/config/i18n.js +64 -0
- package/dist/cli/commands/config/index.js +72 -0
- package/dist/cli/commands/content/index.js +22 -0
- package/dist/cli/commands/content/lint/action.js +102 -0
- package/dist/cli/commands/content/lint/i18n.js +32 -0
- package/dist/cli/commands/content/lint/index.js +19 -0
- package/dist/cli/commands/content/search/action.js +64 -0
- package/dist/cli/commands/content/search/i18n.js +20 -0
- package/dist/cli/commands/content/search/index.js +24 -0
- package/dist/cli/commands/content/validate/action.js +145 -0
- package/dist/cli/commands/content/validate/i18n.js +32 -0
- package/dist/cli/commands/content/validate/index.js +19 -0
- package/dist/cli/commands/index.js +19 -0
- package/dist/cli/commands/init/index.js +53 -0
- package/dist/cli/commands/pack/i18n.js +20 -0
- package/dist/cli/commands/pack/index.js +48 -0
- package/dist/cli/commands/plugin/i18n.js +28 -0
- package/dist/cli/commands/plugin/index.js +41 -0
- package/dist/cli/commands/publish/build/action.js +208 -0
- package/dist/cli/commands/publish/build/i18n.js +50 -0
- package/dist/cli/commands/publish/build/index.js +24 -0
- package/dist/cli/commands/publish/build/mermaidPass.js +93 -0
- package/dist/cli/commands/publish/build/mermaidPrerender.js +199 -0
- package/dist/cli/commands/publish/index.js +21 -0
- package/dist/cli/commands/publish/init/action.js +74 -0
- package/dist/cli/commands/publish/init/i18n.js +22 -0
- package/dist/cli/commands/publish/init/index.js +26 -0
- package/dist/cli/commands/publish/password/action.js +158 -0
- package/dist/cli/commands/publish/password/i18n.js +44 -0
- package/dist/cli/commands/publish/password/index.js +35 -0
- package/dist/cli/commands/publish/serve/action.js +117 -0
- package/dist/cli/commands/publish/serve/i18n.js +32 -0
- package/dist/cli/commands/publish/serve/index.js +37 -0
- package/dist/cli/commands/repo/index.js +19 -0
- package/dist/cli/commands/repo/new/action.js +98 -0
- package/dist/cli/commands/repo/new/i18n.js +46 -0
- package/dist/cli/commands/repo/new/index.js +57 -0
- package/dist/cli/commands/repo/sync/action.js +202 -0
- package/dist/cli/commands/repo/sync/i18n.js +44 -0
- package/dist/cli/commands/repo/sync/index.js +47 -0
- package/dist/cli/commands/repo/templates.js +87 -0
- package/dist/cli/i18n/index.js +141 -0
- package/dist/cli/i18n/shared.js +142 -0
- package/dist/cli/index.js +79 -0
- package/dist/cli/registry/command.js +1 -0
- package/dist/cli/registry/commander-i18n.js +76 -0
- package/dist/cli/registry/help.js +142 -0
- package/dist/cli/registry/mount.js +71 -0
- package/dist/cli/utils/output.js +92 -0
- package/dist/cli/utils/paths.js +13 -0
- package/dist/cli/utils/prompt.js +72 -0
- package/dist/cli/utils/repoGuard.js +41 -0
- package/dist/core/encrypt.js +113 -0
- package/dist/core/index.js +8 -0
- package/dist/core/keystroke/asciiMap.js +39 -0
- package/dist/core/keystroke/chineseMap.js +32 -0
- package/dist/core/keystroke/fullwidthMap.js +41 -0
- package/dist/core/keystroke/index.js +22 -0
- package/dist/core/keystroke/textNormalize.js +68 -0
- package/dist/core/keystroke/types.js +1 -0
- package/dist/core/parser/frontmatter.js +58 -0
- package/dist/core/parser/index.js +2 -0
- package/dist/core/parser/parseMaterial.js +42 -0
- package/dist/core/types.js +1 -0
- package/dist/core/typing/engine.js +112 -0
- package/dist/core/typing/index.js +2 -0
- package/dist/core/typing/metrics.js +20 -0
- package/dist/store/index.js +44 -0
- package/dist/store/kv.js +276 -0
- package/dist/store/storage/browser.js +61 -0
- package/dist/store/storage/json.js +113 -0
- package/dist/store/storage/memory.js +24 -0
- package/dist/store/types.js +47 -0
- package/dist/store/validators.js +71 -0
- package/dist/view/assets/index-DBABH3dG.js +111 -0
- package/dist/view/assets/index-RTLZ-zOC.css +1 -0
- package/dist/view/index.html +14 -0
- package/dist/view/qtype-logo.svg +49 -0
- package/dist/view/qtype-mark.svg +21 -0
- package/docs/README.md +23 -0
- package/docs/README.zh.md +20 -0
- package/docs/en/authoring.md +138 -0
- package/docs/en/cli-reference.md +171 -0
- package/docs/zh/authoring.md +131 -0
- package/docs/zh/cli-reference.md +162 -0
- package/package.json +85 -0
- package/templates/en/QTYPE.md +618 -0
- package/templates/en/README.md +64 -0
- package/templates/en/TODO.md +7 -0
- package/templates/en/index.md +7 -0
- package/templates/en/log.md +3 -0
- package/templates/en/material/.gitkeep +0 -0
- package/templates/en/material/example.md +47 -0
- package/templates/zh/QTYPE.md +618 -0
- package/templates/zh/README.md +64 -0
- package/templates/zh/TODO.md +7 -0
- package/templates/zh/index.md +7 -0
- package/templates/zh/log.md +3 -0
- package/templates/zh/material/.gitkeep +0 -0
- package/templates/zh/material/example.md +47 -0
|
File without changes
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
tags: [example, starter]
|
|
3
|
+
type: normal
|
|
4
|
+
difficulty: 1
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Q:
|
|
8
|
+
|
|
9
|
+
Type this sentence exactly as it appears.
|
|
10
|
+
|
|
11
|
+
## A:
|
|
12
|
+
|
|
13
|
+
Type this sentence exactly as it appears.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
tags: [english, vocab]
|
|
19
|
+
type: word
|
|
20
|
+
phonetic: /ˌsɪəˈriːəl/
|
|
21
|
+
gloss: happening one after another; in a series
|
|
22
|
+
translation: relating to a sequence
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Q:
|
|
26
|
+
|
|
27
|
+
serial
|
|
28
|
+
|
|
29
|
+
## A:
|
|
30
|
+
|
|
31
|
+
serial
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
tags: [english, phrases]
|
|
37
|
+
type: sentence
|
|
38
|
+
translation: With enough practice you master anything.
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Q:
|
|
42
|
+
|
|
43
|
+
Practice makes perfect.
|
|
44
|
+
|
|
45
|
+
## A:
|
|
46
|
+
|
|
47
|
+
Practice makes perfect.
|
|
@@ -0,0 +1,618 @@
|
|
|
1
|
+
# QTYPE — LLM 打字练习卡片规范
|
|
2
|
+
|
|
3
|
+
你是一个打字练习卡片库的维护者。本文件定义**规则**和**操作**。进入仓库后先完整读一次本文件,然后按规则执行。
|
|
4
|
+
|
|
5
|
+
qtype 是一个以 Markdown 为源、以 OS 键盘(含中文 IME)为输入的打字练习工具。用户负责选题材、提问、调整;Agent 负责读、提炼、切分、归档、维护。
|
|
6
|
+
|
|
7
|
+
全文按**概念 / 格式 / 操作 / 守则**四大模块组织。
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 概念
|
|
12
|
+
|
|
13
|
+
### 理念
|
|
14
|
+
|
|
15
|
+
- 用户负责**选主题**或**扔材料**。你负责**读、提炼、切成卡片、归档、维护**。
|
|
16
|
+
- 你不是问答机器人,你是**打字练习卡片库的作者**。每张卡片都要真的可以被用户敲出来。
|
|
17
|
+
- `raw/` 是用户扔进来的原始材料(可选目录),**不可改内容**。
|
|
18
|
+
- `material/` 下的每个 `.md` 文件是一个卡组(deck),**完全由你维护**(用户手写的除外)。
|
|
19
|
+
- 卡片不是随便的问答对,是**能被真人打字的字符串**——所有字符必须在 OS 键盘或中文 IME 下打得出来。
|
|
20
|
+
|
|
21
|
+
### 术语
|
|
22
|
+
|
|
23
|
+
| 术语 | 定义 |
|
|
24
|
+
|---|---|
|
|
25
|
+
| 仓库 | 一个独立的 qtype 目录(例如 `my-typing-deck/`) |
|
|
26
|
+
| 卡组 (deck) | `material/` 下的一个 `.md` 文件,含若干张卡片 |
|
|
27
|
+
| 卡片 (card) | 一个 `## Q:` + `## A:` 单元,前面有一段 frontmatter |
|
|
28
|
+
| 标签 (tag) | 卡片或卡组的分类标记,用于筛选和目录归组 |
|
|
29
|
+
| 单词卡 | `type: word`,练拼写和词形,含 `phonetic` 和 `gloss` |
|
|
30
|
+
| 句子卡 | `type: sentence`,练成句连打,含 `translation` |
|
|
31
|
+
| 普通卡 | `type: normal`(默认),Q 是提示、A 是答案,形式最自由 |
|
|
32
|
+
| raw 材料 | `raw/` 下的原始文本(可选),用于 ingest 生成卡片 |
|
|
33
|
+
| log | `log.md`,只追加的时间线日志 |
|
|
34
|
+
| 复习进度 | 用户在 Web UI 中练习后产生的本地进度数据(Agent 不管) |
|
|
35
|
+
|
|
36
|
+
### 目录布局
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
<仓库根>/
|
|
40
|
+
├── QTYPE.md # 本文件(规则与操作;语言由 qtype 在创建时选定)
|
|
41
|
+
├── AGENTS.md # 软链 → QTYPE.md
|
|
42
|
+
├── CLAUDE.md # 软链 → QTYPE.md
|
|
43
|
+
├── GEMINI.md # 软链 → QTYPE.md
|
|
44
|
+
├── README.md # 仓库介绍(由人维护)
|
|
45
|
+
├── TODO.md # 待补清单(由 todo 命令维护)
|
|
46
|
+
├── index.md # 全部卡组的目录,按标签分组
|
|
47
|
+
├── log.md # 时间线日志,只追加
|
|
48
|
+
├── qtype.config.json # 用户可调设置(主题、目标 WPM、hint 模式等)
|
|
49
|
+
├── material/ # 你写的卡组
|
|
50
|
+
│ ├── .gitkeep
|
|
51
|
+
│ ├── <slug>.md # 一个卡组一个文件
|
|
52
|
+
│ └── assets/ # 卡组引用的图片和其他二进制
|
|
53
|
+
│ └── <deck-slug>/
|
|
54
|
+
│ └── xxx.png
|
|
55
|
+
└── raw/ # (可选)用户扔进来的原始材料
|
|
56
|
+
├── .gitkeep
|
|
57
|
+
├── YYYY-MM-DD-<slug>.md
|
|
58
|
+
└── assets/
|
|
59
|
+
└── <raw-slug>/
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
规则:
|
|
63
|
+
|
|
64
|
+
- `material/` 下**平铺**所有卡组文件,**只允许**一个子目录 `assets/`(存卡组引用的图片和其他二进制)。
|
|
65
|
+
- `raw/` 下**平铺**所有源文件,**只允许**一个子目录 `assets/`(存 raw 引用的图片和其他二进制)。
|
|
66
|
+
- `material/assets/<deck-slug>/` 和 `raw/assets/<raw-slug>/`:按所属 md 文件的 slug 分文件夹,避免全局命名冲突。
|
|
67
|
+
- **首次操作时兜底检查骨架**:仓库的标准初始化由用户完成。Agent 进入仓库时,若 `material/` / `index.md` / `log.md` 有缺失,按规范补建。`material/` 和 `raw/` 新建时放入 `.gitkeep`。
|
|
68
|
+
- `raw/` 是可选目录,用户不扔材料时可不建。
|
|
69
|
+
- 只建本文件规定的目录和文件,**不建**任何规则外的东西。
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 格式
|
|
74
|
+
|
|
75
|
+
### 命名
|
|
76
|
+
|
|
77
|
+
**卡组文件名**
|
|
78
|
+
|
|
79
|
+
- 路径:`material/<slug>.md`
|
|
80
|
+
- `<slug>`:主题的 kebab-case,小写,英文字母和短横线,最长 60 字符。中文主题用英译或拼音。
|
|
81
|
+
- 同名冲突:末尾追加 `-2` / `-3` 等数字后缀。
|
|
82
|
+
- 例:`gre-vocab-list-3.md`、`react-hooks-quiz.md`、`toefl-idioms.md`。
|
|
83
|
+
|
|
84
|
+
**raw 文件名**
|
|
85
|
+
|
|
86
|
+
- 路径:`raw/YYYY-MM-DD-<slug>.md`
|
|
87
|
+
- `YYYY-MM-DD`:材料被收入本仓库的日期。
|
|
88
|
+
- `<slug>`:材料标题的 kebab-case。
|
|
89
|
+
- 没有明确标题的粘贴文本用 `YYYY-MM-DD-note-<N>.md`。
|
|
90
|
+
|
|
91
|
+
**assets 命名**
|
|
92
|
+
|
|
93
|
+
- `material/assets/<deck-slug>/` 和 `raw/assets/<raw-slug>/`:按所属 md 文件的 slug 分组,slug 一致时资产同一目录。
|
|
94
|
+
|
|
95
|
+
### 链接
|
|
96
|
+
|
|
97
|
+
**只用 Markdown link,不用 Wikilink**。
|
|
98
|
+
|
|
99
|
+
| 场景 | 路径写法 | 例子 |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| 卡组文件引用另一个卡组 | `./<slug>.md` | `[GRE 高频](./gre-vocab-list-3.md)` |
|
|
102
|
+
| 卡组引用 raw 文件 | `../raw/<文件名>.md` | `[原文](../raw/2026-08-14-mdn-closures.md)` |
|
|
103
|
+
| 卡组引用 material/assets 下的图片 | `./assets/<deck-slug>/<文件>` | `` |
|
|
104
|
+
| 卡组引用 raw/assets 下的图片 | `../raw/assets/<raw-slug>/<文件>` | `` |
|
|
105
|
+
| index.md / log.md 引用卡组 | 从仓库根起 | `material/gre-vocab-list-3.md` |
|
|
106
|
+
|
|
107
|
+
规则:
|
|
108
|
+
|
|
109
|
+
- **绝不**用 `[[wikilink]]` 语法。
|
|
110
|
+
- **绝不**用绝对路径(不以 `./` 或 `../` 开头的都不行)。
|
|
111
|
+
- 链接目标必须是实际存在的文件。
|
|
112
|
+
|
|
113
|
+
### Deck 文件头(deck-level frontmatter)
|
|
114
|
+
|
|
115
|
+
每个 deck 文件必须以一段 YAML frontmatter 开头,描述整个卡组:
|
|
116
|
+
|
|
117
|
+
```yaml
|
|
118
|
+
---
|
|
119
|
+
title: <卡组标题>
|
|
120
|
+
language: <目标语言 ISO 代码,如 en / zh / ja>
|
|
121
|
+
tags: [<标签 1>, <标签 2>]
|
|
122
|
+
created: YYYY-MM-DD
|
|
123
|
+
updated: YYYY-MM-DD
|
|
124
|
+
---
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
字段说明:
|
|
128
|
+
|
|
129
|
+
- `title`:卡组标题。给人看的,可带中文。
|
|
130
|
+
- `language`:卡组答案文本的主要语言(决定 IME 提示、输入法预期)。常用值:`en` / `zh` / `ja` / `mixed`。
|
|
131
|
+
- `tags`:数组或空格分隔字符串。至少一个,用于 `index.md` 的分组。
|
|
132
|
+
- `created` / `updated`:日期。每次卡组内容变化时 bump `updated`。
|
|
133
|
+
|
|
134
|
+
deck 文件头之后**紧接**第一张卡片的 frontmatter(用 `---` 分隔),不写 deck 层的正文说明——注释信息放在 README 或 index。
|
|
135
|
+
|
|
136
|
+
### 卡片 frontmatter
|
|
137
|
+
|
|
138
|
+
每张卡片以自己的一段 frontmatter 开头,字段:
|
|
139
|
+
|
|
140
|
+
| 字段 | 值 | 适用 | 说明 |
|
|
141
|
+
|---|---|---|---|
|
|
142
|
+
| `type` | `normal` \| `word` \| `sentence` | 全部 | 默认 `normal`。 |
|
|
143
|
+
| `tags` | 数组或空格分隔字符串 | 可选 | 卡片级标签,可与 deck 标签重叠。 |
|
|
144
|
+
| `difficulty` | 1..5 整数 | 可选 | 1=极易,5=极难。默认 3。 |
|
|
145
|
+
| `hint` | `none` \| `ghost` | 可选 | 覆盖全局 hint 模式。不写=跟随全局。 |
|
|
146
|
+
| `phonetic` | IPA 字符串,`/…/` 或 `[…]` | 单词卡 | 例 `/əˈbæn.dən/`。 |
|
|
147
|
+
| `gloss` | 简中释义 | 单词卡 | 例 `抛弃, 放弃`。 |
|
|
148
|
+
| `translation` | 目标句子的译文 | 句子卡 | 表意即可,不必逐字对齐。 |
|
|
149
|
+
|
|
150
|
+
规则:
|
|
151
|
+
|
|
152
|
+
- 单词卡**必须**写 `phonetic` 和 `gloss`。
|
|
153
|
+
- 句子卡**必须**写 `translation`。
|
|
154
|
+
- 普通卡可以不写任何可选字段。
|
|
155
|
+
- 未列在上表的字段一律不允许,避免格式漂移。
|
|
156
|
+
|
|
157
|
+
### 卡片结构
|
|
158
|
+
|
|
159
|
+
一张卡片包含 frontmatter、`## Q:` 段、`## A:` 段:
|
|
160
|
+
|
|
161
|
+
```md
|
|
162
|
+
---
|
|
163
|
+
type: word
|
|
164
|
+
phonetic: /əˈbæn.dən/
|
|
165
|
+
gloss: 抛弃, 放弃
|
|
166
|
+
tags: [gre]
|
|
167
|
+
difficulty: 2
|
|
168
|
+
---
|
|
169
|
+
## Q: abandon
|
|
170
|
+
## A: abandon
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
规则:
|
|
174
|
+
|
|
175
|
+
- `## Q:` 段:提示信息。用户练习时会看到。
|
|
176
|
+
- `## A:` 段:**用户实际要敲的文本**。
|
|
177
|
+
- 卡片之间用一行空行 + `---` + 一行空行分隔(即紧接下一张卡片的 frontmatter 起始行)。
|
|
178
|
+
- deck 文件头 frontmatter 关闭的 `---` 之后紧跟第一张卡片的 frontmatter;不允许在两者之间夹正文。
|
|
179
|
+
|
|
180
|
+
**答案文本约束(`## A:` 的内容)**:
|
|
181
|
+
|
|
182
|
+
- 只允许 OS 键盘(含中文 IME)能打出的字符。禁用 emoji、零宽字符、大多数罕见 Unicode。
|
|
183
|
+
- 全角中文标点会被工具自动规范化(弯引号 → 直引号、破折号 → 双连字符等),你按自然汉语标点写即可。
|
|
184
|
+
- 长度**建议**不超过 200 字符——过长影响体验,宁可拆成多张卡片。
|
|
185
|
+
- 允许包含空格、换行(Enter)、Tab。换行在答案文本中用真实换行(Markdown 里空一行会破坏解析,用软换行或不换)。
|
|
186
|
+
|
|
187
|
+
### 卡片示例
|
|
188
|
+
|
|
189
|
+
**单词卡(word)**
|
|
190
|
+
|
|
191
|
+
```md
|
|
192
|
+
---
|
|
193
|
+
type: word
|
|
194
|
+
phonetic: /əˈbæn.dən/
|
|
195
|
+
gloss: 抛弃, 放弃
|
|
196
|
+
tags: [gre]
|
|
197
|
+
difficulty: 2
|
|
198
|
+
---
|
|
199
|
+
## Q: abandon
|
|
200
|
+
## A: abandon
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**句子卡(sentence)**
|
|
204
|
+
|
|
205
|
+
```md
|
|
206
|
+
---
|
|
207
|
+
type: sentence
|
|
208
|
+
translation: 熟能生巧。
|
|
209
|
+
tags: [idiom]
|
|
210
|
+
difficulty: 3
|
|
211
|
+
---
|
|
212
|
+
## Q: Practice makes perfect.
|
|
213
|
+
## A: Practice makes perfect.
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**普通卡(normal)**
|
|
217
|
+
|
|
218
|
+
```md
|
|
219
|
+
---
|
|
220
|
+
type: normal
|
|
221
|
+
tags: [js, closures]
|
|
222
|
+
difficulty: 4
|
|
223
|
+
---
|
|
224
|
+
## Q: 闭包在 JavaScript 中是什么?
|
|
225
|
+
## A: 函数与其词法作用域的组合,允许函数访问定义时的作用域中的变量。
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
普通卡的 A 段是**用户要敲**的答案文本;Q 段是提示。可以让 A 是一段代码片段、一句话、一个短语——但必须满足答案文本约束。
|
|
229
|
+
|
|
230
|
+
### `index.md` 格式
|
|
231
|
+
|
|
232
|
+
`index.md` 在仓库根,按标签分组。每次 ingest / update / quiz-gen 后**必须**同步更新。
|
|
233
|
+
|
|
234
|
+
```md
|
|
235
|
+
---
|
|
236
|
+
updated: YYYY-MM-DD
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
# 索引
|
|
240
|
+
|
|
241
|
+
## <标签 1>
|
|
242
|
+
|
|
243
|
+
| 卡组 | 卡片数 | 语言 | 摘要 | 更新 |
|
|
244
|
+
|---|---|---|---|---|
|
|
245
|
+
| [标题 1](material/<文件 1>.md) | 32 | en | 一行摘要 | YYYY-MM-DD |
|
|
246
|
+
| [标题 2](material/<文件 2>.md) | 25 | zh | 一行摘要 | YYYY-MM-DD |
|
|
247
|
+
|
|
248
|
+
## <标签 2>
|
|
249
|
+
|
|
250
|
+
| 卡组 | 卡片数 | 语言 | 摘要 | 更新 |
|
|
251
|
+
|---|---|---|---|---|
|
|
252
|
+
| [标题 3](material/<文件 3>.md) | 40 | mixed | 一行摘要 | YYYY-MM-DD |
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
规则:
|
|
256
|
+
|
|
257
|
+
- 一个标签一个 `##` 标题。**同一卡组可出现在多个标签**(tags 有多个时全部列出)。
|
|
258
|
+
- 每个标签下**只有一个 markdown 表格**,不加别的内容。
|
|
259
|
+
- 链接路径从仓库根起(`index.md` 就在仓库根)。
|
|
260
|
+
- 摘要最多 60 字,一句话讲清卡组主题。
|
|
261
|
+
- 卡片数以扫描实际卡片数为准。
|
|
262
|
+
|
|
263
|
+
### `log.md` 格式
|
|
264
|
+
|
|
265
|
+
`log.md` 在仓库根,按时间顺序追加(新条目追加在文件末尾),**绝不删除条目**。每次操作**必须**追加一条。
|
|
266
|
+
|
|
267
|
+
```md
|
|
268
|
+
---
|
|
269
|
+
updated: YYYY-MM-DD
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
# 日志
|
|
273
|
+
|
|
274
|
+
## [YYYY-MM-DD] ingest | <源标题或新卡组名>
|
|
275
|
+
- 新建: [卡组 A](material/<A>.md) — N 张卡片
|
|
276
|
+
- 更新: [卡组 B](material/<B>.md) — 追加 M 张
|
|
277
|
+
|
|
278
|
+
## [YYYY-MM-DD] quiz-gen | <主题>
|
|
279
|
+
- 新建: [卡组 C](material/<C>.md) — N 张卡片
|
|
280
|
+
|
|
281
|
+
## [YYYY-MM-DD] update | <卡组名>
|
|
282
|
+
- 追加: N 张
|
|
283
|
+
- 修正: M 张
|
|
284
|
+
|
|
285
|
+
## [YYYY-MM-DD] cascade | <触发卡组>
|
|
286
|
+
- 影响: [卡组 X](material/<X>.md), [卡组 Y](material/<Y>.md)
|
|
287
|
+
|
|
288
|
+
## [YYYY-MM-DD] check | N 条问题,M 条自动修复
|
|
289
|
+
|
|
290
|
+
## [YYYY-MM-DD] level-up | <合并/拆分描述>
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
规则:
|
|
294
|
+
|
|
295
|
+
- 每次 ingest / update / quiz-gen / cascade / check / level-up 都写一条。
|
|
296
|
+
- 标题行格式:`## [YYYY-MM-DD] <op> | <说明>`。
|
|
297
|
+
- 条目**只追加**在文件末尾;不删、不改已有条目。
|
|
298
|
+
- 可以用 `grep "^## \[" log.md` 扫全部条目。
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## 操作
|
|
303
|
+
|
|
304
|
+
### Ingest
|
|
305
|
+
|
|
306
|
+
**把原始材料变成一叠可打的卡片。**
|
|
307
|
+
|
|
308
|
+
触发:用户说 "ingest <path-or-url>"、"从这篇文章出卡片"、"处理这份词表"。
|
|
309
|
+
|
|
310
|
+
**步骤 1:fetch(把源材料落到 raw/)**
|
|
311
|
+
|
|
312
|
+
四种情况:
|
|
313
|
+
|
|
314
|
+
情况 A:输入是 URL
|
|
315
|
+
- 用可用的抓取工具下载并转为 markdown。无工具时让用户直接粘贴。
|
|
316
|
+
- 保存到 `raw/YYYY-MM-DD-<slug>.md`。
|
|
317
|
+
- 写入 frontmatter:`source: <URL>` + `collected: YYYY-MM-DD`。
|
|
318
|
+
|
|
319
|
+
情况 B:输入是本地文件(`ingest /path/to/wordlist.pdf`)
|
|
320
|
+
- 转换为 markdown,复制到 `raw/YYYY-MM-DD-<slug>.md`。
|
|
321
|
+
- 写入 frontmatter:`source: <原路径>` + `collected: YYYY-MM-DD`。
|
|
322
|
+
|
|
323
|
+
情况 C:输入是粘贴文本
|
|
324
|
+
- 保存到 `raw/YYYY-MM-DD-note-<N>.md`。
|
|
325
|
+
- 写入 frontmatter:`source: 粘贴文本` + `collected: YYYY-MM-DD`。
|
|
326
|
+
|
|
327
|
+
情况 D:输入是主题描述("从我的记忆里给我出 20 张 GRE 高频词")
|
|
328
|
+
- **跳过 fetch**,直接进步骤 2(即 quiz-gen 语义,见 Quiz-gen 操作)。
|
|
329
|
+
|
|
330
|
+
**步骤 2:切卡**
|
|
331
|
+
|
|
332
|
+
读源后按材料类型切分:
|
|
333
|
+
|
|
334
|
+
- **词表** → 每个词一张 word 卡。IPA 从材料里抓;材料没给就查权威来源,实在不知道就留空并在 log 里报告。gloss 用简中。
|
|
335
|
+
- **句子/例句集** → 每句一张 sentence 卡。translation 从材料里抓或自然翻译。
|
|
336
|
+
- **文章 / 教程 / 代码片段** → 提炼要点,出 normal 卡。Q 是问题,A 是简短答案。避免答案超过 200 字符——超了拆成多张。
|
|
337
|
+
|
|
338
|
+
**步骤 3:判断卡组归属**
|
|
339
|
+
|
|
340
|
+
- 扫 `material/` 下现有卡组,找主题最贴近的:
|
|
341
|
+
- 已有卡组主题一致且卡片数 < 50 → 追加到已有卡组。
|
|
342
|
+
- 已有卡组主题一致但卡片数 ≥ 50 → 新建同主题的续集卡组(如 `gre-vocab-list-4.md`)。
|
|
343
|
+
- 没有对应卡组 → 新建 `material/<slug>.md`,写 deck 文件头 frontmatter。
|
|
344
|
+
- **一个 deck 只装一个主题**——不允许把 TypeScript 和英语单词混一起。
|
|
345
|
+
|
|
346
|
+
**步骤 4:验证可打性**
|
|
347
|
+
|
|
348
|
+
对每张新卡片的 `## A:`:
|
|
349
|
+
|
|
350
|
+
- 扫描字符,剔除 emoji、零宽、控制字符(除 Tab / Enter 外)。
|
|
351
|
+
- 全角标点交给工具自动规范化——你按自然写法写即可,不必手改。
|
|
352
|
+
- 长度 > 200 字符 → 拆成多张卡片,Q 段各写不同侧面提示。
|
|
353
|
+
- 单词卡的 A 段应等于 Q 段的目标词(练拼写,不是练释义)。
|
|
354
|
+
|
|
355
|
+
**步骤 5:更新 index.md 和 log.md**
|
|
356
|
+
|
|
357
|
+
- index.md:新建卡组加条目;追加卡片的卡组更新 `卡片数` 和 `updated`。见 Index 格式节。
|
|
358
|
+
- log.md:追加一条 ingest 记录。见 Log 格式节。
|
|
359
|
+
|
|
360
|
+
**步骤 6:告知用户**
|
|
361
|
+
|
|
362
|
+
在对话里简短汇报本次 ingest 做了什么(新建/追加/总卡片数),让用户通过 `git diff` 审阅后自行 commit。
|
|
363
|
+
|
|
364
|
+
**Agent 不主动 `git add` / `git commit` / `git push`**。
|
|
365
|
+
|
|
366
|
+
**不做的事**
|
|
367
|
+
|
|
368
|
+
- **不要**"先 preview 再等用户确认"。直接按规则写。
|
|
369
|
+
- **不要**同时 ingest 多个源。一次一个,避免主题判断相互干扰。
|
|
370
|
+
- **不要**在同一卡组里混主题——宁可多建几个卡组。
|
|
371
|
+
|
|
372
|
+
### Update
|
|
373
|
+
|
|
374
|
+
**修正、增补现有卡组。**
|
|
375
|
+
|
|
376
|
+
触发:用户说 "给 `<deck>` 加几张关于 X 的卡片"、"修一下 `<deck>` 里 abandon 那张的 IPA"、"把这几张卡合到 `<deck>`"。
|
|
377
|
+
|
|
378
|
+
**步骤**
|
|
379
|
+
|
|
380
|
+
1. **读目标卡组**:定位到要改的卡片或要追加的位置。
|
|
381
|
+
2. **改动**:
|
|
382
|
+
- **追加**:新卡片按格式规范加到文件末尾(卡片之间用 `---` 分隔)。
|
|
383
|
+
- **修正**:只改指定字段或指定卡片的 Q/A/frontmatter。**不动**没被要求改的卡片。
|
|
384
|
+
- **删除**:明确要求删除时才删;不主动整理。
|
|
385
|
+
3. **验证可打性**:同 Ingest 步骤 4。
|
|
386
|
+
4. **bump deck 文件头 frontmatter 的 `updated`**。
|
|
387
|
+
5. **更新 index.md**:卡片数变了就更新 `卡片数` 和 `updated`。
|
|
388
|
+
6. **追加 log.md**:`## [YYYY-MM-DD] update | <卡组名>` + 追加/修正数量。
|
|
389
|
+
|
|
390
|
+
**不做的事**
|
|
391
|
+
|
|
392
|
+
- **不改**用户手写的卡片——见守则里的 `<!-- hand-edited -->` 标记规则。
|
|
393
|
+
- **不趁机重整**没被要求改的部分。
|
|
394
|
+
- **不整体重写**——除非用户明确说"重写这个卡组"。
|
|
395
|
+
|
|
396
|
+
### Cascade
|
|
397
|
+
|
|
398
|
+
**大改动之后,检查关联卡组。**
|
|
399
|
+
|
|
400
|
+
触发:Ingest 或 Update 涉及**大量卡片**(≥ 10 张)、**改主题范围**(如某卡组从"GRE 词表"变成"GRE + TOEFL 混合")、或**改术语命名**时自动执行。
|
|
401
|
+
|
|
402
|
+
**步骤**
|
|
403
|
+
|
|
404
|
+
1. **扫 index.md**:找出与刚改动的卡组共享 tag 或主题相近的其他卡组。
|
|
405
|
+
2. **逐个检查**:
|
|
406
|
+
- 术语一致性:新卡组用了新术语,旧卡组是否需要跟进(例如新卡组把 `useState` 改叫 `React state hook`,旧卡组要不要统一)。
|
|
407
|
+
- 重复卡片:新卡组的卡片是否和旧卡组重复;重复的从新卡组删(保留旧的)或者反过来(保留质量更好的)。
|
|
408
|
+
- IPA / gloss / translation 冲突:同一个词/句在多个卡组里,字段应一致。
|
|
409
|
+
3. **修正冲突**:优先"以新为准"或"以质量高者为准"。改动**只限**冲突项,不重整。
|
|
410
|
+
4. **每个被改动的卡组 bump `updated`**。
|
|
411
|
+
5. **追加 log.md**:`## [YYYY-MM-DD] cascade | <触发卡组>` + 影响列表。
|
|
412
|
+
|
|
413
|
+
Cascade 在**触发操作结束前**完成,不推后。
|
|
414
|
+
|
|
415
|
+
### Quiz-gen
|
|
416
|
+
|
|
417
|
+
**从主题描述凭空造一叠卡片。**
|
|
418
|
+
|
|
419
|
+
触发:用户说 "quiz-gen JavaScript closures"、"给我出 30 张 GRE 高频词"、"造一叠 React hooks 的题"。
|
|
420
|
+
|
|
421
|
+
**步骤**
|
|
422
|
+
|
|
423
|
+
1. **确认主题和数量**:默认 25 张,用户指定就按用户指定的。
|
|
424
|
+
2. **选卡片类型**:
|
|
425
|
+
- 词汇/单词 → word 卡为主。
|
|
426
|
+
- 语言学习句子 → sentence 卡为主。
|
|
427
|
+
- 编程概念 / 知识点 → normal 卡(Q 是问题,A 是简短答案)。
|
|
428
|
+
3. **按 Ingest 步骤 2-6 走**:切卡 → 判断卡组归属(通常新建卡组)→ 验证可打性 → 更新 index / log。
|
|
429
|
+
4. **log 里用 `quiz-gen` 而不是 `ingest`**,标明来源是"训练记忆"。
|
|
430
|
+
|
|
431
|
+
**规则**
|
|
432
|
+
|
|
433
|
+
- 内容必须准确——不确定的(比如冷门词的 IPA)宁可留空 + 备注,不要瞎编。
|
|
434
|
+
- 一次一个主题、一个卡组。不同主题分多次 quiz-gen。
|
|
435
|
+
|
|
436
|
+
### Check
|
|
437
|
+
|
|
438
|
+
**用户跑 `qtype check` 报错时,Agent 修。**
|
|
439
|
+
|
|
440
|
+
触发:用户跑 `qtype check`(详见 CLI 节),命令报错并把错误列表给 Agent。
|
|
441
|
+
|
|
442
|
+
**Agent 分类处理**:
|
|
443
|
+
|
|
444
|
+
**确定性问题(自动修)**:
|
|
445
|
+
|
|
446
|
+
- **不合法字符**:卡片答案含 emoji / 零宽 / 控制字符 → 删掉该字符或整张卡片(视上下文决定)。
|
|
447
|
+
- **frontmatter 字段错误**:字段名拼错、类型错、缺必填字段 → 修字段。
|
|
448
|
+
- **单词卡缺 phonetic/gloss、句子卡缺 translation** → 补上(补不出来时用 `TODO` 占位并在对话里报告)。
|
|
449
|
+
- **答案 > 200 字符** → 拆成多张卡片,Q 段各写不同侧面提示。
|
|
450
|
+
- **index.md 一致性**:卡组文件存在但 index 里没有 → 加条目;卡组数变了 → 更新 `卡片数`。
|
|
451
|
+
- **内部链接失效**:目标不存在 → 搜 `material/` 下同名文件,唯一匹配则修;否则报告。
|
|
452
|
+
|
|
453
|
+
**启发式问题(只报告)**:
|
|
454
|
+
|
|
455
|
+
- **重复卡片**:不同卡组里出现相同 Q + A 组合。报告,让用户决定合并还是保留。
|
|
456
|
+
- **卡组过大**:卡片数 > 100 → 建议拆分。
|
|
457
|
+
- **卡组过小**:卡片数 < 5 → 建议合并到相近卡组。
|
|
458
|
+
- **孤立卡组**:卡组的 tag 在 index.md 里只被这一个卡组使用。可能是新主题,也可能是分类错。报告。
|
|
459
|
+
|
|
460
|
+
**报告与日志**:给用户输出修复报告,末尾追加 `## [YYYY-MM-DD] check | N 条问题,M 条自动修复`。
|
|
461
|
+
|
|
462
|
+
### Level-up
|
|
463
|
+
|
|
464
|
+
**把散乱小卡组重构成有序的系列。**
|
|
465
|
+
|
|
466
|
+
触发:用户说 "把这几个卡组合起来"、"这个卡组拆成初级/进阶两个"、"把 GRE 词表整理成 list 1/2/3"。
|
|
467
|
+
|
|
468
|
+
**步骤**
|
|
469
|
+
|
|
470
|
+
1. **读涉及的卡组**:全部 frontmatter + 全部卡片。
|
|
471
|
+
2. **决定切分策略**:
|
|
472
|
+
- **合并**:多个小卡组 → 一个大卡组(按主题、按难度、按标签合并)。
|
|
473
|
+
- **拆分**:一个大卡组 → 多个小卡组(按难度分级、按子主题分类)。
|
|
474
|
+
- **重排序**:卡组内顺序调整——例如按 difficulty 升序、按字母序、按学习先后。
|
|
475
|
+
3. **写新的卡组文件**:新文件按 deck 命名规则命名(如 `gre-vocab-list-1.md`)。
|
|
476
|
+
4. **删除或清空旧卡组**:合并后旧文件删除;拆分后旧文件删除。**Agent 用 `rm`**(不主动 `git rm`)。
|
|
477
|
+
5. **更新 index.md 和 log.md**:条目变化、链接更新、追加 `## [YYYY-MM-DD] level-up | <描述>`。
|
|
478
|
+
6. **保留卡片本体**:不改卡片的 Q / A / IPA / gloss / translation——level-up 只重组,不改内容。用户手写的卡片(见守则)原样搬迁。
|
|
479
|
+
|
|
480
|
+
**不做的事**
|
|
481
|
+
|
|
482
|
+
- **不趁机改卡片内容**。level-up 只重组。要改内容用 Update。
|
|
483
|
+
- **不删用户数据**:如果不确定要不要删旧文件,问用户。
|
|
484
|
+
|
|
485
|
+
---
|
|
486
|
+
|
|
487
|
+
## 守则
|
|
488
|
+
|
|
489
|
+
### 禁令
|
|
490
|
+
|
|
491
|
+
以下行为**严格禁止**:
|
|
492
|
+
|
|
493
|
+
1. **不改 raw/ 内容**:raw 下文件默认只读。除移动、重命名、删除外,改正文都要等用户明确要求。
|
|
494
|
+
2. **不写不可打字符**:卡片答案里 emoji / 零宽字符 / 控制字符(除 Tab、Enter 外)一律禁止。不确定的字符宁可换成 ASCII 或不写。
|
|
495
|
+
3. **不写太长的答案**:`## A:` 建议 ≤ 200 字符。长了拆卡片,别让用户敲十分钟。
|
|
496
|
+
4. **不混主题**:一个 deck 只装一个主题——TypeScript 和英语单词不能塞一个文件。宁可多建几个 deck。
|
|
497
|
+
5. **不改用户手写卡片**:卡片正文含 `<!-- hand-edited -->` HTML 注释的,Agent 只能读、不能改。要改必须先问用户。cascade 遇到这种卡片时跳过。
|
|
498
|
+
6. **不用 Wikilink**:`[[foo]]` 语法禁用,只用 `[文本](./路径.md)`。
|
|
499
|
+
7. **不绝对路径**:所有链接必须相对路径,以 `./` 或 `../` 开头。
|
|
500
|
+
8. **不主动 git commit / push**:所有 commit 由用户决定。
|
|
501
|
+
9. **不建规则外的目录**:`material/` 下只允许平铺的 `.md` 文件和 `assets/` 子目录;`raw/` 下只允许平铺的 `.md` 和 `assets/` 子目录。其他结构(如 `material/words/`、`material/2026/`)都禁止。
|
|
502
|
+
10. **不凭空造 IPA / 释义 / 翻译**:不确定的字段宁可空着并在 log 里报告,不要编。
|
|
503
|
+
|
|
504
|
+
### 内容语言
|
|
505
|
+
|
|
506
|
+
- 卡组的 `title`、`index.md` 摘要、`log.md` 条目:**中文为主,专业术语保留原文**。
|
|
507
|
+
- 单词卡的 `gloss`:**简中**。
|
|
508
|
+
- 句子卡的 `translation`:翻译到用户的母语(默认简中)。表意即可,不必逐字对齐。
|
|
509
|
+
- 卡片的 `## A:` 答案文本本身:**由目标语言决定**,保留材料原样(英语词就是英语,日语句就是日语)。
|
|
510
|
+
|
|
511
|
+
### 卡片数量指导
|
|
512
|
+
|
|
513
|
+
- **一个卡组 20–50 张**是甜蜜区。
|
|
514
|
+
- < 5 张:太薄,考虑合并(Level-up)。
|
|
515
|
+
- \> 100 张:太厚,考虑拆分(Level-up)。
|
|
516
|
+
- 一次 Ingest / Quiz-gen 生成的卡组通常 25 张左右——写多了反而质量下降。
|
|
517
|
+
|
|
518
|
+
### 难度分级
|
|
519
|
+
|
|
520
|
+
`difficulty` 字段的语义(默认 3):
|
|
521
|
+
|
|
522
|
+
| 值 | 含义 |
|
|
523
|
+
|---|---|
|
|
524
|
+
| 1 | 极易识别,无需思考(如常见词、常识事实) |
|
|
525
|
+
| 2 | 一眼可读,无需回忆(如常用短语、基础语法) |
|
|
526
|
+
| 3 | 需要短暂回忆(默认,多数卡片) |
|
|
527
|
+
| 4 | 需要认真思考或较长答案(如概念解释、句子造句) |
|
|
528
|
+
| 5 | 高难度,长答案或复杂概念(如小段代码、长句默写) |
|
|
529
|
+
|
|
530
|
+
### 快速参考
|
|
531
|
+
|
|
532
|
+
**Ingest 一个源**:
|
|
533
|
+
|
|
534
|
+
```
|
|
535
|
+
raw/YYYY-MM-DD-<slug>.md ← 写源(平铺,可选)
|
|
536
|
+
material/<slug>.md ← 写或追加卡组
|
|
537
|
+
index.md ← 更新表格(卡片数 / updated)
|
|
538
|
+
log.md ← 追加 ## [日期] ingest | 标题
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
**Update 一个卡组**:
|
|
542
|
+
|
|
543
|
+
```
|
|
544
|
+
material/<slug>.md ← 追加/修正卡片,bump updated
|
|
545
|
+
index.md ← 更新卡片数和 updated
|
|
546
|
+
log.md ← 追加 ## [日期] update | 卡组名
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
**Quiz-gen 从主题**:
|
|
550
|
+
|
|
551
|
+
```
|
|
552
|
+
material/<slug>.md ← 新建卡组
|
|
553
|
+
index.md ← 加条目
|
|
554
|
+
log.md ← 追加 ## [日期] quiz-gen | 主题
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
**Check 用户报错时**:
|
|
558
|
+
|
|
559
|
+
```
|
|
560
|
+
按错误列表分类修
|
|
561
|
+
自动修:字符 / frontmatter / 长度 / index 一致性
|
|
562
|
+
只报告:重复卡片 / 过大过小 / 孤立卡组
|
|
563
|
+
log.md ← 追加 ## [日期] check | N 条问题
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
**Level-up 重构**:
|
|
567
|
+
|
|
568
|
+
```
|
|
569
|
+
读旧卡组 → 决策合并/拆分/重排
|
|
570
|
+
写新 material/*.md
|
|
571
|
+
rm 旧文件
|
|
572
|
+
index.md ← 条目增减
|
|
573
|
+
log.md ← 追加 ## [日期] level-up | 描述
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
---
|
|
577
|
+
|
|
578
|
+
## 给用户的 CLI 命令(不是给你的)
|
|
579
|
+
|
|
580
|
+
以下命令由**用户**在终端运行,你写内容时不要尝试调用,但要知道它们存在——用户报错时你需要能识别。
|
|
581
|
+
|
|
582
|
+
| 命令 | 作用 |
|
|
583
|
+
|---|---|
|
|
584
|
+
| `qtype check` | 校验仓库:扫**不可打字符**、**frontmatter 缺失/错**、**答案过长**、**index 不一致**(致命)+ 重复卡片 / 过大过小卡组(警告)。**不写任何文件**。 |
|
|
585
|
+
| `qtype publish build` | 把仓库构建成静态站到 `dist/`。 |
|
|
586
|
+
| `qtype publish serve` | 本地起服务,用浏览器进入练习界面。支持中文 IME、目标 WPM 光标、blind / ghost 提示模式。 |
|
|
587
|
+
| `qtype publish init --ci github` | 生成 GitHub Actions workflow。 |
|
|
588
|
+
|
|
589
|
+
**注意**:
|
|
590
|
+
|
|
591
|
+
- 你在 ingest / update / quiz-gen 后**不需要**主动跑这些命令;用户 commit 时 CI 会跑。
|
|
592
|
+
- 用户报 "check 说 XXX 卡片有非法字符",定位到卡片并按 Check 操作节修。
|
|
593
|
+
- 用户报 "publish serve 里练不了这张卡" — 通常是 A 段含不可打字符或者长度超限——按 Check 修。
|
|
594
|
+
|
|
595
|
+
---
|
|
596
|
+
|
|
597
|
+
## 发布产物(仅作背景知识)
|
|
598
|
+
|
|
599
|
+
`qtype publish build` 输出大致:
|
|
600
|
+
|
|
601
|
+
```
|
|
602
|
+
dist/
|
|
603
|
+
├── index.html ← SPA shell
|
|
604
|
+
├── material/<slug>.html ← 每卡组一个 shell(<noscript> 内嵌纯 HTML 兜底)
|
|
605
|
+
├── _app/ ← view bundle
|
|
606
|
+
│ └── app.js + chunks/...
|
|
607
|
+
└── _data/
|
|
608
|
+
└── repo.json ← 单一数据快照(卡组 / 卡片 / 元数据)
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
Web UI 支持:中文 IME 输入(提交后与目标 diff)、三种卡片类型(`type: normal | word | sentence`)、目标速度光标、blind / ghost 提示、全角标点自动规范化、空格 / Enter / Tab 字符输入。
|
|
612
|
+
|
|
613
|
+
**致命错误**:build 在以下情况会直接 throw 中止:
|
|
614
|
+
|
|
615
|
+
- 任一卡片答案含不可打字符
|
|
616
|
+
- 任一卡片 frontmatter 缺必填字段或字段类型错
|
|
617
|
+
- deck 文件头 frontmatter 缺 `title` / `language` / `tags`
|
|
618
|
+
- 单词卡缺 `phonetic` / `gloss`,句子卡缺 `translation`
|