@fenglimg/fabric-cli 2.0.0-rc.10 → 2.0.0-rc.11
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/dist/{chunk-MT3R57VG.js → chunk-5MQ52F42.js} +1 -0
- package/dist/index.js +3 -3
- package/dist/{init-SAVH4SKE.js → init-C56PWHID.js} +46 -9
- package/dist/{scan-ELSNCSKS.js → scan-66EKMNAY.js} +3 -1
- package/package.json +3 -3
- package/templates/skills/fabric-archive/SKILL.md +184 -30
- package/templates/skills/fabric-import/SKILL.md +319 -29
- package/templates/skills/fabric-review/SKILL.md +358 -23
|
@@ -10,11 +10,16 @@ allowed-tools: Read, Glob, Grep, Bash, Edit, mcp__fabric__fab_review
|
|
|
10
10
|
|
|
11
11
|
This skill is invoked when one of the following holds:
|
|
12
12
|
|
|
13
|
-
- The Stop-hook printed a stdout JSON pointer of shape `{"decision":"block","reason":"..."}` carrying a `signal=review` (pending overflow: ≥10
|
|
13
|
+
- The Stop-hook printed a stdout JSON pointer of shape `{"decision":"block","reason":"..."}` carrying a `signal=review` (pending overflow: pending count ≥ `review_hint_pending_count` (config-resolved, default 10) OR oldest pending age ≥ `review_hint_pending_age_days` (config-resolved, default 7) days)
|
|
14
14
|
- The user typed an explicit review request (e.g. "review knowledge", "show pending", "approve what's queued", "what's stale", "look at KT-D-7")
|
|
15
15
|
- A task end where the agent itself判定 review backlog has crossed the overflow threshold
|
|
16
16
|
|
|
17
|
-
If none of the above hold, stop the skill immediately and tell the user
|
|
17
|
+
If none of the above hold, stop the skill immediately and tell the user (UX i18n Policy class 2 — errors/preconditions):
|
|
18
|
+
|
|
19
|
+
- zh-CN: `没有触发 review 信号;如需手动 review 请显式调用 fabric-review`
|
|
20
|
+
- en: `No review signal detected; to manually review, explicitly invoke fabric-review`
|
|
21
|
+
|
|
22
|
+
(Render per `knowledge_language` resolved in Config Load below.)
|
|
18
23
|
|
|
19
24
|
This skill is `Infer-not-Ask` for mode and `Ask-when-genuine` for per-item actions:
|
|
20
25
|
|
|
@@ -29,6 +34,122 @@ Required preconditions before any fab_review call:
|
|
|
29
34
|
- `.fabric/agents.meta.json` is present (the id allocator reads it on approve)
|
|
30
35
|
- `.fabric/events.jsonl` exists (tolerate ENOENT — empty ledger is normal first-run)
|
|
31
36
|
|
|
37
|
+
### Config Load
|
|
38
|
+
|
|
39
|
+
Before any mode inference work, the skill MUST read
|
|
40
|
+
`.fabric/fabric-config.json` to resolve the following tunables (with documented
|
|
41
|
+
defaults if absent):
|
|
42
|
+
|
|
43
|
+
| Config field | Default | Used by |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| `review_topic_result_cap` | 8 | topic mode top-N rendering cap |
|
|
46
|
+
| `review_stale_pending_days` | 14 | health mode stale-pending detection threshold (days) |
|
|
47
|
+
| `review_hint_pending_count` | 10 | precondition overflow signal (pending-count branch) |
|
|
48
|
+
| `review_hint_pending_age_days` | 7 | precondition overflow signal (oldest-pending-age branch) |
|
|
49
|
+
|
|
50
|
+
If `.fabric/fabric-config.json` is missing or unreadable, use defaults silently.
|
|
51
|
+
|
|
52
|
+
### UX i18n Policy (5-class bilingualization)
|
|
53
|
+
|
|
54
|
+
The skill consults `knowledge_language` from `.fabric/fabric-config.json`
|
|
55
|
+
(固化于 init 时,via `scan.ts:detectExistingLanguage`; default `"en"` when no
|
|
56
|
+
CJK signal is detected in README + docs/). All user-facing text in the
|
|
57
|
+
following 5 categories MUST be rendered in the resolved language:
|
|
58
|
+
|
|
59
|
+
1. **Roll-up templates** — the `# Review Summary — mode={...}` final block,
|
|
60
|
+
the `## Health Overview` dashboard in health mode, and any per-item
|
|
61
|
+
display blocks (`## [type=...] [layer=...] pending_path=...` lines).
|
|
62
|
+
zh-CN ↔ en mirror.
|
|
63
|
+
2. **Errors / Preconditions warnings** — abort + trigger-miss messages
|
|
64
|
+
(e.g. "没有触发 review 信号…" / "No review signal detected…").
|
|
65
|
+
zh-CN ↔ en mirror.
|
|
66
|
+
3. **Confirmation prompts** — free-text reject-reason follow-up, the
|
|
67
|
+
"Type relevance_paths (comma-separated globs, …)" narrow-scope
|
|
68
|
+
follow-up, and any other free-text prompts. zh-CN ↔ en mirror.
|
|
69
|
+
4. **Dry-run table headers** — fabric-review does not currently expose
|
|
70
|
+
a dry-run mode; this slot is reserved for parity with fabric-import.
|
|
71
|
+
IF a future revision adds dry-run, the table header MUST be
|
|
72
|
+
bilingualized per this policy. zh-CN ↔ en mirror.
|
|
73
|
+
5. **AskUserQuestion** — `header` + `question` fields (NOT `options[]`).
|
|
74
|
+
zh-CN ↔ en mirror. fabric-review is the heaviest AskUserQuestion
|
|
75
|
+
consumer (per-item action, layer-flip target, stale-item action,
|
|
76
|
+
modify-extended option set), so this class applies broadly.
|
|
77
|
+
|
|
78
|
+
Rendering rule:
|
|
79
|
+
|
|
80
|
+
- `knowledge_language === "zh-CN"` → emit the zh-CN variant.
|
|
81
|
+
- `knowledge_language === "en"` (or any other value) → emit the en variant.
|
|
82
|
+
- The Skill MUST NOT mix languages inside a single user-facing block
|
|
83
|
+
(no "Chinglish" partial translation); each block is either fully zh-CN
|
|
84
|
+
or fully en.
|
|
85
|
+
|
|
86
|
+
Protected tokens (`fab_review`, `relevance_scope`, `relevance_paths`,
|
|
87
|
+
`narrow`, `broad`, `source_sessions`, `proposed_reason`, `session_context`,
|
|
88
|
+
`pending_path`, `layer`, `team`, `personal`, `knowledge_scope_degraded`,
|
|
89
|
+
`MUST`, `NEVER`, `.fabric/knowledge/`, etc.) are NEVER translated — they
|
|
90
|
+
appear verbatim in both language variants. The bilingualization scope is
|
|
91
|
+
prose ONLY.
|
|
92
|
+
|
|
93
|
+
### AskUserQuestion i18n Policy (value vs label)
|
|
94
|
+
|
|
95
|
+
When this skill issues an `AskUserQuestion`, the `header` and `question`
|
|
96
|
+
strings are user-facing prose → translated per `knowledge_language`. The
|
|
97
|
+
`options[]` array entries are **routing keys** consumed by the skill
|
|
98
|
+
state machine — they MUST remain English regardless of `knowledge_language`.
|
|
99
|
+
|
|
100
|
+
Canonical options arrays used by this skill (every value below stays
|
|
101
|
+
English in BOTH language variants):
|
|
102
|
+
|
|
103
|
+
- Per-item action: `["approve", "reject", "modify", "defer", "skip"]`
|
|
104
|
+
- Per-stale-item action (health mode): `["defer", "demote", "skip"]`
|
|
105
|
+
- Layer-flip target: `["team", "personal"]`
|
|
106
|
+
- Modify-extended (import-origin narrow-scope nudge):
|
|
107
|
+
`["narrow scope", "edit summary", "change layer", "change maturity", "skip"]`
|
|
108
|
+
|
|
109
|
+
Worked example — per-item action (the most common AskUserQuestion in this skill):
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
// EN (knowledge_language === "en")
|
|
113
|
+
AskUserQuestion({
|
|
114
|
+
header: "Review pending entry",
|
|
115
|
+
question: "What action for '{title}'? ({pending_path})",
|
|
116
|
+
options: ["approve", "reject", "modify", "defer", "skip"]
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
// zh-CN (knowledge_language === "zh-CN")
|
|
120
|
+
AskUserQuestion({
|
|
121
|
+
header: "审核 pending 条目",
|
|
122
|
+
question: "对 '{title}' 执行什么操作?({pending_path})",
|
|
123
|
+
options: ["approve", "reject", "modify", "defer", "skip"] // 不翻译 — routing key
|
|
124
|
+
})
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Worked example — layer-flip target:
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
// EN
|
|
131
|
+
AskUserQuestion({
|
|
132
|
+
header: "Layer-flip target",
|
|
133
|
+
question: "Move '{title}' to which layer? (current: {current_layer})",
|
|
134
|
+
options: ["team", "personal"]
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
// zh-CN
|
|
138
|
+
AskUserQuestion({
|
|
139
|
+
header: "Layer 切换目标",
|
|
140
|
+
question: "将 '{title}' 切换到哪一层?(当前: {current_layer})",
|
|
141
|
+
options: ["team", "personal"] // 不翻译 — routing key
|
|
142
|
+
})
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Rationale: localizing routing keys would force every routing branch to
|
|
146
|
+
dual-string match (e.g. `if (choice === "approve" || choice === "通过")`),
|
|
147
|
+
which doubles the surface area for protected-token regressions and breaks
|
|
148
|
+
the option-list invariants that downstream tooling (the Skill's own
|
|
149
|
+
`switch` statements over `choice`, plus any future MCP-level audit lint
|
|
150
|
+
that scans for these specific string literals) depends on. Keeping
|
|
151
|
+
`options[]` English-only is contract-locked across all three skills.
|
|
152
|
+
|
|
32
153
|
## Mode Inference (System Infers — NEVER Ask)
|
|
33
154
|
|
|
34
155
|
> Verbatim from rc.3 locked decisions:
|
|
@@ -58,7 +179,7 @@ If exactly one row matches, lock that mode and skip to Step 3.
|
|
|
58
179
|
|
|
59
180
|
**Step 3 — Pending count default.** If Step 1 and Step 2 both produced no signal, glob `.fabric/knowledge/pending/**/*.md`:
|
|
60
181
|
|
|
61
|
-
- If pending count
|
|
182
|
+
- If pending count ≥ `review_hint_pending_count` (config-resolved, default 10) OR oldest pending file mtime is older than `review_hint_pending_age_days` (config-resolved, default 7) days → infer `pending` (overflow signal — same threshold the Stop-hook uses).
|
|
62
183
|
- Otherwise → default to `pending` (most common review entry point).
|
|
63
184
|
|
|
64
185
|
### Inference Examples (Sample User Messages → Expected Mode)
|
|
@@ -85,33 +206,62 @@ Each mode produces user-facing output, then routes per-item or per-batch decisio
|
|
|
85
206
|
4. For each pending item, render a per-item block. v2.0.0-rc.7 T6: render
|
|
86
207
|
`proposed_reason` (frontmatter) + `## Why proposed` line (body, 1-line enum
|
|
87
208
|
explanation) + first line of `## Session context` so future-self has full
|
|
88
|
-
context without re-reading the transcript
|
|
209
|
+
context without re-reading the transcript. UX i18n Policy class 1 — roll-up
|
|
210
|
+
templates; protected tokens (`pending_path`, `layer`, `team`, `decisions`,
|
|
211
|
+
`proposed_reason`, `Tags`, etc.) appear verbatim in BOTH variants:
|
|
212
|
+
|
|
213
|
+
en variant (`knowledge_language === "en"`):
|
|
89
214
|
|
|
90
215
|
```md
|
|
91
216
|
## [type=decisions] [layer=team] pending_path=knowledge/pending/decisions/single-cjs-hook.md
|
|
92
|
-
Title:
|
|
93
|
-
Summary:
|
|
217
|
+
Title: Single .cjs hook across clients
|
|
218
|
+
Summary: stdout JSON shape is identical across the three clients; one script suffices.
|
|
94
219
|
Maturity: draft Tags: [hook, cli]
|
|
220
|
+
Proposed reason: decision-confirmation — ≥2 alternatives weighed; rationale stated.
|
|
221
|
+
Session context: Session goal: ship Stop-hook for v2 release.
|
|
222
|
+
⚠ Possible duplicate of KT-D-0007 (LLM subjective dup/subsumption judgement; thresholds intentionally not quantified)
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
zh-CN variant (`knowledge_language === "zh-CN"`):
|
|
226
|
+
|
|
227
|
+
```md
|
|
228
|
+
## [type=decisions] [layer=team] pending_path=knowledge/pending/decisions/single-cjs-hook.md
|
|
229
|
+
标题: 单 .cjs hook 跨客户端
|
|
230
|
+
摘要: 三客户端 stdout JSON 格式一致,单脚本即可。
|
|
231
|
+
成熟度: draft Tags: [hook, cli]
|
|
95
232
|
Proposed reason: decision-confirmation — ≥2 候选方案经权衡后确认选型。
|
|
96
233
|
Session context: Session goal: ship Stop-hook for v2 release.
|
|
97
|
-
⚠
|
|
234
|
+
⚠ 可能重复 KT-D-0007 (LLM 主观判断 dup/subsumption;具体阈值不可量化)
|
|
98
235
|
```
|
|
99
236
|
|
|
100
237
|
The Skill MUST read `proposed_reason` from the pending file's frontmatter
|
|
101
238
|
(parse the YAML block, key `proposed_reason`) and the `## Why proposed`
|
|
102
239
|
line / first non-blank line of `## Session context` from the body. If
|
|
103
|
-
either is missing on a pre-rc.7 pending entry, render
|
|
104
|
-
|
|
105
|
-
|
|
240
|
+
either is missing on a pre-rc.7 pending entry, render the legacy fallback
|
|
241
|
+
(UX i18n Policy class 1):
|
|
242
|
+
|
|
243
|
+
- en: `Proposed reason: <legacy entry, no reason recorded>` and `Session context: <not recorded>`
|
|
244
|
+
- zh-CN: `Proposed reason: <历史条目,未记录 reason>` 与 `Session context: <未记录>`
|
|
106
245
|
|
|
107
|
-
|
|
246
|
+
…so the reviewer can still proceed.
|
|
247
|
+
|
|
248
|
+
5. Surface a per-item AskUserQuestion. UX i18n Policy class 5 — `header` +
|
|
249
|
+
`question` translated; `options[]` array remain English routing keys:
|
|
108
250
|
|
|
109
251
|
```ts
|
|
252
|
+
// EN
|
|
110
253
|
AskUserQuestion({
|
|
111
254
|
header: "Review pending entry",
|
|
112
|
-
question: "What action for '
|
|
255
|
+
question: "What action for 'Single .cjs hook across clients'?",
|
|
113
256
|
options: ["approve", "reject", "modify", "defer", "skip"]
|
|
114
257
|
})
|
|
258
|
+
|
|
259
|
+
// zh-CN
|
|
260
|
+
AskUserQuestion({
|
|
261
|
+
header: "审核 pending 条目",
|
|
262
|
+
question: "对 '单 .cjs hook 跨客户端' 执行什么操作?",
|
|
263
|
+
options: ["approve", "reject", "modify", "defer", "skip"] // 不翻译
|
|
264
|
+
})
|
|
115
265
|
```
|
|
116
266
|
|
|
117
267
|
6. Route the user's choice:
|
|
@@ -127,7 +277,7 @@ Each mode produces user-facing output, then routes per-item or per-batch decisio
|
|
|
127
277
|
1. Extract the topic keyword(s) from the user's message (e.g. "find about deepMerge" → query="deepMerge").
|
|
128
278
|
2. Call `fab_review action="search"` with `query` and any obvious filters (if user said "team-only" → `filters.layer="team"`).
|
|
129
279
|
3. Server returns `items[]` ranked by relevance — these are entries already in `.fabric/knowledge/{layer}/{type}/` (NOT pending), unless `filters` says otherwise.
|
|
130
|
-
4. Render top-N (cap at 8) results with title / summary / pending_path.
|
|
280
|
+
4. Render top-N (cap at `review_topic_result_cap`, config-resolved, default 8) results with title / summary / pending_path.
|
|
131
281
|
5. If the user follow-up indicates intent to act ("approve all", "modify the second one"), pivot into the corresponding pending mode action — the search result already gives the `pending_path` needed for the action.
|
|
132
282
|
6. NEVER surface a per-item AskUserQuestion just for browsing — only when the user signals an action verb.
|
|
133
283
|
|
|
@@ -135,8 +285,10 @@ Each mode produces user-facing output, then routes per-item or per-batch decisio
|
|
|
135
285
|
|
|
136
286
|
1. Call `fab_review action="list"` with `filters.maturity="draft"` (or no filter for full corpus inspection).
|
|
137
287
|
2. Tail `.fabric/events.jsonl` for layer_changed / demoted / rejected counts in the trailing 30 days.
|
|
138
|
-
3. Compute stale candidates: pending entries with mtime
|
|
139
|
-
4. Render a corpus dashboard
|
|
288
|
+
3. Compute stale candidates: pending entries with mtime older than `review_stale_pending_days` (config-resolved, default 14) OR maturity=draft entries with no recent evidence-append events.
|
|
289
|
+
4. Render a corpus dashboard. UX i18n Policy class 1 — roll-up templates; render per `knowledge_language`:
|
|
290
|
+
|
|
291
|
+
en variant:
|
|
140
292
|
|
|
141
293
|
```md
|
|
142
294
|
## Health Overview
|
|
@@ -146,7 +298,35 @@ Each mode produces user-facing output, then routes per-item or per-batch decisio
|
|
|
146
298
|
- Rejections (30d): 1
|
|
147
299
|
```
|
|
148
300
|
|
|
149
|
-
|
|
301
|
+
zh-CN variant:
|
|
302
|
+
|
|
303
|
+
```md
|
|
304
|
+
## 健康度总览
|
|
305
|
+
- Pending: 12 条 (最旧 18 天) — 建议 `defer` 或 `reject`
|
|
306
|
+
- Drafts: 8 条 (3 条为陈旧候选: KP-G-3, KP-G-5, KT-P-9)
|
|
307
|
+
- Layer 切换 (30 天): 2
|
|
308
|
+
- 已驳回 (30 天): 1
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
5. For each stale candidate, surface AskUserQuestion. UX i18n Policy class 5 — `header` + `question` translated; `options[]` remain English routing keys:
|
|
312
|
+
|
|
313
|
+
```ts
|
|
314
|
+
// EN
|
|
315
|
+
AskUserQuestion({
|
|
316
|
+
header: "Stale entry triage",
|
|
317
|
+
question: "Action for stale entry '{title}'?",
|
|
318
|
+
options: ["defer", "demote", "skip"]
|
|
319
|
+
})
|
|
320
|
+
|
|
321
|
+
// zh-CN
|
|
322
|
+
AskUserQuestion({
|
|
323
|
+
header: "陈旧条目处理",
|
|
324
|
+
question: "对陈旧条目 '{title}' 执行什么操作?",
|
|
325
|
+
options: ["defer", "demote", "skip"] // 不翻译
|
|
326
|
+
})
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Route `defer` → `fab_review action="defer"`, `demote` → `fab_review action="modify"` with `changes.maturity` lowered (or `reject` if the user wants outright removal of a pending entry).
|
|
150
330
|
|
|
151
331
|
### Mode: revisit — Specific Entry Deep Dive
|
|
152
332
|
|
|
@@ -164,9 +344,9 @@ Semantic check is the LLM's job — the MCP tool does NOT compare meaning. Run t
|
|
|
164
344
|
For each pending entry to be presented:
|
|
165
345
|
|
|
166
346
|
1. Call `fab_review action="search"` with `query=<title or summary keywords>` and `filters.type=<same type>` to fetch already-canonical entries of the same type.
|
|
167
|
-
2. Compare semantically (LLM judgment, not string match)
|
|
168
|
-
- **Duplicate** — same essential claim.
|
|
169
|
-
- **Contradiction** — opposing claims about the same subject.
|
|
347
|
+
2. Compare semantically (LLM judgment, not string match). 三类判断均为 LLM 主观判断 dup/subsumption;具体阈值不可量化(不使用百分比 / 相似度数值伪精度):
|
|
348
|
+
- **Duplicate** — same essential claim. 标题与摘要表达同一核心结论,pending 未提供新证据或新上下文。Flag: `⚠ Possible duplicate of <stable_id>`.
|
|
349
|
+
- **Contradiction** — opposing claims about the same subject. 例:一个 entry 说 "use X",pending 说 "avoid X",且作用域一致。Flag: `⚠ Contradicts <stable_id>`.
|
|
170
350
|
- **Subsumption** — pending fully covered by an existing entry plus extras. Flag: `⚠ Subsumed by <stable_id>; consider modify-to-merge`.
|
|
171
351
|
3. Surface the flag in the per-item display block (see pending mode step 4).
|
|
172
352
|
4. The user decides:
|
|
@@ -176,6 +356,63 @@ For each pending entry to be presented:
|
|
|
176
356
|
|
|
177
357
|
DO NOT call `AskUserQuestion` to ask "is this a duplicate?" — the LLM has already judged. The user only chooses among approve / reject / modify, which is a genuine choice.
|
|
178
358
|
|
|
359
|
+
## Narrowing Imported Entries
|
|
360
|
+
|
|
361
|
+
The fabric-import skill creates pending entries with `relevance_scope=broad`
|
|
362
|
+
+ `relevance_paths=[]` as a deliberate contract — it cannot derive paths from
|
|
363
|
+
git history. **Narrowing imported entries is fabric-review's responsibility.**
|
|
364
|
+
|
|
365
|
+
### Detection
|
|
366
|
+
|
|
367
|
+
An entry is "import-origin" when `source_sessions[0]` starts with
|
|
368
|
+
`fabric-import-` (e.g. `fabric-import-2026-05-10`).
|
|
369
|
+
|
|
370
|
+
### Pending mode rendering
|
|
371
|
+
|
|
372
|
+
For each import-origin entry, prepend one warning line to the display block. UX i18n Policy class 1 — roll-up templates; the protected tokens `relevance_scope`, `relevance_paths`, `broad` appear verbatim in BOTH variants:
|
|
373
|
+
|
|
374
|
+
- en: `⚠ Imported (relevance_scope=broad, relevance_paths=[]) — pick 'modify' + say 'narrow to <paths>' to bind scope.`
|
|
375
|
+
- zh-CN: `⚠ Imported (relevance_scope=broad, relevance_paths=[]) — 选择 'modify' 并指定 'narrow to <paths>' 以收紧作用域。`
|
|
376
|
+
|
|
377
|
+
This hint is informational. The user MAY ignore it; broad+[] is a valid
|
|
378
|
+
final state for cross-cutting knowledge.
|
|
379
|
+
|
|
380
|
+
### Modify follow-up — narrow scope
|
|
381
|
+
|
|
382
|
+
When the user picks `modify` on an import-origin entry, surface
|
|
383
|
+
AskUserQuestion with an extended option list. UX i18n Policy class 5 — `header` + `question` translated; `options[]` remain English routing keys:
|
|
384
|
+
|
|
385
|
+
```ts
|
|
386
|
+
// EN
|
|
387
|
+
AskUserQuestion({
|
|
388
|
+
header: "Modify imported entry",
|
|
389
|
+
question: "What aspect of '{title}' to modify?",
|
|
390
|
+
options: ["narrow scope", "edit summary", "change layer", "change maturity", "skip"]
|
|
391
|
+
})
|
|
392
|
+
|
|
393
|
+
// zh-CN
|
|
394
|
+
AskUserQuestion({
|
|
395
|
+
header: "修改 imported 条目",
|
|
396
|
+
question: "要修改 '{title}' 的哪一项?",
|
|
397
|
+
options: ["narrow scope", "edit summary", "change layer", "change maturity", "skip"] // 不翻译
|
|
398
|
+
})
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
When user picks "narrow scope":
|
|
402
|
+
1. Free-text follow-up. UX i18n Policy class 3 — confirmation prompts:
|
|
403
|
+
- en: `Type relevance_paths (comma-separated globs, e.g. packages/server/src/retry/**, packages/server/src/lib/retry.ts)`
|
|
404
|
+
- zh-CN: `请输入 relevance_paths (逗号分隔的 glob,例如 packages/server/src/retry/**, packages/server/src/lib/retry.ts)`
|
|
405
|
+
2. Call fab_review action="modify" with:
|
|
406
|
+
changes: { relevance_scope: "narrow", relevance_paths: [<parsed paths>] }
|
|
407
|
+
3. Display the resolved frontmatter to confirm.
|
|
408
|
+
|
|
409
|
+
### Special cases
|
|
410
|
+
|
|
411
|
+
- Layer=personal entries: server auto-degrades narrow → broad+[]; surface
|
|
412
|
+
the `knowledge_scope_degraded` event back to the user.
|
|
413
|
+
- Non-import-origin entries: modify can still narrow (just doesn't show
|
|
414
|
+
this UX nudge — user types it as a normal modify).
|
|
415
|
+
|
|
179
416
|
## Modify Sub-Flow & Layer-Flip Rules
|
|
180
417
|
|
|
181
418
|
`modify` is the only action that mutates frontmatter or stable_id. It accepts `changes` of shape `{title?, summary?, layer?, maturity?, tags?}`. Server semantics:
|
|
@@ -234,6 +471,10 @@ mcp__fabric__fab_review({
|
|
|
234
471
|
|
|
235
472
|
### Per-Item Question Phrasing Template
|
|
236
473
|
|
|
474
|
+
UX i18n Policy class 5 — `header` + `question` translated per `knowledge_language`; `options[]` arrays remain English routing keys in BOTH variants. Choose the variant matching the resolved language; the structure (field names, options) is identical.
|
|
475
|
+
|
|
476
|
+
en variant:
|
|
477
|
+
|
|
237
478
|
```ts
|
|
238
479
|
AskUserQuestion({
|
|
239
480
|
header: "Review pending entry",
|
|
@@ -242,7 +483,19 @@ AskUserQuestion({
|
|
|
242
483
|
})
|
|
243
484
|
```
|
|
244
485
|
|
|
245
|
-
|
|
486
|
+
zh-CN variant:
|
|
487
|
+
|
|
488
|
+
```ts
|
|
489
|
+
AskUserQuestion({
|
|
490
|
+
header: "审核 pending 条目",
|
|
491
|
+
question: "对 '{title}' 执行什么操作?({pending_path})",
|
|
492
|
+
options: ["approve", "reject", "modify", "defer", "skip"] // 不翻译 — routing key
|
|
493
|
+
})
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
For layer-flip target.
|
|
497
|
+
|
|
498
|
+
en variant:
|
|
246
499
|
|
|
247
500
|
```ts
|
|
248
501
|
AskUserQuestion({
|
|
@@ -252,6 +505,16 @@ AskUserQuestion({
|
|
|
252
505
|
})
|
|
253
506
|
```
|
|
254
507
|
|
|
508
|
+
zh-CN variant:
|
|
509
|
+
|
|
510
|
+
```ts
|
|
511
|
+
AskUserQuestion({
|
|
512
|
+
header: "Layer 切换目标",
|
|
513
|
+
question: "将 '{title}' 切换到哪一层?(当前: {current_layer})",
|
|
514
|
+
options: ["team", "personal"] // 不翻译 — routing key
|
|
515
|
+
})
|
|
516
|
+
```
|
|
517
|
+
|
|
255
518
|
## Decision Tree — Is This Entry Approvable?
|
|
256
519
|
|
|
257
520
|
```
|
|
@@ -289,11 +552,13 @@ Pending entry presented for review
|
|
|
289
552
|
- NEVER batch heterogeneous decisions into a single MCP call. Approve and reject MAY be batched within their own action; modify MUST be one call per entry.
|
|
290
553
|
- NEVER invoke `fab_review action="approve"` without at least one `pending_paths` entry.
|
|
291
554
|
- NEVER infer a layer-flip target — the user MUST choose via AskUserQuestion.
|
|
292
|
-
- MUST preserve protected tokens exactly: `stable_id`, `pending_path`, `layer`, `team`, `personal`, `knowledge_promoted`, `knowledge_layer_changed`, `knowledge_proposed`, `fab_review`, `MUST`, `NEVER`.
|
|
555
|
+
- MUST preserve protected tokens exactly: `stable_id`, `pending_path`, `layer`, `team`, `personal`, `knowledge_promoted`, `knowledge_layer_changed`, `knowledge_proposed`, `knowledge_scope_degraded`, `fab_review`, `MUST`, `NEVER`, `relevance_scope`, `relevance_paths`, `narrow`, `broad`, `proposed_reason`, `session_context`.
|
|
293
556
|
|
|
294
557
|
## Output Contract
|
|
295
558
|
|
|
296
|
-
After each invocation, the skill MUST produce a brief roll-up to the user:
|
|
559
|
+
After each invocation, the skill MUST produce a brief roll-up to the user. UX i18n Policy class 1 — roll-up templates; render per `knowledge_language`. Protected tokens (event-type strings such as `knowledge_promoted` / `knowledge_layer_changed` / `knowledge_rejected` / `knowledge_deferred`, plus `.fabric/events.jsonl`) appear verbatim in BOTH variants:
|
|
560
|
+
|
|
561
|
+
en variant (`knowledge_language === "en"`):
|
|
297
562
|
|
|
298
563
|
```md
|
|
299
564
|
# Review Summary — mode={pending|topic|health|revisit}
|
|
@@ -312,6 +577,51 @@ After each invocation, the skill MUST produce a brief roll-up to the user:
|
|
|
312
577
|
- knowledge_deferred ×D
|
|
313
578
|
```
|
|
314
579
|
|
|
580
|
+
zh-CN variant (`knowledge_language === "zh-CN"`):
|
|
581
|
+
|
|
582
|
+
```md
|
|
583
|
+
# Review 汇总 — mode={pending|topic|health|revisit}
|
|
584
|
+
- 列出: N 条
|
|
585
|
+
- 已批准: M (新分配 stable_ids: KT-D-12, KT-G-4, KP-P-2)
|
|
586
|
+
- 已驳回: R
|
|
587
|
+
- 已修改: U (含 K 次 layer 切换)
|
|
588
|
+
- 已延后: D
|
|
589
|
+
- 已跳过: S
|
|
590
|
+
|
|
591
|
+
## 追加事件 (.fabric/events.jsonl 末尾)
|
|
592
|
+
- knowledge_promote_started ×M
|
|
593
|
+
- knowledge_promoted ×M
|
|
594
|
+
- knowledge_layer_changed ×K
|
|
595
|
+
- knowledge_rejected ×R
|
|
596
|
+
- knowledge_deferred ×D
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
### events.jsonl Constraint Note
|
|
600
|
+
|
|
601
|
+
Event lines appended to `.fabric/events.jsonl` are subject to POSIX
|
|
602
|
+
single-write atomicity: only writes ≤ 4KB (`PIPE_BUF`) are guaranteed
|
|
603
|
+
atomic via `Bash: echo "..." >> file`. Lines exceeding 4KB risk
|
|
604
|
+
interleaved corruption under concurrent skill + server writes to the
|
|
605
|
+
same ledger.
|
|
606
|
+
|
|
607
|
+
Skills MUST ensure:
|
|
608
|
+
|
|
609
|
+
- Each event JSON line is a **single line** (no embedded newlines;
|
|
610
|
+
escape `\n` in any string value).
|
|
611
|
+
- `session_context` and other free-form text fields **self-truncate** to
|
|
612
|
+
keep the entire serialized line under 4KB. Suggested per-field caps:
|
|
613
|
+
`session_context` first 500 chars; `source_sessions` cap at 5
|
|
614
|
+
entries; `recent_paths` cap at 20 entries; `user_messages_summary`
|
|
615
|
+
first 500 chars.
|
|
616
|
+
- If approaching the 4KB ceiling after the per-field caps, drop optional
|
|
617
|
+
fields (e.g. tags / extra metadata) **before** truncating semantic
|
|
618
|
+
content (the summary / context that carries the actual observation).
|
|
619
|
+
- The promote / reject / modify / defer events listed above are emitted
|
|
620
|
+
by the MCP server via `appendEventLedgerEvent` and are already
|
|
621
|
+
length-bounded server-side; this constraint applies to any event the
|
|
622
|
+
skill itself appends directly to the ledger (rare, but possible for
|
|
623
|
+
diagnostic markers).
|
|
624
|
+
|
|
315
625
|
Also surface a one-line `git status` of `.fabric/knowledge/` so the user sees the file moves caused by approve / layer-flip.
|
|
316
626
|
|
|
317
627
|
## Worked Examples
|
|
@@ -332,7 +642,7 @@ Skill flow:
|
|
|
332
642
|
## [type=decisions] [layer=team] pending_path=knowledge/pending/decisions/single-cjs-hook.md
|
|
333
643
|
Title: 单 .cjs hook 跨客户端
|
|
334
644
|
Summary: 三客户端 stdout JSON 格式一致,单脚本即可。
|
|
335
|
-
⚠ Possible duplicate of KT-D-0007 (
|
|
645
|
+
⚠ Possible duplicate of KT-D-0007 (LLM 主观判断 dup/subsumption;具体阈值不可量化)
|
|
336
646
|
```
|
|
337
647
|
|
|
338
648
|
4. AskUserQuestion fires; user picks `reject`.
|
|
@@ -380,3 +690,28 @@ Skill flow:
|
|
|
380
690
|
- KT-P-9 → user picks `defer` (no until) → `fab_review action="defer"` with no `until`.
|
|
381
691
|
- KP-G-3 → user picks `demote` → `fab_review action="modify"` with `changes.maturity="draft"` (already draft; equivalently demote means reject if pending — skill chooses correct action by inspecting current state).
|
|
382
692
|
5. Roll-up: 2 deferred, 1 modified, events appended (`knowledge_deferred ×2`, `knowledge_promote_started/promoted` not relevant; `knowledge_layer_changed` not relevant).
|
|
693
|
+
|
|
694
|
+
### Example D — narrowing an imported decision
|
|
695
|
+
|
|
696
|
+
User: "review the pending knowledge".
|
|
697
|
+
|
|
698
|
+
Inferred mode: `pending`. Skill lists 5 pending entries; entry 3's frontmatter
|
|
699
|
+
shows `source_sessions[0] = "fabric-import-2026-05-10"` → import-origin.
|
|
700
|
+
|
|
701
|
+
Display block prepends warning line. User picks `modify` on entry 3.
|
|
702
|
+
AskUserQuestion fires with extended options including `narrow scope`.
|
|
703
|
+
User picks `narrow scope`; free-text follow-up:
|
|
704
|
+
`packages/server/src/retry/**, packages/server/src/lib/retry.ts`
|
|
705
|
+
|
|
706
|
+
Skill calls:
|
|
707
|
+
|
|
708
|
+
mcp__fabric__fab_review({
|
|
709
|
+
action: "modify",
|
|
710
|
+
pending_path: "knowledge/pending/decisions/<slug>.md",
|
|
711
|
+
changes: {
|
|
712
|
+
relevance_scope: "narrow",
|
|
713
|
+
relevance_paths: ["packages/server/src/retry/**", "packages/server/src/lib/retry.ts"]
|
|
714
|
+
}
|
|
715
|
+
})
|
|
716
|
+
|
|
717
|
+
Roll-up confirms `relevance_scope: narrow` written to frontmatter.
|