@fenglimg/fabric-cli 2.0.0 → 2.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.
Files changed (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +6 -5
  3. package/dist/chunk-BATF4PEJ.js +361 -0
  4. package/dist/{chunk-OBQU6NHO.js → chunk-COI5VDFU.js} +0 -18
  5. package/dist/chunk-D25XJ4BC.js +880 -0
  6. package/dist/chunk-MF3OTILQ.js +544 -0
  7. package/dist/chunk-PWLW3B57.js +18 -0
  8. package/dist/config-XJIPZNUP.js +13 -0
  9. package/dist/doctor-EJDSEJSS.js +810 -0
  10. package/dist/index.js +15 -8
  11. package/dist/{init-BIRSIOXO.js → install-EKWMFLUU.js} +622 -711
  12. package/dist/metrics-ACEQFPDU.js +122 -0
  13. package/dist/onboard-coverage-MFCAEBDO.js +220 -0
  14. package/dist/{plan-context-hint-QMUPAXIB.js → plan-context-hint-FC6P3WFE.js} +34 -28
  15. package/dist/uninstall-MH7ZIB6M.js +1064 -0
  16. package/package.json +30 -5
  17. package/templates/hooks/cite-policy-evict.cjs +231 -0
  18. package/templates/hooks/configs/README.md +29 -6
  19. package/templates/hooks/configs/claude-code.json +14 -3
  20. package/templates/hooks/configs/codex-hooks.json +6 -3
  21. package/templates/hooks/configs/cursor-hooks.json +8 -10
  22. package/templates/hooks/fabric-hint.cjs +833 -105
  23. package/templates/hooks/knowledge-hint-broad.cjs +509 -135
  24. package/templates/hooks/knowledge-hint-narrow.cjs +791 -26
  25. package/templates/hooks/lib/banner-i18n.cjs +309 -0
  26. package/templates/hooks/lib/cite-contract-reminder.cjs +173 -0
  27. package/templates/hooks/lib/cite-line-parser.cjs +158 -0
  28. package/templates/hooks/lib/client-adapter.cjs +106 -0
  29. package/templates/hooks/lib/config-cache.cjs +107 -0
  30. package/templates/hooks/lib/state-store.cjs +84 -0
  31. package/templates/hooks/lib/summary-fallback.cjs +210 -0
  32. package/templates/skills/fabric-archive/SKILL.md +93 -419
  33. package/templates/skills/fabric-archive/ref/dry-run-scope.md +16 -0
  34. package/templates/skills/fabric-archive/ref/e5-cron-recap.md +58 -0
  35. package/templates/skills/fabric-archive/ref/i18n-policy.md +86 -0
  36. package/templates/skills/fabric-archive/ref/phase-0-range-resolution.md +156 -0
  37. package/templates/skills/fabric-archive/ref/phase-1-5-onboard.md +218 -0
  38. package/templates/skills/fabric-archive/ref/phase-1-cross-session.md +62 -0
  39. package/templates/skills/fabric-archive/ref/phase-2-5-viability.md +68 -0
  40. package/templates/skills/fabric-archive/ref/phase-3-5-scope.md +108 -0
  41. package/templates/skills/fabric-archive/ref/phase-3-classify.md +63 -0
  42. package/templates/skills/fabric-archive/ref/phase-4-5-emit.md +78 -0
  43. package/templates/skills/fabric-archive/ref/phase-4-mcp-persist.md +89 -0
  44. package/templates/skills/fabric-archive/ref/rc-history.md +38 -0
  45. package/templates/skills/fabric-archive/ref/worked-examples.md +78 -0
  46. package/templates/skills/fabric-import/SKILL.md +75 -516
  47. package/templates/skills/fabric-import/ref/checkpoint-state.md +85 -0
  48. package/templates/skills/fabric-import/ref/i18n-policy.md +79 -0
  49. package/templates/skills/fabric-import/ref/output-contract.md +61 -0
  50. package/templates/skills/fabric-import/ref/phase-2-mining.md +213 -0
  51. package/templates/skills/fabric-import/ref/phase-3-dedup.md +75 -0
  52. package/templates/skills/fabric-import/ref/state-recovery.md +57 -0
  53. package/templates/skills/fabric-import/ref/worked-examples.md +127 -0
  54. package/templates/skills/fabric-review/SKILL.md +86 -284
  55. package/templates/skills/fabric-review/ref/askuserquestion-policy.md +66 -0
  56. package/templates/skills/fabric-review/ref/i18n-policy.md +111 -0
  57. package/templates/skills/fabric-review/ref/modify-flow.md +103 -0
  58. package/templates/skills/fabric-review/ref/output-contract.md +58 -0
  59. package/templates/skills/fabric-review/ref/per-mode-flows.md +155 -0
  60. package/templates/skills/fabric-review/ref/semantic-check.md +26 -0
  61. package/templates/skills/fabric-review/ref/worked-examples.md +95 -0
  62. package/templates/skills/lib/shared-policy.md +69 -0
  63. package/dist/chunk-6ICJICVU.js +0 -10
  64. package/dist/chunk-74SZWYPH.js +0 -658
  65. package/dist/chunk-EYIDD2YS.js +0 -1000
  66. package/dist/doctor-T7JWODKG.js +0 -282
  67. package/dist/hooks-Y74Y5LQS.js +0 -12
  68. package/dist/scan-LMK3UCWL.js +0 -22
  69. package/dist/serve-H554BHLG.js +0 -124
  70. package/templates/agents-md/AGENTS.md.template +0 -59
  71. package/templates/bootstrap/CLAUDE.md +0 -8
  72. package/templates/bootstrap/codex-AGENTS-header.md +0 -6
  73. package/templates/bootstrap/cursor-fabric-bootstrap.mdc +0 -10
@@ -0,0 +1,66 @@
1
+ # AskUserQuestion Policy — fabric-review
2
+
3
+ Full DO / DO NOT split + per-item question phrasing templates referenced from SKILL.md.
4
+
5
+ ## DO ask (genuine choices that require human judgment)
6
+
7
+ - Per-pending-item action: `["approve", "reject", "modify", "defer", "skip"]`
8
+ - Per-stale-item action (health mode): `["defer", "demote", "skip"]`
9
+ - Layer-flip target when modify path includes layer change: `["team", "personal"]`
10
+ - Reject reason follow-up (free-text, may use AskUserQuestion's free-form variant if available, otherwise plain prompt)
11
+
12
+ ## DO NOT ask (system must infer or operate deterministically)
13
+
14
+ - Mode picking (pending / topic / health / revisit) — INFERRED per the 3-step algorithm
15
+ - Whether to invoke this skill at all — Stop-hook signal or explicit user request decides
16
+ - Whether an entry is a duplicate — LLM semantic check answers
17
+ - Frontmatter parsing — deterministic, never asked
18
+ - Allocate next id — deterministic via KnowledgeIdAllocator, never asked
19
+
20
+ ## Per-Item Question Phrasing Template
21
+
22
+ UX i18n Policy class 5 — `header` + `question` translated per `fabric_language`; `options[]` arrays remain English routing keys in BOTH variants. Choose the variant matching the resolved language; the structure (field names, options) is identical.
23
+
24
+ ### Pending entry action
25
+
26
+ **en variant**:
27
+
28
+ ```ts
29
+ AskUserQuestion({
30
+ header: "Review pending entry",
31
+ question: "What action for '{title}'? ({pending_path})",
32
+ options: ["approve", "reject", "modify", "defer", "skip"]
33
+ })
34
+ ```
35
+
36
+ **zh-CN variant**:
37
+
38
+ ```ts
39
+ AskUserQuestion({
40
+ header: "审核 pending 条目",
41
+ question: "对 '{title}' 执行什么操作?({pending_path})",
42
+ options: ["approve", "reject", "modify", "defer", "skip"] // 不翻译 — routing key
43
+ })
44
+ ```
45
+
46
+ ### Layer-flip target
47
+
48
+ **en variant**:
49
+
50
+ ```ts
51
+ AskUserQuestion({
52
+ header: "Layer-flip target",
53
+ question: "Move '{title}' to which layer? (current: {current_layer})",
54
+ options: ["team", "personal"]
55
+ })
56
+ ```
57
+
58
+ **zh-CN variant**:
59
+
60
+ ```ts
61
+ AskUserQuestion({
62
+ header: "Layer 切换目标",
63
+ question: "将 '{title}' 切换到哪一层?(当前: {current_layer})",
64
+ options: ["team", "personal"] // 不翻译 — routing key
65
+ })
66
+ ```
@@ -0,0 +1,111 @@
1
+ # UX i18n Policy — fabric-review full reference
2
+
3
+ > **Shared core (rc.37 NEW-13):** the cross-skill invariants — protected-token
4
+ > NEVER-translate list, AskUserQuestion routing-key rule, layer heuristic, and
5
+ > events-emit convention — live once in `../../lib/shared-policy.md`. This file
6
+ > keeps only the fabric-review-specific 5-class examples. Read the shared lib
7
+ > for the common rules; do not fork them here.
8
+
9
+ > **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.
10
+
11
+ ## UX i18n Policy (5-class bilingualization)
12
+
13
+ The skill consults `fabric_language` from `.fabric/fabric-config.json`
14
+ (固化于 init 时,via `lib/detect-language.ts:detectExistingLanguage`; default `"en"` when no
15
+ CJK signal is detected in README + docs/; may resolve to `"match-existing"`,
16
+ `"zh-CN"`, `"en"`, or `"zh-CN-hybrid"`). All user-facing text in the
17
+ following 5 categories MUST be rendered in the resolved language:
18
+
19
+ 1. **Roll-up templates** — the `# Review Summary — mode={...}` final block,
20
+ the `## Health Overview` dashboard in health mode, and any per-item
21
+ display blocks (`## [type=...] [layer=...] pending_path=...` lines).
22
+ zh-CN ↔ en mirror.
23
+ 2. **Errors / Preconditions warnings** — abort + trigger-miss messages
24
+ (e.g. "没有触发 review 信号…" / "No review signal detected…").
25
+ zh-CN ↔ en mirror.
26
+ 3. **Confirmation prompts** — free-text reject-reason follow-up, the
27
+ "Type relevance_paths (comma-separated globs, …)" narrow-scope
28
+ follow-up, and any other free-text prompts. zh-CN ↔ en mirror.
29
+ 4. **Dry-run table headers** — fabric-review does not currently expose
30
+ a dry-run mode; this slot is reserved for parity with fabric-import.
31
+ IF a future revision adds dry-run, the table header MUST be
32
+ bilingualized per this policy. zh-CN ↔ en mirror.
33
+ 5. **AskUserQuestion** — `header` + `question` fields (NOT `options[]`).
34
+ zh-CN ↔ en mirror. fabric-review is the heaviest AskUserQuestion
35
+ consumer (per-item action, layer-flip target, stale-item action,
36
+ modify-extended option set), so this class applies broadly.
37
+
38
+ Rendering rule:
39
+
40
+ - `fabric_language === "zh-CN"` → emit the zh-CN variant; pure monolingual, no language mixing inside a single user-facing block.
41
+ - `fabric_language === "en"` → emit the en variant; pure monolingual, no language mixing inside a single user-facing block.
42
+ - `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. `fabric install`), file paths, technical concepts (`Skill`, `SessionStart`, `hook`, `MCP`, `revision_hash`, `pending`, `proven`, `verified`, `draft`).
43
+ - `fabric_language === "match-existing"` or any other value → emit the en variant; pure monolingual.
44
+
45
+ Protected tokens (`fab_review`, `relevance_scope`, `relevance_paths`,
46
+ `narrow`, `broad`, `source_sessions`, `proposed_reason`, `session_context`,
47
+ `pending_path`, `layer`, `team`, `personal`, `knowledge_scope_degraded`,
48
+ `MUST`, `NEVER`, `.fabric/knowledge/`, etc.) are NEVER translated — they
49
+ appear verbatim in both language variants. The bilingualization scope is
50
+ prose ONLY.
51
+
52
+ ### AskUserQuestion i18n Policy (value vs label)
53
+
54
+ When this skill issues an `AskUserQuestion`, the `header` and `question`
55
+ strings are user-facing prose → translated per `fabric_language`. The
56
+ `options[]` array entries are **routing keys** consumed by the skill
57
+ state machine — they MUST remain English regardless of `fabric_language`.
58
+
59
+ Canonical options arrays used by this skill (every value below stays
60
+ English in BOTH language variants):
61
+
62
+ - Per-item action: `["approve", "reject", "modify", "defer", "skip"]`
63
+ - Per-stale-item action (health mode): `["defer", "demote", "skip"]`
64
+ - Layer-flip target: `["team", "personal"]`
65
+ - Modify-extended (import-origin narrow-scope nudge):
66
+ `["narrow scope", "edit summary", "change layer", "change maturity", "skip"]`
67
+
68
+ Worked example — per-item action (the most common AskUserQuestion in this skill):
69
+
70
+ ```ts
71
+ // EN (fabric_language === "en")
72
+ AskUserQuestion({
73
+ header: "Review pending entry",
74
+ question: "What action for '{title}'? ({pending_path})",
75
+ options: ["approve", "reject", "modify", "defer", "skip"]
76
+ })
77
+
78
+ // zh-CN (fabric_language === "zh-CN")
79
+ AskUserQuestion({
80
+ header: "审核 pending 条目",
81
+ question: "对 '{title}' 执行什么操作?({pending_path})",
82
+ options: ["approve", "reject", "modify", "defer", "skip"] // 不翻译 — routing key
83
+ })
84
+ ```
85
+
86
+ Worked example — layer-flip target:
87
+
88
+ ```ts
89
+ // EN
90
+ AskUserQuestion({
91
+ header: "Layer-flip target",
92
+ question: "Move '{title}' to which layer? (current: {current_layer})",
93
+ options: ["team", "personal"]
94
+ })
95
+
96
+ // zh-CN
97
+ AskUserQuestion({
98
+ header: "Layer 切换目标",
99
+ question: "将 '{title}' 切换到哪一层?(当前: {current_layer})",
100
+ options: ["team", "personal"] // 不翻译 — routing key
101
+ })
102
+ ```
103
+
104
+ Rationale: localizing routing keys would force every routing branch to
105
+ dual-string match (e.g. `if (choice === "approve" || choice === "通过")`),
106
+ which doubles the surface area for protected-token regressions and breaks
107
+ the option-list invariants that downstream tooling (the Skill's own
108
+ `switch` statements over `choice`, plus any future MCP-level audit lint
109
+ that scans for these specific string literals) depends on. Keeping
110
+ `options[]` English-only is contract-locked across all three skills.
111
+
@@ -0,0 +1,103 @@
1
+ # Modify Sub-Flow, Layer-Flip Rules & Narrowing Imported Entries
2
+
3
+ ## Modify Sub-Flow
4
+
5
+ The modify family is the only action group that mutates frontmatter or stable_id. It accepts `changes` of shape `{title?, summary?, layer?, maturity?, tags?, relevance_scope?, relevance_paths?}`.
6
+
7
+ **v2.0.0-rc.37 NEW-12 — explicit split.** Prefer the dedicated action over the legacy combined `modify`:
8
+
9
+ - `action="modify-content"` — scalar edits (title/summary/tags/maturity/relevance_*); stable_id PRESERVED; the server STRIPS any `changes.layer` so this path can never flip layer. Emits `knowledge_slug_renamed` only when slug derives from title.
10
+ - `action="modify-layer"` — the dedicated layer-flip path; `changes.layer` is REQUIRED. The ONLY legal stable_id mutation in the system (see Layer-Flip Rules below).
11
+ - `action="modify"` (legacy alias) — still accepted; routes to content-edit OR layer-flip by whether `changes.layer` is present. New call sites should use the explicit pair.
12
+
13
+ Server semantics (identical regardless of which action selected the path):
14
+
15
+ - **title / summary / tags / maturity changes** → in-place rewrite; stable_id PRESERVED; emits `knowledge_slug_renamed` only when slug derives from title.
16
+ - **layer change** → the ONLY legal stable_id mutation in the system.
17
+
18
+ ## Layer-Flip Rules (the only legal stable_id mutation)
19
+
20
+ Triggered when `changes.layer` differs from current entry layer. Server-side transaction:
21
+
22
+ 1. Allocate new id under target layer via `KnowledgeIdAllocator.allocate(new_layer, type)` (e.g. KT-D-7 in `team/decisions/` flips to KP-D-3 in `personal/decisions/`).
23
+ 2. `git mv <old-layer>/<type>/<old-id>--<slug>.md <new-layer>/<type>/<new-id>--<slug>.md`.
24
+ 3. Append `knowledge_layer_changed` event with `{from_layer, to_layer, prior_stable_id, new_stable_id}`.
25
+ 4. Server response includes `prior_stable_id` and `new_stable_id` — surface BOTH to the user in the roll-up.
26
+
27
+ Skill responsibilities for layer flip:
28
+
29
+ - BEFORE calling fab_review, surface `AskUserQuestion {options: ["team", "personal"]}` to confirm target layer. The default in the question header should reflect the verbatim layer heuristic (default team unless 强 personal signals dominate). This IS a genuine choice — the user must pick.
30
+ - AFTER server returns, render: `Layer flipped: <prior_stable_id> → <new_stable_id>`. Do NOT silently swallow the id change — downstream agents may have cached the prior id.
31
+
32
+ ## Modify Examples
33
+
34
+ ```ts
35
+ // Maturity bump only (no id change)
36
+ mcp__fabric__fab_review({
37
+ action: "modify",
38
+ pending_path: "knowledge/team/decisions/KT-D-0007--single-cjs-hook.md",
39
+ changes: { maturity: "verified" }
40
+ })
41
+
42
+ // Layer flip team → personal (id WILL change)
43
+ mcp__fabric__fab_review({
44
+ action: "modify",
45
+ pending_path: "knowledge/team/guidelines/KT-G-0003--indent-style.md",
46
+ changes: { layer: "personal" }
47
+ })
48
+ ```
49
+
50
+ ---
51
+
52
+ ## Narrowing Imported Entries
53
+
54
+ The fabric-import skill creates pending entries with `relevance_scope=broad` + `relevance_paths=[]` as a deliberate contract — it cannot derive paths from git history. **Narrowing imported entries is fabric-review's responsibility.**
55
+
56
+ ### Detection
57
+
58
+ An entry is "import-origin" when `source_sessions[0]` starts with `fabric-import-` (e.g. `fabric-import-2026-05-10`).
59
+
60
+ ### Pending mode rendering
61
+
62
+ 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:
63
+
64
+ - en: `⚠ Imported (relevance_scope=broad, relevance_paths=[]) — pick 'modify' + say 'narrow to <paths>' to bind scope.`
65
+ - zh-CN: `⚠ Imported (relevance_scope=broad, relevance_paths=[]) — 选择 'modify' 并指定 'narrow to <paths>' 以收紧作用域。`
66
+
67
+ This hint is informational. The user MAY ignore it; broad+[] is a valid final state for cross-cutting knowledge.
68
+
69
+ ### Modify follow-up — narrow scope
70
+
71
+ When the user picks `modify` on an import-origin entry, surface AskUserQuestion with an extended option list. UX i18n Policy class 5 — `header` + `question` translated; `options[]` remain English routing keys:
72
+
73
+ ```ts
74
+ // EN
75
+ AskUserQuestion({
76
+ header: "Modify imported entry",
77
+ question: "What aspect of '{title}' to modify?",
78
+ options: ["narrow scope", "edit summary", "change layer", "change maturity", "skip"]
79
+ })
80
+
81
+ // zh-CN
82
+ AskUserQuestion({
83
+ header: "修改 imported 条目",
84
+ question: "要修改 '{title}' 的哪一项?",
85
+ options: ["narrow scope", "edit summary", "change layer", "change maturity", "skip"] // 不翻译
86
+ })
87
+ ```
88
+
89
+ When user picks "narrow scope":
90
+
91
+ 1. Free-text follow-up. UX i18n Policy class 3 — confirmation prompts:
92
+ - en: `Type relevance_paths (comma-separated globs, e.g. packages/server/src/retry/**, packages/server/src/lib/retry.ts)`
93
+ - zh-CN: `请输入 relevance_paths (逗号分隔的 glob,例如 packages/server/src/retry/**, packages/server/src/lib/retry.ts)`
94
+ 2. Call fab_review action="modify" with:
95
+ ```ts
96
+ changes: { relevance_scope: "narrow", relevance_paths: [<parsed paths>] }
97
+ ```
98
+ 3. Display the resolved frontmatter to confirm.
99
+
100
+ ### Special cases
101
+
102
+ - **Layer=personal entries**: server auto-degrades narrow → broad+[]; surface the `knowledge_scope_degraded` event back to the user.
103
+ - **Non-import-origin entries**: modify can still narrow (just doesn't show this UX nudge — user types it as a normal modify).
@@ -0,0 +1,58 @@
1
+ # Output Contract — fabric-review
2
+
3
+ Bilingual roll-up templates + events.jsonl atomicity constraint referenced from SKILL.md.
4
+
5
+ ## Roll-up Template
6
+
7
+ After each invocation, the skill MUST produce a brief roll-up to the user. UX i18n Policy class 1 — roll-up templates; render per `fabric_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:
8
+
9
+ **en variant** (`fabric_language === "en"`):
10
+
11
+ ```md
12
+ # Review Summary — mode={pending|topic|health|revisit}
13
+ - Listed: N entries
14
+ - Approved: M (new stable_ids: KT-D-12, KT-G-4, KP-P-2)
15
+ - Rejected: R
16
+ - Modified: U (incl. K layer flips)
17
+ - Deferred: D
18
+ - Skipped: S
19
+
20
+ ## Events appended (.fabric/events.jsonl tail)
21
+ - knowledge_promote_started ×M
22
+ - knowledge_promoted ×M
23
+ - knowledge_layer_changed ×K
24
+ - knowledge_rejected ×R
25
+ - knowledge_deferred ×D
26
+ ```
27
+
28
+ **zh-CN variant** (`fabric_language === "zh-CN"`):
29
+
30
+ ```md
31
+ # Review 汇总 — mode={pending|topic|health|revisit}
32
+ - 列出: N 条
33
+ - 已批准: M (新分配 stable_ids: KT-D-12, KT-G-4, KP-P-2)
34
+ - 已驳回: R
35
+ - 已修改: U (含 K 次 layer 切换)
36
+ - 已延后: D
37
+ - 已跳过: S
38
+
39
+ ## 追加事件 (.fabric/events.jsonl 末尾)
40
+ - knowledge_promote_started ×M
41
+ - knowledge_promoted ×M
42
+ - knowledge_layer_changed ×K
43
+ - knowledge_rejected ×R
44
+ - knowledge_deferred ×D
45
+ ```
46
+
47
+ Also surface a one-line `git status` of `.fabric/knowledge/` so the user sees the file moves caused by approve / layer-flip.
48
+
49
+ ## events.jsonl Constraint Note
50
+
51
+ Event lines appended to `.fabric/events.jsonl` are subject to POSIX single-write atomicity: only writes ≤ 4KB (`PIPE_BUF`) are guaranteed atomic via `Bash: echo "..." >> file`. Lines exceeding 4KB risk interleaved corruption under concurrent skill + server writes to the same ledger.
52
+
53
+ Skills MUST ensure:
54
+
55
+ - Each event JSON line is a **single line** (no embedded newlines; escape `\n` in any string value).
56
+ - `session_context` and other free-form text fields **self-truncate** to keep the entire serialized line under 4KB. Suggested per-field caps: `session_context` first 500 chars; `source_sessions` cap at 5 entries; `recent_paths` cap at 20 entries; `user_messages_summary` first 500 chars.
57
+ - If approaching the 4KB ceiling after the per-field caps, drop optional fields (e.g. tags / extra metadata) **before** truncating semantic content (the summary / context that carries the actual observation).
58
+ - The promote / reject / modify / defer events listed above are emitted by the MCP server via `appendEventLedgerEvent` and are already length-bounded server-side; this constraint applies to any event the skill itself appends directly to the ledger (rare, but possible for diagnostic markers).
@@ -0,0 +1,155 @@
1
+ # Per-Mode Flows — fabric-review
2
+
3
+ Full bilingual rendering blocks + step-by-step procedures for the four modes referenced from SKILL.md.
4
+
5
+ ---
6
+
7
+ ## Mode: pending — Approve / Reject / Modify Backlog
8
+
9
+ 1. Call `fab_review` with `action: "list"`, no filters (or `filters.layer="both"` if user explicitly mentioned both layers).
10
+ 2. Server returns `items[]` (each = `{pending_path, type, layer, maturity, tags?, title?, summary?}`).
11
+ 3. Before presenting, perform **Semantic Check** (see `ref/semantic-check.md`) by issuing one or more `action: "search"` calls scoped by `filters.type` to surface possible duplicates / contradictions among already-canonical entries.
12
+ 4. For each pending item, render a per-item block. v2.0.0-rc.7 T6: render `proposed_reason` (frontmatter) + `## Why proposed` line (body, 1-line enum explanation) + first line of `## Session context` so future-self has full context without re-reading the transcript. UX i18n Policy class 1 — roll-up templates; protected tokens (`pending_path`, `layer`, `team`, `decisions`, `proposed_reason`, `Tags`, etc.) appear verbatim in BOTH variants:
13
+
14
+ **en variant** (`fabric_language === "en"`):
15
+
16
+ ```md
17
+ ## [type=decisions] [layer=team] pending_path=knowledge/pending/decisions/single-cjs-hook.md
18
+ Title: Single .cjs hook across clients
19
+ Summary: stdout JSON shape is identical across the three clients; one script suffices.
20
+ Maturity: draft Tags: [hook, cli]
21
+ Proposed reason: decision-confirmation — ≥2 alternatives weighed; rationale stated.
22
+ Session context: Session goal: ship Stop-hook for v2 release.
23
+ ⚠ Possible duplicate of KT-D-0007 (LLM subjective dup/subsumption judgement; thresholds intentionally not quantified)
24
+ ```
25
+
26
+ **zh-CN variant** (`fabric_language === "zh-CN"`):
27
+
28
+ ```md
29
+ ## [type=decisions] [layer=team] pending_path=knowledge/pending/decisions/single-cjs-hook.md
30
+ 标题: 单 .cjs hook 跨客户端
31
+ 摘要: 三客户端 stdout JSON 格式一致,单脚本即可。
32
+ 成熟度: draft Tags: [hook, cli]
33
+ Proposed reason: decision-confirmation — ≥2 候选方案经权衡后确认选型。
34
+ Session context: Session goal: ship Stop-hook for v2 release.
35
+ ⚠ 可能重复 KT-D-0007 (LLM 主观判断 dup/subsumption;具体阈值不可量化)
36
+ ```
37
+
38
+ The Skill MUST read `proposed_reason` from the pending file's frontmatter (parse the YAML block, key `proposed_reason`) and the `## Why proposed` line / first non-blank line of `## Session context` from the body. If either is missing on a pre-rc.7 pending entry, render the legacy fallback (UX i18n Policy class 1):
39
+
40
+ - en: `Proposed reason: <legacy entry, no reason recorded>` and `Session context: <not recorded>`
41
+ - zh-CN: `Proposed reason: <历史条目,未记录 reason>` 与 `Session context: <未记录>`
42
+
43
+ …so the reviewer can still proceed.
44
+
45
+ 5. Surface a per-item AskUserQuestion. UX i18n Policy class 5 — `header` + `question` translated; `options[]` array remain English routing keys:
46
+
47
+ ```ts
48
+ // EN
49
+ AskUserQuestion({
50
+ header: "Review pending entry",
51
+ question: "What action for 'Single .cjs hook across clients'?",
52
+ options: ["approve", "reject", "modify", "defer", "skip"]
53
+ })
54
+
55
+ // zh-CN
56
+ AskUserQuestion({
57
+ header: "审核 pending 条目",
58
+ question: "对 '单 .cjs hook 跨客户端' 执行什么操作?",
59
+ options: ["approve", "reject", "modify", "defer", "skip"] // 不翻译
60
+ })
61
+ ```
62
+
63
+ 6. Route the user's choice:
64
+ - `approve` → accumulate pending_path into a batch; flush via single `fab_review action="approve"` with `pending_paths=[…]` after the loop ends.
65
+ - `reject` → ask the user for a one-line reason via free-text follow-up; call `fab_review action="reject"` with `pending_paths=[path]` and `reason`.
66
+ - `modify` → see `ref/modify-flow.md`.
67
+ - `defer` → call `fab_review action="defer"` with `pending_paths=[path]`; optional `until` ISO datetime if the user supplies one ("defer 2 weeks" → compute and set).
68
+ - `skip` → no MCP call; move to next item.
69
+
70
+ 7. After the loop, display a roll-up: counts by action, list of newly-allocated `stable_id`s (from approve output), and tail of `.fabric/events.jsonl` showing the appended events. See `ref/output-contract.md` for the bilingual rollup template.
71
+
72
+ ---
73
+
74
+ ## Mode: topic — Search & Surface Findings
75
+
76
+ 1. Extract the topic keyword(s) from the user's message (e.g. "find about deepMerge" → query="deepMerge").
77
+ 2. Call `fab_review action="search"` with `query` and any obvious filters (if user said "team-only" → `filters.layer="team"`).
78
+ 3. Server returns `items[]` ranked by relevance — these are entries already in `.fabric/knowledge/{layer}/{type}/` (NOT pending), unless `filters` says otherwise.
79
+ 4. Render top-N (cap at `review_topic_result_cap`, config-resolved, default 8) results with title / summary / pending_path.
80
+ 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.
81
+ 6. NEVER surface a per-item AskUserQuestion just for browsing — only when the user signals an action verb.
82
+
83
+ ---
84
+
85
+ ## Mode: health — Corpus Health & Stale Detection
86
+
87
+ 1. Call `fab_review action="list"` with `filters.maturity="draft"` (or no filter for full corpus inspection).
88
+ 2. Tail `.fabric/events.jsonl` for layer_changed / demoted / rejected counts in the trailing 30 days.
89
+ 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.
90
+ 4. Render a corpus dashboard. UX i18n Policy class 1 — roll-up templates; render per `fabric_language`:
91
+
92
+ **en variant**:
93
+
94
+ ```md
95
+ ## Health Overview
96
+ - Pending: 12 entries (oldest 18d) — recommend `defer` or `reject`
97
+ - Drafts: 8 (3 are stale candidates: KP-G-3, KP-G-5, KT-P-9)
98
+ - Layer flips (30d): 2
99
+ - Rejections (30d): 1
100
+ ```
101
+
102
+ **zh-CN variant**:
103
+
104
+ ```md
105
+ ## 健康度总览
106
+ - Pending: 12 条 (最旧 18 天) — 建议 `defer` 或 `reject`
107
+ - Drafts: 8 条 (3 条为陈旧候选: KP-G-3, KP-G-5, KT-P-9)
108
+ - Layer 切换 (30 天): 2
109
+ - 已驳回 (30 天): 1
110
+ ```
111
+
112
+ 5. For each stale candidate, surface AskUserQuestion. UX i18n Policy class 5 — `header` + `question` translated; `options[]` remain English routing keys:
113
+
114
+ ```ts
115
+ // EN
116
+ AskUserQuestion({
117
+ header: "Stale entry triage",
118
+ question: "Action for stale entry '{title}'?",
119
+ options: ["defer", "demote", "skip"]
120
+ })
121
+
122
+ // zh-CN
123
+ AskUserQuestion({
124
+ header: "陈旧条目处理",
125
+ question: "对陈旧条目 '{title}' 执行什么操作?",
126
+ options: ["defer", "demote", "skip"] // 不翻译
127
+ })
128
+ ```
129
+
130
+ 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).
131
+
132
+ ---
133
+
134
+ ## Mode: revisit — Specific Entry Deep Dive
135
+
136
+ 1. The user referenced a specific entry (by id `KT-D-7` or by slug `single-cjs-hook`).
137
+ 2. Call `fab_review action="list"` with `filters` narrowed by best-guess fields; if the entry is canonical (has stable_id), `Read` the file directly at `.fabric/knowledge/{layer}/{type}/<id>--<slug>.md`.
138
+ 3. Display the full body (frontmatter + content). Tail the events.jsonl for any history events tagged with this stable_id.
139
+ 4. Surface AskUserQuestion `{options: ["approve", "modify", "reject", "skip"]}` only if the entry is still pending; for canonical entries the only mutation path is `modify` (incl. layer flip).
140
+
141
+ ---
142
+
143
+ ## Mode Inference — Examples & Anti-Pattern (companion to SKILL.md table)
144
+
145
+ ### Inference Examples (Sample User Messages → Expected Mode)
146
+
147
+ - "review the pending knowledge" → `pending` (Step 1 keyword "review pending")
148
+ - "find anything about deepMerge" → `topic` (Step 1 keyword "find … about")
149
+ - "anything stale in our knowledge base?" → `health` (Step 1 keyword "stale")
150
+ - "look at KT-D-7" → `revisit` (Step 1 keyword "look at <id>")
151
+ - (Stop-hook fired with signal=review, no user typing) → `pending` (Step 3 default, overflow threshold tripped)
152
+
153
+ ### Anti-Pattern (Hard Rule restatement)
154
+
155
+ NEVER emit an `AskUserQuestion` whose options include {pending, maintain} (or the legacy {topic, health, revisit} aliases). The user does not pick the mode. If inference is genuinely ambiguous after both steps, default to `pending` and proceed; the user can always cancel and redirect. (rc.37 NEW-12 collapsed the 4 legacy modes to 2: `pending` + `maintain`.)
@@ -0,0 +1,26 @@
1
+ # Semantic Check Guidance — fabric-review
2
+
3
+ LLM-assisted duplicate / contradiction / subsumption detection during `pending` mode (and on demand during `topic` mode).
4
+
5
+ > Boundary B (locked): "extraction classification / layer inference / slug naming / mode inference / **semantic dedup** → Skill (LLM); pending file write / frontmatter assembly / idempotency check / counter mgmt / layer-flip transaction / atomic promote → MCP (deterministic)"
6
+
7
+ Semantic check is the LLM's job — the MCP tool does NOT compare meaning.
8
+
9
+ ## Procedure
10
+
11
+ For each pending entry to be presented:
12
+
13
+ 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.
14
+ 2. Compare semantically (LLM judgment, not string match). 三类判断均为 LLM 主观判断 dup/subsumption;具体阈值不可量化(不使用百分比 / 相似度数值伪精度):
15
+ - **Duplicate** — same essential claim. 标题与摘要表达同一核心结论,pending 未提供新证据或新上下文。Flag: `⚠ Possible duplicate of <stable_id>`.
16
+ - **Contradiction** — opposing claims about the same subject. 例:一个 entry 说 "use X",pending 说 "avoid X",且作用域一致。Flag: `⚠ Contradicts <stable_id>`.
17
+ - **Subsumption** — pending fully covered by an existing entry plus extras. Flag: `⚠ Subsumed by <stable_id>; consider modify-to-merge`.
18
+ 3. Surface the flag in the per-item display block (see `per-mode-flows.md` pending mode step 4).
19
+ 4. The user decides:
20
+ - Still approve → flag is informational; pending becomes canonical alongside the existing entry.
21
+ - Modify-to-harmonize → user supplies edits via `modify` action; consider merging language with the existing entry.
22
+ - Reject as duplicate → reason field MUST cite the existing stable_id (e.g. `reason="duplicate of KT-D-7"`).
23
+
24
+ ## What NOT to do
25
+
26
+ 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.
@@ -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.