@fenglimg/fabric-cli 2.0.0-rc.27 → 2.0.0-rc.28
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-XEGXQOOJ.js → chunk-PNRWNUFX.js} +63 -0
- package/dist/index.js +3 -3
- package/dist/{install-UJOFZUYF.js → install-MPSTI654.js} +2 -2
- package/dist/{uninstall-O3PXESM2.js → uninstall-VLLJG7JT.js} +1 -1
- package/package.json +3 -3
- package/templates/skills/fabric-archive/SKILL.md +15 -410
- package/templates/skills/fabric-archive/ref/e5-cron-recap.md +58 -0
- package/templates/skills/fabric-archive/ref/i18n-policy.md +80 -0
- package/templates/skills/fabric-archive/ref/phase-0-4-onboard.md +218 -0
- package/templates/skills/fabric-archive/ref/rc-history.md +38 -0
- package/templates/skills/fabric-archive/ref/worked-examples.md +78 -0
- package/templates/skills/fabric-import/SKILL.md +7 -117
- package/templates/skills/fabric-import/ref/i18n-policy.md +73 -0
- package/templates/skills/fabric-import/ref/state-recovery.md +57 -0
- package/templates/skills/fabric-review/SKILL.md +6 -187
- package/templates/skills/fabric-review/ref/i18n-policy.md +105 -0
- package/templates/skills/fabric-review/ref/worked-examples.md +95 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# UX i18n Policy — fabric-import full reference
|
|
2
|
+
|
|
3
|
+
> **Loaded on demand.** Only consult when you need to disambiguate which of the 5 classes a given string belongs to. SKILL.md gives the operative rule.
|
|
4
|
+
|
|
5
|
+
## UX i18n Policy (5-class bilingualization)
|
|
6
|
+
|
|
7
|
+
The skill consults `fabric_language` from `.fabric/fabric-config.json`
|
|
8
|
+
(固化于 install 时,via `scan.ts:detectExistingLanguage`; default `"en"` when no
|
|
9
|
+
CJK signal is detected in README + docs/; may resolve to `"match-existing"`,
|
|
10
|
+
`"zh-CN"`, `"en"`, or `"zh-CN-hybrid"`). All user-facing text in the
|
|
11
|
+
following 5 categories MUST be rendered in the resolved language:
|
|
12
|
+
|
|
13
|
+
1. **Roll-up templates** — final summary blocks (`# Import Summary — phase=...`,
|
|
14
|
+
`## Phase 2 — Mining`, `## Phase 3 — Dedup`, etc.). zh-CN ↔ en mirror.
|
|
15
|
+
2. **Errors / Preconditions warnings** — abort + gate-fail messages (e.g.
|
|
16
|
+
"请先运行 fabric install 完成基线扫描…" / "Please run fabric install first…").
|
|
17
|
+
zh-CN ↔ en mirror.
|
|
18
|
+
3. **Confirmation prompts** — re-run-within-24h prompt, reset prompts, etc.
|
|
19
|
+
zh-CN ↔ en mirror.
|
|
20
|
+
4. **Dry-run table headers** — `# Import Dry Run — would propose N pending
|
|
21
|
+
entries…` + the `| # | Source | Type | Slug | Scope | Summary |` header row.
|
|
22
|
+
zh-CN ↔ en mirror.
|
|
23
|
+
5. **AskUserQuestion** — `header` + `question` fields (NOT `options[]`).
|
|
24
|
+
zh-CN ↔ en mirror. fabric-import itself does not surface AskUserQuestion
|
|
25
|
+
in the current contract (the rare re-run prompt is free-text), but if a
|
|
26
|
+
future version adds one, this rule applies.
|
|
27
|
+
|
|
28
|
+
Rendering rule:
|
|
29
|
+
|
|
30
|
+
- `fabric_language === "zh-CN"` → emit the zh-CN variant; pure monolingual, no language mixing inside a single user-facing block.
|
|
31
|
+
- `fabric_language === "en"` → emit the en variant; pure monolingual, no language mixing inside a single user-facing block.
|
|
32
|
+
- `fabric_language === "zh-CN-hybrid"` → emit Chinese narrative prose with English technical terms preserved. Protected tokens (always EN): MCP tool names (e.g. `fab_get_knowledge_sections`), CLI command names (e.g. `fab install`), file paths, technical concepts (`Skill`, `SessionStart`, `hook`, `MCP`, `revision_hash`, `pending`, `proven`, `verified`, `draft`).
|
|
33
|
+
- `fabric_language === "match-existing"` or any other value → emit the en variant; pure monolingual.
|
|
34
|
+
|
|
35
|
+
Protected tokens (`fab_extract_knowledge`, `fab_review`, `relevance_scope`,
|
|
36
|
+
`relevance_paths`, `broad`, `narrow`, `source_sessions`, `proposed_reason`,
|
|
37
|
+
`session_context`, `intent_clues`, `tech_stack`, `impact`, `must_read_if`,
|
|
38
|
+
`pending_path`, `layer`, `team`, `personal`,
|
|
39
|
+
`knowledge_scope_degraded`, `MUST`, `NEVER`, `.fabric/knowledge/`, etc.)
|
|
40
|
+
are NEVER translated — they appear verbatim in both language variants.
|
|
41
|
+
The bilingualization scope is prose ONLY.
|
|
42
|
+
|
|
43
|
+
### AskUserQuestion i18n Policy (value vs label)
|
|
44
|
+
|
|
45
|
+
When a skill (this one or any sibling skill the user is composing with)
|
|
46
|
+
issues an `AskUserQuestion`, the `header` and `question` strings are
|
|
47
|
+
user-facing prose → translated per `fabric_language`. The `options[]`
|
|
48
|
+
array entries (e.g. `["approve", "reject", "modify", "defer", "skip"]` in
|
|
49
|
+
fabric-review) are **routing keys** consumed by the skill state machine —
|
|
50
|
+
they MUST remain English regardless of `fabric_language`.
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
// EN (fabric_language === "en")
|
|
54
|
+
AskUserQuestion({
|
|
55
|
+
header: "Review pending entry",
|
|
56
|
+
question: "What action for '{title}'?",
|
|
57
|
+
options: ["approve", "reject", "modify", "defer", "skip"]
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
// zh-CN (fabric_language === "zh-CN")
|
|
61
|
+
AskUserQuestion({
|
|
62
|
+
header: "审核 pending 条目",
|
|
63
|
+
question: "对 '{title}' 执行什么操作?",
|
|
64
|
+
options: ["approve", "reject", "modify", "defer", "skip"] // 不翻译 — routing key
|
|
65
|
+
})
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Rationale: localizing routing keys would force every routing branch to
|
|
69
|
+
dual-string match (e.g. `if (choice === "approve" || choice === "通过")`),
|
|
70
|
+
which doubles the surface area for protected-token regressions and breaks
|
|
71
|
+
the option-list invariants that downstream tooling depends on. Keeping
|
|
72
|
+
`options[]` English-only is contract-locked across all three skills.
|
|
73
|
+
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Phase 0 + 0.1 — State Recovery (fabric-import ref-only)
|
|
2
|
+
|
|
3
|
+
> **Loaded on demand.** Only relevant when a prior import crashed mid-phase, leaving `.tmp-*` residue or a torn `.fabric/.import-state.json`. SKILL.md's hot path inline says "scan for .tmp residue + load state" — this file is the full recovery procedure (atomic-write pattern, sweep rules, corruption detection, fallback to fresh import).
|
|
4
|
+
|
|
5
|
+
## Phase 0 — Init & .tmp Residue Scan
|
|
6
|
+
|
|
7
|
+
Before reading `.fabric/.import-state.json`, scan for residue left by a
|
|
8
|
+
prior crashed run. Skill state writes use a 2-step atomic pattern (Write
|
|
9
|
+
`.tmp` then `Bash mv`); a crash between Step A and Step B leaves a
|
|
10
|
+
`.fabric/.import-state.json.tmp` sidecar that the next invocation MUST
|
|
11
|
+
triage.
|
|
12
|
+
|
|
13
|
+
1. Does `.fabric/.import-state.json.tmp` exist? (`Bash: ls .fabric/.import-state.json.tmp 2>/dev/null`)
|
|
14
|
+
- **Does not exist** → proceed normally to Phase 0.1 (no residue work).
|
|
15
|
+
- **Exists** → triage:
|
|
16
|
+
1. `Read` the `.tmp` file; try `JSON.parse` on the content.
|
|
17
|
+
2. Compare `mtime` of `.tmp` vs `.fabric/.import-state.json` via `Bash: stat`.
|
|
18
|
+
- **Parse OK + .tmp mtime newer than main file** → rescue:
|
|
19
|
+
`Bash: mv .fabric/.import-state.json.tmp .fabric/.import-state.json`
|
|
20
|
+
(commits the last incomplete write atomically).
|
|
21
|
+
- **Parse OK + .tmp mtime older than main file** → stale residue
|
|
22
|
+
from an earlier run that subsequently completed; delete it:
|
|
23
|
+
`Bash: rm .fabric/.import-state.json.tmp`.
|
|
24
|
+
- **Parse fails** (syntax error / unterminated structure / truncated
|
|
25
|
+
mid-write) → half-written, unrecoverable; delete it:
|
|
26
|
+
`Bash: rm .fabric/.import-state.json.tmp`.
|
|
27
|
+
3. After triage, proceed to Phase 0.1.
|
|
28
|
+
|
|
29
|
+
The 5-minute mtime heuristic (treat any `.tmp` older than 5 minutes as
|
|
30
|
+
stale regardless of parse result) is an acceptable conservative simplification:
|
|
31
|
+
no legitimate atomic write window stays open that long; anything older
|
|
32
|
+
than 5 minutes is definitely crash residue. Implementations MAY use either
|
|
33
|
+
the mtime-comparison rule above OR the 5-minute staleness rule.
|
|
34
|
+
|
|
35
|
+
### Phase 0.1 — State Corruption Recovery
|
|
36
|
+
|
|
37
|
+
After residue triage, `Read` `.fabric/.import-state.json`. Detect
|
|
38
|
+
corruption if ANY of the following hold:
|
|
39
|
+
|
|
40
|
+
- `JSON.parse` throws (syntax error / unterminated structure / truncated)
|
|
41
|
+
- Missing required field: `phase` OR `started_at` OR `last_checkpoint_at`
|
|
42
|
+
- `phase` value not in the enum `{P1-done, P2-done, complete}`
|
|
43
|
+
|
|
44
|
+
On corruption (any condition above):
|
|
45
|
+
|
|
46
|
+
1. `Bash: mv .fabric/.import-state.json .fabric/.import-state.json.corrupt-<ISO8601>`
|
|
47
|
+
(preserve the corrupt file for postmortem; do NOT silently overwrite).
|
|
48
|
+
2. Phase 1 restarts from scratch (Phase 1 produces no MCP calls, so re-run
|
|
49
|
+
is safe — re-globbing `.fabric/knowledge/team/**/*.md` is cheap and
|
|
50
|
+
idempotent; the `p1_baseline_titles` array is regenerated).
|
|
51
|
+
3. DO NOT attempt automatic partial recovery; corrupt state is a signal
|
|
52
|
+
that something serious happened (disk-full, kill -9 mid-write, fs
|
|
53
|
+
error). Discard-and-restart is the only safe path.
|
|
54
|
+
|
|
55
|
+
ENOENT (state file absent) is NOT corruption — it is the normal
|
|
56
|
+
first-run state. Proceed to Phase 0.5.
|
|
57
|
+
|
|
@@ -49,106 +49,13 @@ defaults if absent):
|
|
|
49
49
|
|
|
50
50
|
If `.fabric/fabric-config.json` is missing or unreadable, use defaults silently.
|
|
51
51
|
|
|
52
|
-
### UX i18n Policy
|
|
53
|
-
|
|
54
|
-
The skill consults `fabric_language` from `.fabric/fabric-config.json`
|
|
55
|
-
(固化于 init 时,via `lib/detect-language.ts:detectExistingLanguage`; default `"en"` when no
|
|
56
|
-
CJK signal is detected in README + docs/; may resolve to `"match-existing"`,
|
|
57
|
-
`"zh-CN"`, `"en"`, or `"zh-CN-hybrid"`). All user-facing text in the
|
|
58
|
-
following 5 categories MUST be rendered in the resolved language:
|
|
59
|
-
|
|
60
|
-
1. **Roll-up templates** — the `# Review Summary — mode={...}` final block,
|
|
61
|
-
the `## Health Overview` dashboard in health mode, and any per-item
|
|
62
|
-
display blocks (`## [type=...] [layer=...] pending_path=...` lines).
|
|
63
|
-
zh-CN ↔ en mirror.
|
|
64
|
-
2. **Errors / Preconditions warnings** — abort + trigger-miss messages
|
|
65
|
-
(e.g. "没有触发 review 信号…" / "No review signal detected…").
|
|
66
|
-
zh-CN ↔ en mirror.
|
|
67
|
-
3. **Confirmation prompts** — free-text reject-reason follow-up, the
|
|
68
|
-
"Type relevance_paths (comma-separated globs, …)" narrow-scope
|
|
69
|
-
follow-up, and any other free-text prompts. zh-CN ↔ en mirror.
|
|
70
|
-
4. **Dry-run table headers** — fabric-review does not currently expose
|
|
71
|
-
a dry-run mode; this slot is reserved for parity with fabric-import.
|
|
72
|
-
IF a future revision adds dry-run, the table header MUST be
|
|
73
|
-
bilingualized per this policy. zh-CN ↔ en mirror.
|
|
74
|
-
5. **AskUserQuestion** — `header` + `question` fields (NOT `options[]`).
|
|
75
|
-
zh-CN ↔ en mirror. fabric-review is the heaviest AskUserQuestion
|
|
76
|
-
consumer (per-item action, layer-flip target, stale-item action,
|
|
77
|
-
modify-extended option set), so this class applies broadly.
|
|
78
|
-
|
|
79
|
-
Rendering rule:
|
|
80
|
-
|
|
81
|
-
- `fabric_language === "zh-CN"` → emit the zh-CN variant; pure monolingual, no language mixing inside a single user-facing block.
|
|
82
|
-
- `fabric_language === "en"` → emit the en variant; pure monolingual, no language mixing inside a single user-facing block.
|
|
83
|
-
- `fabric_language === "zh-CN-hybrid"` → emit Chinese narrative prose with English technical terms preserved. Protected tokens (always EN): MCP tool names (e.g. `fab_get_knowledge_sections`), CLI command names (e.g. `fab install`), file paths, technical concepts (`Skill`, `SessionStart`, `hook`, `MCP`, `revision_hash`, `pending`, `proven`, `verified`, `draft`).
|
|
84
|
-
- `fabric_language === "match-existing"` or any other value → emit the en variant; pure monolingual.
|
|
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 `fabric_language`. The
|
|
97
|
-
`options[]` array entries are **routing keys** consumed by the skill
|
|
98
|
-
state machine — they MUST remain English regardless of `fabric_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"]`
|
|
52
|
+
### UX i18n Policy
|
|
108
53
|
|
|
109
|
-
|
|
54
|
+
Read `.fabric/fabric-config.json` → `fabric_language` (`zh-CN` / `en` / `zh-CN-hybrid` / `match-existing`). Emit user-facing prose in the resolved variant. Protected tokens (`fab_review`, `fab_extract_knowledge`, `relevance_scope`, layer/scope enum values, `stable_id`, the verbatim `强 team` / `强 personal` / `默认 team` block) are NEVER translated.
|
|
110
55
|
|
|
111
|
-
|
|
112
|
-
// EN (fabric_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
|
-
})
|
|
56
|
+
`AskUserQuestion` policy: `header` + `question` translate; `options[]` are routing keys — stay English regardless of locale.
|
|
118
57
|
|
|
119
|
-
|
|
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.
|
|
58
|
+
**For the full 5-class taxonomy + edge cases:** `Read packages/cli/templates/skills/fabric-review/ref/i18n-policy.md` (or `.claude/skills/fabric-review/ref/i18n-policy.md` post-install).
|
|
152
59
|
|
|
153
60
|
## Mode Inference (System Infers — NEVER Ask)
|
|
154
61
|
|
|
@@ -624,94 +531,6 @@ Skills MUST ensure:
|
|
|
624
531
|
|
|
625
532
|
Also surface a one-line `git status` of `.fabric/knowledge/` so the user sees the file moves caused by approve / layer-flip.
|
|
626
533
|
|
|
627
|
-
## Worked Examples
|
|
628
|
-
|
|
629
|
-
### Example A — pending mode with semantic check flagging a duplicate (user chooses reject)
|
|
630
|
-
|
|
631
|
-
User: "review the pending knowledge".
|
|
632
|
-
|
|
633
|
-
Inferred mode: `pending` (Step 1 keyword "review … pending").
|
|
634
|
-
|
|
635
|
-
Skill flow:
|
|
636
|
-
|
|
637
|
-
1. `fab_review action="list"` → returns 3 pending items.
|
|
638
|
-
2. Semantic check on item 2 (`pending/decisions/single-cjs-hook.md`) — `fab_review action="search"` with `query="single cjs hook"` filter `type=decisions` returns canonical `KT-D-0007--single-cjs-hook-across-clients.md` (similarity high).
|
|
639
|
-
3. Display block:
|
|
640
|
-
|
|
641
|
-
```md
|
|
642
|
-
## [type=decisions] [layer=team] pending_path=knowledge/pending/decisions/single-cjs-hook.md
|
|
643
|
-
Title: 单 .cjs hook 跨客户端
|
|
644
|
-
Summary: 三客户端 stdout JSON 格式一致,单脚本即可。
|
|
645
|
-
⚠ Possible duplicate of KT-D-0007 (LLM 主观判断 dup/subsumption;具体阈值不可量化)
|
|
646
|
-
```
|
|
647
|
-
|
|
648
|
-
4. AskUserQuestion fires; user picks `reject`.
|
|
649
|
-
5. Free-text follow-up: user types `duplicate of KT-D-7`.
|
|
650
|
-
6. `fab_review action="reject"` with `pending_paths=["knowledge/pending/decisions/single-cjs-hook.md"]` and `reason="duplicate of KT-D-7"`.
|
|
651
|
-
7. Roll-up reports: 1 rejected, 0 approved, events appended.
|
|
652
|
-
|
|
653
|
-
### Example B — revisit mode with layer flip (KT → KP)
|
|
654
|
-
|
|
655
|
-
User: "look at KT-G-3, that's actually personal not team".
|
|
656
|
-
|
|
657
|
-
Inferred mode: `revisit` (Step 1 keyword "look at <id>").
|
|
658
|
-
|
|
659
|
-
Skill flow:
|
|
660
|
-
|
|
661
|
-
1. Read `.fabric/knowledge/team/guidelines/KT-G-0003--indent-style.md`. Display body to user.
|
|
662
|
-
2. AskUserQuestion `{options: ["approve", "modify", "reject", "skip"]}` — user picks `modify`.
|
|
663
|
-
3. Skill detects user-stated intent "actually personal not team" — surface AskUserQuestion `{options: ["team", "personal"]}` with current layer=team noted; user confirms `personal`.
|
|
664
|
-
4. Call:
|
|
665
|
-
|
|
666
|
-
```ts
|
|
667
|
-
mcp__fabric__fab_review({
|
|
668
|
-
action: "modify",
|
|
669
|
-
pending_path: "knowledge/team/guidelines/KT-G-0003--indent-style.md",
|
|
670
|
-
changes: { layer: "personal" }
|
|
671
|
-
})
|
|
672
|
-
```
|
|
673
|
-
|
|
674
|
-
5. Server returns `{prior_stable_id: "KT-G-0003", new_stable_id: "KP-G-0001"}`.
|
|
675
|
-
6. Roll-up: `Layer flipped: KT-G-0003 → KP-G-0001`. `git status` shows the rename across layer roots.
|
|
676
|
-
|
|
677
|
-
### Example C — health mode finding stale entries (defer 2, demote 1)
|
|
678
|
-
|
|
679
|
-
User: "anything stale in our knowledge base?"
|
|
680
|
-
|
|
681
|
-
Inferred mode: `health` (Step 1 keyword "stale").
|
|
682
|
-
|
|
683
|
-
Skill flow:
|
|
684
|
-
|
|
685
|
-
1. `fab_review action="list"` (no filter) + tail events.jsonl for trailing-30d demoted/layer_changed counts.
|
|
686
|
-
2. Compute stale candidates: 3 pending entries with mtime >14d (KP-G-5 candidate-pending, KT-P-9 candidate-pending, KP-G-3 canonical draft with no evidence-append in 21d).
|
|
687
|
-
3. Render dashboard then loop per stale item.
|
|
688
|
-
4. Per-item AskUserQuestion fires:
|
|
689
|
-
- KP-G-5 → user picks `defer` (until="2026-06-01") → `fab_review action="defer"` with `until` set.
|
|
690
|
-
- KT-P-9 → user picks `defer` (no until) → `fab_review action="defer"` with no `until`.
|
|
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).
|
|
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
|
-
})
|
|
534
|
+
## Worked Examples (ref-only)
|
|
716
535
|
|
|
717
|
-
|
|
536
|
+
Four worked examples (pending-mode dedupe / revisit layer-flip / health mode / narrowing imported entries) live in `packages/cli/templates/skills/fabric-review/ref/worked-examples.md` (or `.claude/skills/fabric-review/ref/worked-examples.md` post-install). Load when you want to see how the full Mode + AskUserQuestion + MCP-call shape composes on real candidate sets.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# UX i18n Policy — fabric-review full reference
|
|
2
|
+
|
|
3
|
+
> **Loaded on demand.** Only consult when you need to disambiguate which of the 5 classes a given string belongs to. SKILL.md gives the operative rule.
|
|
4
|
+
|
|
5
|
+
## UX i18n Policy (5-class bilingualization)
|
|
6
|
+
|
|
7
|
+
The skill consults `fabric_language` from `.fabric/fabric-config.json`
|
|
8
|
+
(固化于 init 时,via `lib/detect-language.ts:detectExistingLanguage`; default `"en"` when no
|
|
9
|
+
CJK signal is detected in README + docs/; may resolve to `"match-existing"`,
|
|
10
|
+
`"zh-CN"`, `"en"`, or `"zh-CN-hybrid"`). All user-facing text in the
|
|
11
|
+
following 5 categories MUST be rendered in the resolved language:
|
|
12
|
+
|
|
13
|
+
1. **Roll-up templates** — the `# Review Summary — mode={...}` final block,
|
|
14
|
+
the `## Health Overview` dashboard in health mode, and any per-item
|
|
15
|
+
display blocks (`## [type=...] [layer=...] pending_path=...` lines).
|
|
16
|
+
zh-CN ↔ en mirror.
|
|
17
|
+
2. **Errors / Preconditions warnings** — abort + trigger-miss messages
|
|
18
|
+
(e.g. "没有触发 review 信号…" / "No review signal detected…").
|
|
19
|
+
zh-CN ↔ en mirror.
|
|
20
|
+
3. **Confirmation prompts** — free-text reject-reason follow-up, the
|
|
21
|
+
"Type relevance_paths (comma-separated globs, …)" narrow-scope
|
|
22
|
+
follow-up, and any other free-text prompts. zh-CN ↔ en mirror.
|
|
23
|
+
4. **Dry-run table headers** — fabric-review does not currently expose
|
|
24
|
+
a dry-run mode; this slot is reserved for parity with fabric-import.
|
|
25
|
+
IF a future revision adds dry-run, the table header MUST be
|
|
26
|
+
bilingualized per this policy. zh-CN ↔ en mirror.
|
|
27
|
+
5. **AskUserQuestion** — `header` + `question` fields (NOT `options[]`).
|
|
28
|
+
zh-CN ↔ en mirror. fabric-review is the heaviest AskUserQuestion
|
|
29
|
+
consumer (per-item action, layer-flip target, stale-item action,
|
|
30
|
+
modify-extended option set), so this class applies broadly.
|
|
31
|
+
|
|
32
|
+
Rendering rule:
|
|
33
|
+
|
|
34
|
+
- `fabric_language === "zh-CN"` → emit the zh-CN variant; pure monolingual, no language mixing inside a single user-facing block.
|
|
35
|
+
- `fabric_language === "en"` → emit the en variant; pure monolingual, no language mixing inside a single user-facing block.
|
|
36
|
+
- `fabric_language === "zh-CN-hybrid"` → emit Chinese narrative prose with English technical terms preserved. Protected tokens (always EN): MCP tool names (e.g. `fab_get_knowledge_sections`), CLI command names (e.g. `fab install`), file paths, technical concepts (`Skill`, `SessionStart`, `hook`, `MCP`, `revision_hash`, `pending`, `proven`, `verified`, `draft`).
|
|
37
|
+
- `fabric_language === "match-existing"` or any other value → emit the en variant; pure monolingual.
|
|
38
|
+
|
|
39
|
+
Protected tokens (`fab_review`, `relevance_scope`, `relevance_paths`,
|
|
40
|
+
`narrow`, `broad`, `source_sessions`, `proposed_reason`, `session_context`,
|
|
41
|
+
`pending_path`, `layer`, `team`, `personal`, `knowledge_scope_degraded`,
|
|
42
|
+
`MUST`, `NEVER`, `.fabric/knowledge/`, etc.) are NEVER translated — they
|
|
43
|
+
appear verbatim in both language variants. The bilingualization scope is
|
|
44
|
+
prose ONLY.
|
|
45
|
+
|
|
46
|
+
### AskUserQuestion i18n Policy (value vs label)
|
|
47
|
+
|
|
48
|
+
When this skill issues an `AskUserQuestion`, the `header` and `question`
|
|
49
|
+
strings are user-facing prose → translated per `fabric_language`. The
|
|
50
|
+
`options[]` array entries are **routing keys** consumed by the skill
|
|
51
|
+
state machine — they MUST remain English regardless of `fabric_language`.
|
|
52
|
+
|
|
53
|
+
Canonical options arrays used by this skill (every value below stays
|
|
54
|
+
English in BOTH language variants):
|
|
55
|
+
|
|
56
|
+
- Per-item action: `["approve", "reject", "modify", "defer", "skip"]`
|
|
57
|
+
- Per-stale-item action (health mode): `["defer", "demote", "skip"]`
|
|
58
|
+
- Layer-flip target: `["team", "personal"]`
|
|
59
|
+
- Modify-extended (import-origin narrow-scope nudge):
|
|
60
|
+
`["narrow scope", "edit summary", "change layer", "change maturity", "skip"]`
|
|
61
|
+
|
|
62
|
+
Worked example — per-item action (the most common AskUserQuestion in this skill):
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
// EN (fabric_language === "en")
|
|
66
|
+
AskUserQuestion({
|
|
67
|
+
header: "Review pending entry",
|
|
68
|
+
question: "What action for '{title}'? ({pending_path})",
|
|
69
|
+
options: ["approve", "reject", "modify", "defer", "skip"]
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
// zh-CN (fabric_language === "zh-CN")
|
|
73
|
+
AskUserQuestion({
|
|
74
|
+
header: "审核 pending 条目",
|
|
75
|
+
question: "对 '{title}' 执行什么操作?({pending_path})",
|
|
76
|
+
options: ["approve", "reject", "modify", "defer", "skip"] // 不翻译 — routing key
|
|
77
|
+
})
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Worked example — layer-flip target:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
// EN
|
|
84
|
+
AskUserQuestion({
|
|
85
|
+
header: "Layer-flip target",
|
|
86
|
+
question: "Move '{title}' to which layer? (current: {current_layer})",
|
|
87
|
+
options: ["team", "personal"]
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
// zh-CN
|
|
91
|
+
AskUserQuestion({
|
|
92
|
+
header: "Layer 切换目标",
|
|
93
|
+
question: "将 '{title}' 切换到哪一层?(当前: {current_layer})",
|
|
94
|
+
options: ["team", "personal"] // 不翻译 — routing key
|
|
95
|
+
})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Rationale: localizing routing keys would force every routing branch to
|
|
99
|
+
dual-string match (e.g. `if (choice === "approve" || choice === "通过")`),
|
|
100
|
+
which doubles the surface area for protected-token regressions and breaks
|
|
101
|
+
the option-list invariants that downstream tooling (the Skill's own
|
|
102
|
+
`switch` statements over `choice`, plus any future MCP-level audit lint
|
|
103
|
+
that scans for these specific string literals) depends on. Keeping
|
|
104
|
+
`options[]` English-only is contract-locked across all three skills.
|
|
105
|
+
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Worked Examples — fabric-review full reference
|
|
2
|
+
|
|
3
|
+
> **Loaded on demand.** Four end-to-end mode walkthroughs (pending dedupe / revisit layer-flip / health mode / narrowing imported entries). SKILL.md gives the operative contract; load these to see how Mode + AskUserQuestion + MCP-call shape composes on real candidates.
|
|
4
|
+
|
|
5
|
+
## Worked Examples
|
|
6
|
+
|
|
7
|
+
## Example A — pending mode with semantic check flagging a duplicate (user chooses reject)
|
|
8
|
+
|
|
9
|
+
User: "review the pending knowledge".
|
|
10
|
+
|
|
11
|
+
Inferred mode: `pending` (Step 1 keyword "review … pending").
|
|
12
|
+
|
|
13
|
+
Skill flow:
|
|
14
|
+
|
|
15
|
+
1. `fab_review action="list"` → returns 3 pending items.
|
|
16
|
+
2. Semantic check on item 2 (`pending/decisions/single-cjs-hook.md`) — `fab_review action="search"` with `query="single cjs hook"` filter `type=decisions` returns canonical `KT-D-0007--single-cjs-hook-across-clients.md` (similarity high).
|
|
17
|
+
3. Display block:
|
|
18
|
+
|
|
19
|
+
```md
|
|
20
|
+
## [type=decisions] [layer=team] pending_path=knowledge/pending/decisions/single-cjs-hook.md
|
|
21
|
+
Title: 单 .cjs hook 跨客户端
|
|
22
|
+
Summary: 三客户端 stdout JSON 格式一致,单脚本即可。
|
|
23
|
+
⚠ Possible duplicate of KT-D-0007 (LLM 主观判断 dup/subsumption;具体阈值不可量化)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
4. AskUserQuestion fires; user picks `reject`.
|
|
27
|
+
5. Free-text follow-up: user types `duplicate of KT-D-7`.
|
|
28
|
+
6. `fab_review action="reject"` with `pending_paths=["knowledge/pending/decisions/single-cjs-hook.md"]` and `reason="duplicate of KT-D-7"`.
|
|
29
|
+
7. Roll-up reports: 1 rejected, 0 approved, events appended.
|
|
30
|
+
|
|
31
|
+
### Example B — revisit mode with layer flip (KT → KP)
|
|
32
|
+
|
|
33
|
+
User: "look at KT-G-3, that's actually personal not team".
|
|
34
|
+
|
|
35
|
+
Inferred mode: `revisit` (Step 1 keyword "look at <id>").
|
|
36
|
+
|
|
37
|
+
Skill flow:
|
|
38
|
+
|
|
39
|
+
1. Read `.fabric/knowledge/team/guidelines/KT-G-0003--indent-style.md`. Display body to user.
|
|
40
|
+
2. AskUserQuestion `{options: ["approve", "modify", "reject", "skip"]}` — user picks `modify`.
|
|
41
|
+
3. Skill detects user-stated intent "actually personal not team" — surface AskUserQuestion `{options: ["team", "personal"]}` with current layer=team noted; user confirms `personal`.
|
|
42
|
+
4. Call:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
mcp__fabric__fab_review({
|
|
46
|
+
action: "modify",
|
|
47
|
+
pending_path: "knowledge/team/guidelines/KT-G-0003--indent-style.md",
|
|
48
|
+
changes: { layer: "personal" }
|
|
49
|
+
})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
5. Server returns `{prior_stable_id: "KT-G-0003", new_stable_id: "KP-G-0001"}`.
|
|
53
|
+
6. Roll-up: `Layer flipped: KT-G-0003 → KP-G-0001`. `git status` shows the rename across layer roots.
|
|
54
|
+
|
|
55
|
+
### Example C — health mode finding stale entries (defer 2, demote 1)
|
|
56
|
+
|
|
57
|
+
User: "anything stale in our knowledge base?"
|
|
58
|
+
|
|
59
|
+
Inferred mode: `health` (Step 1 keyword "stale").
|
|
60
|
+
|
|
61
|
+
Skill flow:
|
|
62
|
+
|
|
63
|
+
1. `fab_review action="list"` (no filter) + tail events.jsonl for trailing-30d demoted/layer_changed counts.
|
|
64
|
+
2. Compute stale candidates: 3 pending entries with mtime >14d (KP-G-5 candidate-pending, KT-P-9 candidate-pending, KP-G-3 canonical draft with no evidence-append in 21d).
|
|
65
|
+
3. Render dashboard then loop per stale item.
|
|
66
|
+
4. Per-item AskUserQuestion fires:
|
|
67
|
+
- KP-G-5 → user picks `defer` (until="2026-06-01") → `fab_review action="defer"` with `until` set.
|
|
68
|
+
- KT-P-9 → user picks `defer` (no until) → `fab_review action="defer"` with no `until`.
|
|
69
|
+
- 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).
|
|
70
|
+
5. Roll-up: 2 deferred, 1 modified, events appended (`knowledge_deferred ×2`, `knowledge_promote_started/promoted` not relevant; `knowledge_layer_changed` not relevant).
|
|
71
|
+
|
|
72
|
+
### Example D — narrowing an imported decision
|
|
73
|
+
|
|
74
|
+
User: "review the pending knowledge".
|
|
75
|
+
|
|
76
|
+
Inferred mode: `pending`. Skill lists 5 pending entries; entry 3's frontmatter
|
|
77
|
+
shows `source_sessions[0] = "fabric-import-2026-05-10"` → import-origin.
|
|
78
|
+
|
|
79
|
+
Display block prepends warning line. User picks `modify` on entry 3.
|
|
80
|
+
AskUserQuestion fires with extended options including `narrow scope`.
|
|
81
|
+
User picks `narrow scope`; free-text follow-up:
|
|
82
|
+
`packages/server/src/retry/**, packages/server/src/lib/retry.ts`
|
|
83
|
+
|
|
84
|
+
Skill calls:
|
|
85
|
+
|
|
86
|
+
mcp__fabric__fab_review({
|
|
87
|
+
action: "modify",
|
|
88
|
+
pending_path: "knowledge/pending/decisions/<slug>.md",
|
|
89
|
+
changes: {
|
|
90
|
+
relevance_scope: "narrow",
|
|
91
|
+
relevance_paths: ["packages/server/src/retry/**", "packages/server/src/lib/retry.ts"]
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
Roll-up confirms `relevance_scope: narrow` written to frontmatter.
|