@fenglimg/fabric-shared 2.2.0-rc.3 → 2.2.0-rc.8

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.
@@ -1,6 +1,10 @@
1
+ import {
2
+ resolveGlobalLocale
3
+ } from "./chunk-2GLIAZ5M.js";
4
+
1
5
  // src/i18n/locales/en.ts
2
6
  var enMessages = {
3
- "cli.main.description": "Fabric CLI \u2014 feeds your project's decisions, pitfalls & conventions to your AI assistant automatically, so it stops re-learning them every session.\n\nThree-step mental model:\n Install (\u88C5) - fabric install one-shot project setup\n Configure (\u914D) - fabric config interactive configuration panel\n Run (\u8DD1) - fabric serve launch the local MCP HTTP service\n fabric doctor run target-state diagnostics\n\nExamples:\n fabric install install Fabric in the current project\n fabric config open the interactive configuration panel\n fabric serve --port 7373 start the MCP HTTP service\n fabric doctor --fix repair derived Fabric state\n fabric uninstall --dry-run preview uninstall without removing files",
7
+ "cli.main.description": "Fabric CLI \u2014 feeds your project's decisions, pitfalls & conventions to your AI assistant automatically, so it stops re-learning them every session.\n\nThree-step mental model:\n Install (\u88C5) - fabric install one-shot project setup\n Configure (\u914D) - fabric config interactive configuration panel\n Maintain (\u8DD1) - fabric doctor run target-state diagnostics\n fabric sync sync mounted knowledge stores\n\nExamples:\n fabric install install Fabric in the current project\n fabric config open the interactive configuration panel\n fabric doctor --fix repair derived Fabric state\n fabric doctor --fix-knowledge repair knowledge entry state\n fabric sync pull/rebase and push mounted stores\n fabric uninstall --dry-run preview uninstall without removing files",
4
8
  "cli.shared.created": "Created",
5
9
  "cli.shared.skipped": "Skipped",
6
10
  "cli.shared.next": "Next",
@@ -15,36 +19,36 @@ var enMessages = {
15
19
  "cli.shared.loading": "loading",
16
20
  "cli.shared.refresh": "Refresh",
17
21
  "cli.shared.target-invalid": "Target must be an existing directory: {target}",
22
+ "cli.shared.target-invalid.action-hint": "Choose an existing project directory, or create it before running the command again.",
18
23
  "cli.shared.template-not-found": "Template not found: {path}",
19
24
  "cli.shared.invalid-host-empty": "Invalid host: <empty>",
20
25
  "cli.shared.invalid-port": "Invalid port: {value}",
21
26
  "cli.shared.error": "Error",
22
- "cli.approve.description": "Approve drifted human-lock entries from the command line.",
23
- "cli.approve.args.all.description": "Approve all drifted human-lock entries without prompting.",
24
- "cli.approve.args.interactive.description": "Prompt before approving each drifted human-lock entry.",
25
- "cli.approve.args.target.description": "Target project path, default is the current working directory.",
26
- "cli.approve.no-drift": "No drift entries found.",
27
- "cli.approve.prompt": "Approve this entry? [y/N] ",
28
- "cli.approve.approved-one": "Approved {location}",
29
- "cli.approve.skipped-one": "Skipped {location}",
30
- "cli.approve.summary": "Approved {approved}/{total} drift entries. Skipped {skipped}.",
31
- "cli.approve.table.expected": "Expected",
32
- "cli.approve.table.current": "Current",
33
- "cli.bootstrap.description": "Install Fabric bootstrap prompts for supported AI clients.",
34
- "cli.bootstrap.install.description": "Copy Fabric bootstrap templates into native client locations.",
35
- "cli.bootstrap.install.args.clients.description": "Optional comma-separated client filter, for example claude,cursor,codex.",
36
- "cli.bootstrap.install.no-targets": "No bootstrap targets detected. Pass --clients claude,cursor,codex to install explicitly.",
37
- "cli.bootstrap.install.installed": "Installed {path}",
38
- "cli.bootstrap.install.skipped-header": "Skipped {path}: Fabric Bootstrap header already present.",
39
- "cli.bootstrap.install.prepended": "Prepended {path}",
40
- "cli.bootstrap.errors.unknown-client": 'Unknown client "{client}". Use a comma-separated list such as claude,cursor,codex.',
27
+ // EPIC-011: Grouped help display i18n keys
28
+ "cli.help.group.setup.install": "Initialize Fabric in this repository",
29
+ "cli.help.group.setup.config": "Configure Fabric settings",
30
+ "cli.help.group.daily.sync": "Sync team knowledge with remote stores",
31
+ "cli.help.group.daily.info": "Show project status",
32
+ "cli.help.group.diagnostic.doctor": "Check Fabric health and repair issues",
33
+ "cli.help.group.advanced.store": "Manage knowledge stores (see: fabric store --help)",
34
+ "cli.help.group.advanced.whoami": "Show machine identity",
35
+ "cli.help.group.advanced.whoami.deprecated": "deprecated \u2192 info --global",
36
+ "cli.help.group.advanced.status": "Show project status",
37
+ "cli.help.group.advanced.status.deprecated": "deprecated \u2192 info",
38
+ "cli.help.group.advanced.scope-explain": "Explain scope",
39
+ "cli.help.group.advanced.scope-explain.deprecated": "deprecated \u2192 info scope",
40
+ // v2.1 hidden-command i18n keys cleanup: approve/bootstrap/hooks/human-lint/
41
+ // ledger-append/pre-commit/scan/sync-meta/update commands removed from CLI
42
+ // surface in v2.0.0-rc.18. Keys intentionally retained for backward compat
43
+ // with external tooling that may still reference them. Remove in v2.2
44
+ // if no external consumers surface.
41
45
  "cli.config.description": "Open the interactive Fabric configuration panel (language, knowledge layer, audit mode, hint windows, MCP client wiring, etc.).\n\nExamples:\n fabric config open the interactive panel\n fabric config --target /path edit configuration for a specific project",
42
46
  "cli.config.args.target.description": "Target project directory (defaults to cwd).",
43
47
  "cli.config.clients.claude": "Claude Code CLI",
44
48
  "cli.config.install.description": "Install Fabric MCP server entries into detected client configs.",
45
- "cli.config.install.args.clients.description": "Optional comma-separated client filter, for example cursor,codex.",
49
+ "cli.config.install.args.clients.description": "Optional comma-separated client filter, for example cc,codex.",
46
50
  "cli.config.install.args.dry-run.description": "Preview detected write operations without modifying files.",
47
- "cli.config.errors.unknown-client": 'Unknown client "{client}". Use a comma-separated list such as cursor,codex.',
51
+ "cli.config.errors.unknown-client": 'Unknown client "{client}". Use a comma-separated list such as cc,codex.',
48
52
  "cli.config.errors.expected-object": "Expected object in {path}",
49
53
  "cli.config.install.no-configs": "No Fabric MCP client config detected. Create the client directory or set clientPaths in fabric.config.json.",
50
54
  "cli.config.install.no-config-path": "Skipping {client}: no config path detected.",
@@ -72,7 +76,7 @@ var enMessages = {
72
76
  "cli.config.errors.no-enum-options": "No enum options available for this field \u2014 skipping.",
73
77
  // Per-field labels (11 total: 2 Group A + 8 Group B + 1 Group C).
74
78
  "cli.config.fields.fabric_language.label": "Language",
75
- "cli.config.fields.fabric_language.description": "Language used by Fabric hooks and Skills output.",
79
+ "cli.config.fields.fabric_language.description": "Fabric's global language base tone (UI + knowledge), saved to ~/.fabric/fabric-global.json.",
76
80
  "cli.config.fields.default_layer_filter.label": "Default knowledge layer",
77
81
  "cli.config.fields.default_layer_filter.description": "Default layer scope for knowledge listings (team / personal / both).",
78
82
  "cli.config.fields.archive_hint_hours.label": "Archive hint window (hours)",
@@ -93,7 +97,11 @@ var enMessages = {
93
97
  "cli.config.fields.maintenance_hint_cooldown_days.description": "Cooldown (in days) before the maintenance hint can fire again.",
94
98
  "cli.config.fields.audit_mode.label": "Audit mode",
95
99
  "cli.config.fields.audit_mode.description": "Audit verbosity for human-lock + drift detection (strict / warn / off).",
96
- "cli.doctor.description": "Run Fabric target-state diagnostics (meta sync, knowledge index, bootstrap, events ledger, human-lock drift).\n\nExamples:\n fabric doctor read-only diagnostics report\n fabric doctor --fix repair derived state (meta + indexes)\n fabric doctor --fix-knowledge apply lint mutations (demote / archive)\n fabric doctor --json --strict machine-readable output, warnings as errors",
100
+ "cli.config.fields.nudge_mode.label": "Nudge level",
101
+ "cli.config.fields.nudge_mode.description": "Preset for human-visible nudges (silent / minimal / normal / verbose). Governs only the human channel \u2014 never the knowledge injected to the AI.",
102
+ "cli.config.fields.embed_enabled.label": "Vector semantic search",
103
+ "cli.config.fields.embed_enabled.description": "Enable vector semantic recall (true / false). Note: turning this on also needs `fabric install --enable-embed` for the host-side setup (fastembed + model cache); flipping it here alone does not enable it.",
104
+ "cli.doctor.description": "Run Fabric target-state diagnostics (meta sync, knowledge index, bootstrap, events ledger, human-lock drift).\n\nExamples:\n fabric doctor read-only diagnostics report\n fabric doctor --fix repair derived state (meta + indexes)\n fabric doctor --fix-knowledge apply lint mutations (counter / archive / cache)\n fabric doctor --json machine-readable output",
97
105
  "doctor.section.fixable": "Fixable errors:",
98
106
  "doctor.section.manual": "Manual errors:",
99
107
  "doctor.section.warnings": "Warnings:",
@@ -179,16 +187,16 @@ var enMessages = {
179
187
  "cli.doctor.args.fix.description": "Repair derived Fabric state (meta + indexes).",
180
188
  "cli.doctor.args.json.description": "Print the doctor report as JSON.",
181
189
  "cli.doctor.args.strict.description": "Treat warnings as failures.",
182
- "cli.doctor.args.fix-knowledge.description": "Apply knowledge lint mutations: demote orphaned canonical entries, archive stale drafts, and bump drifted index counters. Default doctor run remains report-only.",
190
+ "cli.doctor.args.fix-knowledge.description": "Apply knowledge lint mutations: archive overdue pending drafts, floor drifted per-store id counters, and prune stale session-hint caches. Decay lints (orphan demote / stale archive) are report-only \u2014 remediate those via the fab_review flow. Default doctor run remains report-only.",
183
191
  "cli.doctor.args.yes.description": "Skip the --fix-knowledge safety confirm. Required for non-tty invocations unless FABRIC_NONINTERACTIVE=1 is set in the environment.",
184
192
  // rc.35 TASK-12 (P0-11): --verbose unfolds maintainer-audience hints.
185
193
  "cli.doctor.args.verbose.description": "Show all action hints including maintainer-audience ones (Fabric contributors editing the source tree). By default these are folded for npm end users.",
186
194
  "doctor.maintainer-hint-folded": "(maintainer-only remediation \u2014 re-run with `fabric doctor --verbose` to see)",
187
- "cli.doctor.errors.fix-knowledge-fix-mutually-exclusive": "--fix-knowledge and --fix cannot be combined. --fix-knowledge mutates user knowledge state (demote/archive); --fix repairs derived state (meta/index). Run them separately.",
195
+ "cli.doctor.errors.fix-knowledge-fix-mutually-exclusive": "--fix-knowledge and --fix cannot be combined. --fix-knowledge mutates user knowledge state (archive/counter/cache); --fix repairs derived state (meta/index). Run them separately.",
188
196
  // rc.20 TASK-05: --cite-coverage report flags. Read-only; mutually exclusive with --fix/--fix-knowledge.
189
197
  "cli.doctor.args.cite-coverage.description": "Generate cite policy adherence report (read-only; skips standard inspections)",
190
198
  "cli.doctor.args.since.description": "Time window for cite coverage (e.g. 7d, 24h, 30m)",
191
- "cli.doctor.args.client.description": "Filter cite coverage by client (cc|codex|cursor|all)",
199
+ "cli.doctor.args.client.description": "Filter cite coverage by client (cc|codex|all)",
192
200
  // v2.0.0-rc.24 TASK-10: --layer filters cite contract audit by KB layer (team|personal|all).
193
201
  "cli.doctor.args.layer.description": "Filter cite contract audit by KB layer (team|personal|all)",
194
202
  "cli.doctor.errors.cite-coverage-mutex": "--cite-coverage cannot be combined with --fix or --fix-knowledge",
@@ -203,7 +211,7 @@ var enMessages = {
203
211
  "doctor.conflict.verdict.similar": "similar (possible duplicate)",
204
212
  "doctor.conflict.verdict.unknown": "review (possible duplicate or conflict)",
205
213
  "cli.doctor.errors.invalid-since": "Invalid --since value: {input}. Expected duration like 7d, 24h, 30m or epoch ms.",
206
- "cli.doctor.errors.invalid-client": "Invalid --client value: {input}. Expected cc, codex, cursor, or all.",
214
+ "cli.doctor.errors.invalid-client": "Invalid --client value: {input}. Expected cc, codex, or all.",
207
215
  "cli.doctor.errors.invalid-layer": "Invalid --layer value: {input}. Expected team, personal, or all.",
208
216
  // rc.23 TASK-007 (a-C2): --enrich-descriptions flag set. Back-fills the
209
217
  // four description-grade frontmatter fields on canonical knowledge entries.
@@ -212,14 +220,10 @@ var enMessages = {
212
220
  "cli.doctor.args.dry-run.description": "With --enrich-descriptions --auto or --fix: preview the planned changes without writing to disk. The fix-dry-run output mirrors --fix's fixable_errors list but executes no mutations.",
213
221
  // v2.0.0-rc.33 W4-B1 (T6 P2): --fix --dry-run banner — printed before the standard report so users see no mutations were applied.
214
222
  "cli.doctor.fix-dry-run-banner": "[dry-run] No mutations were applied. The fixable_errors list below shows what `fabric doctor --fix` would address; rerun without --dry-run to actually fix.",
223
+ "cli.doctor.unbound-project-backfilled": "Backfilled project-scope binding for store '{alias}' \u2192 project '{project}' (minted project_id + active_project).",
215
224
  "cli.doctor.errors.enrich-descriptions-mutex": "--enrich-descriptions cannot be combined with --fix, --fix-knowledge, or --cite-coverage. Run them separately.",
216
225
  "doctor.enrich.allComplete": "All canonical knowledge entries already declare intent_clues / tech_stack / impact / must_read_if.",
217
226
  // rc.26 TASK-02a: doctor foundation-batch check messages.
218
- "doctor.check.bootstrap_marker_migration.name": "Bootstrap marker migration",
219
- "doctor.check.bootstrap_marker_migration.ok": "No legacy fabric:knowledge-base markers detected in bootstrap target files.",
220
- "doctor.check.bootstrap_marker_migration.message.singular": "{count} file still carry the legacy fabric:knowledge-base bootstrap marker: {list}.",
221
- "doctor.check.bootstrap_marker_migration.message.plural": "{count} files still carry the legacy fabric:knowledge-base bootstrap marker: {list}.",
222
- "doctor.check.bootstrap_marker_migration.remediation": "Run `fabric doctor --fix` to migrate to fabric:bootstrap marker",
223
227
  "doctor.check.bootstrap_snapshot_drift.name": "Bootstrap snapshot drift",
224
228
  "doctor.check.bootstrap_snapshot_drift.message.drift": ".fabric/AGENTS.md content diverges byte-for-byte from BOOTSTRAP_CANONICAL.",
225
229
  "doctor.check.bootstrap_snapshot_drift.remediation.drift": "Run `fabric doctor --fix` to restore canonical bootstrap snapshot",
@@ -235,17 +239,7 @@ var enMessages = {
235
239
  "doctor.check.bootstrap_anchor.message.missing": "Neither AGENTS.md nor CLAUDE.md exists at the repo root. Fabric requires a bootstrap anchor file at the project root.",
236
240
  "doctor.check.bootstrap_anchor.remediation.missing": "Run `fabric install` to generate the AGENTS.md / CLAUDE.md bootstrap anchor at the repo root.",
237
241
  "doctor.check.bootstrap_anchor.ok": "Bootstrap anchor present at repo root: {present}.",
238
- "doctor.check.baseline_filename_format.name": "Baseline filename format",
239
- "doctor.check.baseline_filename_format.ok": "All baseline knowledge files use the canonical `${id}--${slug}.md` filename format.",
240
- "doctor.check.baseline_filename_format.message.singular": "{count} baseline knowledge file uses the deprecated bare-slug filename format and must be migrated to `${id}--${slug}.md`. First: {detail}.",
241
- "doctor.check.baseline_filename_format.message.plural": "{count} baseline knowledge files use the deprecated bare-slug filename format and must be migrated to `${id}--${slug}.md`. First: {detail}.",
242
242
  // v2.0.0-rc.33 W3-2 (T6 #5): reference the file names from the message so users can copy-paste rm targets rather than grep for them.
243
- "doctor.check.baseline_filename_format.remediation": "Manually rm the bare-slug baseline file(s) listed in the message (e.g. `rm <file from message>`). The baseline pipeline was removed in rc.23 and is no longer an auto-fix path.",
244
- "doctor.check.knowledge_dir_missing.name": "Knowledge layout",
245
- "doctor.check.knowledge_dir_missing.message.singular": "{count} required knowledge subdir is missing: {list}.",
246
- "doctor.check.knowledge_dir_missing.message.plural": "{count} required knowledge subdirs are missing: {list}.",
247
- "doctor.check.knowledge_dir_missing.remediation": "Run `fabric doctor --fix` to create the missing .fabric/knowledge/* subdirectories.",
248
- "doctor.check.knowledge_dir_missing.ok": "All {count} required .fabric/knowledge/* subdirectories exist.",
249
243
  "doctor.check.forensic.name": "Scan evidence",
250
244
  "doctor.check.forensic.message.missing.singular": "{error} Live scan detects {frameworkKind} with {count} entry point.",
251
245
  "doctor.check.forensic.message.missing.plural": "{error} Live scan detects {frameworkKind} with {count} entry points.",
@@ -255,27 +249,27 @@ var enMessages = {
255
249
  "doctor.check.forensic.ok": ".fabric/forensic.json is valid for {frameworkKind}.",
256
250
  "doctor.check.agents_meta.name": "Agents metadata",
257
251
  "doctor.check.agents_meta.message.missing": ".fabric/agents.meta.json is missing.",
258
- "doctor.check.agents_meta.remediation.missing": "Run `fabric doctor --fix` to rebuild agents.meta.json from .fabric/knowledge/.",
252
+ "doctor.check.agents_meta.remediation.missing": "No action needed for store-backed knowledge. Project-local agents.meta rebuilds are retired.",
259
253
  "doctor.check.agents_meta.message.invalid-default": ".fabric/agents.meta.json is invalid.",
260
254
  // rc.35 TASK-09 (P0-14): humanised parse-failure messages.
261
255
  "doctor.check.agents_meta.message.invalid-zod": ".fabric/agents.meta.json fails schema validation \u2014 {issues}. The file was likely written by an incompatible fabric CLI version, or hand-edited.",
262
256
  "doctor.check.agents_meta.message.invalid-from-old-cli": ".fabric/agents.meta.json fails schema validation because the GLOBAL `fabric` CLI on PATH ({version}) is older than the minimum-supported {minVersion}. The schema gained backward-compatible singular\u2192plural normalisation in rc.31; older CLIs cannot parse the result they themselves write back.",
263
- "doctor.check.agents_meta.remediation.invalid": "Run `fabric doctor --fix` to let reconcile rebuild agents.meta.json from the .fabric/knowledge/ disk ground-truth (rc.31+ auto-migrates legacy singular knowledge_type values to canonical plural; do NOT manually delete agents.meta.json \u2014 you would lose counters envelope and promote-ledger associations).",
264
- "doctor.check.agents_meta.message.stale": ".fabric/agents.meta.json revision {revision} does not match .fabric/knowledge derived revision {computedRevision}.",
265
- "doctor.check.agents_meta.message.stale_hash_equal": ".fabric/agents.meta.json content is aligned with .fabric/knowledge (revision {revision}) but the mtime/counters derived state is out of date. Benign.",
266
- "doctor.check.agents_meta.remediation.stale": "Benign \u2014 engine auto-heals on next plan-context/get-sections call. Run `fabric doctor --fix` for explicit reconciliation.",
267
- "doctor.check.agents_meta.ok": ".fabric/agents.meta.json revision {revision} is aligned with .fabric/knowledge.",
257
+ "doctor.check.agents_meta.remediation.invalid": "Project-local agents.meta is retired. Run `fabric install` to refresh client bootstrap, and keep knowledge in mounted stores under ~/.fabric/stores/.",
258
+ "doctor.check.agents_meta.message.stale": ".fabric/agents.meta.json revision {revision} does not match the retired local derived revision {computedRevision}.",
259
+ "doctor.check.agents_meta.message.stale_hash_equal": ".fabric/agents.meta.json content is aligned with the retired local derived revision {revision}; this check is legacy-only.",
260
+ "doctor.check.agents_meta.remediation.stale": "No project-local reconciliation is performed anymore; mounted stores are read directly.",
261
+ "doctor.check.agents_meta.ok": "Legacy agents.meta revision {revision} is present; store-backed knowledge does not depend on it.",
268
262
  "doctor.check.rule_content_refs.name": "Rule content refs",
269
263
  "doctor.check.rule_content_refs.message.unavailable": "Cannot inspect content_ref entries until agents.meta.json is valid.",
270
264
  "doctor.check.rule_content_refs.remediation.unavailable": "Fix agents.meta.json first: run `fabric doctor --fix`.",
271
- "doctor.check.rule_content_refs.message.outside.singular": "{count} content_ref entry is outside .fabric/knowledge.",
272
- "doctor.check.rule_content_refs.message.outside.plural": "{count} content_ref entries are outside .fabric/knowledge.",
265
+ "doctor.check.rule_content_refs.message.outside.singular": "{count} legacy content_ref entry is outside the retired local knowledge root.",
266
+ "doctor.check.rule_content_refs.message.outside.plural": "{count} legacy content_ref entries are outside the retired local knowledge root.",
273
267
  // v2.0.0-rc.33 W3-2 (T6 #12): project rules forbid hand-editing agents.meta.json (see .fabric/AGENTS.md). Direct users through doctor --fix reconcile path instead.
274
268
  "doctor.check.rule_content_refs.remediation.outside": "Run `fabric doctor --fix` to let reconcile auto-prune external content_refs (rc.31+ compatible). Do NOT hand-edit agents.meta.json \u2014 the engine reconciles automatically.",
275
269
  "doctor.check.rule_content_refs.message.missing.singular": "{count} content_ref target is missing. Run `fabric doctor --fix` to reconcile.",
276
270
  "doctor.check.rule_content_refs.message.missing.plural": "{count} content_ref targets are missing. Run `fabric doctor --fix` to reconcile.",
277
- "doctor.check.rule_content_refs.remediation.missing": "Run `fabric doctor --fix` to reconcile agents.meta.json with the files present in .fabric/knowledge/.",
278
- "doctor.check.rule_content_refs.ok": "All content_ref entries resolve to .fabric/knowledge files.",
271
+ "doctor.check.rule_content_refs.remediation.missing": "Project-local content_ref reconciliation is retired; bind/read mounted stores instead.",
272
+ "doctor.check.rule_content_refs.ok": "All legacy content_ref entries resolve; store-backed knowledge is read from mounted stores.",
279
273
  "doctor.check.knowledge_test_index.name": "Knowledge-test index",
280
274
  "doctor.check.knowledge_test_index.remediation.missing": "Run `fabric doctor --fix` to rebuild .fabric/.cache/knowledge-test.index.json.",
281
275
  "doctor.check.knowledge_test_index.remediation.invalid": "Delete .fabric/.cache/knowledge-test.index.json and run `fabric doctor --fix` to regenerate it.",
@@ -304,10 +298,6 @@ var enMessages = {
304
298
  "doctor.check.events_jsonl_health.message.metrics_stale": ".fabric/metrics.jsonl hasn't been updated for {minutes} minutes; the server-side 60s flush may be stalled.",
305
299
  "doctor.check.events_jsonl_health.message.rotation_overdue": ".fabric/events.jsonl hasn't rotated for {days} days; the 6h rotation tick may not be running.",
306
300
  "doctor.check.events_jsonl_health.remediation": "Run `fabric doctor --fix` \u2014 it triggers a rotation AND flushes metrics.jsonl (rc.2 F16: clears idle-buffered metric counters without a server restart). If the warning persists, restart the MCP server so startMetricsFlush + startRotationTick reschedule. If metric_leak fires, audit recent code changes for direct appendEventLedgerEvent calls bypassing bumpCounter for one of the 4 metric-managed event_types.",
307
- "doctor.check.mcp_config_in_wrong_file.name": "Claude MCP config location",
308
- "doctor.check.mcp_config_in_wrong_file.message": ".claude/settings.json contains mcpServers.fabric \u2014 this file is for hooks/permissions only. Run --fix to remove it, then re-run fabric install to write .mcp.json.",
309
- "doctor.check.mcp_config_in_wrong_file.remediation": "Run `fabric doctor --fix` to remove mcpServers.fabric from .claude/settings.json, then run `fabric install` to write .mcp.json.",
310
- "doctor.check.mcp_config_in_wrong_file.ok": "mcpServers.fabric is not in .claude/settings.json.",
311
301
  "doctor.check.event_ledger_partial_write.name": "Event ledger partial write",
312
302
  "doctor.check.event_ledger_partial_write.ok.skipped": "No partial-write check needed (ledger missing or not writable).",
313
303
  "doctor.check.event_ledger_partial_write.message": "events.jsonl has a partial write at byte offset {byteOffset} ({byteLength} corrupted bytes). Run --fix to truncate and preserve corrupted bytes.",
@@ -338,23 +328,18 @@ var enMessages = {
338
328
  "doctor.check.skill_description.message.singular": "{count} SKILL.md description structural issue: {list}. The description field is the host's primary auto-invoke matching signal.",
339
329
  "doctor.check.skill_description.message.plural": "{count} SKILL.md description structural issues: {list}. The description field is the host's primary auto-invoke matching signal.",
340
330
  "doctor.check.skill_description.remediation": "Edit the `description:` field in `packages/cli/templates/skills/<slug>/SKILL.md` frontmatter: (1) non-empty; (2) <60 tokens (chars/3 estimate, ~180 chars); (3) at least one Chinese trigger phrase; (4) at least one English trigger phrase. See W1 description rewrite style. Re-run `fabric install` to sync both client subtrees. For recall verification, run the W1 gemini delegate (see .workflow/.scratchpad/rc33-plan/W1-VERIFY-RESULT.md).",
341
- // v2.0.0-rc.33 W3-3 (P1-3): cite-policy Goodhart pattern detection. Scans 7d of assistant_turn_observed events for 4 anti-patterns (G1 ritual / G2 dismissal abuse / G3 chained-from misuse / G5 placeholder cite). Warning severity — heuristics can false-positive; advisory only.
331
+ // v2.0.0-rc.33 W3-3 (P1-3): cite-policy Goodhart pattern detection. Scans 7d of assistant_turn_observed events for 3 anti-patterns (G1 ritual / G2 dismissal abuse / G5 placeholder cite). Warning severity — heuristics can false-positive; advisory only.
342
332
  "doctor.check.cite_goodhart.name": "Cite-policy Goodhart",
343
333
  "doctor.check.cite_goodhart.ok": "No cite-policy Goodhart patterns detected over the last 7 days.",
344
334
  "doctor.check.cite_goodhart.message.singular": "Detected {count} cite-policy Goodhart pattern: {list}.",
345
335
  "doctor.check.cite_goodhart.message.plural": "Detected {count} cite-policy Goodhart patterns: {list}.",
346
- "doctor.check.cite_goodhart.remediation": "Review the fired patterns: G1 ritual \u2192 the same id repeated as [recalled] suggests the KB should land into a contract instead; G2 dismissal abuse \u2192 > 60% of recalled cites used skip: bypasses contract enforcement, audit skip-reason validity; G3 chained-from misuse \u2192 chained-from tag with no commitment (operators=[] + skip_reason=null), add operators or use a different tag; G5 placeholder cite \u2192 too many bare 'KB: none' / [unspecified], prefer specific sentinels like [no-relevant] / [not-applicable]. For raw data, run `fabric doctor --cite-coverage --since=7d`.",
336
+ "doctor.check.cite_goodhart.remediation": "Review the fired patterns: G1 ritual \u2192 the same id repeated as [applied] suggests the KB should land into a contract instead; G2 dismissal abuse \u2192 > 60% of applied cites used skip: bypasses contract enforcement, audit skip-reason validity; G5 placeholder cite \u2192 too many bare 'KB: none' / [unspecified], prefer specific sentinels like [no-relevant] / [not-applicable]. For raw data, run `fabric doctor --cite-coverage --since=7d`.",
347
337
  // v2.0.0-rc.33 W4-A4 (T5 P2): draft-backlog lint. rc.32 baseline showed 92% of entries stuck at draft, signaling a broken promote loop. Warns when > 50% draft (workspace must have >= 10 entries to compute the ratio — small corpora are noisy).
348
338
  "doctor.check.draft_backlog.name": "Knowledge draft backlog",
349
339
  "doctor.check.draft_backlog.ok": "draft-maturity entry ratio is healthy (< 50%, or workspace too small to compute).",
350
340
  "doctor.check.draft_backlog.message": "{draftCount}/{totalCount} ({pct}%) canonical knowledge entries are stuck at draft maturity \u2014 promote loop is broken (rc.32 baseline was 92%).",
351
341
  "doctor.check.draft_backlog.remediation": "Run `/fabric-review` to triage drafts: approve to promote to verified/proven, reject to drop, modify to fix. A long-standing draft backlog usually means archive produces drafts faster than review can promote them.",
352
342
  // rc.37 NEW-38: knowledge auto-promote (info surface; --fix applies).
353
- "doctor.check.draft_auto_promote.name": "Knowledge auto-promote",
354
- "doctor.check.draft_auto_promote.ok": "No settled drafts awaiting auto-promote (drafts are younger than 14 days or flagged drifted).",
355
- "doctor.check.draft_auto_promote.message": "{count} draft entries have settled for \u226514 days with no drift ({sample}{suffix}) \u2014 eligible for auto-promote to verified. Run `fabric doctor --fix` to apply.",
356
- "doctor.check.draft_auto_promote.remediation": "Run `fabric doctor --fix` to auto-promote these settled drafts to verified (drains draft_backlog); or run `/fabric-review` to triage each manually.",
357
- "doctor.check.draft_auto_promote.fixed": "Auto-promoted {count} settled draft entries \u2192 verified.",
358
343
  // rc.36 TASK-05 (P0-8): empty-tags ratio warn.
359
344
  "doctor.check.knowledge_tags_empty.name": "Knowledge tags coverage",
360
345
  "doctor.check.knowledge_tags_empty.ok": "empty-tag ratio is healthy (\u2264 50%, or workspace too small to compute).",
@@ -364,68 +349,43 @@ var enMessages = {
364
349
  "doctor.check.drift_unconsumed.name": "Knowledge drift unconsumed",
365
350
  "doctor.check.drift_unconsumed.ok": "knowledge_drift_detected events in the last 30 days have been consumed by paired knowledge_demoted, or event volume is too low to compute.",
366
351
  "doctor.check.drift_unconsumed.message": "{driftCount} knowledge_drift_detected events in the last 30 days, but only {demoteCount} knowledge_demoted. Drift > demote by \u2265 5 means part of the drift is going unconsumed \u2014 KB slowly stales.",
367
- "doctor.check.drift_unconsumed.remediation": "Run `fabric doctor --fix` to trigger orphan-demote / stale-archive auto-heal, or invoke `/fabric-review` to manually triage drift-flagged entries.",
352
+ "doctor.check.drift_unconsumed.remediation": "Invoke `/fabric-review` to triage drift-flagged entries \u2014 demote or archive them via the store-write review flow. (The doctor `orphan_demote` / `stale_archive` lints surface decay; they do not auto-heal store-backed knowledge.)",
368
353
  "doctor.check.meta_manually_diverged.name": "Meta manual divergence",
369
354
  "doctor.check.meta_manually_diverged.ok.unreadable": "agents.meta.json not readable; skipping divergence check.",
370
355
  "doctor.check.meta_manually_diverged.message.extra.singular": "agents.meta.json has {count} entry with no backing file on disk. Run --fix to reconcile.",
371
356
  "doctor.check.meta_manually_diverged.message.extra.plural": "agents.meta.json has {count} entries with no backing file on disk. Run --fix to reconcile.",
372
- "doctor.check.meta_manually_diverged.remediation.extra": "Run `fabric doctor --fix` to reconcile agents.meta.json with the rule files currently on disk.",
357
+ "doctor.check.meta_manually_diverged.remediation.extra": "Project-local agents.meta reconciliation is retired; mounted stores are the source of truth.",
373
358
  "doctor.check.meta_manually_diverged.message.hash.singular": "agents.meta.json has {count} entry whose hash does not match the file on disk. Run --fix to reconcile.",
374
359
  "doctor.check.meta_manually_diverged.message.hash.plural": "agents.meta.json has {count} entries whose hash does not match the file on disk. Run --fix to reconcile.",
375
- "doctor.check.meta_manually_diverged.remediation.hash": "Run `fabric doctor --fix` to reconcile agents.meta.json with the current rule file contents.",
360
+ "doctor.check.meta_manually_diverged.remediation.hash": "Project-local agents.meta reconciliation is retired; mounted stores are the source of truth.",
376
361
  "doctor.check.meta_manually_diverged.ok.consistent": "agents.meta.json is consistent with rule files on disk.",
377
362
  "doctor.check.knowledge_dir_unindexed.name": "Knowledge dir unindexed",
378
- "doctor.check.knowledge_dir_unindexed.message.singular": "{count} .md file in .fabric/knowledge/ not indexed in agents.meta.json. Run `fabric doctor --fix` to index the missing knowledge files.",
379
- "doctor.check.knowledge_dir_unindexed.message.plural": "{count} .md files in .fabric/knowledge/ not indexed in agents.meta.json. Run `fabric doctor --fix` to index the missing knowledge files.",
380
- "doctor.check.knowledge_dir_unindexed.remediation": "Run `fabric doctor --fix` to index the missing knowledge files.",
381
- "doctor.check.knowledge_dir_unindexed.ok": "All .fabric/knowledge/ .md files are indexed in agents.meta.json.",
382
- "doctor.check.stable_id_collision.name": "Stable ID collision",
383
- "doctor.check.stable_id_collision.message.singular": 'stable_id "{stableId}" is declared in {fileCount} files: {files}. Edit one of the knowledge files to use a unique stable_id.',
384
- "doctor.check.stable_id_collision.message.plural": '{count} stable_id collisions detected. First: "{stableId}" in {files}. Edit one of the knowledge files to use a unique stable_id.',
363
+ "doctor.check.knowledge_dir_unindexed.message.singular": "{count} legacy local knowledge .md file is not indexed. Move it into a mounted store; non-store knowledge roots are retired.",
364
+ "doctor.check.knowledge_dir_unindexed.message.plural": "{count} legacy local knowledge .md files are not indexed. Move them into a mounted store; non-store knowledge roots are retired.",
365
+ "doctor.check.knowledge_dir_unindexed.remediation": "Use `fabric store bind` / `fabric store switch-write`, then migrate knowledge into the store's knowledge/ tree.",
366
+ "doctor.check.knowledge_dir_unindexed.ok": "No legacy local knowledge indexing action is needed.",
385
367
  // v2.0.0-rc.33 W3-2 (T6 #27): route through fabric-review modify so the canonical id allocator picks a fresh id (avoids hand-counter math).
386
- "doctor.check.stable_id_collision.remediation": "Run `/fabric-review modify <one of the colliding ids from the message>` to let the canonical id allocator reassign it (updates frontmatter + counters + historical cross-refs atomically). Do NOT hand-edit id frontmatter \u2014 it will desync counters.",
387
- "doctor.check.stable_id_collision.ok": "No declared stable_id collisions found in .fabric/knowledge/.",
388
368
  "doctor.check.counter_desync.name": "Knowledge counter desync",
389
369
  "doctor.check.counter_desync.message.singular": "{count} knowledge counter desynced from observed stable_ids. {counterPath} = {current} but observed {observedId}. Run `fabric doctor --fix` to bump counters.",
390
370
  "doctor.check.counter_desync.message.plural": "{count} knowledge counters desynced from observed stable_ids. {counterPath} = {current} but observed {observedId}. Run `fabric doctor --fix` to bump counters.",
391
371
  "doctor.check.counter_desync.remediation": "Run `fabric doctor --fix` to bump agents.meta.json counters to the maximum observed counter value.",
392
372
  "doctor.check.counter_desync.ok": "agents.meta.json counters envelope is consistent with observed stable_ids.",
373
+ "doctor.check.store_counter_drift.name": "Store counter drift",
374
+ "doctor.check.store_counter_drift.message.singular": "{count} store counter is below its on-disk max stable_id ({detail}). The next allocation in that store would re-mint an existing id. Run `fabric doctor --fix` to floor the store counters.json.",
375
+ "doctor.check.store_counter_drift.message.plural": "{count} store counters are below their on-disk max stable_id ({detail}). The next allocation in those stores would re-mint an existing id. Run `fabric doctor --fix` to floor the store counters.json.",
376
+ "doctor.check.store_counter_drift.remediation": "Run `fabric doctor --fix` to floor each store's counters.json at the highest stable_id observed on disk (the floor never lowers \u2014 KT-DEC-0004 monotonic invariant).",
377
+ "doctor.check.store_counter_drift.ok": "Every read-set store's counters.json is floored at its on-disk max stable_id.",
378
+ "doctor.check.store_orphan.name": "Store orphan",
379
+ "doctor.check.store_orphan.message.singular": "{count} store exists on disk but is not registered in the global registry ({detail}); recall / bind cannot see it. Run `fabric doctor --fix` to adopt it (re-register \u2014 never deletes the on-disk tree).",
380
+ "doctor.check.store_orphan.message.plural": "{count} stores exist on disk but are not registered in the global registry (first: {detail}); recall / bind cannot see them. Run `fabric doctor --fix` to adopt them (re-register \u2014 never deletes the on-disk tree).",
381
+ "doctor.check.store_orphan.remediation": "Run `fabric doctor --fix` to adopt the orphan store(s) into the registry (re-register by store_uuid, alias auto-disambiguated on clash; rescue-before-delete \u2014 registers, never deletes on disk).",
382
+ "doctor.check.store_orphan.ok": "No unregistered orphan stores under ~/.fabric/stores.",
393
383
  "doctor.check.preexisting_root_files.name": "Preexisting root markdown",
394
384
  "doctor.check.preexisting_root_files.ok": "No CLAUDE.md or AGENTS.md detected at project root.",
395
385
  "doctor.check.preexisting_root_files.message": "{files} detected at project root. These root files are not auto-loaded by Fabric MCP.",
396
- "doctor.check.preexisting_root_files.remediation": "Move knowledge content to `.fabric/knowledge/{type}/` if you want it available in MCP responses.",
397
- "doctor.check.filesystem_edit_fallback.name": "Filesystem-edit fallback",
398
- "doctor.check.filesystem_edit_fallback.ok": "No orphan canonical knowledge entries detected; events.jsonl promotion trail is complete.",
399
- "doctor.check.filesystem_edit_fallback.message.synthesized.singular": "Synthesized {count} knowledge_promoted event for orphan canonical entries ({sample}{suffix}). Reason='{reason}'.",
400
- "doctor.check.filesystem_edit_fallback.message.synthesized.plural": "Synthesized {count} knowledge_promoted events for orphan canonical entries ({sample}{suffix}). Reason='{reason}'.",
401
- "doctor.check.filesystem_edit_fallback.remediation.synthesized": "These entries were moved into .fabric/knowledge/<type>/ outside fab_review.approve. The synthesized events restore audit-trail completeness.",
402
- "doctor.check.orphan_demote.name": "Knowledge orphan demote",
403
- "doctor.check.orphan_demote.ok": "No canonical knowledge entries exceed their maturity-keyed inactivity threshold.",
404
- "doctor.check.orphan_demote.message.singular": "{count} canonical knowledge entry exceeds their maturity-keyed inactivity threshold (stable={stableDays}d / endorsed={endorsedDays}d / draft={draftDays}d). First: {detail}.",
405
- "doctor.check.orphan_demote.message.plural": "{count} canonical knowledge entries exceed their maturity-keyed inactivity threshold (stable={stableDays}d / endorsed={endorsedDays}d / draft={draftDays}d). First: {detail}.",
406
- "doctor.check.orphan_demote.remediation": "Run `fabric doctor --fix-knowledge` to demote orphan entries one maturity tier.",
407
- "doctor.check.stale_archive.name": "Knowledge stale archive",
408
- "doctor.check.stale_archive.ok": "No draft knowledge entries exceed the additional stale-archive quiet window.",
409
- "doctor.check.stale_archive.message.singular": "{count} draft knowledge entry is stale beyond the demote+{additionalDays}d additional quiet window. First: {detail}.",
410
- "doctor.check.stale_archive.message.plural": "{count} draft knowledge entries are stale beyond the demote+{additionalDays}d additional quiet window. First: {detail}.",
411
- "doctor.check.stale_archive.remediation": "Run `fabric doctor --fix-knowledge` to move stale entries into `.fabric/.archive/<type>/`.",
412
- "doctor.check.pending_overdue.name": "Knowledge pending overdue",
413
- "doctor.check.pending_overdue.ok": "No pending knowledge entries exceed the 14-day review threshold.",
414
- "doctor.check.pending_overdue.message.singular": "{count} pending knowledge entry has been awaiting review for more than {thresholdDays} days. First: {detail}.",
415
- "doctor.check.pending_overdue.message.plural": "{count} pending knowledge entries have been awaiting review for more than {thresholdDays} days. First: {detail}.",
416
- "doctor.check.pending_overdue.remediation": "Review pending entries via the fabric-review Skill (`/fabric-review`) and approve, reject, defer, or modify.",
417
- "doctor.check.stable_id_duplicate.name": "Knowledge stable_id duplicate",
418
- "doctor.check.stable_id_duplicate.ok": "No canonical knowledge files share a stable_id across team / personal trees.",
419
- "doctor.check.stable_id_duplicate.message.singular": "{count} stable_id duplicated across canonical knowledge files (path-decoupled identity invariant). First: {detail}.",
420
- "doctor.check.stable_id_duplicate.message.plural": "{count} stable_ids duplicated across canonical knowledge files (path-decoupled identity invariant). First: {detail}.",
386
+ "doctor.check.preexisting_root_files.remediation": "Move knowledge content into a mounted store's `knowledge/{type}/` tree if you want it available in MCP responses.",
421
387
  // v2.0.0-rc.33 W3-2 (T6 #34): same as stable_id_collision — route through fabric-review modify so allocator handles the new id.
422
- "doctor.check.stable_id_duplicate.remediation": "Run `/fabric-review modify <one of the duplicate ids from the message>` to let the canonical id allocator assign a fresh `<prefix>-<type>-<counter>--<slug>.md` (renames the file + updates frontmatter + corrects counters in one shot).",
423
- "doctor.check.layer_mismatch.name": "Knowledge layer mismatch",
424
- "doctor.check.layer_mismatch.ok": "All canonical knowledge files are physically located under the layer their stable_id prefix declares.",
425
- "doctor.check.layer_mismatch.message.singular": "{count} canonical knowledge file are physically misaligned with their stable_id layer prefix (KT-* must live under team/, KP-* under personal/). First: {detail}.",
426
- "doctor.check.layer_mismatch.message.plural": "{count} canonical knowledge files are physically misaligned with their stable_id layer prefix (KT-* must live under team/, KP-* under personal/). First: {detail}.",
427
388
  // v2.0.0-rc.33 W3-2 (T6 #35): make the skill entry point explicit so users know how to invoke fabric-review.
428
- "doctor.check.layer_mismatch.remediation": "Move the file to the correct layer root (KT-* \u2192 .fabric/knowledge/team/, KP-* \u2192 ~/.fabric/knowledge/personal/), or run `/fabric-review modify <id from the message>` to flip its layer (which renames the stable_id prefix accordingly).",
429
389
  "doctor.check.index_drift.name": "Knowledge index drift",
430
390
  "doctor.check.index_drift.ok": "agents.meta.json counters envelope is at or above the highest existing canonical counter for every (layer, type) pair.",
431
391
  "doctor.check.index_drift.message.singular": "{count} (layer, type) counter slot have drifted below the observed canonical maximum (next allocate would collide). First: {detail}.",
@@ -436,45 +396,15 @@ var enMessages = {
436
396
  "doctor.check.underseeded.message.singular": "Knowledge corpus has only {count} canonical entry (< {threshold} threshold). The plan_context retrieval surface is below its useful floor.",
437
397
  "doctor.check.underseeded.message.plural": "Knowledge corpus has only {count} canonical entries (< {threshold} threshold). The plan_context retrieval surface is below its useful floor.",
438
398
  "doctor.check.underseeded.remediation": "Run the fabric-import Skill (`/fabric-import`) to backfill knowledge from git history and existing docs.",
439
- "doctor.check.narrow_no_paths.name": "Knowledge narrow without paths",
440
- "doctor.check.narrow_no_paths.ok": "No narrow-scope canonical entries have an empty relevance_paths array.",
441
- "doctor.check.narrow_no_paths.message.singular": "{count} narrow-scope canonical entry has an empty relevance_paths array (silent recall risk \u2014 narrow without anchors can never match a target path). First: {detail}.",
442
- "doctor.check.narrow_no_paths.message.plural": "{count} narrow-scope canonical entries have an empty relevance_paths array (silent recall risk \u2014 narrow without anchors can never match a target path). First: {detail}.",
443
- "doctor.check.narrow_no_paths.remediation": "Run `/fabric-review`, select the entry \u2192 modify to add path anchors to relevance_paths or widen relevance_scope to broad; or edit the entry frontmatter directly.",
444
- "doctor.check.relevance_paths_dangling.name": "Knowledge relevance_paths dangling",
445
- "doctor.check.relevance_paths_dangling.ok": "All relevance_paths globs resolve to at least one file under the workspace root.",
446
- "doctor.check.relevance_paths_dangling.message.singular": "{count} relevance_paths glob resolves to zero files in the current workspace. First: {detail}.",
447
- "doctor.check.relevance_paths_dangling.message.plural": "{count} relevance_paths globs resolve to zero files in the current workspace. First: {detail}.",
448
- "doctor.check.relevance_paths_dangling.remediation": "Update the entry's relevance_paths to remove globs that no longer match any files, or use `fab_review.modify` to rewrite the anchor set.",
449
- "doctor.check.relevance_paths_drift.name": "Knowledge relevance_paths drift",
450
- "doctor.check.relevance_paths_drift.ok.skipped": "Skipped (git history unavailable; cannot evaluate {windowDays}d drift window).",
451
- "doctor.check.relevance_paths_drift.ok.fresh": "All narrow-scope canonical entries have at least one relevance_path touched in the last {windowDays}d.",
452
- "doctor.check.relevance_paths_drift.message.singular": "{count} narrow-scope canonical entry has relevance_paths whose globs match no file touched in the last {windowDays}d of git history. First: {detail}.",
453
- "doctor.check.relevance_paths_drift.message.plural": "{count} narrow-scope canonical entries have relevance_paths whose globs match no file touched in the last {windowDays}d of git history. First: {detail}.",
454
- "doctor.check.relevance_paths_drift.remediation": "Review whether the entry is still relevant \u2014 use `fab_review.modify` to refresh the anchors or `fab_review.reject` to archive.",
455
- "doctor.check.personal_layer_path_misclassify.name": "Personal-layer path misclassify",
456
- "doctor.check.personal_layer_path_misclassify.ok": "No personal-layer entries declare relevance_paths that resolve against the current project.",
457
- "doctor.check.personal_layer_path_misclassify.message.singular": "{count} personal-layer entry declares relevance_paths that match files in the current project (personal layer should be project-agnostic). First: {detail}.",
458
- "doctor.check.personal_layer_path_misclassify.message.plural": "{count} personal-layer entries declare relevance_paths that match files in the current project (personal layer should be project-agnostic). First: {detail}.",
459
- "doctor.check.personal_layer_path_misclassify.remediation": 'Use `fab_review.modify` with `layer: "team"` to flip the entry, or rewrite the relevance_paths so the anchors are project-agnostic (e.g. drop project-specific globs).',
460
- "doctor.check.suspicious_kb.name": "Suspicious KB injection",
461
- "doctor.check.suspicious_kb.ok": "No canonical knowledge bodies match known prompt-injection patterns.",
462
- "doctor.check.suspicious_kb.message.singular": "{count} canonical entry body contains tokens matching prompt-injection patterns (likely legacy pre-NEW-31 archive). First: {detail}.",
463
- "doctor.check.suspicious_kb.message.plural": "{count} canonical entry bodies contain tokens matching prompt-injection patterns (likely legacy pre-NEW-31 archive). First: {detail}.",
464
- "doctor.check.suspicious_kb.remediation": "Review the flagged entries \u2014 use `fab_review.modify` to scrub the injection tokens from the body, or `fab_review.reject` to archive entries that should not have been canonicalised.",
465
- "doctor.check.narrow_too_few.name": "Knowledge narrow too few",
466
- "doctor.check.narrow_too_few.ok": "Narrow-with-paths ratio {ratioPct}% ({narrowCount}/{totalCount}); {teleNote}.",
467
- "doctor.check.narrow_too_few.message.telemetry_skipped": "telemetry skipped (no edit-counter fires in window)",
468
- "doctor.check.narrow_too_few.message.telemetry_window": "silence rate {silencePct}% over {windowDays}d",
469
- "doctor.check.narrow_too_few.message.structural": "narrow-with-paths share {ratioPct}% ({narrowCount}/{totalCount}) below {thresholdPct}% threshold",
470
- "doctor.check.narrow_too_few.message.telemetry": "narrow-hook silence rate {silencePct}% ({silenceFires}/{totalFires}) over {windowDays}d above {thresholdPct}% threshold",
471
- "doctor.check.narrow_too_few.message.summary": "Narrow-scope KB coverage is below the useful floor: {parts}.",
472
- "doctor.check.narrow_too_few.remediation": "Run the fabric-import Skill (`/fabric-import`) to re-seed narrow anchors against the current codebase.",
473
399
  "doctor.check.session_hints_stale.name": "Knowledge session-hints stale",
474
400
  "doctor.check.session_hints_stale.ok": "No session-hints cache files older than {days} days under .fabric/.cache/.",
475
401
  "doctor.check.session_hints_stale.message.singular": "{count} session-hints cache file under .fabric/.cache/ is older than {days} days. First: {detail}.",
476
402
  "doctor.check.session_hints_stale.message.plural": "{count} session-hints cache files under .fabric/.cache/ are older than {days} days. First: {detail}.",
477
403
  "doctor.check.session_hints_stale.remediation": "Run `fabric doctor --fix-knowledge` to delete stale session-hints cache files.",
404
+ "doctor.check.hook_cache_writable.name": "Hook cache writable",
405
+ "doctor.check.hook_cache_writable.ok": "Hook sidecar cache path {path} accepts write probes.",
406
+ "doctor.check.hook_cache_writable.message": "Hook sidecar cache path {path} is not writable; hook state updates will silently fail. Error: {error}.",
407
+ "doctor.check.hook_cache_writable.remediation": "Restore write permissions for {path}, remove a blocking file at that path, or rerun `fabric install` after fixing the filesystem state.",
478
408
  "doctor.check.stale_serve_lock.name": "Serve lock",
479
409
  "doctor.check.stale_serve_lock.ok.no_lock": "No .fabric/.serve.lock present.",
480
410
  "doctor.check.stale_serve_lock.ok.live_pid": ".fabric/.serve.lock held by live PID {pid}.",
@@ -484,11 +414,6 @@ var enMessages = {
484
414
  "doctor.check.stale_serve_lock.age.hour.plural": "{count} hours ago",
485
415
  "doctor.check.stale_serve_lock.message.dead_pid": "[advisory] .fabric/.serve.lock holds dead PID {pid} (acquired {acquiredAgo}). Run `fabric doctor --fix` to remove.",
486
416
  "doctor.check.stale_serve_lock.remediation.dead_pid": "Run `fabric doctor --fix` to remove the stale .fabric/.serve.lock.",
487
- "doctor.check.relevance_fields_missing.name": "Knowledge relevance fields missing",
488
- "doctor.check.relevance_fields_missing.ok": "All pending entries declare both relevance_scope and relevance_paths.",
489
- "doctor.check.relevance_fields_missing.message.singular": "{count} pending entry is missing relevance_scope and/or relevance_paths in frontmatter. First: {detail}.",
490
- "doctor.check.relevance_fields_missing.message.plural": "{count} pending entries are missing relevance_scope and/or relevance_paths in frontmatter. First: {detail}.",
491
- "doctor.check.relevance_fields_missing.remediation": "Run `fabric doctor --fix-knowledge` to back-fill the schema defaults (relevance_scope: broad, relevance_paths: []).",
492
417
  // rc.31 BUG-M3/NEW-4: hooks_wired observability.
493
418
  "doctor.check.hooks_wired.name": "Claude Code hooks wired",
494
419
  "doctor.check.hooks_wired.ok.skipped": "Project does not use Claude Code (no .claude/ directory); hooks_wired check skipped.",
@@ -499,7 +424,7 @@ var enMessages = {
499
424
  // v2.0.0-rc.37 NEW-20: hooks_runtime — shebang + Node.js syntax validity
500
425
  // of installed *.cjs hook files (one layer below hooks_wired).
501
426
  "doctor.check.hooks_runtime.name": "Hooks runtime health",
502
- "doctor.check.hooks_runtime.ok.skipped": "No installed hook files found under .claude/hooks/ / .codex/hooks/ / .cursor/hooks/; skipping hooks_runtime check.",
427
+ "doctor.check.hooks_runtime.ok.skipped": "No installed hook files found under .claude/hooks/ / .codex/hooks/; skipping hooks_runtime check.",
503
428
  "doctor.check.hooks_runtime.ok.healthy": "Scanned {count} hook .cjs file(s); shebang and Node.js syntax parse all pass.",
504
429
  "doctor.check.hooks_runtime.message.singular": "{count} hook file is unhealthy at runtime; first: {first_path} ({first_detail}).",
505
430
  "doctor.check.hooks_runtime.message.plural": "{count} hook files are unhealthy at runtime; first: {first_path} ({first_detail}).",
@@ -507,8 +432,8 @@ var enMessages = {
507
432
  // v2.0.0-rc.37 NEW-27: hooks_content_drift — cross-client sha256 parity.
508
433
  "doctor.check.hooks_content_drift.name": "Hooks cross-client content parity",
509
434
  "doctor.check.hooks_content_drift.ok.skipped": "No hook files co-exist across multiple clients (single-client install or no hooks present); skipping hooks_content_drift check.",
510
- "doctor.check.hooks_content_drift.ok.aligned": "Scanned {count} hook copies; sha256 of every basename matches across .claude / .codex / .cursor.",
511
- "doctor.check.hooks_content_drift.message": "{count} hook basename(s) drift across clients; first: {first_basename} (involves {first_clients}). `fabric install` copies the same template to all three clients \u2014 drift usually comes from manual edits.",
435
+ "doctor.check.hooks_content_drift.ok.aligned": "Scanned {count} hook copies; sha256 of every basename matches across .claude / .codex.",
436
+ "doctor.check.hooks_content_drift.message": "{count} hook basename(s) drift across clients; first: {first_basename} (involves {first_clients}). `fabric install` copies the same template to both clients \u2014 drift usually comes from manual edits.",
512
437
  "doctor.check.hooks_content_drift.remediation": "Run `fabric install` to restore each client's hook copy to the canonical template. If you actually need client-specific behavior, modify a shared lib/ helper or templates/hooks/configs/ wiring instead of editing the installed .cjs in place.",
513
438
  // rc.31 BUG-G2/G5: promote-ledger invariant check.
514
439
  "doctor.check.promote_ledger_invariant.name": "Promote ledger invariant",
@@ -529,6 +454,62 @@ var enMessages = {
529
454
  "doctor.check.knowledge_summary_opaque.ok": "{opaque}/{total} entries have summary == stable_id; opacity ratio is within the healthy band.",
530
455
  "doctor.check.knowledge_summary_opaque.message.warn": "{opaque}/{total} entries ({pct}%) have description.summary equal to their stable_id, exceeding the {threshold}% threshold. Narrow-hint output renders as `<id> \xB7 <id>`, signaling nothing useful, and AI clients skip the fetch. First opaque: {sample}.",
531
456
  "doctor.check.knowledge_summary_opaque.remediation": "Run the fabric-review skill to rewrite opaque summaries with one short human-readable phrase. The rc.35 hint renderer fallback (TASK-06) will also synthesize a temporary summary from the entry's `## Summary` section.",
457
+ // v2.2 W4 (G-GUARD / A6): store scope lint.
458
+ "doctor.check.store_scope_lint.name": "Store scope lint",
459
+ "doctor.check.store_scope_lint.ok": "All read-set store entries carry valid scope metadata (semantic_scope + visibility_store, no personal leak, no dangling project).",
460
+ "doctor.check.store_scope_lint.message": "{total} store scope issue(s): {breakdown}. e.g. {sample}.",
461
+ "doctor.check.store_scope_lint.remediation": "Run `fabric store backfill-scope` to add missing semantic_scope/visibility_store; `fabric store re-scope` to fix a dangling project: coordinate; move any personal-scope entry out of a shared store (personal knowledge lives only in your personal store, R5#3).",
462
+ // v2.2 Goal B (G-INTEGRITY): store stable_id collision + layer mismatch lints.
463
+ "doctor.check.stable_id_collision.name": "Stable ID collision",
464
+ "doctor.check.stable_id_collision.message.singular": 'stable_id "{stableId}" is declared in {fileCount} files: {files}. Edit one of the knowledge files to use a unique stable_id.',
465
+ "doctor.check.stable_id_collision.message.plural": '{count} stable_id collisions detected. First: "{stableId}" in {files}. Edit one of the knowledge files to use a unique stable_id.',
466
+ "doctor.check.stable_id_collision.remediation": "Run `/fabric-review modify <one of the colliding ids from the message>` to let the canonical id allocator reassign it (updates frontmatter + counters + historical cross-refs atomically). Do NOT hand-edit id frontmatter \u2014 it will desync counters.",
467
+ "doctor.check.stable_id_collision.ok": "No declared stable_id collisions found in mounted store knowledge.",
468
+ "doctor.check.layer_mismatch.name": "Knowledge layer mismatch",
469
+ "doctor.check.layer_mismatch.ok": "All canonical knowledge files are physically located under the layer their stable_id prefix declares.",
470
+ "doctor.check.layer_mismatch.message.singular": "{count} canonical knowledge file is physically misaligned with its stable_id layer prefix (KT-* must live under team/, KP-* under personal/). First: {detail}.",
471
+ "doctor.check.layer_mismatch.message.plural": "{count} canonical knowledge files are physically misaligned with their stable_id layer prefix (KT-* must live under team/, KP-* under personal/). First: {detail}.",
472
+ "doctor.check.layer_mismatch.remediation": "Move the file to the correct write-target store or run `/fabric-review modify <id from the message>` to flip its layer (which renames the stable_id prefix accordingly).",
473
+ // v2.2 Goal B (G-RELEVANCE): store relevance_paths hygiene (dangling + drift).
474
+ "doctor.check.relevance_paths_dangling.name": "Knowledge relevance_paths dangling",
475
+ "doctor.check.relevance_paths_dangling.ok": "All relevance_paths globs resolve to at least one file under the workspace root.",
476
+ "doctor.check.relevance_paths_dangling.message.singular": "{count} relevance_paths glob resolves to zero files in the current workspace. First: {detail}.",
477
+ "doctor.check.relevance_paths_dangling.message.plural": "{count} relevance_paths globs resolve to zero files in the current workspace. First: {detail}.",
478
+ "doctor.check.relevance_paths_dangling.remediation": "Update the entry's relevance_paths to remove globs that no longer match any files, or use `fab_review.modify` to rewrite the anchor set.",
479
+ "doctor.check.relevance_paths_drift.name": "Knowledge relevance_paths drift",
480
+ "doctor.check.relevance_paths_drift.ok.skipped": "Skipped (git history unavailable; cannot evaluate {windowDays}d drift window).",
481
+ "doctor.check.relevance_paths_drift.ok.fresh": "All narrow-scope canonical entries have at least one relevance_path touched in the last {windowDays}d.",
482
+ "doctor.check.relevance_paths_drift.message.singular": "{count} narrow-scope canonical entry has relevance_paths whose globs match no file touched in the last {windowDays}d of git history. First: {detail}.",
483
+ "doctor.check.relevance_paths_drift.message.plural": "{count} narrow-scope canonical entries have relevance_paths whose globs match no file touched in the last {windowDays}d of git history. First: {detail}.",
484
+ "doctor.check.relevance_paths_drift.remediation": "Review whether the entry is still relevant \u2014 use `fab_review.modify` to refresh the anchors or `fab_review.reject` to archive.",
485
+ // W4-3 (KT-MOD-0001): narrow-scope entry with an empty relevance_paths set.
486
+ "doctor.check.narrow_no_paths.name": "Knowledge narrow scope without paths",
487
+ "doctor.check.narrow_no_paths.ok": "Every narrow-scope canonical entry carries at least one relevance_path.",
488
+ "doctor.check.narrow_no_paths.message.singular": "{count} narrow-scope entry has an empty relevance_paths set \u2014 it can never path-match, so it will never surface (permanently dead). First: {detail}.",
489
+ "doctor.check.narrow_no_paths.message.plural": "{count} narrow-scope entries have an empty relevance_paths set \u2014 they can never path-match, so they will never surface (permanently dead). First: {detail}.",
490
+ "doctor.check.narrow_no_paths.remediation": "Use `fab_review.modify` to add relevance_paths globs anchoring the entry, or switch its relevance_scope to `broad` if it is meant to be always-on.",
491
+ // W4-2 (KT-DEC-0028): per-store broad index nearing the backstop.
492
+ "doctor.check.broad_index_drift.name": "Knowledge broad index drift",
493
+ "doctor.check.broad_index_drift.ok": "No store's broad-scope entry count reaches the drift threshold ({threshold} of backstop {backstop}).",
494
+ "doctor.check.broad_index_drift.message.singular": "{count} store's broad-scope index has reached {threshold} (80% of backstop {backstop}) \u2014 the SessionStart banner is close to truncating broad entries. First: {detail}.",
495
+ "doctor.check.broad_index_drift.message.plural": "{count} stores' broad-scope indexes have reached {threshold} (80% of backstop {backstop}) \u2014 the SessionStart banner is close to truncating broad entries. First: {detail}.",
496
+ "doctor.check.broad_index_drift.remediation": "Run the `fabric-audit` skill to prune or demote stale broad-scope entries in the flagged store, or raise `broad_index_backstop` in .fabric/fabric-config.json if the corpus is legitimately large.",
497
+ // v2.2 Goal B (G-AGE): knowledge decay lints (orphan_demote + stale_archive).
498
+ "doctor.check.orphan_demote.name": "Knowledge orphan demote",
499
+ "doctor.check.orphan_demote.ok": "No canonical knowledge entries exceed their maturity-keyed inactivity threshold.",
500
+ "doctor.check.orphan_demote.message.singular": "{count} canonical knowledge entry exceeds its maturity-keyed inactivity threshold (proven={provenDays}d / verified={verifiedDays}d / draft={draftDays}d). First: {detail}.",
501
+ "doctor.check.orphan_demote.message.plural": "{count} canonical knowledge entries exceed their maturity-keyed inactivity threshold (proven={provenDays}d / verified={verifiedDays}d / draft={draftDays}d). First: {detail}.",
502
+ "doctor.check.orphan_demote.remediation": "Demote the entry one maturity tier via `/fabric-review modify <id>`, or re-engage it so it logs fresh activity. (Rewriting store-backed knowledge is the store-write flow's job \u2014 this read-side lint only surfaces the decay.)",
503
+ "doctor.check.stale_archive.name": "Knowledge stale archive",
504
+ "doctor.check.stale_archive.ok": "No draft knowledge entries exceed the additional stale-archive quiet window.",
505
+ "doctor.check.stale_archive.message.singular": "{count} draft knowledge entry is stale beyond the demote+{additionalDays}d additional quiet window. First: {detail}.",
506
+ "doctor.check.stale_archive.message.plural": "{count} draft knowledge entries are stale beyond the demote+{additionalDays}d additional quiet window. First: {detail}.",
507
+ "doctor.check.stale_archive.remediation": "Archive the stale draft via `/fabric-review reject <id>`, or revive it if still relevant. (Moving store-backed files is the store-write flow's job \u2014 this read-side lint only surfaces the staleness.)",
508
+ // project-scope binding backfill lint (unbound_project).
509
+ "doctor.check.unbound_project.name": "Project-scope binding",
510
+ "doctor.check.unbound_project.ok": "The bound write store carries a project coordinate (project_id + active_project), so project-scope recall/writes route correctly.",
511
+ "doctor.check.unbound_project.message": "Store '{alias}' is bound as the write target but the project coordinate is incomplete (missing {missing}); project-scope recall/writes fall back to team scope.",
512
+ "doctor.check.unbound_project.remediation": "Run `fabric doctor --fix` to backfill the project binding (mints project_id, registers the project in the store, sets active_project). Idempotent \u2014 a second run is a no-op.",
532
513
  "doctor.check.skill_md_yaml_invalid.name": "Skill markdown YAML",
533
514
  "doctor.check.skill_md_yaml_invalid.ok": "All .claude/.codex SKILL.md frontmatter values parse as strict YAML.",
534
515
  "doctor.check.skill_md_yaml_invalid.message.singular": "{count} SKILL.md frontmatter value contains an unquoted ': ' that strict YAML parsers reject (Claude Code tolerates it; Codex CLI drops the skill at load). First: {detail}.",
@@ -556,21 +537,6 @@ var enMessages = {
556
537
  "cli.doctor.errors.invalid-history-mode": "Invalid --history mode '{input}'. Use archive | fix | all.",
557
538
  "doctor.history.header": "Doctor history (mode={mode}, last {sinceLabel}, {days} day(s))",
558
539
  "doctor.history.empty": "No doctor or archive activity within the --since={sinceLabel} window (mode={mode}).",
559
- "cli.hooks.description": "Manage Fabric Git hook templates.",
560
- "cli.hooks.install.description": "Install the Fabric Husky pre-commit hook template.",
561
- "cli.hooks.install.args.target.description": "Target project path, default is the current working directory.",
562
- "cli.hooks.errors.package-json-required": "package.json is required to install hooks: {path}",
563
- "cli.hooks.install.hook-skipped": "Fabric hook already present in {path}, skipped.",
564
- "cli.hooks.install.hook-appended": "Appended Fabric hook to existing {path}",
565
- "cli.hooks.install.hook-created": "Created {path}",
566
- "cli.hooks.install.prepare-left": "Left existing prepare script unchanged in {path}",
567
- "cli.hooks.install.prepare-added": "Added prepare script to {path}",
568
- "cli.human-lint.description": "Validate locked human-edit regions.",
569
- "cli.human-lint.args.target.description": "Target project path, default is the current working directory.",
570
- "cli.human-lint.drift-detected": "Human-locked content drift detected. Revert the edit or update approved hashes before committing.",
571
- "cli.human-lint.table.location": "Location",
572
- "cli.human-lint.table.expected": "Expected",
573
- "cli.human-lint.table.got": "Got",
574
540
  "cli.install.description": "Install Fabric in the target project (scaffold .fabric/, bootstrap templates, MCP client wiring, git hooks).\n\nExamples:\n fabric install interactive install in the current project\n fabric install --yes accept defaults, skip the TTY wizard\n fabric install --dry-run preview the install plan without writing files",
575
541
  "cli.install.args.target.description": "Target project path. Defaults to --target, then EXTERNAL_FIXTURE_PATH, then cwd.",
576
542
  "cli.install.args.debug.description": "Print target resolution details to stderr.",
@@ -579,13 +545,13 @@ var enMessages = {
579
545
  "cli.install.args.enable-embed.description": "Opt in to vector semantic search (sets embed_enabled + embed_model; prints fastembed install steps)",
580
546
  "cli.install.args.embed-model.description": "With --enable-embed: override the pinned embed model (default fast-bge-small-zh-v1.5)",
581
547
  // rc.35 TASK-08 (P0-5/6): --force-skills-only.
582
- "cli.install.args.force-skills-only.description": "Skip bootstrap / MCP / hooks / settings; refresh ONLY the fabric Skill template copies (.claude/.codex/.cursor/skills/*).",
548
+ "cli.install.args.force-skills-only.description": "Skip bootstrap / MCP / hooks / settings; refresh ONLY the fabric Skill template copies (.claude/.codex/skills/*).",
583
549
  "cli.install.force-skills-only.banner": "Refreshing fabric Skill templates only",
584
550
  "cli.install.force-skills-only.uninitialised.message": "fabric install --force-skills-only: project is not initialised (.fabric/agents.meta.json is missing).",
585
551
  "cli.install.force-skills-only.uninitialised.hint": "Run `fabric install` (without --force-skills-only) first to lay down the base scaffold, then re-run with --force-skills-only for subsequent Skill refreshes.",
586
552
  "cli.install.force-skills-only.summary": "Skills refresh complete \u2014 written: {written}, skipped: {skipped}, errors: {errors}",
587
553
  // v2.0.0-rc.37 NEW-26: --force-hooks-only mirror of --force-skills-only.
588
- "cli.install.args.force-hooks-only.description": "Skip bootstrap / MCP / skills / settings; only refresh fabric hook scripts + per-client hook config merges (.claude/.codex/.cursor/hooks/*).",
554
+ "cli.install.args.force-hooks-only.description": "Skip bootstrap / MCP / skills / settings; only refresh fabric hook scripts + per-client hook config merges (.claude/.codex/hooks/*).",
589
555
  "cli.install.force-hooks-only.banner": "Refreshing fabric hooks only",
590
556
  "cli.install.force-hooks-only.uninitialised.message": "fabric install --force-hooks-only: project not initialised (.fabric/agents.meta.json missing).",
591
557
  "cli.install.force-hooks-only.uninitialised.hint": "Run `fabric install` (without --force-hooks-only) first to lay down the base scaffold; then re-run with --force-hooks-only to refresh hooks.",
@@ -605,7 +571,6 @@ var enMessages = {
605
571
  "cli.install.stages.bootstrap.snapshot.skipped": "Skipped .fabric/AGENTS.md \u2014 already current",
606
572
  "cli.install.steps.bootstrap-claude": "Updated CLAUDE.md with @-import directives",
607
573
  "cli.install.steps.bootstrap-codex": "Updated AGENTS.md with fabric:bootstrap managed block",
608
- "cli.install.steps.bootstrap-cursor": "Updated .cursor/rules/fabric-bootstrap.mdc",
609
574
  "cli.install.stages.mcp": "Configuring MCP clients...",
610
575
  "cli.install.stages.hooks": "Installing git hooks...",
611
576
  "cli.install.stages.skipped": "skipped",
@@ -614,9 +579,22 @@ var enMessages = {
614
579
  "cli.install.stages.summary.ran": "ran",
615
580
  "cli.install.stages.summary.skipped": "skipped",
616
581
  "cli.install.stages.summary.failed": "failed",
582
+ "cli.install.pipeline.title": "Fabric Install",
583
+ "cli.install.pipeline.complete": "Fabric Install Complete",
584
+ "cli.install.pipeline.running": "Running {count} stages...",
585
+ "cli.install.pipeline.label.preflight": "Preflight check",
586
+ "cli.install.pipeline.label.env": "Environment setup",
587
+ "cli.install.pipeline.label.store": "Store configuration",
588
+ "cli.install.pipeline.label.hooks": "Hooks & skills",
589
+ "cli.install.pipeline.label.mcp": "MCP server",
590
+ "cli.install.pipeline.label.validate": "Validation",
591
+ "cli.install.pipeline.label.guidance": "Next steps",
592
+ "cli.install.pipeline.desc.store": "Bind the current project's read/write store; refresh the resolved-bindings snapshot.",
617
593
  "cli.install.next-step": "{label} {message}",
618
594
  "cli.install.reason-message": "{label} {message}",
619
- "cli.install.language_preference_hint": "Fabric language preference: {value}. To change, edit `fabric_language` in `.fabric/fabric-config.json` (values: match-existing | zh-CN | en | zh-CN-hybrid).",
595
+ "cli.install.language.prompt": "Choose the Fabric language (used for both UI and knowledge; change later via `fabric config`):",
596
+ "cli.install.language.option.zh-CN": "\u7B80\u4F53\u4E2D\u6587 (zh-CN)",
597
+ "cli.install.language.option.en": "English (en)",
620
598
  "cli.install.plan.title": "Fabric install plan",
621
599
  "cli.install.plan.mode-banner.default": "[mode: apply] Standard install execution",
622
600
  "cli.install.plan.mode-banner.plan": "[mode: plan] Dry run only, no files will be written",
@@ -648,11 +626,55 @@ var enMessages = {
648
626
  "cli.install.wizard.cancelled": "Fabric install cancelled before execution.",
649
627
  "cli.install.capabilities.title": "Client capability summary",
650
628
  // v2.0.0-rc.37 NEW-22: post-install restart banner. The MCP server is
651
- // spawned by the client; already-running Claude Code / Cursor / Codex
629
+ // spawned by the client; already-running Claude Code / Codex
652
630
  // sessions won't pick up the new mcp config until they restart.
653
- "cli.install.restart-banner": "Restart hint: any already-running Claude Code / Cursor / Codex CLI session must restart to pick up the new MCP server config; new sessions will autoload the Fabric tools.",
631
+ "cli.install.restart-banner": "Restart hint: any already-running Claude Code / Codex CLI session must restart to pick up the new MCP server config; new sessions will autoload the Fabric tools.",
654
632
  "cli.install.next-steps": 'Next steps \u2014 get your first value:\n 1. Restart your AI client (Claude Code / Codex). It now auto-surfaces this project\'s knowledge to the assistant.\n 2. Seed knowledge: just work normally \u2014 when you make a decision or hit a pitfall, the fabric-archive skill proposes an entry. Or run the fabric-import skill to backfill from git history.\n 3. Verify it works: ask your AI "what does Fabric know about this repo?", or run `fabric doctor` to check health.',
655
633
  "cli.install.store-bind-nudge": "\u{1F4A1} Mounted store(s) not bound to this project: {aliases}. Run `fabric store bind {first}` to read their knowledge here, then `fabric store switch-write {first}` to write team knowledge into it.",
634
+ // C1/C5: semantic-search interactive copy routed through t().
635
+ "cli.install.semantic.prompt": "Enable vector semantic search? (the first recall downloads an embedding model)",
636
+ "cli.install.semantic.enabled": "Semantic search enabled (embed_enabled=true, embed_model={model}).",
637
+ "cli.install.semantic.already-enabled": "Semantic search already enabled (embed_model={model}); {path} unchanged.",
638
+ "cli.install.semantic.offer-install": "Install the optional embedder now? Runs `npm i -g fastembed` (a no-op if already installed).",
639
+ "cli.install.semantic.installing": "Running `npm i -g fastembed` \u2026",
640
+ "cli.install.semantic.installed": "fastembed installed. The embedding model downloads automatically on the first recall (~tens\u2013hundreds of MB; no KB data is uploaded).",
641
+ "cli.install.semantic.install-failed": "Auto-install failed ({reason}). Run the steps manually:",
642
+ "cli.install.semantic.manual-steps": " 1. Install the optional embedder where the MCP server resolves modules (a global install is global):\n npm i -g fastembed\n 2. Warm the model cache (the first run downloads the weights, ~tens\u2013hundreds of MB; no KB data is uploaded):\n export FABRIC_EMBED_CACHE_DIR=~/.cache/fabric-embed # strict-offline: pre-place the weights here\n Note: after switching embed_model the existing vector dim/semantics change; the next recall re-embeds with the new model (doc vectors are cached by text and auto-recompute on mismatch).\n Disable: set embed_enabled=false in fabric.config.json.",
643
+ // C5: store onboarding interactive copy routed through t().
644
+ "cli.install.store.local-store": "local store",
645
+ "cli.install.store.bind-mounted.prompt": "Bind an already-mounted knowledge store to this project?",
646
+ "cli.install.store.setup.prompt": "Set up a knowledge store for this project?",
647
+ "cli.install.store.setup.bind-label": "bind mounted: {alias}",
648
+ "cli.install.store.setup.already-bound": "already bound to this project: {aliases} \u2713",
649
+ "cli.install.store.skip-label": "skip",
650
+ "cli.install.store.bind-mounted.skip-hint": "leave mounted stores unbound for now",
651
+ "cli.install.store.project-coordinate": "Project coordinate in store '{store}':",
652
+ "cli.install.store.project-pick.prompt": "store '{store}' already serves other projects and none match this repo's git name \u2014 join an existing project or create a new one?",
653
+ "cli.install.store.project-pick.join": "Join existing: {name} ({id})",
654
+ "cli.install.store.project-pick.new": "\u2795 New project {id}",
655
+ "cli.install.store.project-pick.new-name": "New project id (project coordinate):",
656
+ "cli.install.store.bound-success": "bound store '{alias}' to this project and set it as the write target.",
657
+ "cli.install.store.created-success": "created store '{alias}', bound it to this project, and set it as the write target.",
658
+ "cli.install.store.onboard.prompt": "Set up a team / shared knowledge store for this project?",
659
+ "cli.install.store.onboard.skip-hint": "personal store only (default)",
660
+ "cli.install.store.onboard.join-label": "join existing",
661
+ "cli.install.store.onboard.join-hint": "clone + bind a shared store from a git remote",
662
+ "cli.install.store.onboard.create-label": "create new",
663
+ "cli.install.store.onboard.create-hint": "start a fresh local store (optionally remote-backed)",
664
+ "cli.install.store.onboard.join-url": "Shared store git remote (url):",
665
+ "cli.install.store.onboard.alias": "Local alias for the new store:",
666
+ "cli.install.store.onboard.remote": "Git remote to back it (optional - leave blank to skip):",
667
+ "cli.install.store.unbound-note": "Note: The following stores are mounted but not bound to this project: {aliases}.",
668
+ "cli.install.store.unbound-hint": " Run 'fabric store bind {first}' to bind one.",
669
+ // C4: personal store clone-or-new.
670
+ "cli.install.store.personal.prompt": "No personal store on this machine yet. Create a fresh one, or clone your existing one from a remote?",
671
+ "cli.install.store.personal.new-label": "create local (default)",
672
+ "cli.install.store.personal.new-hint": "a fresh empty personal store",
673
+ "cli.install.store.personal.clone-label": "clone existing",
674
+ "cli.install.store.personal.clone-hint": "clone your backed-up personal store from a git remote",
675
+ "cli.install.store.personal.clone-url": "Your personal store git remote (url):",
676
+ "cli.install.store.personal.cloned-success": "cloned personal store from remote ({uuid}).",
677
+ "cli.install.store.personal.clone-failed": "cloning the personal store failed ({reason}); falling back to a fresh local store.",
656
678
  "cli.install.capabilities.none": "No supported client was detected for bootstrap or MCP follow-up.",
657
679
  "cli.install.capabilities.header.client": "Client",
658
680
  "cli.install.capabilities.header.bootstrap": "Bootstrap",
@@ -670,7 +692,7 @@ var enMessages = {
670
692
  "cli.install.capabilities.follow-up.ready": "continue in client",
671
693
  "cli.install.capabilities.follow-up.install": "install client assets",
672
694
  "cli.install.capabilities.follow-up.manual": "manual step required",
673
- "cli.install.next-step.message": "run fabric hooks install to add the Day 4 pre-commit pipeline.",
695
+ "cli.install.next-step.message": "run fabric install --reapply --yes to refresh Fabric-managed hooks and client config.",
674
696
  "cli.install.reason-message.installable-body": ".fabric/forensic.json is ready; some detected clients support Fabric follow-up but still need client assets installed.",
675
697
  "cli.install.reason-message.manual-body": ".fabric/forensic.json is ready; some detected clients still need manual follow-up because no Fabric skill is installed for them yet.",
676
698
  "cli.install.codex-hooks.created": "{label} {path} with Codex hooks config (requires features.codex_hooks = true).",
@@ -688,22 +710,24 @@ var enMessages = {
688
710
  "cli.install.diff.canonical": "Workspace already canonical ({count} files verified).",
689
711
  "cli.install.diff.applying-missing": "Applying {count} missing pieces: {files}",
690
712
  "cli.install.diff.drift-abort": "Drift detected in {path}. Run `fabric doctor` to inspect, or `fabric uninstall && fabric install` to reset.",
713
+ "cli.install.diff.drift-abort.action-hint": "Inspect the drift with `fabric doctor`; if the managed files should be reset, run `fabric uninstall && fabric install`.",
691
714
  "cli.install.diff.state.missing": "missing",
692
715
  "cli.install.diff.state.present-canonical": "canonical",
693
716
  "cli.install.diff.state.drifted": "drifted",
694
717
  "cli.install.diff.state.user-modified": "user-modified",
695
- "cli.uninstall.description": "Uninstall Fabric from the target project. .fabric/knowledge/ is always preserved; ~/.fabric/knowledge/ is never touched.\n\nExamples:\n fabric uninstall interactive uninstall in the current project\n fabric uninstall --yes accept defaults, skip the TTY wizard\n fabric uninstall --dry-run preview the uninstall plan without removing files",
718
+ "cli.uninstall.description": "Uninstall Fabric from the target project. Global knowledge stores under ~/.fabric/stores/ are never deleted by project uninstall.\n\nExamples:\n fabric uninstall interactive uninstall in the current project\n fabric uninstall --yes accept defaults, skip the TTY wizard\n fabric uninstall --dry-run preview the uninstall plan without removing files",
696
719
  "cli.uninstall.args.target.description": "Target project path. Defaults to --target, then EXTERNAL_FIXTURE_PATH, then cwd.",
697
720
  "cli.uninstall.args.debug.description": "Print target resolution details to stderr.",
698
721
  "cli.uninstall.args.yes.description": "Accept the current uninstall plan and run without the TTY wizard.",
699
722
  "cli.uninstall.args.dry-run.description": "Print the uninstall plan without removing files or running follow-up stages.",
700
723
  "cli.uninstall.plan.title": "Fabric uninstall plan",
724
+ // C3: mirror install's phase banner ("Fabric install 将按 N 个阶段执行").
725
+ "cli.uninstall.plan.phase-banner": "Fabric uninstall runs in {total} phases",
701
726
  "cli.uninstall.plan.target": "Target: {target}",
702
727
  "cli.uninstall.plan.actions": "Plan: scaffold={scaffold} bootstrap={bootstrap} mcp={mcp}",
703
728
  "cli.uninstall.plan.detected": "Detected clients: {clients}",
704
729
  "cli.uninstall.plan.preserves": "Preserves:",
705
- "cli.uninstall.plan.preserves.knowledge": "team knowledge tree (always preserved)",
706
- "cli.uninstall.plan.preserves.personal": "personal root, never touched",
730
+ "cli.uninstall.plan.preserves.stores": "global knowledge stores, never deleted by project uninstall",
707
731
  "cli.uninstall.plan.preview-title": "Fabric uninstall dry run",
708
732
  "cli.uninstall.plan.preview-result": "scaffold={scaffold} bootstrap={bootstrap} mcp={mcp}",
709
733
  "cli.uninstall.plan.scaffold-entries.title": "Scaffold entries:",
@@ -716,53 +740,18 @@ var enMessages = {
716
740
  "cli.uninstall.summary.title": "Uninstall summary",
717
741
  "cli.uninstall.summary.body": "removed={removed} skipped={skipped} errors={errors}",
718
742
  "cli.uninstall.wizard.intro": "Fabric uninstall",
719
- "cli.uninstall.wizard.overview.title": "Uninstall overview",
720
- "cli.uninstall.wizard.overview.body": "Target: {target}\nThis wizard only reshapes the uninstall plan; execution still runs through the existing Fabric uninstall stages.\n.fabric/knowledge/ is always preserved. ~/.fabric/knowledge/ is never touched.",
721
- "cli.uninstall.wizard.step.target": "Confirm target",
722
- "cli.uninstall.wizard.step.plan": "Shape uninstall plan",
723
- "cli.uninstall.wizard.step.review": "Review final plan",
724
- "cli.uninstall.wizard.target.confirm": "Continue uninstalling Fabric from {target}? [Y/n]",
725
- "cli.uninstall.wizard.stage.scaffold": "Remove scaffold artifacts? [{defaultValue}]",
726
- "cli.uninstall.wizard.stage.bootstrap": "Remove bootstrap (Skills + hooks)? [{defaultValue}]",
727
- "cli.uninstall.wizard.stage.mcp": "Un-register MCP clients? [{defaultValue}]",
743
+ "cli.uninstall.wizard.select.prompt": "What should be removed from {target}? (space to toggle / enter to confirm; global knowledge stores under ~/.fabric/stores/ are never deleted)",
744
+ "cli.uninstall.wizard.select.scaffold.label": "Scaffold artifacts",
745
+ "cli.uninstall.wizard.select.scaffold.hint": "Scaffolded files under .fabric/",
746
+ "cli.uninstall.wizard.select.bootstrap.label": "Bootstrap (Skills + hooks)",
747
+ "cli.uninstall.wizard.select.bootstrap.hint": "Per-client skills and git hooks",
748
+ "cli.uninstall.wizard.select.mcp.label": "MCP client registration",
749
+ "cli.uninstall.wizard.select.mcp.hint": "Un-register the fabric MCP server from clients",
728
750
  "cli.uninstall.wizard.execute.confirm": "Execute this uninstall plan now? [Y/n]",
729
751
  "cli.uninstall.wizard.outro": "Uninstall plan accepted. Running Fabric uninstall...",
730
752
  "cli.uninstall.wizard.cancelled": "Fabric uninstall cancelled before execution.",
731
753
  "cli.uninstall.confirm.proceed": "Proceed with uninstalling Fabric from {target}? [y/N]",
732
754
  "cli.uninstall.errors.target-not-directory": "Target must be an existing directory: {path}",
733
- "cli.ledger-append.description": "Append an entry to the Fabric intent ledger.",
734
- "cli.ledger-append.args.target.description": "Target project path, default is the current working directory.",
735
- "cli.ledger-append.args.staged.description": "Derive the entry from staged changes (used during pre-commit).",
736
- "cli.ledger-append.requires-staged": "requires --staged in pre-commit context",
737
- "cli.ledger-append.intent.auto": "auto: {head}{suffix}",
738
- "cli.ledger-append.intent.auto-more": " +{count} more",
739
- "cli.pre-commit.description": "Composite pre-commit hook: runs sync-meta --check-only, human-lint, and ledger-append --staged in one Node process.",
740
- "cli.pre-commit.args.target.description": "Project root directory, defaults to cwd or EXTERNAL_FIXTURE_PATH.",
741
- "cli.pre-commit.run-failed": "fabric pre-commit: {name} failed - {message}",
742
- "cli.scan.description": "Scan the project to detect Fabric bootstrap candidates.",
743
- "cli.scan.args.target.description": "Target absolute path. Defaults to --target, then EXTERNAL_FIXTURE_PATH, then cwd.",
744
- "cli.scan.args.debug.description": "Print detection evidence in formatted output.",
745
- "cli.scan.args.json.description": "Print the diagnostic report as JSON.",
746
- "cli.scan.error.missing-forensic": "forensic.json not found at {path}; run `fabric install` first to produce the deterministic project snapshot.",
747
- "cli.scan.summary.created": "Wrote {count} knowledge entries to .fabric/knowledge/.",
748
- "cli.scan.summary.skipped": "No changes detected; {count} entries already up-to-date.",
749
- "cli.scan.report.title": "Fabric scan report",
750
- "cli.scan.report.target": "Target",
751
- "cli.scan.report.framework": "Framework",
752
- "cli.scan.report.evidence": "Evidence",
753
- "cli.scan.report.readme-quality": "README quality",
754
- "cli.scan.report.contributing": "CONTRIBUTING.md",
755
- "cli.scan.report.files-counted": "Files counted",
756
- "cli.scan.report.ignored-entries": "Ignored entries",
757
- "cli.scan.report.existing-fabric": "Existing Fabric files",
758
- "cli.scan.report.recommendations": "Recommendations:",
759
- "cli.scan.readme-quality.ok": "ok",
760
- "cli.scan.readme-quality.stub": "stub",
761
- "cli.scan.recommendation.init": "L0: Run fabric install to scaffold `.fabric/AGENTS.md` with the canonical Fabric bootstrap content.",
762
- "cli.scan.recommendation.readme": "L0: Expand README.md before promoting project facts into Fabric references.",
763
- "cli.scan.recommendation.contributing": "L0: Add CONTRIBUTING.md or leave a bootstrap TODO reference for contribution flow.",
764
- "cli.scan.recommendation.unknown-framework": "L1: Add tech-stack TODOs manually because no framework marker was detected.",
765
- "cli.scan.recommendation.framework-dirs": "L1: Review {framework} directories for future scoped Fabric rule files.",
766
755
  // v2.0.0-rc.37 Wave A2 Part 2: cli.serve.* + FABRIC_AUTH_TOKEN keys removed
767
756
  // alongside `fabric serve` quarantine to packages/server-http-experimental/
768
757
  // per [[fabric-serve-quarantine-not-delete]]. Restore from git history when
@@ -771,15 +760,6 @@ var enMessages = {
771
760
  "cli.onboard-coverage.description": "Report S5 onboard-slot coverage for the workspace. Used by the fabric-archive Skill's first-run phase to detect unclaimed project-tone slots.",
772
761
  "cli.onboard-coverage.args.json.description": "Emit machine-readable JSON to stdout instead of the human table.",
773
762
  "cli.onboard-coverage.args.target.description": "Override the project root (defaults to cwd).",
774
- "cli.update.description": "Refresh MCP host configuration and git hooks without re-creating Fabric files.",
775
- "cli.update.args.target.description": "Target project path. Defaults to --target, then EXTERNAL_FIXTURE_PATH, then cwd.",
776
- "cli.update.args.no-mcp.description": "Skip re-configuring MCP clients",
777
- "cli.update.args.no-hooks.description": "Skip re-installing git hooks",
778
- "cli.sync-meta.description": "Sync Fabric metadata from internal rule files.",
779
- "cli.sync-meta.args.target.description": "Target project path, default is the current working directory.",
780
- "cli.sync-meta.args.check-only.description": "Exit with code 1 when .fabric/agents.meta.json is out of date.",
781
- "cli.sync-meta.drift-detected": "Fabric metadata drift detected. Run fabric sync-meta to update.",
782
- "cli.sync-meta.updated": "{label} {path}",
783
763
  "dashboard.app.nav.aria-label": "Dashboard views",
784
764
  "dashboard.app.nav.readiness.label": "Readiness",
785
765
  "dashboard.app.nav.readiness.label-bilingual": "\u51C6\u5907\u60C5\u51B5 Readiness",
@@ -997,12 +977,6 @@ var enMessages = {
997
977
  "cli.store.detached": "detached '{alias}' \u2014 on-disk store tree left intact (detach \u2260 delete)",
998
978
  "cli.store.bound": "bound required store '{id}' ({count} required)",
999
979
  "cli.store.switch-write": "active write store set to '{alias}' for this project",
1000
- "cli.store.migrate.none": "no project-local knowledge to migrate (dual-root is empty)",
1001
- "cli.store.migrate.dry-run-header": "migration preview (dry-run, nothing written):",
1002
- "cli.store.migrate.applied-header": "migrated {count} entries into stores:",
1003
- "cli.store.migrate.committed": "committed migration changes in the store repo",
1004
- "cli.store.migrate.remap-note": " \u2191 remapped {oldId} \u2192 {newId} (target store id collision)",
1005
- "cli.store.migrate.skips-header": "skipped {count} item(s):",
1006
980
  "cli.sync.deferred": "{count} store(s) offline \u2014 push deferred; re-run `fabric sync` when online",
1007
981
  "cli.sync.paused": "sync paused on a conflict \u2014 resolve it, then run `fabric sync --continue` (or `--abort`)",
1008
982
  "cli.metrics.invalid-since": '--since: invalid duration "{raw}" (expected e.g. 24h, 7d, 30m)',
@@ -1016,9 +990,9 @@ var enMessages = {
1016
990
  "cli.install.scan-complete": " project scan complete",
1017
991
  // W4-11 (ISS-021): unified project-scan recommendations (cli forensic +
1018
992
  // http scan share this single i18n-keyed set).
1019
- "scan.rec.install": "Run `fabric install` to scaffold the .fabric/ knowledge layout (decisions, pitfalls, guidelines, models, processes).",
993
+ "scan.rec.install": "Run `fabric install`, then bind/select a mounted knowledge store for decisions, pitfalls, guidelines, models, and processes.",
1020
994
  "scan.rec.readme": "Expand README.md (project goal, run steps, no-touch zones) before promoting facts into Fabric knowledge.",
1021
- "scan.rec.contributing": "Add CONTRIBUTING.md or capture contribution-flow guidance under .fabric/knowledge/processes/.",
995
+ "scan.rec.contributing": "Add CONTRIBUTING.md or capture contribution-flow guidance in a mounted store under knowledge/processes/.",
1022
996
  "scan.rec.cocos.lifecycle": "Confirm the Cocos Creator Component lifecycle (onLoad/onEnable/start) ordering with the user.",
1023
997
  "scan.rec.cocos.human-protect": "Ask whether assets/prefabs and assets/scenes are @HUMAN-protected zones.",
1024
998
  "scan.rec.cocos.meta-lock": "`.meta` files detected \u2014 consider @HUMAN-locking them so the AI does not modify them.",
@@ -1030,7 +1004,7 @@ var enMessages = {
1030
1004
 
1031
1005
  // src/i18n/locales/zh-CN.ts
1032
1006
  var zhCNMessages = {
1033
- "cli.main.description": "Fabric CLI \u2014 \u81EA\u52A8\u628A\u672C\u9879\u76EE\u7684\u51B3\u7B56 / \u8E29\u5751 / \u89C4\u8303\u5582\u7ED9\u4F60\u7684 AI \u52A9\u624B\uFF0C\u8BA9\u5B83\u4E0D\u5FC5\u6BCF\u6B21\u4F1A\u8BDD\u91CD\u65B0\u5B66\u3002\n\n\u4E09\u6B65\u5FC3\u667A\u6A21\u578B\uFF1A\n \u88C5 (install) - fabric install \u4E00\u952E\u5B8C\u6210\u9879\u76EE\u521D\u59CB\u5316\n \u914D (config) - fabric config \u6253\u5F00\u4EA4\u4E92\u5F0F\u914D\u7F6E\u9762\u677F\n \u8DD1 (run) - fabric serve \u542F\u52A8\u672C\u5730 MCP HTTP \u670D\u52A1\n fabric doctor \u8FD0\u884C\u76EE\u6807\u6001\u8BCA\u65AD\n\n\u793A\u4F8B\uFF1A\n fabric install \u5728\u5F53\u524D\u9879\u76EE\u4E2D\u5B89\u88C5 Fabric\n fabric config \u6253\u5F00\u4EA4\u4E92\u5F0F\u914D\u7F6E\u9762\u677F\n fabric serve --port 7373 \u542F\u52A8 MCP HTTP \u670D\u52A1\n fabric doctor --fix \u4FEE\u590D Fabric \u6D3E\u751F\u72B6\u6001\n fabric uninstall --dry-run \u9884\u89C8\u5378\u8F7D\uFF0C\u4E0D\u5220\u9664\u6587\u4EF6",
1007
+ "cli.main.description": "Fabric CLI \u2014 \u81EA\u52A8\u628A\u672C\u9879\u76EE\u7684\u51B3\u7B56 / \u8E29\u5751 / \u89C4\u8303\u5582\u7ED9\u4F60\u7684 AI \u52A9\u624B\uFF0C\u8BA9\u5B83\u4E0D\u5FC5\u6BCF\u6B21\u4F1A\u8BDD\u91CD\u65B0\u5B66\u3002\n\n\u4E09\u6B65\u5FC3\u667A\u6A21\u578B\uFF1A\n \u88C5 (install) - fabric install \u4E00\u952E\u5B8C\u6210\u9879\u76EE\u521D\u59CB\u5316\n \u914D (config) - fabric config \u6253\u5F00\u4EA4\u4E92\u5F0F\u914D\u7F6E\u9762\u677F\n \u7EF4\u62A4 (run) - fabric doctor \u8FD0\u884C\u76EE\u6807\u6001\u8BCA\u65AD\n fabric sync \u540C\u6B65\u5DF2\u6302\u8F7D\u7684\u77E5\u8BC6 store\n\n\u793A\u4F8B\uFF1A\n fabric install \u5728\u5F53\u524D\u9879\u76EE\u4E2D\u5B89\u88C5 Fabric\n fabric config \u6253\u5F00\u4EA4\u4E92\u5F0F\u914D\u7F6E\u9762\u677F\n fabric doctor --fix \u4FEE\u590D Fabric \u6D3E\u751F\u72B6\u6001\n fabric doctor --fix-knowledge \u4FEE\u590D\u77E5\u8BC6\u6761\u76EE\u72B6\u6001\n fabric sync pull/rebase \u5E76 push \u5DF2\u6302\u8F7D store\n fabric uninstall --dry-run \u9884\u89C8\u5378\u8F7D\uFF0C\u4E0D\u5220\u9664\u6587\u4EF6",
1034
1008
  "cli.shared.created": "\u5DF2\u521B\u5EFA",
1035
1009
  "cli.shared.skipped": "\u5DF2\u8DF3\u8FC7",
1036
1010
  "cli.shared.next": "\u4E0B\u4E00\u6B65",
@@ -1045,36 +1019,31 @@ var zhCNMessages = {
1045
1019
  "cli.shared.loading": "\u52A0\u8F7D\u4E2D",
1046
1020
  "cli.shared.refresh": "\u5237\u65B0",
1047
1021
  "cli.shared.target-invalid": "\u76EE\u6807\u5FC5\u987B\u662F\u5DF2\u5B58\u5728\u7684\u76EE\u5F55\uFF1A{target}",
1022
+ "cli.shared.target-invalid.action-hint": "\u8BF7\u9009\u62E9\u4E00\u4E2A\u5DF2\u5B58\u5728\u7684\u9879\u76EE\u76EE\u5F55\uFF0C\u6216\u5148\u521B\u5EFA\u8BE5\u76EE\u5F55\u540E\u518D\u91CD\u65B0\u8FD0\u884C\u547D\u4EE4\u3002",
1048
1023
  "cli.shared.template-not-found": "\u672A\u627E\u5230\u6A21\u677F\uFF1A{path}",
1049
1024
  "cli.shared.invalid-host-empty": "\u65E0\u6548 host\uFF1A<empty>",
1050
1025
  "cli.shared.invalid-port": "\u65E0\u6548\u7AEF\u53E3\uFF1A{value}",
1051
1026
  "cli.shared.error": "\u9519\u8BEF",
1052
- "cli.approve.description": "\u4ECE\u547D\u4EE4\u884C\u6279\u51C6\u5DF2\u6F02\u79FB\u7684 human-lock \u8BB0\u5F55\u3002",
1053
- "cli.approve.args.all.description": "\u4E0D\u63D0\u793A\uFF0C\u6279\u51C6\u6240\u6709\u5DF2\u6F02\u79FB\u7684 human-lock \u8BB0\u5F55\u3002",
1054
- "cli.approve.args.interactive.description": "\u9010\u6761\u63D0\u793A\u540E\u6279\u51C6\u5DF2\u6F02\u79FB\u7684 human-lock \u8BB0\u5F55\u3002",
1055
- "cli.approve.args.target.description": "\u76EE\u6807\u9879\u76EE\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u3002",
1056
- "cli.approve.no-drift": "\u672A\u53D1\u73B0\u6F02\u79FB\u8BB0\u5F55\u3002",
1057
- "cli.approve.prompt": "\u6279\u51C6\u6B64\u8BB0\u5F55\uFF1F[y/N] ",
1058
- "cli.approve.approved-one": "\u5DF2\u6279\u51C6 {location}",
1059
- "cli.approve.skipped-one": "\u5DF2\u8DF3\u8FC7 {location}",
1060
- "cli.approve.summary": "\u5DF2\u6279\u51C6 {approved}/{total} \u6761\u6F02\u79FB\u8BB0\u5F55\u3002\u5DF2\u8DF3\u8FC7 {skipped} \u6761\u3002",
1061
- "cli.approve.table.expected": "\u9884\u671F",
1062
- "cli.approve.table.current": "\u5F53\u524D",
1063
- "cli.bootstrap.description": "\u4E3A\u652F\u6301\u7684 AI \u5BA2\u6237\u7AEF\u5B89\u88C5 Fabric \u5F15\u5BFC\u63D0\u793A\u6A21\u677F\u3002",
1064
- "cli.bootstrap.install.description": "\u5C06 Fabric \u5F15\u5BFC\u6A21\u677F\u590D\u5236\u5230\u5404\u5BA2\u6237\u7AEF\u7684\u539F\u751F\u4F4D\u7F6E\u3002",
1065
- "cli.bootstrap.install.args.clients.description": "\u53EF\u9009\u7684\u9017\u53F7\u5206\u9694\u5BA2\u6237\u7AEF\u8FC7\u6EE4\u5668\uFF0C\u4F8B\u5982 claude,cursor,codex\u3002",
1066
- "cli.bootstrap.install.no-targets": "\u672A\u68C0\u6D4B\u5230\u53EF\u5B89\u88C5\u7684 bootstrap \u76EE\u6807\u3002\u53EF\u663E\u5F0F\u4F20\u5165 --clients claude,cursor,codex\u3002",
1067
- "cli.bootstrap.install.installed": "\u5DF2\u5B89\u88C5 {path}",
1068
- "cli.bootstrap.install.skipped-header": "\u5DF2\u8DF3\u8FC7 {path}\uFF1AFabric Bootstrap \u5934\u90E8\u5DF2\u5B58\u5728\u3002",
1069
- "cli.bootstrap.install.prepended": "\u5DF2\u524D\u7F6E\u5199\u5165 {path}",
1070
- "cli.bootstrap.errors.unknown-client": "\u672A\u77E5\u5BA2\u6237\u7AEF\u201C{client}\u201D\u3002\u8BF7\u4F7F\u7528\u9017\u53F7\u5206\u9694\u5217\u8868\uFF0C\u4F8B\u5982 claude,cursor,codex\u3002",
1027
+ // EPIC-011: 分组帮助显示 i18n
1028
+ "cli.help.group.setup.install": "\u5728\u5F53\u524D\u4ED3\u5E93\u521D\u59CB\u5316 Fabric",
1029
+ "cli.help.group.setup.config": "\u914D\u7F6E Fabric \u8BBE\u7F6E",
1030
+ "cli.help.group.daily.sync": "\u4E0E\u8FDC\u7A0B store \u540C\u6B65\u56E2\u961F\u77E5\u8BC6",
1031
+ "cli.help.group.daily.info": "\u663E\u793A\u9879\u76EE\u72B6\u6001",
1032
+ "cli.help.group.diagnostic.doctor": "\u68C0\u67E5 Fabric \u5065\u5EB7\u72B6\u6001\u5E76\u4FEE\u590D\u95EE\u9898",
1033
+ "cli.help.group.advanced.store": "\u7BA1\u7406\u77E5\u8BC6 store (\u8BE6\u89C1: fabric store --help)",
1034
+ "cli.help.group.advanced.whoami": "\u663E\u793A\u673A\u5668\u6807\u8BC6",
1035
+ "cli.help.group.advanced.whoami.deprecated": "\u5DF2\u5F03\u7528 \u2192 info --global",
1036
+ "cli.help.group.advanced.status": "\u663E\u793A\u9879\u76EE\u72B6\u6001",
1037
+ "cli.help.group.advanced.status.deprecated": "\u5DF2\u5F03\u7528 \u2192 info",
1038
+ "cli.help.group.advanced.scope-explain": "\u89E3\u91CA scope",
1039
+ "cli.help.group.advanced.scope-explain.deprecated": "\u5DF2\u5F03\u7528 \u2192 info scope",
1071
1040
  "cli.config.description": "\u6253\u5F00 Fabric \u4EA4\u4E92\u5F0F\u914D\u7F6E\u9762\u677F\uFF08\u8BED\u8A00\u3001\u77E5\u8BC6\u5C42\u3001\u5BA1\u8BA1\u6A21\u5F0F\u3001\u63D0\u793A\u7A97\u53E3\u3001MCP \u5BA2\u6237\u7AEF\u914D\u7F6E\u7B49\uFF09\u3002\n\n\u793A\u4F8B\uFF1A\n fabric config \u6253\u5F00\u4EA4\u4E92\u5F0F\u9762\u677F\n fabric config --target /path \u7F16\u8F91\u6307\u5B9A\u9879\u76EE\u7684\u914D\u7F6E",
1072
1041
  "cli.config.args.target.description": "\u76EE\u6807\u9879\u76EE\u76EE\u5F55\uFF08\u9ED8\u8BA4\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF09\u3002",
1073
1042
  "cli.config.clients.claude": "Claude Code CLI",
1074
1043
  "cli.config.install.description": "\u5C06 Fabric MCP \u670D\u52A1\u7AEF\u6761\u76EE\u5B89\u88C5\u5230\u68C0\u6D4B\u5230\u7684\u5BA2\u6237\u7AEF\u914D\u7F6E\u4E2D\u3002",
1075
- "cli.config.install.args.clients.description": "\u53EF\u9009\u7684\u9017\u53F7\u5206\u9694\u5BA2\u6237\u7AEF\u8FC7\u6EE4\u5668\uFF0C\u4F8B\u5982 cursor,codex\u3002",
1044
+ "cli.config.install.args.clients.description": "\u53EF\u9009\u7684\u9017\u53F7\u5206\u9694\u5BA2\u6237\u7AEF\u8FC7\u6EE4\u5668\uFF0C\u4F8B\u5982 cc,codex\u3002",
1076
1045
  "cli.config.install.args.dry-run.description": "\u4EC5\u9884\u89C8\u5C06\u8981\u53D1\u751F\u7684\u5199\u5165\u64CD\u4F5C\uFF0C\u4E0D\u4FEE\u6539\u6587\u4EF6\u3002",
1077
- "cli.config.errors.unknown-client": "\u672A\u77E5\u5BA2\u6237\u7AEF\u201C{client}\u201D\u3002\u8BF7\u4F7F\u7528\u9017\u53F7\u5206\u9694\u5217\u8868\uFF0C\u4F8B\u5982 cursor,codex\u3002",
1046
+ "cli.config.errors.unknown-client": "\u672A\u77E5\u5BA2\u6237\u7AEF\u201C{client}\u201D\u3002\u8BF7\u4F7F\u7528\u9017\u53F7\u5206\u9694\u5217\u8868\uFF0C\u4F8B\u5982 cc,codex\u3002",
1078
1047
  "cli.config.errors.expected-object": "{path} \u4E2D\u5E94\u4E3A\u5BF9\u8C61\u3002",
1079
1048
  "cli.config.install.no-configs": "\u672A\u68C0\u6D4B\u5230 Fabric MCP \u5BA2\u6237\u7AEF\u914D\u7F6E\u3002\u8BF7\u521B\u5EFA\u5BA2\u6237\u7AEF\u76EE\u5F55\uFF0C\u6216\u5728 fabric.config.json \u4E2D\u8BBE\u7F6E clientPaths\u3002",
1080
1049
  "cli.config.install.no-config-path": "\u8DF3\u8FC7 {client}\uFF1A\u672A\u68C0\u6D4B\u5230\u914D\u7F6E\u8DEF\u5F84\u3002",
@@ -1102,7 +1071,7 @@ var zhCNMessages = {
1102
1071
  "cli.config.errors.no-enum-options": "\u8BE5\u5B57\u6BB5\u6CA1\u6709\u53EF\u9009\u679A\u4E3E\u503C \u2014 \u5DF2\u8DF3\u8FC7\u3002",
1103
1072
  // 11 个面板字段标签(A 组 2 个 + B 组 8 个 + C 组 1 个)。
1104
1073
  "cli.config.fields.fabric_language.label": "\u8BED\u8A00",
1105
- "cli.config.fields.fabric_language.description": "Fabric \u94A9\u5B50\u4E0E Skill \u8F93\u51FA\u4F7F\u7528\u7684\u8BED\u8A00\u3002",
1074
+ "cli.config.fields.fabric_language.description": "Fabric \u7684\u5168\u5C40\u8BED\u8A00\u57FA\u8C03\uFF08\u754C\u9762\u4E0E\u77E5\u8BC6\u7EDF\u4E00\uFF09\uFF0C\u4FDD\u5B58\u5230 ~/.fabric/fabric-global.json\u3002",
1106
1075
  "cli.config.fields.default_layer_filter.label": "\u9ED8\u8BA4\u77E5\u8BC6\u5C42",
1107
1076
  "cli.config.fields.default_layer_filter.description": "\u77E5\u8BC6\u5217\u8868\u7684\u9ED8\u8BA4\u5C42\u7EA7\u8303\u56F4\uFF08team / personal / both\uFF09\u3002",
1108
1077
  "cli.config.fields.archive_hint_hours.label": "\u5F52\u6863\u63D0\u793A\u7A97\u53E3\uFF08\u5C0F\u65F6\uFF09",
@@ -1123,7 +1092,11 @@ var zhCNMessages = {
1123
1092
  "cli.config.fields.maintenance_hint_cooldown_days.description": "\u7EF4\u62A4\u63D0\u793A\u518D\u6B21\u89E6\u53D1\u524D\u7684\u51B7\u5374\u65F6\u95F4\uFF08\u5929\uFF09\u3002",
1124
1093
  "cli.config.fields.audit_mode.label": "\u5BA1\u8BA1\u6A21\u5F0F",
1125
1094
  "cli.config.fields.audit_mode.description": "human-lock \u4E0E\u6F02\u79FB\u68C0\u6D4B\u7684\u5BA1\u8BA1\u7C92\u5EA6\uFF08strict / warn / off\uFF09\u3002",
1126
- "cli.doctor.description": "\u8FD0\u884C Fabric \u76EE\u6807\u6001\u8BCA\u65AD\uFF08meta \u540C\u6B65\u3001\u77E5\u8BC6\u7D22\u5F15\u3001bootstrap\u3001events ledger\u3001human-lock \u6F02\u79FB\uFF09\u3002\n\n\u793A\u4F8B\uFF1A\n fabric doctor \u53EA\u8BFB\u8BCA\u65AD\u62A5\u544A\n fabric doctor --fix \u4FEE\u590D\u6D3E\u751F\u72B6\u6001\uFF08meta + \u7D22\u5F15\uFF09\n fabric doctor --fix-knowledge \u5E94\u7528\u77E5\u8BC6\u5E93 lint \u53D8\u66F4\uFF08\u964D\u7EA7 / \u5F52\u6863\uFF09\n fabric doctor --json --strict \u673A\u5668\u53EF\u8BFB\u8F93\u51FA\uFF0Cwarning \u89C6\u4E3A\u5931\u8D25",
1095
+ "cli.config.fields.nudge_mode.label": "\u63D0\u793A\u6863\u4F4D",
1096
+ "cli.config.fields.nudge_mode.description": "\u4EBA\u7C7B\u53EF\u89C1 nudge \u7684\u603B\u6863\u4F4D\uFF08silent \u9759\u9ED8 / minimal \u7CBE\u7B80 / normal \u6B63\u5E38 / verbose \u8BE6\u5C3D\uFF09\uFF1B\u4EC5\u63A7\u4EBA\u7C7B\u63D0\u793A\u901A\u9053\uFF0C\u4E0D\u5F71\u54CD\u6CE8\u5165\u7ED9 AI \u7684\u77E5\u8BC6\u3002",
1097
+ "cli.config.fields.embed_enabled.label": "\u5411\u91CF\u8BED\u4E49\u68C0\u7D22",
1098
+ "cli.config.fields.embed_enabled.description": "\u662F\u5426\u542F\u7528\u5411\u91CF\u8BED\u4E49\u68C0\u7D22\uFF08true / false\uFF09\u3002\u6CE8\u610F\uFF1A\u5F00\u542F\u8FD8\u9700 `fabric install --enable-embed` \u5B8C\u6210\u4E3B\u673A\u4FA7\u5B89\u88C5\uFF08fastembed + \u6A21\u578B\u7F13\u5B58\uFF09\uFF0C\u4EC5\u5728\u6B64\u7F6E true \u4E0D\u4F1A\u81EA\u52A8\u751F\u6548\u3002",
1099
+ "cli.doctor.description": "\u8FD0\u884C Fabric \u76EE\u6807\u6001\u8BCA\u65AD\uFF08meta \u540C\u6B65\u3001\u77E5\u8BC6\u7D22\u5F15\u3001bootstrap\u3001events ledger\u3001human-lock \u6F02\u79FB\uFF09\u3002\n\n\u793A\u4F8B\uFF1A\n fabric doctor \u53EA\u8BFB\u8BCA\u65AD\u62A5\u544A\n fabric doctor --fix \u4FEE\u590D\u6D3E\u751F\u72B6\u6001\uFF08meta + \u7D22\u5F15\uFF09\n fabric doctor --fix-knowledge \u5E94\u7528\u77E5\u8BC6\u5E93 lint \u53D8\u66F4\uFF08\u8BA1\u6570\u5668 / \u5F52\u6863 / \u7F13\u5B58\uFF09\n fabric doctor --json \u673A\u5668\u53EF\u8BFB\u8F93\u51FA",
1127
1100
  "doctor.section.fixable": "\u53EF\u4FEE\u590D\u9519\u8BEF\uFF1A",
1128
1101
  "doctor.section.manual": "\u9700\u624B\u52A8\u4FEE\u590D\uFF1A",
1129
1102
  "doctor.section.warnings": "\u8B66\u544A\uFF1A",
@@ -1204,16 +1177,16 @@ var zhCNMessages = {
1204
1177
  "cli.doctor.args.fix.description": "\u4FEE\u590D Fabric \u6D3E\u751F\u72B6\u6001\uFF08meta + \u7D22\u5F15\uFF09\u3002",
1205
1178
  "cli.doctor.args.json.description": "\u4EE5 JSON \u8F93\u51FA doctor \u62A5\u544A\u3002",
1206
1179
  "cli.doctor.args.strict.description": "\u5C06 warning \u4E5F\u89C6\u4E3A\u5931\u8D25\u3002",
1207
- "cli.doctor.args.fix-knowledge.description": "\u5E94\u7528\u77E5\u8BC6\u5E93 lint \u53D8\u66F4\uFF1A\u964D\u7EA7\u5B64\u7ACB\u7684\u89C4\u8303\u6761\u76EE\u3001\u5F52\u6863\u9648\u65E7 draft\u3001\u4FEE\u6B63\u6F02\u79FB\u7684\u7D22\u5F15\u8BA1\u6570\u5668\u3002\u9ED8\u8BA4 doctor \u8FD0\u884C\u4ECD\u7136\u53EA\u8BFB\u3002",
1180
+ "cli.doctor.args.fix-knowledge.description": "\u5E94\u7528\u77E5\u8BC6\u5E93 lint \u53D8\u66F4:\u5F52\u6863\u903E\u671F pending draft\u3001\u4FEE\u6B63\u6F02\u79FB\u7684 per-store id \u8BA1\u6570\u5668\u3001\u6E05\u7406\u9648\u65E7 session-hint \u7F13\u5B58\u3002\u8870\u51CF\u7C7B lint(orphan demote / stale archive)\u53EA\u8BFB\u4E0A\u62A5 \u2014 \u8BF7\u901A\u8FC7 fab_review \u6D41\u7A0B\u5904\u7406\u3002\u9ED8\u8BA4 doctor \u8FD0\u884C\u4ECD\u7136\u53EA\u8BFB\u3002",
1208
1181
  "cli.doctor.args.yes.description": "\u8DF3\u8FC7 --fix-knowledge \u7684\u5B89\u5168\u786E\u8BA4\uFF1B\u975E tty \u8C03\u7528\u5FC5\u987B\u663E\u5F0F\u8BBE\u7F6E\u8BE5\u6807\u8BB0\uFF0C\u6216\u5728\u73AF\u5883\u53D8\u91CF\u4E2D\u8BBE\u7F6E FABRIC_NONINTERACTIVE=1\u3002",
1209
1182
  // rc.35 TASK-12 (P0-11): --verbose 展开 maintainer 受众的 remediation。
1210
1183
  "cli.doctor.args.verbose.description": "\u5C55\u5F00\u5168\u90E8 action hint,\u5305\u62EC maintainer \u53D7\u4F17\u7684(Fabric \u8D21\u732E\u8005\u4FEE\u6E90\u7801\u7528)\u3002\u9ED8\u8BA4 npm \u7EC8\u7AEF\u7528\u6237\u89C6\u56FE\u4F1A\u628A\u8FD9\u4E9B\u6298\u53E0\u3002",
1211
1184
  "doctor.maintainer-hint-folded": "(maintainer-only remediation \u2014 \u52A0 `fabric doctor --verbose` \u67E5\u770B)",
1212
- "cli.doctor.errors.fix-knowledge-fix-mutually-exclusive": "--fix-knowledge \u4E0E --fix \u4E0D\u53EF\u540C\u65F6\u4F7F\u7528\u3002--fix-knowledge \u4FEE\u6539\u7528\u6237\u77E5\u8BC6\u72B6\u6001\uFF08\u964D\u7EA7/\u5F52\u6863\uFF09\uFF1B--fix \u4FEE\u590D\u6D3E\u751F\u72B6\u6001\uFF08meta/\u7D22\u5F15\uFF09\u3002\u8BF7\u5206\u522B\u8FD0\u884C\u3002",
1185
+ "cli.doctor.errors.fix-knowledge-fix-mutually-exclusive": "--fix-knowledge \u4E0E --fix \u4E0D\u53EF\u540C\u65F6\u4F7F\u7528\u3002--fix-knowledge \u4FEE\u6539\u7528\u6237\u77E5\u8BC6\u72B6\u6001\uFF08\u5F52\u6863/\u8BA1\u6570\u5668/\u7F13\u5B58\uFF09\uFF1B--fix \u4FEE\u590D\u6D3E\u751F\u72B6\u6001\uFF08meta/\u7D22\u5F15\uFF09\u3002\u8BF7\u5206\u522B\u8FD0\u884C\u3002",
1213
1186
  // rc.20 TASK-05: --cite-coverage 报告参数;只读,与 --fix/--fix-knowledge 互斥。
1214
1187
  "cli.doctor.args.cite-coverage.description": "Cite \u653F\u7B56\u5408\u89C4\u62A5\u544A(\u53EA\u8BFB;\u8DF3\u8FC7\u6807\u51C6\u68C0\u67E5)",
1215
1188
  "cli.doctor.args.since.description": "Cite \u8986\u76D6\u7387\u7EDF\u8BA1\u7A97\u53E3(\u5982 7d, 24h, 30m)",
1216
- "cli.doctor.args.client.description": "\u6309\u5BA2\u6237\u7AEF\u8FC7\u6EE4(cc|codex|cursor|all)",
1189
+ "cli.doctor.args.client.description": "\u6309\u5BA2\u6237\u7AEF\u8FC7\u6EE4(cc|codex|all)",
1217
1190
  // v2.0.0-rc.24 TASK-10: --layer 过滤 cite 合约审计的知识层 (team|personal|all)。
1218
1191
  "cli.doctor.args.layer.description": "\u6309\u77E5\u8BC6\u5C42\u8FC7\u6EE4 cite \u5408\u7EA6\u5BA1\u8BA1 (team|personal|all)",
1219
1192
  "cli.doctor.errors.cite-coverage-mutex": "--cite-coverage \u4E0D\u80FD\u4E0E --fix \u6216 --fix-knowledge \u540C\u65F6\u4F7F\u7528",
@@ -1228,7 +1201,7 @@ var zhCNMessages = {
1228
1201
  "doctor.conflict.verdict.similar": "\u76F8\u4F3C (\u53EF\u80FD\u91CD\u590D)",
1229
1202
  "doctor.conflict.verdict.unknown": "\u5F85\u5BA1 (\u53EF\u80FD\u91CD\u590D\u6216\u77DB\u76FE)",
1230
1203
  "cli.doctor.errors.invalid-since": "--since \u53D6\u503C\u65E0\u6548: {input}\u3002\u9884\u671F\u683C\u5F0F 7d / 24h / 30m \u6216 epoch ms\u3002",
1231
- "cli.doctor.errors.invalid-client": "--client \u53D6\u503C\u65E0\u6548: {input}\u3002\u9884\u671F cc / codex / cursor / all\u3002",
1204
+ "cli.doctor.errors.invalid-client": "--client \u53D6\u503C\u65E0\u6548: {input}\u3002\u9884\u671F cc / codex / all\u3002",
1232
1205
  "cli.doctor.errors.invalid-layer": "--layer \u53D6\u503C\u65E0\u6548: {input}\u3002\u9884\u671F team / personal / all\u3002",
1233
1206
  // rc.23 TASK-007 (a-C2): --enrich-descriptions 回填四个 description 字段。
1234
1207
  "cli.doctor.args.enrich-descriptions.description": "\u56DE\u586B\u6B63\u5F0F\u77E5\u8BC6\u6761\u76EE\u7F3A\u5931\u7684 intent_clues / tech_stack / impact / must_read_if \u5B57\u6BB5\uFF08\u9ED8\u8BA4\u53EA\u8BFB;\u642D\u914D --auto \u5199\u5165 stub\uFF09\u3002",
@@ -1236,14 +1209,10 @@ var zhCNMessages = {
1236
1209
  "cli.doctor.args.dry-run.description": "\u4E0E --enrich-descriptions --auto \u6216 --fix \u642D\u914D:\u4EC5\u9884\u89C8\u6539\u52A8\u8BA1\u5212,\u4E0D\u5199\u5165\u78C1\u76D8\u3002fix-dry-run \u8F93\u51FA\u4E0E --fix \u76F8\u540C\u7684 fixable_errors \u5217\u8868,\u4F46\u4E0D\u6267\u884C\u4EFB\u4F55 mutation\u3002",
1237
1210
  // v2.0.0-rc.33 W4-B1 (T6 P2): --fix --dry-run banner — 出现在 report 之前, 让用户明确没有发生 mutation。
1238
1211
  "cli.doctor.fix-dry-run-banner": "[dry-run] \u672A\u5E94\u7528\u4EFB\u4F55 mutation\u3002\u4E0B\u65B9 fixable_errors \u5217\u8868\u5C31\u662F `fabric doctor --fix` \u4F1A\u5904\u7406\u7684\u9879;\u53BB\u6389 --dry-run \u518D\u8DD1\u53EF\u5B9E\u9645\u4FEE\u590D\u3002",
1212
+ "cli.doctor.unbound-project-backfilled": "\u5DF2\u56DE\u586B store '{alias}' \u7684 project-scope \u7ED1\u5B9A \u2192 project '{project}'(\u94F8 project_id + active_project)\u3002",
1239
1213
  "cli.doctor.errors.enrich-descriptions-mutex": "--enrich-descriptions \u4E0D\u80FD\u4E0E --fix / --fix-knowledge / --cite-coverage \u540C\u65F6\u4F7F\u7528,\u8BF7\u5206\u522B\u8FD0\u884C\u3002",
1240
1214
  "doctor.enrich.allComplete": "\u6240\u6709\u6B63\u5F0F\u77E5\u8BC6\u6761\u76EE\u5747\u5DF2\u5305\u542B intent_clues / tech_stack / impact / must_read_if\u3002",
1241
1215
  // rc.26 TASK-02a: doctor foundation-batch check messages.
1242
- "doctor.check.bootstrap_marker_migration.name": "Bootstrap marker \u8FC1\u79FB",
1243
- "doctor.check.bootstrap_marker_migration.ok": "bootstrap \u76EE\u6807\u6587\u4EF6\u4E2D\u672A\u68C0\u6D4B\u5230\u65E7 fabric:knowledge-base marker\u3002",
1244
- "doctor.check.bootstrap_marker_migration.message.singular": "{count} \u4E2A\u6587\u4EF6\u4ECD\u5E26\u6709\u65E7 fabric:knowledge-base bootstrap marker\uFF1A{list}\u3002",
1245
- "doctor.check.bootstrap_marker_migration.message.plural": "{count} \u4E2A\u6587\u4EF6\u4ECD\u5E26\u6709\u65E7 fabric:knowledge-base bootstrap marker\uFF1A{list}\u3002",
1246
- "doctor.check.bootstrap_marker_migration.remediation": "\u8FD0\u884C `fabric doctor --fix` \u8FC1\u79FB\u5230 fabric:bootstrap marker",
1247
1216
  "doctor.check.bootstrap_snapshot_drift.name": "Bootstrap snapshot drift",
1248
1217
  "doctor.check.bootstrap_snapshot_drift.message.drift": ".fabric/AGENTS.md \u5185\u5BB9\u4E0E BOOTSTRAP_CANONICAL \u9010\u5B57\u8282\u4E0D\u4E00\u81F4\u3002",
1249
1218
  "doctor.check.bootstrap_snapshot_drift.remediation.drift": "\u8FD0\u884C `fabric doctor --fix` \u6062\u590D canonical bootstrap snapshot",
@@ -1259,17 +1228,7 @@ var zhCNMessages = {
1259
1228
  "doctor.check.bootstrap_anchor.message.missing": "repo root \u4E0B AGENTS.md \u4E0E CLAUDE.md \u90FD\u4E0D\u5B58\u5728\u3002Fabric \u9700\u8981\u5728\u9879\u76EE\u6839\u76EE\u5F55\u5B58\u5728 bootstrap anchor \u6587\u4EF6\u3002",
1260
1229
  "doctor.check.bootstrap_anchor.remediation.missing": "\u8FD0\u884C `fabric install` \u5728 repo root \u751F\u6210 AGENTS.md / CLAUDE.md bootstrap anchor\u3002",
1261
1230
  "doctor.check.bootstrap_anchor.ok": "repo root \u4E0B\u5DF2\u5B58\u5728 Bootstrap anchor\uFF1A{present}\u3002",
1262
- "doctor.check.baseline_filename_format.name": "Baseline \u6587\u4EF6\u540D\u683C\u5F0F",
1263
- "doctor.check.baseline_filename_format.ok": "\u6240\u6709 baseline knowledge \u6587\u4EF6\u90FD\u4F7F\u7528 canonical `${id}--${slug}.md` \u6587\u4EF6\u540D\u683C\u5F0F\u3002",
1264
- "doctor.check.baseline_filename_format.message.singular": "{count} \u4E2A baseline knowledge \u6587\u4EF6\u4ECD\u4F7F\u7528\u5DF2\u5E9F\u5F03\u7684 bare-slug \u6587\u4EF6\u540D\u683C\u5F0F\uFF0C\u5FC5\u987B\u8FC1\u79FB\u4E3A `${id}--${slug}.md`\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1265
- "doctor.check.baseline_filename_format.message.plural": "{count} \u4E2A baseline knowledge \u6587\u4EF6\u4ECD\u4F7F\u7528\u5DF2\u5E9F\u5F03\u7684 bare-slug \u6587\u4EF6\u540D\u683C\u5F0F\uFF0C\u5FC5\u987B\u8FC1\u79FB\u4E3A `${id}--${slug}.md`\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1266
1231
  // v2.0.0-rc.33 W3-2 (T6 #5): 文案显式引用 message 内已列出的 detail (file 名), 让用户直接 rm 而非自己去 grep 找。baseline pipeline 已 rc.23 移除, 没有 auto-fix。
1267
- "doctor.check.baseline_filename_format.remediation": "\u624B\u52A8\u5220\u9664\u4E0A\u9762 message \u4E2D\u5217\u51FA\u7684 bare-slug baseline file(s) (\u4F8B\u5982 `rm <message \u5217\u51FA\u7684 file>`);baseline pipeline \u5DF2\u5728 rc.23 \u79FB\u9664, \u4E0D\u518D\u63D0\u4F9B auto-fix \u8DEF\u5F84\u3002",
1268
- "doctor.check.knowledge_dir_missing.name": "Knowledge layout",
1269
- "doctor.check.knowledge_dir_missing.message.singular": "{count} \u4E2A\u5FC5\u9700 knowledge subdir \u7F3A\u5931\uFF1A{list}\u3002",
1270
- "doctor.check.knowledge_dir_missing.message.plural": "{count} \u4E2A\u5FC5\u9700 knowledge subdir \u7F3A\u5931\uFF1A{list}\u3002",
1271
- "doctor.check.knowledge_dir_missing.remediation": "\u8FD0\u884C `fabric doctor --fix` \u521B\u5EFA\u7F3A\u5931\u7684 .fabric/knowledge/* subdirectories\u3002",
1272
- "doctor.check.knowledge_dir_missing.ok": "\u5168\u90E8 {count} \u4E2A\u5FC5\u9700 .fabric/knowledge/* subdirectories \u5747\u5DF2\u5B58\u5728\u3002",
1273
1232
  "doctor.check.forensic.name": "Scan evidence",
1274
1233
  "doctor.check.forensic.message.missing.singular": "{error} \u5B9E\u65F6\u626B\u63CF\u68C0\u6D4B\u5230 {frameworkKind}\uFF0C\u5171\u6709 {count} \u4E2A\u5165\u53E3\u70B9\u3002",
1275
1234
  "doctor.check.forensic.message.missing.plural": "{error} \u5B9E\u65F6\u626B\u63CF\u68C0\u6D4B\u5230 {frameworkKind}\uFF0C\u5171\u6709 {count} \u4E2A\u5165\u53E3\u70B9\u3002",
@@ -1279,27 +1238,27 @@ var zhCNMessages = {
1279
1238
  "doctor.check.forensic.ok": ".fabric/forensic.json \u5BF9 {frameworkKind} \u6709\u6548\u3002",
1280
1239
  "doctor.check.agents_meta.name": "Agents metadata",
1281
1240
  "doctor.check.agents_meta.message.missing": ".fabric/agents.meta.json \u7F3A\u5931\u3002",
1282
- "doctor.check.agents_meta.remediation.missing": "\u8FD0\u884C `fabric doctor --fix` \u4ECE .fabric/knowledge/ \u91CD\u5EFA agents.meta.json\u3002",
1241
+ "doctor.check.agents_meta.remediation.missing": "store-backed knowledge \u4E0B\u65E0\u9700\u5904\u7406\uFF1B\u9879\u76EE\u672C\u5730 agents.meta \u91CD\u5EFA\u8DEF\u5F84\u5DF2\u9000\u4F11\u3002",
1283
1242
  "doctor.check.agents_meta.message.invalid-default": ".fabric/agents.meta.json \u65E0\u6548\u3002",
1284
1243
  // rc.35 TASK-09 (P0-14): 人话化的 schema 解析失败消息。
1285
1244
  "doctor.check.agents_meta.message.invalid-zod": ".fabric/agents.meta.json schema \u6821\u9A8C\u5931\u8D25 \u2014 {issues}\u3002\u8BE5\u6587\u4EF6\u5F88\u53EF\u80FD\u7531\u4E0D\u517C\u5BB9\u7248\u672C\u7684 fabric CLI \u5199\u5165,\u6216\u88AB\u624B\u5DE5\u7F16\u8F91\u3002",
1286
1245
  "doctor.check.agents_meta.message.invalid-from-old-cli": ".fabric/agents.meta.json schema \u6821\u9A8C\u5931\u8D25,\u56E0\u4E3A PATH \u4E0A\u7684\u5168\u5C40 `fabric` CLI ({version}) \u4F4E\u4E8E\u6700\u4F4E\u652F\u6301\u7248\u672C {minVersion}\u3002rc.31 \u5F15\u5165\u4E86\u5411\u540E\u517C\u5BB9\u7684 singular\u2192plural \u5F52\u4E00\u5316,\u65E7\u7248 CLI \u5199\u51FA\u7684\u6587\u4EF6\u81EA\u5DF1\u4E5F\u65E0\u6CD5\u89E3\u6790\u3002",
1287
- "doctor.check.agents_meta.remediation.invalid": "\u8FD0\u884C `fabric doctor --fix` \u8BA9 reconcile \u4ECE .fabric/knowledge/ \u78C1\u76D8 ground-truth \u91CD\u5EFA agents.meta.json\uFF08rc.31 \u8D77\u517C\u5BB9\u5386\u53F2 schema \u7684 singular knowledge_type \u81EA\u52A8\u8FC1\u79FB\u5230 plural\uFF1B\u4E0D\u8981\u624B\u52A8\u5220\u9664 agents.meta.json\uFF0C\u4F1A\u4E22 counters envelope \u4E0E promote ledger \u5173\u8054\uFF09\u3002",
1288
- "doctor.check.agents_meta.message.stale": ".fabric/agents.meta.json revision {revision} \u4E0E .fabric/knowledge \u6D3E\u751F revision {computedRevision} \u4E0D\u4E00\u81F4\u3002",
1289
- "doctor.check.agents_meta.message.stale_hash_equal": ".fabric/agents.meta.json \u5DF2\u4E0E .fabric/knowledge \u5185\u5BB9\u4E00\u81F4\uFF08revision {revision}\uFF09\uFF0C\u4F46 mtime/counters \u6D3E\u751F\u72B6\u6001\u8FC7\u671F\u3002\u53EF\u5FFD\u7565\u3002",
1290
- "doctor.check.agents_meta.remediation.stale": "\u53EF\u5FFD\u7565\uFF1Bengine \u4F1A\u5728\u4E0B\u4E00\u6B21 plan-context/get-sections \u8C03\u7528\u65F6\u81EA\u52A8\u4FEE\u590D\u3002\u9700\u8981\u663E\u5F0F reconcile \u65F6\u8FD0\u884C `fabric doctor --fix`\u3002",
1291
- "doctor.check.agents_meta.ok": ".fabric/agents.meta.json revision {revision} \u5DF2\u4E0E .fabric/knowledge \u5BF9\u9F50\u3002",
1246
+ "doctor.check.agents_meta.remediation.invalid": "\u9879\u76EE\u672C\u5730 agents.meta \u5DF2\u9000\u4F11\u3002\u8FD0\u884C `fabric install` \u5237\u65B0\u5BA2\u6237\u7AEF bootstrap\uFF0C\u5E76\u628A knowledge \u4FDD\u6301\u5728 ~/.fabric/stores/ \u4E0B\u7684 mounted store \u4E2D\u3002",
1247
+ "doctor.check.agents_meta.message.stale": ".fabric/agents.meta.json revision {revision} \u4E0E\u5DF2\u9000\u4F11\u7684\u672C\u5730\u6D3E\u751F revision {computedRevision} \u4E0D\u4E00\u81F4\u3002",
1248
+ "doctor.check.agents_meta.message.stale_hash_equal": ".fabric/agents.meta.json \u5DF2\u4E0E\u5DF2\u9000\u4F11\u7684\u672C\u5730\u6D3E\u751F revision {revision} \u5BF9\u9F50\uFF1B\u8BE5\u68C0\u67E5\u4EC5\u4F5C\u5386\u53F2\u517C\u5BB9\u3002",
1249
+ "doctor.check.agents_meta.remediation.stale": "\u4E0D\u518D\u6267\u884C\u9879\u76EE\u672C\u5730 reconcile\uFF1Bmounted stores \u4F1A\u88AB\u76F4\u63A5\u8BFB\u53D6\u3002",
1250
+ "doctor.check.agents_meta.ok": "\u68C0\u6D4B\u5230 legacy agents.meta revision {revision}\uFF1Bstore-backed knowledge \u4E0D\u4F9D\u8D56\u5B83\u3002",
1292
1251
  "doctor.check.rule_content_refs.name": "Rule content refs",
1293
1252
  "doctor.check.rule_content_refs.message.unavailable": "agents.meta.json \u6709\u6548\u524D\uFF0C\u65E0\u6CD5\u68C0\u67E5 content_ref entries\u3002",
1294
1253
  "doctor.check.rule_content_refs.remediation.unavailable": "\u5148\u4FEE\u590D agents.meta.json\uFF1A\u8FD0\u884C `fabric doctor --fix`\u3002",
1295
- "doctor.check.rule_content_refs.message.outside.singular": "{count} \u4E2A content_ref entry \u4F4D\u4E8E .fabric/knowledge \u5916\u90E8\u3002",
1296
- "doctor.check.rule_content_refs.message.outside.plural": "{count} \u4E2A content_ref entries \u4F4D\u4E8E .fabric/knowledge \u5916\u90E8\u3002",
1254
+ "doctor.check.rule_content_refs.message.outside.singular": "{count} \u4E2A legacy content_ref entry \u4F4D\u4E8E\u5DF2\u9000\u4F11\u7684\u672C\u5730 knowledge root \u5916\u90E8\u3002",
1255
+ "doctor.check.rule_content_refs.message.outside.plural": "{count} \u4E2A legacy content_ref entries \u4F4D\u4E8E\u5DF2\u9000\u4F11\u7684\u672C\u5730 knowledge root \u5916\u90E8\u3002",
1297
1256
  // v2.0.0-rc.33 W3-2 (T6 #12): 项目规则禁止手动编辑 agents.meta.json (见 .fabric/AGENTS.md); 改引导用户跑 doctor --fix 走 reconcile 路径 (rc.31+ 兼容自动剔除外部 refs)。
1298
1257
  "doctor.check.rule_content_refs.remediation.outside": "\u8FD0\u884C `fabric doctor --fix` \u8BA9 reconcile \u81EA\u52A8\u5254\u9664\u5916\u90E8 content_ref (rc.31+ \u517C\u5BB9)\u3002\u4E25\u7981\u624B\u52A8\u7F16\u8F91 agents.meta.json \u2014 engine \u4F1A\u81EA\u52A8 reconcile\u3002",
1299
1258
  "doctor.check.rule_content_refs.message.missing.singular": "{count} \u4E2A content_ref target \u7F3A\u5931\u3002\u8FD0\u884C `fabric doctor --fix` \u6267\u884C reconcile\u3002",
1300
1259
  "doctor.check.rule_content_refs.message.missing.plural": "{count} \u4E2A content_ref targets \u7F3A\u5931\u3002\u8FD0\u884C `fabric doctor --fix` \u6267\u884C reconcile\u3002",
1301
- "doctor.check.rule_content_refs.remediation.missing": "\u8FD0\u884C `fabric doctor --fix` \u8BA9 agents.meta.json \u4E0E .fabric/knowledge/ \u4E2D\u7684\u73B0\u6709\u6587\u4EF6 reconcile\u3002",
1302
- "doctor.check.rule_content_refs.ok": "\u6240\u6709 content_ref entries \u90FD\u80FD\u89E3\u6790\u5230 .fabric/knowledge files\u3002",
1260
+ "doctor.check.rule_content_refs.remediation.missing": "\u9879\u76EE\u672C\u5730 content_ref reconcile \u5DF2\u9000\u4F11\uFF1B\u8BF7\u7ED1\u5B9A\u5E76\u8BFB\u53D6 mounted stores\u3002",
1261
+ "doctor.check.rule_content_refs.ok": "\u6240\u6709 legacy content_ref entries \u90FD\u80FD\u89E3\u6790\uFF1Bstore-backed knowledge \u4ECE mounted stores \u8BFB\u53D6\u3002",
1303
1262
  "doctor.check.knowledge_test_index.name": "Knowledge-test index",
1304
1263
  "doctor.check.knowledge_test_index.remediation.missing": "\u8FD0\u884C `fabric doctor --fix` \u91CD\u5EFA .fabric/.cache/knowledge-test.index.json\u3002",
1305
1264
  "doctor.check.knowledge_test_index.remediation.invalid": "\u5220\u9664 .fabric/.cache/knowledge-test.index.json \u5E76\u8FD0\u884C `fabric doctor --fix` \u91CD\u65B0\u751F\u6210\u3002",
@@ -1327,10 +1286,6 @@ var zhCNMessages = {
1327
1286
  "doctor.check.events_jsonl_health.message.metrics_stale": ".fabric/metrics.jsonl \u5DF2 {minutes} \u5206\u949F\u672A\u66F4\u65B0\uFF1Bserver-side 60s flush \u53EF\u80FD stalled\u3002",
1328
1287
  "doctor.check.events_jsonl_health.message.rotation_overdue": ".fabric/events.jsonl \u5DF2 {days} \u5929\u672A rotate\uFF1B6h rotation tick \u53EF\u80FD\u672A\u8FD0\u884C\u3002",
1329
1288
  "doctor.check.events_jsonl_health.remediation": "\u8FD0\u884C `fabric doctor --fix` \u2014\u2014 \u5B83\u4F1A\u89E6\u53D1 rotation \u5E76 flush metrics.jsonl(rc.2 F16: \u65E0\u9700\u91CD\u542F server \u5373\u53EF\u6E05\u51FA idle \u671F\u672A\u5237\u7684 metric counter)\u3002\u82E5\u544A\u8B66\u4ECD\u6301\u7EED, \u518D\u91CD\u542F MCP server \u8BA9 startMetricsFlush + startRotationTick \u91CD\u65B0\u8C03\u5EA6\u3002\u82E5 metric_leak \u547D\u4E2D, \u68C0\u67E5\u6700\u8FD1\u4EE3\u7801\u6539\u52A8\u662F\u5426\u7ED5\u8FC7 bumpCounter API \u76F4\u63A5 appendEventLedgerEvent \u5199\u4E86 4 \u4E2A metric-managed event_type \u4E4B\u4E00\u3002",
1330
- "doctor.check.mcp_config_in_wrong_file.name": "Claude MCP config \u4F4D\u7F6E",
1331
- "doctor.check.mcp_config_in_wrong_file.message": ".claude/settings.json \u5305\u542B mcpServers.fabric\uFF1B\u6B64\u6587\u4EF6\u4EC5\u7528\u4E8E hooks/permissions\u3002\u8FD0\u884C --fix \u79FB\u9664\u5B83\uFF0C\u7136\u540E\u91CD\u65B0\u8FD0\u884C fabric install \u5199\u5165 .mcp.json\u3002",
1332
- "doctor.check.mcp_config_in_wrong_file.remediation": "\u8FD0\u884C `fabric doctor --fix` \u4ECE .claude/settings.json \u4E2D\u79FB\u9664 mcpServers.fabric\uFF0C\u7136\u540E\u8FD0\u884C `fabric install` \u5199\u5165 .mcp.json\u3002",
1333
- "doctor.check.mcp_config_in_wrong_file.ok": "mcpServers.fabric \u4E0D\u5728 .claude/settings.json \u4E2D\u3002",
1334
1289
  "doctor.check.event_ledger_partial_write.name": "Event ledger partial write",
1335
1290
  "doctor.check.event_ledger_partial_write.ok.skipped": "\u65E0\u9700\u6267\u884C partial-write \u68C0\u67E5\uFF08ledger \u7F3A\u5931\u6216\u4E0D\u53EF\u5199\uFF09\u3002",
1336
1291
  "doctor.check.event_ledger_partial_write.message": "events.jsonl \u5728 byte offset {byteOffset} \u5904\u5B58\u5728 partial write\uFF08{byteLength} \u4E2A corrupted bytes\uFF09\u3002\u8FD0\u884C --fix \u622A\u65AD\u5E76\u4FDD\u7559 corrupted bytes\u3002",
@@ -1361,23 +1316,18 @@ var zhCNMessages = {
1361
1316
  "doctor.check.skill_description.message.singular": "{count} \u4E2A SKILL.md description \u7ED3\u6784\u95EE\u9898: {list}\u3002description \u662F host \u7AEF auto-invoke \u7684\u4E3B\u8981\u5339\u914D\u4FE1\u53F7\u3002",
1362
1317
  "doctor.check.skill_description.message.plural": "{count} \u4E2A SKILL.md description \u7ED3\u6784\u95EE\u9898: {list}\u3002description \u662F host \u7AEF auto-invoke \u7684\u4E3B\u8981\u5339\u914D\u4FE1\u53F7\u3002",
1363
1318
  "doctor.check.skill_description.remediation": "\u7F16\u8F91 `packages/cli/templates/skills/<slug>/SKILL.md` frontmatter `description:` \u5B57\u6BB5: (1) \u975E\u7A7A; (2) <60 token (chars/3 \u4F30\u7B97, \u7EA6 180 \u5B57\u7B26); (3) \u81F3\u5C11 1 \u4E2A\u4E2D\u6587 trigger \u77ED\u8BED; (4) \u81F3\u5C11 1 \u4E2A\u82F1\u6587 trigger \u77ED\u8BED\u3002\u53C2\u8003 W1 description rewrite \u98CE\u683C\u3002\u91CD\u65B0\u8DD1 `fabric install` \u540C\u6B65\u4E24\u7AEF\u3002\u5982\u9700\u9A8C\u8BC1 recall, \u8DD1 W1 \u7684 gemini delegate (\u89C1 .workflow/.scratchpad/rc33-plan/W1-VERIFY-RESULT.md)\u3002",
1364
- // v2.0.0-rc.33 W3-3 (P1-3): cite-policy Goodhart 模式检测。扫 7d 内 assistant_turn_observed 事件, 4 个 anti-pattern (G1 仪式化 / G2 抄底引用 / G3 chained-from 滥用 / G5 placeholder cite)。warning 级 (启发式有 false-positive, 不阻断)。
1319
+ // v2.0.0-rc.33 W3-3 (P1-3): cite-policy Goodhart 模式检测。扫 7d 内 assistant_turn_observed 事件, 3 个 anti-pattern (G1 仪式化 / G2 抄底引用 / G5 placeholder cite)。warning 级 (启发式有 false-positive, 不阻断)。
1365
1320
  "doctor.check.cite_goodhart.name": "Cite-policy Goodhart",
1366
1321
  "doctor.check.cite_goodhart.ok": "\u8FC7\u53BB 7d \u672A\u68C0\u6D4B\u5230 cite-policy Goodhart \u53CD\u6A21\u5F0F\u3002",
1367
1322
  "doctor.check.cite_goodhart.message.singular": "\u68C0\u6D4B\u5230 {count} \u4E2A cite-policy Goodhart \u6A21\u5F0F: {list}\u3002",
1368
1323
  "doctor.check.cite_goodhart.message.plural": "\u68C0\u6D4B\u5230 {count} \u4E2A cite-policy Goodhart \u6A21\u5F0F: {list}\u3002",
1369
- "doctor.check.cite_goodhart.remediation": "\u5BA1\u9605\u89E6\u53D1\u7684 pattern: G1 \u4EEA\u5F0F\u5316 \u2192 \u540C\u4E00 [recalled] cite \u91CD\u590D\u7528,\u8BE5\u628A KB \u771F\u6B63\u843D\u5230 contract; G2 \u6284\u5E95\u5F15\u7528 \u2192 > 60% recalled \u7528 skip: \u662F\u7ED5\u8FC7 contract, review skip reason \u771F\u5B9E\u6027; G3 chained-from \u6EE5\u7528 \u2192 chained-from \u6807\u4E86\u4F46\u6CA1 commitment, \u8981\u8865 operators \u6216\u6539\u7528\u5176\u4ED6 tag; G5 placeholder cite \u2192 'KB: none' / [unspecified] \u592A\u591A, \u8BE5\u7528\u5177\u4F53 sentinel \u5982 [no-relevant] / [not-applicable]\u3002\u8BE6\u7EC6\u6570\u636E\u8DD1 `fabric doctor --cite-coverage --since=7d`\u3002",
1324
+ "doctor.check.cite_goodhart.remediation": "\u5BA1\u9605\u89E6\u53D1\u7684 pattern: G1 \u4EEA\u5F0F\u5316 \u2192 \u540C\u4E00 [applied] cite \u91CD\u590D\u7528,\u8BE5\u628A KB \u771F\u6B63\u843D\u5230 contract; G2 \u6284\u5E95\u5F15\u7528 \u2192 > 60% applied \u7528 skip: \u662F\u7ED5\u8FC7 contract, review skip reason \u771F\u5B9E\u6027; G5 placeholder cite \u2192 'KB: none' / [unspecified] \u592A\u591A, \u8BE5\u7528\u5177\u4F53 sentinel \u5982 [no-relevant] / [not-applicable]\u3002\u8BE6\u7EC6\u6570\u636E\u8DD1 `fabric doctor --cite-coverage --since=7d`\u3002",
1370
1325
  // v2.0.0-rc.33 W4-A4 (T5 P2): draft-backlog lint。rc.32 baseline 92% entry 卡在 draft, 揭示 promote 断流。> 50% draft 触发 warning (workspace 必须 >= 10 entries 才计算比率, 避免小语料噪音)。
1371
1326
  "doctor.check.draft_backlog.name": "Knowledge draft backlog",
1372
1327
  "doctor.check.draft_backlog.ok": "canonical knowledge entries \u4E2D draft \u5360\u6BD4\u6B63\u5E38 (< 50%, \u6216 workspace \u592A\u5C0F\u4E0D\u8BC4)\u3002",
1373
1328
  "doctor.check.draft_backlog.message": "{draftCount}/{totalCount} ({pct}%) canonical knowledge entries \u5361\u5728 draft maturity \u2014 promote \u65AD\u6D41 (rc.32 baseline 92%)\u3002",
1374
1329
  "doctor.check.draft_backlog.remediation": "\u8C03 `/fabric-review` \u6279\u91CF\u5BA1 draft entries: approve \u5347 verified/proven, reject \u4E22, modify \u4FEE\u3002draft \u957F\u671F\u5806\u79EF\u901A\u5E38\u610F\u5473\u7740 archive skill \u4EA7 draft \u592A\u5FEB\u6216 review skill \u6CA1\u8DDF\u4E0A\u3002",
1375
1330
  // rc.37 NEW-38: knowledge auto-promote (info surface; --fix 执行).
1376
- "doctor.check.draft_auto_promote.name": "Knowledge auto-promote",
1377
- "doctor.check.draft_auto_promote.ok": "\u65E0 settled draft \u5F85\u81EA\u52A8 promote (draft \u5747\u672A\u6EE1 14 \u5929\u6216\u5DF2\u88AB drift \u6807\u8BB0)\u3002",
1378
- "doctor.check.draft_auto_promote.message": "{count} \u4E2A draft entries \u5DF2\u6C89\u6DC0 \u226514 \u5929\u4E14\u65E0 drift ({sample}{suffix}) \u2014 \u53EF\u81EA\u52A8 promote \u5230 verified\u3002\u8DD1 `fabric doctor --fix` \u6267\u884C\u3002",
1379
- "doctor.check.draft_auto_promote.remediation": "\u8DD1 `fabric doctor --fix` \u628A\u8FD9\u4E9B settled draft \u81EA\u52A8\u5347\u5230 verified (\u6392\u6389 draft_backlog); \u6216\u8C03 `/fabric-review` \u624B\u52A8\u9010\u6761\u5B9A\u593A\u3002",
1380
- "doctor.check.draft_auto_promote.fixed": "\u81EA\u52A8 promote {count} \u4E2A settled draft entries \u2192 verified\u3002",
1381
1331
  // rc.36 TASK-05 (P0-8): empty-tags ratio warn.
1382
1332
  "doctor.check.knowledge_tags_empty.name": "Knowledge tags coverage",
1383
1333
  "doctor.check.knowledge_tags_empty.ok": "canonical knowledge entries \u4E2D empty tags \u5360\u6BD4\u6B63\u5E38 (\u2264 50%, \u6216 workspace \u592A\u5C0F\u4E0D\u8BC4)\u3002",
@@ -1387,68 +1337,43 @@ var zhCNMessages = {
1387
1337
  "doctor.check.drift_unconsumed.name": "Knowledge drift unconsumed",
1388
1338
  "doctor.check.drift_unconsumed.ok": "\u8FD1 30 \u5929\u5185 knowledge_drift_detected \u4E8B\u4EF6\u5DF2\u88AB\u5BF9\u5E94 knowledge_demoted \u6D88\u5316,\u6216\u4E8B\u4EF6\u6570\u592A\u5C11\u4E0D\u8BC4\u3002",
1389
1339
  "doctor.check.drift_unconsumed.message": "\u8FD1 30 \u5929\u5185 knowledge_drift_detected \u4E8B\u4EF6 {driftCount} \u6B21,knowledge_demoted \u4E8B\u4EF6 {demoteCount} \u6B21\u3002drift > demote \u81F3\u5C11 5 \u2192 \u90E8\u5206 drift \u6CA1\u88AB\u6D88\u5316,KB \u4F1A\u7F13\u6162\u5931\u6D3B\u3002",
1390
- "doctor.check.drift_unconsumed.remediation": "\u8FD0\u884C `fabric doctor --fix` \u89E6\u53D1 orphan-demote / stale-archive \u81EA\u6108\u6D41,\u6216\u8C03 `/fabric-review` \u4E3B\u52A8\u5BA1 drift \u6807\u8BB0\u7684\u6761\u76EE\u3002",
1340
+ "doctor.check.drift_unconsumed.remediation": "\u8C03 `/fabric-review` \u5BA1 drift \u6807\u8BB0\u7684\u6761\u76EE \u2014 \u901A\u8FC7 store \u5199\u4FA7 review \u6D41\u7A0B\u964D\u7EA7\u6216\u5F52\u6863\u5B83\u4EEC\u3002(doctor \u7684 orphan_demote / stale_archive lint \u53EA\u4E0A\u62A5\u8870\u51CF,\u4E0D\u81EA\u6108 store \u77E5\u8BC6\u3002)",
1391
1341
  "doctor.check.meta_manually_diverged.name": "Meta manual divergence",
1392
1342
  "doctor.check.meta_manually_diverged.ok.unreadable": "agents.meta.json \u4E0D\u53EF\u8BFB\uFF0C\u8DF3\u8FC7 divergence \u68C0\u67E5\u3002",
1393
1343
  "doctor.check.meta_manually_diverged.message.extra.singular": "agents.meta.json \u4E2D\u6709 {count} \u4E2A entry \u5728\u78C1\u76D8\u4E0A\u6CA1\u6709\u5BF9\u5E94\u6587\u4EF6\u3002\u8FD0\u884C --fix \u6267\u884C reconcile\u3002",
1394
1344
  "doctor.check.meta_manually_diverged.message.extra.plural": "agents.meta.json \u4E2D\u6709 {count} \u4E2A entries \u5728\u78C1\u76D8\u4E0A\u6CA1\u6709\u5BF9\u5E94\u6587\u4EF6\u3002\u8FD0\u884C --fix \u6267\u884C reconcile\u3002",
1395
- "doctor.check.meta_manually_diverged.remediation.extra": "\u8FD0\u884C `fabric doctor --fix` \u8BA9 agents.meta.json \u4E0E\u78C1\u76D8\u4E0A\u5F53\u524D\u7684 rule files reconcile\u3002",
1345
+ "doctor.check.meta_manually_diverged.remediation.extra": "\u9879\u76EE\u672C\u5730 agents.meta reconcile \u5DF2\u9000\u4F11\uFF1Bmounted stores \u662F source of truth\u3002",
1396
1346
  "doctor.check.meta_manually_diverged.message.hash.singular": "agents.meta.json \u4E2D\u6709 {count} \u4E2A entry \u7684 hash \u4E0E\u78C1\u76D8\u6587\u4EF6\u4E0D\u5339\u914D\u3002\u8FD0\u884C --fix \u6267\u884C reconcile\u3002",
1397
1347
  "doctor.check.meta_manually_diverged.message.hash.plural": "agents.meta.json \u4E2D\u6709 {count} \u4E2A entries \u7684 hash \u4E0E\u78C1\u76D8\u6587\u4EF6\u4E0D\u5339\u914D\u3002\u8FD0\u884C --fix \u6267\u884C reconcile\u3002",
1398
- "doctor.check.meta_manually_diverged.remediation.hash": "\u8FD0\u884C `fabric doctor --fix` \u8BA9 agents.meta.json \u4E0E\u5F53\u524D rule file \u5185\u5BB9 reconcile\u3002",
1348
+ "doctor.check.meta_manually_diverged.remediation.hash": "\u9879\u76EE\u672C\u5730 agents.meta reconcile \u5DF2\u9000\u4F11\uFF1Bmounted stores \u662F source of truth\u3002",
1399
1349
  "doctor.check.meta_manually_diverged.ok.consistent": "agents.meta.json \u4E0E\u78C1\u76D8\u4E0A\u7684 rule files \u4E00\u81F4\u3002",
1400
1350
  "doctor.check.knowledge_dir_unindexed.name": "Knowledge dir unindexed",
1401
- "doctor.check.knowledge_dir_unindexed.message.singular": ".fabric/knowledge/ \u4E2D\u6709 {count} \u4E2A .md file \u672A\u7D22\u5F15\u5230 agents.meta.json\u3002\u8FD0\u884C `fabric doctor --fix` \u7D22\u5F15\u7F3A\u5931\u7684 knowledge files\u3002",
1402
- "doctor.check.knowledge_dir_unindexed.message.plural": ".fabric/knowledge/ \u4E2D\u6709 {count} \u4E2A .md files \u672A\u7D22\u5F15\u5230 agents.meta.json\u3002\u8FD0\u884C `fabric doctor --fix` \u7D22\u5F15\u7F3A\u5931\u7684 knowledge files\u3002",
1403
- "doctor.check.knowledge_dir_unindexed.remediation": "\u8FD0\u884C `fabric doctor --fix` \u7D22\u5F15\u7F3A\u5931\u7684 knowledge files\u3002",
1404
- "doctor.check.knowledge_dir_unindexed.ok": "\u6240\u6709 .fabric/knowledge/ .md files \u90FD\u5DF2\u7D22\u5F15\u5230 agents.meta.json\u3002",
1405
- "doctor.check.stable_id_collision.name": "Stable ID collision",
1406
- "doctor.check.stable_id_collision.message.singular": 'stable_id "{stableId}" \u88AB\u58F0\u660E\u5728 {fileCount} \u4E2A\u6587\u4EF6\u4E2D\uFF1A{files}\u3002\u8BF7\u7F16\u8F91\u5176\u4E2D\u4E00\u4E2A knowledge file\uFF0C\u6539\u7528\u552F\u4E00 stable_id\u3002',
1407
- "doctor.check.stable_id_collision.message.plural": '\u68C0\u6D4B\u5230 {count} \u4E2A stable_id collisions\u3002\u9996\u4E2A\uFF1A"{stableId}" \u4F4D\u4E8E {files}\u3002\u8BF7\u7F16\u8F91\u5176\u4E2D\u4E00\u4E2A knowledge file\uFF0C\u6539\u7528\u552F\u4E00 stable_id\u3002',
1351
+ "doctor.check.knowledge_dir_unindexed.message.singular": "\u68C0\u6D4B\u5230 {count} \u4E2A legacy local knowledge .md file \u672A\u7D22\u5F15\u3002\u8BF7\u79FB\u5165 mounted store\uFF1B\u975E store knowledge root \u5DF2\u9000\u4F11\u3002",
1352
+ "doctor.check.knowledge_dir_unindexed.message.plural": "\u68C0\u6D4B\u5230 {count} \u4E2A legacy local knowledge .md files \u672A\u7D22\u5F15\u3002\u8BF7\u79FB\u5165 mounted store\uFF1B\u975E store knowledge root \u5DF2\u9000\u4F11\u3002",
1353
+ "doctor.check.knowledge_dir_unindexed.remediation": "\u4F7F\u7528 `fabric store bind` / `fabric store switch-write`\uFF0C\u7136\u540E\u628A knowledge \u8FC1\u5165 store \u7684 knowledge/ tree\u3002",
1354
+ "doctor.check.knowledge_dir_unindexed.ok": "\u65E0\u9700\u6267\u884C legacy local knowledge \u7D22\u5F15\u52A8\u4F5C\u3002",
1408
1355
  // v2.0.0-rc.33 W3-2 (T6 #27): 走 fabric-review modify 流程让 canonical id allocator 重新分配, 而非让用户自己选 id (易撞 counter, 难手算)。
1409
- "doctor.check.stable_id_collision.remediation": "\u8C03 `/fabric-review modify <message \u4E2D\u5217\u51FA\u7684 colliding id \u4E4B\u4E00>`, \u8BA9 canonical id allocator \u81EA\u52A8\u91CD\u5206\u914D id (\u4F1A\u540C\u6B65\u66F4\u65B0 frontmatter + counters + \u5386\u53F2 cross-ref)\u3002\u4E25\u7981\u624B\u5DE5\u7F16\u8F91 id frontmatter \u2014 \u4F1A\u649E counter\u3002",
1410
- "doctor.check.stable_id_collision.ok": ".fabric/knowledge/ \u4E2D\u672A\u53D1\u73B0\u5DF2\u58F0\u660E\u7684 stable_id collisions\u3002",
1411
1356
  "doctor.check.counter_desync.name": "Knowledge counter desync",
1412
1357
  "doctor.check.counter_desync.message.singular": "{count} \u4E2A knowledge counter \u4E0E\u89C2\u6D4B\u5230\u7684 stable_ids \u4E0D\u540C\u6B65\u3002{counterPath} = {current}\uFF0C\u4F46\u68C0\u6D4B\u5230 {observedId}\u3002\u8FD0\u884C `fabric doctor --fix` bump counters\u3002",
1413
1358
  "doctor.check.counter_desync.message.plural": "{count} \u4E2A knowledge counters \u4E0E\u89C2\u6D4B\u5230\u7684 stable_ids \u4E0D\u540C\u6B65\u3002{counterPath} = {current}\uFF0C\u4F46\u68C0\u6D4B\u5230 {observedId}\u3002\u8FD0\u884C `fabric doctor --fix` bump counters\u3002",
1414
1359
  "doctor.check.counter_desync.remediation": "\u8FD0\u884C `fabric doctor --fix` \u5C06 agents.meta.json counters \u63D0\u5347\u5230\u89C2\u6D4B\u5230\u7684\u6700\u5927 counter \u503C\u3002",
1415
1360
  "doctor.check.counter_desync.ok": "agents.meta.json counters envelope \u4E0E\u89C2\u6D4B\u5230\u7684 stable_ids \u4E00\u81F4\u3002",
1361
+ "doctor.check.store_counter_drift.name": "Store counter drift",
1362
+ "doctor.check.store_counter_drift.message.singular": "{count} \u4E2A store counter \u4F4E\u4E8E\u78C1\u76D8\u4E0A\u7684\u6700\u5927 stable_id\uFF08{detail}\uFF09\u3002\u8BE5 store \u4E0B\u4E00\u6B21\u94F8\u53F7\u4F1A\u590D\u7528\u5DF2\u5B58\u5728\u7684 id\u3002\u8FD0\u884C `fabric doctor --fix` \u5C06 store counters.json \u63D0\u5347\u5230\u78C1\u76D8\u6700\u5927\u503C\u3002",
1363
+ "doctor.check.store_counter_drift.message.plural": "{count} \u4E2A store counter \u4F4E\u4E8E\u78C1\u76D8\u4E0A\u7684\u6700\u5927 stable_id\uFF08{detail}\uFF09\u3002\u8FD9\u4E9B store \u4E0B\u4E00\u6B21\u94F8\u53F7\u4F1A\u590D\u7528\u5DF2\u5B58\u5728\u7684 id\u3002\u8FD0\u884C `fabric doctor --fix` \u5C06 store counters.json \u63D0\u5347\u5230\u78C1\u76D8\u6700\u5927\u503C\u3002",
1364
+ "doctor.check.store_counter_drift.remediation": "\u8FD0\u884C `fabric doctor --fix` \u5C06\u6BCF\u4E2A store \u7684 counters.json \u63D0\u5347\uFF08floor\uFF09\u5230\u78C1\u76D8\u4E0A\u89C2\u6D4B\u5230\u7684\u6700\u5927 stable_id\uFF08floor \u53EA\u5347\u4E0D\u964D\u2014\u2014KT-DEC-0004 \u5355\u8C03\u4E0D\u53D8\u91CF\uFF09\u3002",
1365
+ "doctor.check.store_counter_drift.ok": "read-set \u5185\u6BCF\u4E2A store \u7684 counters.json \u90FD\u5DF2 floor \u5230\u78C1\u76D8\u6700\u5927 stable_id\u3002",
1366
+ "doctor.check.store_orphan.name": "Store orphan",
1367
+ "doctor.check.store_orphan.message.singular": "{count} \u4E2A store \u5728\u78C1\u76D8\u4E0A\u5B58\u5728\u4F46\u672A\u767B\u8BB0\u5230\u5168\u5C40 registry\uFF08{detail}\uFF09\uFF0Crecall / bind \u90FD\u770B\u4E0D\u5230\u5B83\u3002\u8FD0\u884C `fabric doctor --fix` \u628A\u5B83\u6536\u7F16\uFF08\u91CD\u65B0\u767B\u8BB0\uFF0C\u7EDD\u4E0D\u5220\u9664\u78C1\u76D8\u6587\u4EF6\uFF09\u3002",
1368
+ "doctor.check.store_orphan.message.plural": "{count} \u4E2A store \u5728\u78C1\u76D8\u4E0A\u5B58\u5728\u4F46\u672A\u767B\u8BB0\u5230\u5168\u5C40 registry\uFF08\u9996\u4E2A\uFF1A{detail}\uFF09\uFF0Crecall / bind \u90FD\u770B\u4E0D\u5230\u5B83\u4EEC\u3002\u8FD0\u884C `fabric doctor --fix` \u628A\u5B83\u4EEC\u6536\u7F16\uFF08\u91CD\u65B0\u767B\u8BB0,\u7EDD\u4E0D\u5220\u9664\u78C1\u76D8\u6587\u4EF6\uFF09\u3002",
1369
+ "doctor.check.store_orphan.remediation": "\u8FD0\u884C `fabric doctor --fix` \u628A\u8FD9\u4E9B\u5B64\u513F store \u6536\u7F16\u8FDB registry(\u6309 store_uuid \u91CD\u65B0\u767B\u8BB0\u3001alias \u649E\u5E93\u81EA\u52A8\u6D88\u6B67;rescue-before-delete\u2014\u2014\u53EA\u767B\u8BB0\u4E0D\u5220\u76D8)\u3002",
1370
+ "doctor.check.store_orphan.ok": "~/.fabric/stores \u4E0B\u6CA1\u6709\u672A\u767B\u8BB0\u7684\u5B64\u513F store\u3002",
1416
1371
  "doctor.check.preexisting_root_files.name": "Preexisting root markdown",
1417
1372
  "doctor.check.preexisting_root_files.ok": "project root \u672A\u68C0\u6D4B\u5230 CLAUDE.md \u6216 AGENTS.md\u3002",
1418
1373
  "doctor.check.preexisting_root_files.message": "project root \u68C0\u6D4B\u5230 {files}\u3002\u8FD9\u4E9B root files \u4E0D\u4F1A\u88AB Fabric MCP \u81EA\u52A8\u52A0\u8F7D\u3002",
1419
- "doctor.check.preexisting_root_files.remediation": "\u5982\u679C\u5E0C\u671B\u8FD9\u4E9B knowledge \u5185\u5BB9\u5728 MCP \u54CD\u5E94\u4E2D\u53EF\u7528\uFF0C\u8BF7\u5C06\u5176\u79FB\u52A8\u5230 `.fabric/knowledge/{type}/`\u3002",
1420
- "doctor.check.filesystem_edit_fallback.name": "Filesystem-edit fallback",
1421
- "doctor.check.filesystem_edit_fallback.ok": "No orphan canonical knowledge entries detected\uFF1Bevents.jsonl promotion trail \u5B8C\u6574\u3002",
1422
- "doctor.check.filesystem_edit_fallback.message.synthesized.singular": "\u5DF2\u4E3A\u5B64\u7ACB canonical entries \u5408\u6210 {count} \u4E2A knowledge_promoted event\uFF08{sample}{suffix}\uFF09\u3002Reason='{reason}'\u3002",
1423
- "doctor.check.filesystem_edit_fallback.message.synthesized.plural": "\u5DF2\u4E3A\u5B64\u7ACB canonical entries \u5408\u6210 {count} \u4E2A knowledge_promoted events\uFF08{sample}{suffix}\uFF09\u3002Reason='{reason}'\u3002",
1424
- "doctor.check.filesystem_edit_fallback.remediation.synthesized": "\u8FD9\u4E9B entries \u662F\u5728 fab_review.approve \u4E4B\u5916\u88AB\u79FB\u52A8\u5230 .fabric/knowledge/<type>/ \u7684\u3002\u5408\u6210 events \u4F1A\u6062\u590D audit-trail \u5B8C\u6574\u6027\u3002",
1425
- "doctor.check.orphan_demote.name": "Knowledge orphan demote",
1426
- "doctor.check.orphan_demote.ok": "\u6CA1\u6709 canonical knowledge entries \u8D85\u8FC7\u6309 maturity \u8BBE\u5B9A\u7684 inactivity threshold\u3002",
1427
- "doctor.check.orphan_demote.message.singular": "{count} \u4E2A canonical knowledge entry \u8D85\u8FC7\u6309 maturity \u8BBE\u5B9A\u7684 inactivity threshold\uFF08stable={stableDays}d / endorsed={endorsedDays}d / draft={draftDays}d\uFF09\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1428
- "doctor.check.orphan_demote.message.plural": "{count} \u4E2A canonical knowledge entries \u8D85\u8FC7\u6309 maturity \u8BBE\u5B9A\u7684 inactivity threshold\uFF08stable={stableDays}d / endorsed={endorsedDays}d / draft={draftDays}d\uFF09\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1429
- "doctor.check.orphan_demote.remediation": "\u8FD0\u884C `fabric doctor --fix-knowledge`\u5C06 orphan entries \u964D\u7EA7\u4E00\u4E2A maturity tier\u3002",
1430
- "doctor.check.stale_archive.name": "Knowledge stale archive",
1431
- "doctor.check.stale_archive.ok": "\u6CA1\u6709 draft knowledge entries \u8D85\u8FC7\u989D\u5916\u7684 stale-archive quiet window\u3002",
1432
- "doctor.check.stale_archive.message.singular": "{count} \u4E2A draft knowledge entry \u5DF2\u8D85\u8FC7 demote+{additionalDays}d \u989D\u5916 quiet window\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1433
- "doctor.check.stale_archive.message.plural": "{count} \u4E2A draft knowledge entries \u5DF2\u8D85\u8FC7 demote+{additionalDays}d \u989D\u5916 quiet window\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1434
- "doctor.check.stale_archive.remediation": "\u8FD0\u884C `fabric doctor --fix-knowledge`\u5C06 stale entries \u79FB\u52A8\u5230 `.fabric/.archive/<type>/`\u3002",
1435
- "doctor.check.pending_overdue.name": "Knowledge pending overdue",
1436
- "doctor.check.pending_overdue.ok": "\u6CA1\u6709 pending knowledge entries \u8D85\u8FC7 14-day review threshold\u3002",
1437
- "doctor.check.pending_overdue.message.singular": "{count} \u4E2A pending knowledge entry \u5DF2\u7B49\u5F85 review \u8D85\u8FC7 {thresholdDays} \u5929\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1438
- "doctor.check.pending_overdue.message.plural": "{count} \u4E2A pending knowledge entries \u5DF2\u7B49\u5F85 review \u8D85\u8FC7 {thresholdDays} \u5929\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1439
- "doctor.check.pending_overdue.remediation": "\u901A\u8FC7 fabric-review Skill\uFF08`/fabric-review`\uFF09\u5BA1\u9605 pending entries\uFF0C\u5E76\u6267\u884C approve / reject / defer / modify\u3002",
1440
- "doctor.check.stable_id_duplicate.name": "Knowledge stable_id duplicate",
1441
- "doctor.check.stable_id_duplicate.ok": "team / personal trees \u4E2D\u6CA1\u6709 canonical knowledge files \u5171\u4EAB stable_id\u3002",
1442
- "doctor.check.stable_id_duplicate.message.singular": "{count} \u4E2A stable_id \u5728 canonical knowledge files \u4E2D\u91CD\u590D\uFF08path-decoupled identity invariant\uFF09\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1443
- "doctor.check.stable_id_duplicate.message.plural": "{count} \u4E2A stable_ids \u5728 canonical knowledge files \u4E2D\u91CD\u590D\uFF08path-decoupled identity invariant\uFF09\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1374
+ "doctor.check.preexisting_root_files.remediation": "\u5982\u679C\u5E0C\u671B\u8FD9\u4E9B knowledge \u5185\u5BB9\u5728 MCP \u54CD\u5E94\u4E2D\u53EF\u7528\uFF0C\u8BF7\u5C06\u5176\u79FB\u52A8\u5230 mounted store \u7684 `knowledge/{type}/` tree\u3002",
1444
1375
  // v2.0.0-rc.33 W3-2 (T6 #34): 同 stable_id_collision — 走 fabric-review modify 让 allocator 分配新 id, 不让用户手算。
1445
- "doctor.check.stable_id_duplicate.remediation": "\u8C03 `/fabric-review modify <message \u4E2D\u5217\u51FA\u7684 duplicate id \u4E4B\u4E00>`, \u7531 canonical id allocator \u5206\u914D\u65B0\u7684 `<prefix>-<type>-<counter>--<slug>.md` (\u4F1A\u540C\u6B65\u91CD\u547D\u540D\u6587\u4EF6 + \u66F4\u65B0 frontmatter + \u4FEE\u6B63 counters)\u3002",
1446
- "doctor.check.layer_mismatch.name": "Knowledge layer mismatch",
1447
- "doctor.check.layer_mismatch.ok": "\u6240\u6709 canonical knowledge files \u90FD\u4F4D\u4E8E stable_id prefix \u58F0\u660E\u7684 layer \u4E0B\u3002",
1448
- "doctor.check.layer_mismatch.message.singular": "{count} \u4E2A canonical knowledge file \u4E0E\u5176 stable_id layer prefix \u7684\u7269\u7406\u4F4D\u7F6E\u4E0D\u4E00\u81F4\uFF08KT-* must live under team/, KP-* under personal/\uFF09\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1449
- "doctor.check.layer_mismatch.message.plural": "{count} \u4E2A canonical knowledge files \u4E0E\u5176 stable_id layer prefix \u7684\u7269\u7406\u4F4D\u7F6E\u4E0D\u4E00\u81F4\uFF08KT-* must live under team/, KP-* under personal/\uFF09\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1450
1376
  // v2.0.0-rc.33 W3-2 (T6 #35): 加 skill 入口 (`/fabric-review modify <id>`) 让用户知道怎么 invoke。
1451
- "doctor.check.layer_mismatch.remediation": "\u5C06\u6587\u4EF6\u79FB\u52A8\u5230\u6B63\u786E\u7684 layer root (KT-* \u2192 .fabric/knowledge/team/, KP-* \u2192 ~/.fabric/knowledge/personal/), \u6216\u8C03 `/fabric-review modify <message \u4E2D\u5217\u51FA\u7684 id>` \u5207\u6362\u5176 layer (\u4F1A\u76F8\u5E94\u91CD\u547D\u540D stable_id prefix)\u3002",
1452
1377
  "doctor.check.index_drift.name": "Knowledge index drift",
1453
1378
  "doctor.check.index_drift.ok": "agents.meta.json counters envelope \u5BF9\u6BCF\u4E2A (layer, type) pair \u90FD\u5927\u4E8E\u6216\u7B49\u4E8E\u73B0\u6709 canonical counter \u6700\u5927\u503C\u3002",
1454
1379
  "doctor.check.index_drift.message.singular": "{count} \u4E2A (layer, type) counter slot \u5DF2\u4F4E\u4E8E\u89C2\u6D4B\u5230\u7684 canonical maximum\uFF08next allocate would collide\uFF09\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
@@ -1459,45 +1384,15 @@ var zhCNMessages = {
1459
1384
  "doctor.check.underseeded.message.singular": "\u77E5\u8BC6\u5E93\u4EC5\u6709 {count} \u4E2A canonical entry\uFF08< {threshold} threshold\uFF09\u3002plan_context \u68C0\u7D22\u9762\u4F4E\u4E8E\u53EF\u7528\u4E0B\u9650\u3002",
1460
1385
  "doctor.check.underseeded.message.plural": "\u77E5\u8BC6\u5E93\u4EC5\u6709 {count} \u4E2A canonical entries\uFF08< {threshold} threshold\uFF09\u3002plan_context \u68C0\u7D22\u9762\u4F4E\u4E8E\u53EF\u7528\u4E0B\u9650\u3002",
1461
1386
  "doctor.check.underseeded.remediation": "\u8FD0\u884C fabric-import Skill\uFF08`/fabric-import`\uFF09\u4ECE git history \u4E0E\u73B0\u6709\u6587\u6863\u56DE\u586B knowledge\u3002",
1462
- "doctor.check.narrow_no_paths.name": "Knowledge narrow without paths",
1463
- "doctor.check.narrow_no_paths.ok": "\u6CA1\u6709 narrow-scope canonical entries \u7684 relevance_paths array \u4E3A\u7A7A\u3002",
1464
- "doctor.check.narrow_no_paths.message.singular": "{count} \u4E2A narrow-scope canonical entry \u7684 relevance_paths array \u4E3A\u7A7A\uFF08silent recall risk \u2014 narrow without anchors can never match a target path\uFF09\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1465
- "doctor.check.narrow_no_paths.message.plural": "{count} \u4E2A narrow-scope canonical entries \u7684 relevance_paths array \u4E3A\u7A7A\uFF08silent recall risk \u2014 narrow without anchors can never match a target path\uFF09\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1466
- "doctor.check.narrow_no_paths.remediation": "\u8C03 `/fabric-review` \u9009\u8BE5 entry \u2192 modify \u4E3A relevance_paths \u6DFB\u52A0 path anchors\uFF0C\u6216\u5C06 relevance_scope \u653E\u5BBD\u5230 broad\uFF1B\u4E5F\u53EF\u76F4\u63A5\u7F16\u8F91 entry frontmatter\u3002",
1467
- "doctor.check.relevance_paths_dangling.name": "Knowledge relevance_paths dangling",
1468
- "doctor.check.relevance_paths_dangling.ok": "\u6240\u6709 relevance_paths globs \u90FD\u80FD\u5728 workspace root \u4E0B\u89E3\u6790\u5230\u81F3\u5C11 1 \u4E2A\u6587\u4EF6\u3002",
1469
- "doctor.check.relevance_paths_dangling.message.singular": "{count} \u4E2A relevance_paths glob \u5728\u5F53\u524D workspace \u4E2D\u89E3\u6790\u5230 0 \u4E2A\u6587\u4EF6\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1470
- "doctor.check.relevance_paths_dangling.message.plural": "{count} \u4E2A relevance_paths globs \u5728\u5F53\u524D workspace \u4E2D\u89E3\u6790\u5230 0 \u4E2A\u6587\u4EF6\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1471
- "doctor.check.relevance_paths_dangling.remediation": "\u66F4\u65B0 entry \u7684 relevance_paths\uFF0C\u79FB\u9664\u4E0D\u518D\u5339\u914D\u4EFB\u4F55\u6587\u4EF6\u7684 globs\uFF0C\u6216\u4F7F\u7528 `fab_review.modify` \u91CD\u5199 anchor set\u3002",
1472
- "doctor.check.relevance_paths_drift.name": "Knowledge relevance_paths drift",
1473
- "doctor.check.relevance_paths_drift.ok.skipped": "\u5DF2\u8DF3\u8FC7\uFF08git history unavailable\uFF1B\u65E0\u6CD5\u8BC4\u4F30 {windowDays}d drift window\uFF09\u3002",
1474
- "doctor.check.relevance_paths_drift.ok.fresh": "\u6240\u6709 narrow-scope canonical entries \u90FD\u81F3\u5C11\u6709 1 \u4E2A relevance_path \u5728\u6700\u8FD1 {windowDays}d \u5185\u88AB\u89E6\u78B0\u3002",
1475
- "doctor.check.relevance_paths_drift.message.singular": "{count} \u4E2A narrow-scope canonical entry \u7684 relevance_paths globs \u6CA1\u6709\u5339\u914D\u5230\u6700\u8FD1 {windowDays}d git history \u4E2D\u89E6\u78B0\u8FC7\u7684\u6587\u4EF6\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1476
- "doctor.check.relevance_paths_drift.message.plural": "{count} \u4E2A narrow-scope canonical entries \u7684 relevance_paths globs \u6CA1\u6709\u5339\u914D\u5230\u6700\u8FD1 {windowDays}d git history \u4E2D\u89E6\u78B0\u8FC7\u7684\u6587\u4EF6\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1477
- "doctor.check.relevance_paths_drift.remediation": "\u5BA1\u9605\u8BE5 entry \u662F\u5426\u4ECD\u7136\u76F8\u5173 \u2014 \u4F7F\u7528 `fab_review.modify` \u5237\u65B0 anchors\uFF0C\u6216\u4F7F\u7528 `fab_review.reject` \u5F52\u6863\u3002",
1478
- "doctor.check.personal_layer_path_misclassify.name": "Personal-layer path misclassify",
1479
- "doctor.check.personal_layer_path_misclassify.ok": "\u6CA1\u6709 personal-layer entries \u7684 relevance_paths \u89E3\u6790\u5230\u5F53\u524D\u9879\u76EE\u5185\u7684\u6587\u4EF6\u3002",
1480
- "doctor.check.personal_layer_path_misclassify.message.singular": "{count} \u4E2A personal-layer entry \u7684 relevance_paths \u547D\u4E2D\u5F53\u524D\u9879\u76EE\u5185\u7684\u6587\u4EF6\uFF08personal \u5C42\u5E94\u4FDD\u6301\u9879\u76EE\u65E0\u5173\uFF09\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1481
- "doctor.check.personal_layer_path_misclassify.message.plural": "{count} \u4E2A personal-layer entries \u7684 relevance_paths \u547D\u4E2D\u5F53\u524D\u9879\u76EE\u5185\u7684\u6587\u4EF6\uFF08personal \u5C42\u5E94\u4FDD\u6301\u9879\u76EE\u65E0\u5173\uFF09\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1482
- "doctor.check.personal_layer_path_misclassify.remediation": "\u7528 `fab_review.modify` \u628A layer \u7FFB\u6210 team\uFF0C\u6216\u91CD\u5199 relevance_paths \u8BA9 anchors \u4FDD\u6301\u9879\u76EE\u65E0\u5173\uFF08\u5220\u6389\u9879\u76EE\u7279\u5B9A globs\uFF09\u3002",
1483
- "doctor.check.suspicious_kb.name": "Suspicious KB injection",
1484
- "doctor.check.suspicious_kb.ok": "\u6240\u6709 canonical knowledge body \u5747\u672A\u547D\u4E2D\u5DF2\u77E5 prompt-injection \u6A21\u5F0F\u3002",
1485
- "doctor.check.suspicious_kb.message.singular": "{count} \u4E2A canonical entry body \u542B\u547D\u4E2D prompt-injection \u6A21\u5F0F\u7684 token\uFF08\u591A\u534A\u662F NEW-31 \u4E4B\u524D\u5F52\u6863\u7684 legacy \u6761\u76EE\uFF09\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1486
- "doctor.check.suspicious_kb.message.plural": "{count} \u4E2A canonical entry bodies \u542B\u547D\u4E2D prompt-injection \u6A21\u5F0F\u7684 token\uFF08\u591A\u534A\u662F NEW-31 \u4E4B\u524D\u5F52\u6863\u7684 legacy \u6761\u76EE\uFF09\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1487
- "doctor.check.suspicious_kb.remediation": "\u5BA1\u9605\u88AB\u6807\u8BB0\u7684\u6761\u76EE \u2014 \u7528 `fab_review.modify` \u64E6\u6389 body \u4E2D\u7684 injection token\uFF0C\u6216 `fab_review.reject` \u5F52\u6863\u4E0D\u8BE5 canonicalize \u7684\u6761\u76EE\u3002",
1488
- "doctor.check.narrow_too_few.name": "Knowledge narrow too few",
1489
- "doctor.check.narrow_too_few.ok": "Narrow-with-paths ratio {ratioPct}%\uFF08{narrowCount}/{totalCount}\uFF09\uFF1B{teleNote}\u3002",
1490
- "doctor.check.narrow_too_few.message.telemetry_skipped": "telemetry skipped\uFF08no edit-counter fires in window\uFF09",
1491
- "doctor.check.narrow_too_few.message.telemetry_window": "silence rate {silencePct}% over {windowDays}d",
1492
- "doctor.check.narrow_too_few.message.structural": "narrow-with-paths share {ratioPct}%\uFF08{narrowCount}/{totalCount}\uFF09below {thresholdPct}% threshold",
1493
- "doctor.check.narrow_too_few.message.telemetry": "narrow-hook silence rate {silencePct}%\uFF08{silenceFires}/{totalFires}\uFF09over {windowDays}d above {thresholdPct}% threshold",
1494
- "doctor.check.narrow_too_few.message.summary": "Narrow-scope KB coverage \u4F4E\u4E8E\u53EF\u7528\u4E0B\u9650\uFF1A{parts}\u3002",
1495
- "doctor.check.narrow_too_few.remediation": "\u8FD0\u884C fabric-import Skill\uFF08`/fabric-import`\uFF09\u9488\u5BF9\u5F53\u524D codebase \u91CD\u65B0\u64AD\u79CD narrow anchors\u3002",
1496
1387
  "doctor.check.session_hints_stale.name": "Knowledge session-hints stale",
1497
1388
  "doctor.check.session_hints_stale.ok": ".fabric/.cache/ \u4E0B\u6CA1\u6709\u8D85\u8FC7 {days} \u5929\u7684 session-hints cache files\u3002",
1498
1389
  "doctor.check.session_hints_stale.message.singular": ".fabric/.cache/ \u4E0B\u6709 {count} \u4E2A session-hints cache file \u8D85\u8FC7 {days} \u5929\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1499
1390
  "doctor.check.session_hints_stale.message.plural": ".fabric/.cache/ \u4E0B\u6709 {count} \u4E2A session-hints cache files \u8D85\u8FC7 {days} \u5929\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1500
1391
  "doctor.check.session_hints_stale.remediation": "\u8FD0\u884C `fabric doctor --fix-knowledge` \u5220\u9664\u8FC7\u671F\u7684 session-hints cache files\u3002",
1392
+ "doctor.check.hook_cache_writable.name": "Hook cache writable",
1393
+ "doctor.check.hook_cache_writable.ok": "Hook sidecar cache \u8DEF\u5F84 {path} \u53EF\u5199\u5165\u63A2\u9488\u6587\u4EF6\u3002",
1394
+ "doctor.check.hook_cache_writable.message": "Hook sidecar cache \u8DEF\u5F84 {path} \u4E0D\u53EF\u5199\uFF1Bhook state updates \u4F1A\u9759\u9ED8\u5931\u8D25\u3002\u9519\u8BEF\uFF1A{error}\u3002",
1395
+ "doctor.check.hook_cache_writable.remediation": "\u6062\u590D {path} \u5199\u6743\u9650\uFF0C\u79FB\u9664\u5360\u7528\u8BE5\u8DEF\u5F84\u7684\u963B\u585E\u6587\u4EF6\uFF0C\u6216\u4FEE\u590D\u6587\u4EF6\u7CFB\u7EDF\u72B6\u6001\u540E\u91CD\u65B0\u8FD0\u884C `fabric install`\u3002",
1501
1396
  "doctor.check.stale_serve_lock.name": "Serve lock",
1502
1397
  "doctor.check.stale_serve_lock.ok.no_lock": "\u672A\u53D1\u73B0 .fabric/.serve.lock\u3002",
1503
1398
  "doctor.check.stale_serve_lock.ok.live_pid": ".fabric/.serve.lock \u7531 live PID {pid} \u6301\u6709\u3002",
@@ -1507,11 +1402,6 @@ var zhCNMessages = {
1507
1402
  "doctor.check.stale_serve_lock.age.hour.plural": "{count} \u5C0F\u65F6\u524D",
1508
1403
  "doctor.check.stale_serve_lock.message.dead_pid": "[advisory] .fabric/.serve.lock \u6301\u6709 dead PID {pid}\uFF08acquired {acquiredAgo}\uFF09\u3002\u8FD0\u884C `fabric doctor --fix` \u79FB\u9664\u3002",
1509
1404
  "doctor.check.stale_serve_lock.remediation.dead_pid": "\u8FD0\u884C `fabric doctor --fix` \u79FB\u9664\u8FC7\u671F\u7684 .fabric/.serve.lock\u3002",
1510
- "doctor.check.relevance_fields_missing.name": "Knowledge relevance fields missing",
1511
- "doctor.check.relevance_fields_missing.ok": "\u6240\u6709 pending entries \u90FD\u58F0\u660E\u4E86 relevance_scope \u548C relevance_paths\u3002",
1512
- "doctor.check.relevance_fields_missing.message.singular": "{count} \u4E2A pending entry \u7684 frontmatter \u7F3A\u5C11 relevance_scope \u548C/\u6216 relevance_paths\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1513
- "doctor.check.relevance_fields_missing.message.plural": "{count} \u4E2A pending entries \u7684 frontmatter \u7F3A\u5C11 relevance_scope \u548C/\u6216 relevance_paths\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
1514
- "doctor.check.relevance_fields_missing.remediation": "\u8FD0\u884C `fabric doctor --fix-knowledge` \u56DE\u586B schema defaults\uFF08relevance_scope: broad\uFF0Crelevance_paths: []\uFF09\u3002",
1515
1405
  // rc.31 BUG-M3/NEW-4: hooks_wired observability.
1516
1406
  "doctor.check.hooks_wired.name": "Claude Code hooks wired",
1517
1407
  "doctor.check.hooks_wired.ok.skipped": "\u9879\u76EE\u672A\u542F\u7528 Claude Code\uFF08\u65E0 .claude/ \u76EE\u5F55\uFF09\uFF1B\u8DF3\u8FC7 hooks_wired \u68C0\u67E5\u3002",
@@ -1522,7 +1412,7 @@ var zhCNMessages = {
1522
1412
  // v2.0.0-rc.37 NEW-20: hooks_runtime — shebang + Node.js syntax validity
1523
1413
  // of installed *.cjs hook files (one layer below hooks_wired).
1524
1414
  "doctor.check.hooks_runtime.name": "Hooks \u8FD0\u884C\u65F6\u5065\u5EB7",
1525
- "doctor.check.hooks_runtime.ok.skipped": "\u672A\u53D1\u73B0\u5DF2\u5B89\u88C5\u7684 hook \u6587\u4EF6\uFF08.claude/hooks/ / .codex/hooks/ / .cursor/hooks/ \u90FD\u7F3A\uFF09\uFF1B\u8DF3\u8FC7 hooks_runtime \u68C0\u67E5\u3002",
1415
+ "doctor.check.hooks_runtime.ok.skipped": "\u672A\u53D1\u73B0\u5DF2\u5B89\u88C5\u7684 hook \u6587\u4EF6\uFF08.claude/hooks/ / .codex/hooks/ \u90FD\u7F3A\uFF09\uFF1B\u8DF3\u8FC7 hooks_runtime \u68C0\u67E5\u3002",
1526
1416
  "doctor.check.hooks_runtime.ok.healthy": "\u5DF2\u626B\u63CF {count} \u4E2A hook .cjs \u6587\u4EF6\uFF0Cshebang \u4E0E Node.js \u8BED\u6CD5\u89E3\u6790\u5168\u90E8\u901A\u8FC7\u3002",
1527
1417
  "doctor.check.hooks_runtime.message.singular": "{count} \u4E2A hook \u6587\u4EF6 runtime \u4E0D\u5065\u5EB7\uFF1B\u9996\u4F8B\uFF1A{first_path}\uFF08{first_detail}\uFF09\u3002",
1528
1418
  "doctor.check.hooks_runtime.message.plural": "{count} \u4E2A hook \u6587\u4EF6 runtime \u4E0D\u5065\u5EB7\uFF1B\u9996\u4F8B\uFF1A{first_path}\uFF08{first_detail}\uFF09\u3002",
@@ -1530,7 +1420,7 @@ var zhCNMessages = {
1530
1420
  // v2.0.0-rc.37 NEW-27: hooks_content_drift — cross-client sha256 parity.
1531
1421
  "doctor.check.hooks_content_drift.name": "Hooks \u8DE8\u5BA2\u6237\u7AEF\u5185\u5BB9\u4E00\u81F4\u6027",
1532
1422
  "doctor.check.hooks_content_drift.ok.skipped": "\u672A\u53D1\u73B0\u8DE8\u5BA2\u6237\u7AEF\u5171\u5B58\u7684 hook \u6587\u4EF6\uFF08\u5355 client \u5B89\u88C5\u6216\u5168\u90E8\u7F3A\u5931\uFF09\uFF1B\u8DF3\u8FC7 hooks_content_drift \u68C0\u67E5\u3002",
1533
- "doctor.check.hooks_content_drift.ok.aligned": "\u5DF2\u626B\u63CF {count} \u4E2A hook \u526F\u672C\uFF0C\u8DE8 client (.claude / .codex / .cursor) sha256 \u5168\u90E8\u4E00\u81F4\u3002",
1423
+ "doctor.check.hooks_content_drift.ok.aligned": "\u5DF2\u626B\u63CF {count} \u4E2A hook \u526F\u672C\uFF0C\u8DE8 client (.claude / .codex) sha256 \u5168\u90E8\u4E00\u81F4\u3002",
1534
1424
  "doctor.check.hooks_content_drift.message": "{count} \u4E2A hook basename \u5728 client \u4E4B\u95F4\u5185\u5BB9 drift\uFF1B\u9996\u4F8B\uFF1A{first_basename}\uFF08\u6D89\u53CA {first_clients}\uFF09\u3002`fabric install` \u590D\u5236\u540C\u4E00\u6A21\u677F\u5230\u4E09 client\uFF0Cdrift \u901A\u5E38\u6765\u81EA\u624B\u52A8\u7F16\u8F91\u3002",
1535
1425
  "doctor.check.hooks_content_drift.remediation": "\u8FD0\u884C `fabric install` \u628A\u6240\u6709 client \u7684 hook \u526F\u672C\u6062\u590D\u5230 canonical \u6A21\u677F\u3002\u82E5\u4F60\u786E\u5B9E\u9700\u8981 client-specific hook \u884C\u4E3A\uFF0C\u5EFA\u8BAE\u6539 lib/ \u5171\u4EAB\u811A\u672C\u6216 templates/hooks/configs/ \u914D\u7F6E\u800C\u975E\u76F4\u63A5\u7F16\u8F91\u5B89\u88C5\u540E\u7684 .cjs\u3002",
1536
1426
  // rc.31 BUG-G2/G5: promote-ledger invariant check.
@@ -1552,6 +1442,62 @@ var zhCNMessages = {
1552
1442
  "doctor.check.knowledge_summary_opaque.ok": "{opaque}/{total} \u4E2A entry \u7684 summary == stable_id\uFF0C\u6BD4\u4F8B\u5728\u5065\u5EB7\u8303\u56F4\u5185\u3002",
1553
1443
  "doctor.check.knowledge_summary_opaque.message.warn": "{opaque}/{total} \u4E2A entry ({pct}%) \u7684 description.summary \u7B49\u4E8E stable_id\uFF0C\u8D85\u8FC7 {threshold}% \u9608\u503C\u3002narrow hint \u8F93\u51FA\u4F1A\u53D8\u6210 `<id> \xB7 <id>` \u800C\u975E\u771F\u5B9E\u6982\u8981\uFF0CAI \u770B\u4E0D\u5230\u4FE1\u606F\u4F1A\u4E3B\u52A8\u8DF3\u8FC7 fetch\u3002\u9996\u6279\u4E0D\u900F\u660E: {sample}\u3002",
1554
1444
  "doctor.check.knowledge_summary_opaque.remediation": "\u8C03 fabric-review skill \u91CD\u5199\u4E0D\u900F\u660E summary \u4E3A\u4E00\u53E5\u4EBA\u7C7B\u53EF\u8BFB\u7684\u6982\u8981\u3002rc.35 hint renderer fallback (TASK-06) \u4E5F\u4F1A\u4ECE entry \u7684 `## Summary` \u6BB5\u81EA\u52A8\u5408\u6210\u4E34\u65F6 summary\u3002",
1445
+ // v2.2 W4 (G-GUARD / A6): store scope lint。
1446
+ "doctor.check.store_scope_lint.name": "Store scope lint",
1447
+ "doctor.check.store_scope_lint.ok": "read-set \u5185\u6240\u6709 store \u6761\u76EE scope \u5143\u6570\u636E\u9F50\u5907(semantic_scope + visibility_store,\u65E0 personal \u6CC4\u6F0F,\u65E0 dangling project)\u3002",
1448
+ "doctor.check.store_scope_lint.message": "{total} \u4E2A store scope \u95EE\u9898: {breakdown}\u3002\u4F8B\u5982 {sample}\u3002",
1449
+ "doctor.check.store_scope_lint.remediation": "\u8C03 `fabric store backfill-scope` \u8865\u7F3A\u5931\u7684 semantic_scope/visibility_store;`fabric store re-scope` \u4FEE dangling \u7684 project: \u5750\u6807;\u628A personal-scope \u6761\u76EE\u79FB\u51FA shared store(personal \u77E5\u8BC6\u53EA\u5B58\u4E2A\u4EBA store,R5#3)\u3002",
1450
+ // v2.2 Goal B (G-INTEGRITY): store stable_id collision + layer mismatch lints。
1451
+ "doctor.check.stable_id_collision.name": "Stable ID collision",
1452
+ "doctor.check.stable_id_collision.message.singular": 'stable_id "{stableId}" \u88AB\u58F0\u660E\u5728 {fileCount} \u4E2A\u6587\u4EF6\u4E2D:{files}\u3002\u8BF7\u7F16\u8F91\u5176\u4E2D\u4E00\u4E2A knowledge file,\u6539\u7528\u552F\u4E00 stable_id\u3002',
1453
+ "doctor.check.stable_id_collision.message.plural": '\u68C0\u6D4B\u5230 {count} \u4E2A stable_id collisions\u3002\u9996\u4E2A:"{stableId}" \u4F4D\u4E8E {files}\u3002\u8BF7\u7F16\u8F91\u5176\u4E2D\u4E00\u4E2A knowledge file,\u6539\u7528\u552F\u4E00 stable_id\u3002',
1454
+ "doctor.check.stable_id_collision.remediation": "\u8C03 `/fabric-review modify <message \u4E2D\u5217\u51FA\u7684 colliding id \u4E4B\u4E00>`, \u8BA9 canonical id allocator \u81EA\u52A8\u91CD\u5206\u914D id (\u4F1A\u540C\u6B65\u66F4\u65B0 frontmatter + counters + \u5386\u53F2 cross-ref)\u3002\u4E25\u7981\u624B\u5DE5\u7F16\u8F91 id frontmatter \u2014 \u4F1A\u649E counter\u3002",
1455
+ "doctor.check.stable_id_collision.ok": "mounted store knowledge \u4E2D\u672A\u53D1\u73B0\u5DF2\u58F0\u660E\u7684 stable_id collisions\u3002",
1456
+ "doctor.check.layer_mismatch.name": "Knowledge layer mismatch",
1457
+ "doctor.check.layer_mismatch.ok": "\u6240\u6709 canonical knowledge files \u90FD\u4F4D\u4E8E stable_id prefix \u58F0\u660E\u7684 layer \u4E0B\u3002",
1458
+ "doctor.check.layer_mismatch.message.singular": "{count} \u4E2A canonical knowledge file \u4E0E\u5176 stable_id layer prefix \u7684\u7269\u7406\u4F4D\u7F6E\u4E0D\u4E00\u81F4(KT-* must live under team/, KP-* under personal/)\u3002\u9996\u4E2A:{detail}\u3002",
1459
+ "doctor.check.layer_mismatch.message.plural": "{count} \u4E2A canonical knowledge files \u4E0E\u5176 stable_id layer prefix \u7684\u7269\u7406\u4F4D\u7F6E\u4E0D\u4E00\u81F4(KT-* must live under team/, KP-* under personal/)\u3002\u9996\u4E2A:{detail}\u3002",
1460
+ "doctor.check.layer_mismatch.remediation": "\u5C06\u6587\u4EF6\u79FB\u52A8\u5230\u6B63\u786E\u7684 write-target store,\u6216\u8C03 `/fabric-review modify <message \u4E2D\u5217\u51FA\u7684 id>` \u5207\u6362\u5176 layer (\u4F1A\u76F8\u5E94\u91CD\u547D\u540D stable_id prefix)\u3002",
1461
+ // v2.2 Goal B (G-RELEVANCE): store relevance_paths hygiene (dangling + drift)。
1462
+ "doctor.check.relevance_paths_dangling.name": "Knowledge relevance_paths dangling",
1463
+ "doctor.check.relevance_paths_dangling.ok": "\u6240\u6709 relevance_paths globs \u90FD\u80FD\u5728 workspace root \u4E0B\u89E3\u6790\u5230\u81F3\u5C11 1 \u4E2A\u6587\u4EF6\u3002",
1464
+ "doctor.check.relevance_paths_dangling.message.singular": "{count} \u4E2A relevance_paths glob \u5728\u5F53\u524D workspace \u4E2D\u89E3\u6790\u5230 0 \u4E2A\u6587\u4EF6\u3002\u9996\u4E2A:{detail}\u3002",
1465
+ "doctor.check.relevance_paths_dangling.message.plural": "{count} \u4E2A relevance_paths globs \u5728\u5F53\u524D workspace \u4E2D\u89E3\u6790\u5230 0 \u4E2A\u6587\u4EF6\u3002\u9996\u4E2A:{detail}\u3002",
1466
+ "doctor.check.relevance_paths_dangling.remediation": "\u66F4\u65B0 entry \u7684 relevance_paths,\u79FB\u9664\u4E0D\u518D\u5339\u914D\u4EFB\u4F55\u6587\u4EF6\u7684 globs,\u6216\u4F7F\u7528 `fab_review.modify` \u91CD\u5199 anchor set\u3002",
1467
+ "doctor.check.relevance_paths_drift.name": "Knowledge relevance_paths drift",
1468
+ "doctor.check.relevance_paths_drift.ok.skipped": "\u5DF2\u8DF3\u8FC7(git history unavailable;\u65E0\u6CD5\u8BC4\u4F30 {windowDays}d drift window)\u3002",
1469
+ "doctor.check.relevance_paths_drift.ok.fresh": "\u6240\u6709 narrow-scope canonical entries \u90FD\u81F3\u5C11\u6709 1 \u4E2A relevance_path \u5728\u6700\u8FD1 {windowDays}d \u5185\u88AB\u89E6\u78B0\u3002",
1470
+ "doctor.check.relevance_paths_drift.message.singular": "{count} \u4E2A narrow-scope canonical entry \u7684 relevance_paths globs \u6CA1\u6709\u5339\u914D\u5230\u6700\u8FD1 {windowDays}d git history \u4E2D\u89E6\u78B0\u8FC7\u7684\u6587\u4EF6\u3002\u9996\u4E2A:{detail}\u3002",
1471
+ "doctor.check.relevance_paths_drift.message.plural": "{count} \u4E2A narrow-scope canonical entries \u7684 relevance_paths globs \u6CA1\u6709\u5339\u914D\u5230\u6700\u8FD1 {windowDays}d git history \u4E2D\u89E6\u78B0\u8FC7\u7684\u6587\u4EF6\u3002\u9996\u4E2A:{detail}\u3002",
1472
+ "doctor.check.relevance_paths_drift.remediation": "\u5BA1\u9605\u8BE5 entry \u662F\u5426\u4ECD\u7136\u76F8\u5173 \u2014 \u4F7F\u7528 `fab_review.modify` \u5237\u65B0 anchors,\u6216\u4F7F\u7528 `fab_review.reject` \u5F52\u6863\u3002",
1473
+ // W4-3 (KT-MOD-0001): narrow scope 但 relevance_paths 为空。
1474
+ "doctor.check.narrow_no_paths.name": "Knowledge narrow scope \u7F3A\u8DEF\u5F84",
1475
+ "doctor.check.narrow_no_paths.ok": "\u6BCF\u6761 narrow scope canonical entry \u90FD\u81F3\u5C11\u5E26\u4E00\u4E2A relevance_path\u3002",
1476
+ "doctor.check.narrow_no_paths.message.singular": "{count} \u6761 narrow scope entry \u7684 relevance_paths \u4E3A\u7A7A \u2014 \u6C38\u8FDC\u65E0\u6CD5\u8DEF\u5F84\u5339\u914D,\u56E0\u6B64\u6C38\u4E0D\u6D6E\u51FA(\u6B7B\u6761\u76EE)\u3002\u9996\u6761: {detail}\u3002",
1477
+ "doctor.check.narrow_no_paths.message.plural": "{count} \u6761 narrow scope entry \u7684 relevance_paths \u4E3A\u7A7A \u2014 \u6C38\u8FDC\u65E0\u6CD5\u8DEF\u5F84\u5339\u914D,\u56E0\u6B64\u6C38\u4E0D\u6D6E\u51FA(\u6B7B\u6761\u76EE)\u3002\u9996\u6761: {detail}\u3002",
1478
+ "doctor.check.narrow_no_paths.remediation": "\u7528 `fab_review.modify` \u8865 relevance_paths glob \u951A\u5B9A\u8BE5 entry,\u6216\u82E5\u672C\u610F\u662F\u5E38\u9A7B\u5219\u628A relevance_scope \u6539\u4E3A `broad`\u3002",
1479
+ // W4-2 (KT-DEC-0028): 单 store broad 索引接近 backstop。
1480
+ "doctor.check.broad_index_drift.name": "Knowledge broad \u7D22\u5F15\u6F02\u79FB",
1481
+ "doctor.check.broad_index_drift.ok": "\u6CA1\u6709 store \u7684 broad scope \u6761\u76EE\u6570\u8FBE\u5230\u6F02\u79FB\u9608\u503C({threshold},backstop {backstop} \u7684 80%)\u3002",
1482
+ "doctor.check.broad_index_drift.message.singular": "{count} \u4E2A store \u7684 broad \u7D22\u5F15\u5DF2\u8FBE {threshold}(backstop {backstop} \u7684 80%) \u2014 SessionStart banner \u63A5\u8FD1\u622A\u65AD broad \u6761\u76EE\u3002\u9996\u6761: {detail}\u3002",
1483
+ "doctor.check.broad_index_drift.message.plural": "{count} \u4E2A store \u7684 broad \u7D22\u5F15\u5DF2\u8FBE {threshold}(backstop {backstop} \u7684 80%) \u2014 SessionStart banner \u63A5\u8FD1\u622A\u65AD broad \u6761\u76EE\u3002\u9996\u6761: {detail}\u3002",
1484
+ "doctor.check.broad_index_drift.remediation": "\u8DD1 `fabric-audit` skill \u5728\u544A\u8B66 store \u5185 prune/\u964D\u7EA7\u9648\u65E7 broad \u6761\u76EE,\u6216\u82E5\u8BED\u6599\u786E\u5B9E\u5927\u5219\u5728 .fabric/fabric-config.json \u8C03\u9AD8 `broad_index_backstop`\u3002",
1485
+ // v2.2 Goal B (G-AGE): knowledge decay lints (orphan_demote + stale_archive)。
1486
+ "doctor.check.orphan_demote.name": "Knowledge orphan demote",
1487
+ "doctor.check.orphan_demote.ok": "\u6CA1\u6709 canonical knowledge entries \u8D85\u8FC7\u6309 maturity \u8BBE\u5B9A\u7684 inactivity threshold\u3002",
1488
+ "doctor.check.orphan_demote.message.singular": "{count} \u4E2A canonical knowledge entry \u8D85\u8FC7\u6309 maturity \u8BBE\u5B9A\u7684 inactivity threshold(proven={provenDays}d / verified={verifiedDays}d / draft={draftDays}d)\u3002\u9996\u4E2A:{detail}\u3002",
1489
+ "doctor.check.orphan_demote.message.plural": "{count} \u4E2A canonical knowledge entries \u8D85\u8FC7\u6309 maturity \u8BBE\u5B9A\u7684 inactivity threshold(proven={provenDays}d / verified={verifiedDays}d / draft={draftDays}d)\u3002\u9996\u4E2A:{detail}\u3002",
1490
+ "doctor.check.orphan_demote.remediation": "\u901A\u8FC7 `/fabric-review modify <id>` \u5C06\u8BE5 entry \u964D\u7EA7\u4E00\u4E2A maturity tier,\u6216\u91CD\u65B0\u4F7F\u7528\u5B83\u4EE5\u8BB0\u5F55\u65B0\u6D3B\u52A8\u3002(\u6539\u5199 store \u77E5\u8BC6\u662F store \u5199\u4FA7\u6D41\u7A0B\u7684\u804C\u8D23 \u2014 \u8FD9\u4E2A\u8BFB\u4FA7 lint \u53EA\u8D1F\u8D23\u66B4\u9732\u8870\u51CF\u3002)",
1491
+ "doctor.check.stale_archive.name": "Knowledge stale archive",
1492
+ "doctor.check.stale_archive.ok": "\u6CA1\u6709 draft knowledge entries \u8D85\u8FC7\u989D\u5916\u7684 stale-archive quiet window\u3002",
1493
+ "doctor.check.stale_archive.message.singular": "{count} \u4E2A draft knowledge entry \u5DF2\u8D85\u8FC7 demote+{additionalDays}d \u989D\u5916 quiet window\u3002\u9996\u4E2A:{detail}\u3002",
1494
+ "doctor.check.stale_archive.message.plural": "{count} \u4E2A draft knowledge entries \u5DF2\u8D85\u8FC7 demote+{additionalDays}d \u989D\u5916 quiet window\u3002\u9996\u4E2A:{detail}\u3002",
1495
+ "doctor.check.stale_archive.remediation": "\u901A\u8FC7 `/fabric-review reject <id>` \u5F52\u6863\u8BE5 stale draft,\u6216\u82E5\u4ECD\u76F8\u5173\u5219\u590D\u6D3B\u5B83\u3002(\u79FB\u52A8 store \u6587\u4EF6\u662F store \u5199\u4FA7\u6D41\u7A0B\u7684\u804C\u8D23 \u2014 \u8FD9\u4E2A\u8BFB\u4FA7 lint \u53EA\u8D1F\u8D23\u66B4\u9732\u9648\u65E7\u3002)",
1496
+ // project-scope binding 回填 lint (unbound_project)。
1497
+ "doctor.check.unbound_project.name": "Project-scope binding",
1498
+ "doctor.check.unbound_project.ok": "\u5DF2\u7ED1\u5199\u5165 store \u5E26\u6709 project \u5750\u6807(project_id + active_project),project-scope \u7684 recall/\u5199\u5165\u8DEF\u7531\u6B63\u5E38\u3002",
1499
+ "doctor.check.unbound_project.message": "store '{alias}' \u5DF2\u7ED1\u4E3A\u5199\u5165\u76EE\u6807\u4F46 project \u5750\u6807\u4E0D\u5B8C\u6574(\u7F3A {missing});project-scope \u7684 recall/\u5199\u5165\u4F1A fallback \u5230 team scope\u3002",
1500
+ "doctor.check.unbound_project.remediation": "\u8C03 `fabric doctor --fix` \u56DE\u586B project \u7ED1\u5B9A(\u94F8 project_id\u3001\u628A project \u6CE8\u518C\u8FDB store\u3001\u8BBE active_project)\u3002\u5E42\u7B49 \u2014\u2014 \u4E8C\u6B21\u8DD1\u4E3A no-op\u3002",
1555
1501
  "doctor.check.skill_md_yaml_invalid.name": "Skill markdown YAML",
1556
1502
  "doctor.check.skill_md_yaml_invalid.ok": "\u6240\u6709 .claude/.codex SKILL.md frontmatter values \u90FD\u80FD\u6309 strict YAML \u89E3\u6790\u3002",
1557
1503
  "doctor.check.skill_md_yaml_invalid.message.singular": "{count} \u4E2A SKILL.md frontmatter value \u5305\u542B\u672A\u52A0\u5F15\u53F7\u7684 ': '\uFF0Cstrict YAML parsers \u4F1A\u62D2\u7EDD\uFF08Claude Code tolerates it\uFF1BCodex CLI drops the skill at load\uFF09\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
@@ -1577,21 +1523,6 @@ var zhCNMessages = {
1577
1523
  "cli.doctor.errors.invalid-history-mode": "\u65E0\u6548\u7684 --history mode '{input}'\u3002\u53EF\u9009: archive | fix | all\u3002",
1578
1524
  "doctor.history.header": "Doctor \u5386\u53F2 (mode={mode}, \u8FD1 {sinceLabel}, \u5171 {days} \u5929)",
1579
1525
  "doctor.history.empty": "--since={sinceLabel} \u7A97\u53E3\u5185\u65E0 doctor \u6216 archive \u6D3B\u52A8 (mode={mode})\u3002",
1580
- "cli.hooks.description": "\u7BA1\u7406 Fabric Git \u94A9\u5B50\u6A21\u677F\u3002",
1581
- "cli.hooks.install.description": "\u5B89\u88C5 Fabric Husky pre-commit \u94A9\u5B50\u6A21\u677F\u3002",
1582
- "cli.hooks.install.args.target.description": "\u76EE\u6807\u9879\u76EE\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u3002",
1583
- "cli.hooks.errors.package-json-required": "\u5B89\u88C5 hooks \u9700\u8981 package.json\uFF1A{path}",
1584
- "cli.hooks.install.hook-skipped": "{path} \u4E2D\u5DF2\u5B58\u5728 Fabric hook\uFF0C\u5DF2\u8DF3\u8FC7\u3002",
1585
- "cli.hooks.install.hook-appended": "\u5DF2\u5411\u73B0\u6709 {path} \u8FFD\u52A0 Fabric hook",
1586
- "cli.hooks.install.hook-created": "\u5DF2\u521B\u5EFA {path}",
1587
- "cli.hooks.install.prepare-left": "\u4FDD\u7559 {path} \u4E2D\u539F\u6709\u7684 prepare \u811A\u672C\u4E0D\u53D8",
1588
- "cli.hooks.install.prepare-added": "\u5DF2\u5411 {path} \u6DFB\u52A0 prepare \u811A\u672C",
1589
- "cli.human-lint.description": "\u9A8C\u8BC1\u9501\u5B9A\u7684\u4EBA\u5DE5\u7F16\u8F91\u533A\u5757\u3002",
1590
- "cli.human-lint.args.target.description": "\u76EE\u6807\u9879\u76EE\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u3002",
1591
- "cli.human-lint.drift-detected": "\u68C0\u6D4B\u5230 human-lock \u5185\u5BB9\u6F02\u79FB\u3002\u8BF7\u56DE\u9000\u7F16\u8F91\uFF0C\u6216\u5728\u63D0\u4EA4\u524D\u66F4\u65B0\u5DF2\u6279\u51C6\u7684\u54C8\u5E0C\u3002",
1592
- "cli.human-lint.table.location": "\u4F4D\u7F6E",
1593
- "cli.human-lint.table.expected": "\u9884\u671F",
1594
- "cli.human-lint.table.got": "\u5B9E\u9645",
1595
1526
  "cli.install.description": "\u5728\u76EE\u6807\u9879\u76EE\u4E2D\u5B89\u88C5 Fabric\uFF08\u811A\u624B\u67B6 .fabric/\u3001bootstrap \u6A21\u677F\u3001MCP \u5BA2\u6237\u7AEF\u914D\u7F6E\u3001git hooks\uFF09\u3002\n\n\u793A\u4F8B\uFF1A\n fabric install \u5728\u5F53\u524D\u9879\u76EE\u4E2D\u4EE5\u4EA4\u4E92\u6A21\u5F0F\u5B89\u88C5\n fabric install --yes \u63A5\u53D7\u9ED8\u8BA4\u503C\uFF0C\u8DF3\u8FC7 TTY \u5411\u5BFC\n fabric install --dry-run \u4EC5\u9884\u89C8\u5B89\u88C5\u8BA1\u5212\uFF0C\u4E0D\u5199\u5165\u6587\u4EF6",
1596
1527
  "cli.install.args.target.description": "\u76EE\u6807\u9879\u76EE\u8DEF\u5F84\u3002\u9ED8\u8BA4\u4F9D\u6B21\u4F7F\u7528 --target\u3001EXTERNAL_FIXTURE_PATH\u3001\u5F53\u524D\u76EE\u5F55\u3002",
1597
1528
  "cli.install.args.debug.description": "\u5C06\u76EE\u6807\u89E3\u6790\u7EC6\u8282\u8F93\u51FA\u5230 stderr\u3002",
@@ -1600,13 +1531,13 @@ var zhCNMessages = {
1600
1531
  "cli.install.args.enable-embed.description": "\u542F\u7528\u5411\u91CF\u8BED\u4E49\u641C\u7D22 (\u8BBE embed_enabled + embed_model;\u6253\u5370 fastembed \u5B89\u88C5\u6B65\u9AA4)",
1601
1532
  "cli.install.args.embed-model.description": "\u914D\u5408 --enable-embed:\u8986\u76D6\u56FA\u5B9A\u7684 embed \u6A21\u578B (\u9ED8\u8BA4 fast-bge-small-zh-v1.5)",
1602
1533
  // rc.35 TASK-08 (P0-5/6): --force-skills-only。
1603
- "cli.install.args.force-skills-only.description": "\u8DF3\u8FC7 bootstrap / MCP / hooks / settings,\u53EA\u91CD\u65B0\u5237\u65B0 fabric Skill \u6A21\u677F (.claude/.codex/.cursor/skills/*)\u3002",
1534
+ "cli.install.args.force-skills-only.description": "\u8DF3\u8FC7 bootstrap / MCP / hooks / settings,\u53EA\u91CD\u65B0\u5237\u65B0 fabric Skill \u6A21\u677F (.claude/.codex/skills/*)\u3002",
1604
1535
  "cli.install.force-skills-only.banner": "\u53EA\u5237\u65B0 fabric Skill \u6A21\u677F",
1605
1536
  "cli.install.force-skills-only.uninitialised.message": "fabric install --force-skills-only: \u9879\u76EE\u672A\u521D\u59CB\u5316(\u627E\u4E0D\u5230 .fabric/agents.meta.json)\u3002",
1606
1537
  "cli.install.force-skills-only.uninitialised.hint": "\u8BF7\u5148\u8FD0\u884C `fabric install`(\u4E0D\u5E26 --force-skills-only)\u94FA\u8BBE\u57FA\u7840 scaffold;\u4E4B\u540E\u518D\u7528 --force-skills-only \u505A\u540E\u7EED Skill \u5237\u65B0\u3002",
1607
1538
  "cli.install.force-skills-only.summary": "Skill \u5237\u65B0\u5B8C\u6210 \u2014 \u5199\u5165: {written}, \u8DF3\u8FC7: {skipped}, \u9519\u8BEF: {errors}",
1608
1539
  // v2.0.0-rc.37 NEW-26: --force-hooks-only mirror of --force-skills-only。
1609
- "cli.install.args.force-hooks-only.description": "\u8DF3\u8FC7 bootstrap / MCP / skills / settings,\u53EA\u91CD\u65B0\u5237\u65B0 fabric hook scripts + per-client hook config \u5408\u5E76 (.claude/.codex/.cursor/hooks/*)\u3002",
1540
+ "cli.install.args.force-hooks-only.description": "\u8DF3\u8FC7 bootstrap / MCP / skills / settings,\u53EA\u91CD\u65B0\u5237\u65B0 fabric hook scripts + per-client hook config \u5408\u5E76 (.claude/.codex/hooks/*)\u3002",
1610
1541
  "cli.install.force-hooks-only.banner": "\u53EA\u5237\u65B0 fabric hooks",
1611
1542
  "cli.install.force-hooks-only.uninitialised.message": "fabric install --force-hooks-only: \u9879\u76EE\u672A\u521D\u59CB\u5316(\u627E\u4E0D\u5230 .fabric/agents.meta.json)\u3002",
1612
1543
  "cli.install.force-hooks-only.uninitialised.hint": "\u8BF7\u5148\u8FD0\u884C `fabric install`(\u4E0D\u5E26 --force-hooks-only)\u94FA\u8BBE\u57FA\u7840 scaffold;\u4E4B\u540E\u518D\u7528 --force-hooks-only \u505A\u540E\u7EED hook \u5237\u65B0\u3002",
@@ -1626,7 +1557,6 @@ var zhCNMessages = {
1626
1557
  "cli.install.stages.bootstrap.snapshot.skipped": "\u5DF2\u8DF3\u8FC7 .fabric/AGENTS.md \u2014 \u5DF2\u662F\u6700\u65B0",
1627
1558
  "cli.install.steps.bootstrap-claude": "\u5DF2\u66F4\u65B0 CLAUDE.md \u7684 @-import \u5F15\u7528",
1628
1559
  "cli.install.steps.bootstrap-codex": "\u5DF2\u66F4\u65B0 AGENTS.md \u7684 fabric:bootstrap managed block",
1629
- "cli.install.steps.bootstrap-cursor": "\u5DF2\u66F4\u65B0 .cursor/rules/fabric-bootstrap.mdc",
1630
1560
  "cli.install.stages.mcp": "\u6B63\u5728\u914D\u7F6E MCP \u5BA2\u6237\u7AEF...",
1631
1561
  "cli.install.stages.hooks": "\u6B63\u5728\u5B89\u88C5 git hooks...",
1632
1562
  "cli.install.stages.skipped": "\u5DF2\u8DF3\u8FC7",
@@ -1635,9 +1565,22 @@ var zhCNMessages = {
1635
1565
  "cli.install.stages.summary.ran": "\u5DF2\u6267\u884C",
1636
1566
  "cli.install.stages.summary.skipped": "\u5DF2\u8DF3\u8FC7",
1637
1567
  "cli.install.stages.summary.failed": "\u5931\u8D25",
1568
+ "cli.install.pipeline.title": "Fabric \u5B89\u88C5",
1569
+ "cli.install.pipeline.complete": "Fabric \u5B89\u88C5\u5B8C\u6210",
1570
+ "cli.install.pipeline.running": "\u5C06\u6309 {count} \u4E2A\u9636\u6BB5\u6267\u884C",
1571
+ "cli.install.pipeline.label.preflight": "\u5168\u5C40\u4E0E\u9879\u76EE\u9884\u68C0",
1572
+ "cli.install.pipeline.label.env": "\u9879\u76EE\u73AF\u5883\u521D\u59CB\u5316",
1573
+ "cli.install.pipeline.label.store": "\u77E5\u8BC6\u5E93\u62D3\u6251",
1574
+ "cli.install.pipeline.label.hooks": "Hook \u4E0E skill \u5B89\u88C5",
1575
+ "cli.install.pipeline.label.mcp": "MCP \u670D\u52A1\u914D\u7F6E",
1576
+ "cli.install.pipeline.label.validate": "\u5B89\u88C5\u6821\u9A8C",
1577
+ "cli.install.pipeline.label.guidance": "\u540E\u7EED\u6307\u5F15",
1578
+ "cli.install.pipeline.desc.store": "\u7ED1\u5B9A\u5F53\u524D\u9879\u76EE\u7684 read/write store\uFF0C\u5237\u65B0 resolved-bindings snapshot\u3002",
1638
1579
  "cli.install.next-step": "{label} {message}",
1639
1580
  "cli.install.reason-message": "{label} {message}",
1640
- "cli.install.language_preference_hint": "Fabric \u8BED\u8A00\u504F\u597D\uFF1A{value}\u3002\u5982\u9700\u8C03\u6574\uFF0C\u8BF7\u7F16\u8F91 .fabric/fabric-config.json \u4E2D\u7684 fabric_language \u5B57\u6BB5\uFF08\u53EF\u9009\u503C\uFF1Amatch-existing | zh-CN | en | zh-CN-hybrid\uFF09\u3002",
1581
+ "cli.install.language.prompt": "\u9009\u62E9 Fabric \u8BED\u8A00\uFF08\u754C\u9762\u4E0E\u77E5\u8BC6\u7EDF\u4E00\u4F7F\u7528\uFF0C\u4E4B\u540E\u53EF\u7528 fabric config \u4FEE\u6539\uFF09\uFF1A",
1582
+ "cli.install.language.option.zh-CN": "\u7B80\u4F53\u4E2D\u6587 (zh-CN)",
1583
+ "cli.install.language.option.en": "English (en)",
1641
1584
  "cli.install.plan.title": "Fabric \u5B89\u88C5\u8BA1\u5212",
1642
1585
  "cli.install.plan.mode-banner.default": "[mode: apply] \u6807\u51C6\u5B89\u88C5\u6267\u884C",
1643
1586
  "cli.install.plan.mode-banner.plan": "[mode: plan] \u4EC5\u9884\u89C8\uFF0C\u4E0D\u4F1A\u5199\u5165\u6587\u4EF6",
@@ -1669,11 +1612,55 @@ var zhCNMessages = {
1669
1612
  "cli.install.wizard.cancelled": "Fabric \u5B89\u88C5\u5DF2\u5728\u6267\u884C\u524D\u53D6\u6D88\u3002",
1670
1613
  "cli.install.capabilities.title": "\u5BA2\u6237\u7AEF\u80FD\u529B\u6458\u8981",
1671
1614
  // v2.0.0-rc.37 NEW-22: post-install 重启提示。MCP server 在 client 启动
1672
- // 时 spawn, 已运行的 Claude Code / Cursor / Codex session 不会自动加载
1615
+ // 时 spawn, 已运行的 Claude Code / Codex session 不会自动加载
1673
1616
  // 新 mcp config — 必须重启才能拿到 Fabric tools。
1674
- "cli.install.restart-banner": "\u91CD\u542F\u63D0\u793A: \u5DF2\u8FD0\u884C\u7684 Claude Code / Cursor / Codex CLI session \u9700\u91CD\u542F\u624D\u80FD\u52A0\u8F7D\u65B0 MCP server \u914D\u7F6E;\u65B0\u4F1A\u8BDD\u4F1A\u81EA\u52A8\u4F7F\u7528 Fabric tools\u3002",
1675
- "cli.install.next-steps": "\u4E0B\u4E00\u6B65 \u2014\u2014 \u62FF\u5230\u7B2C\u4E00\u4EFD\u4EF7\u503C:\n 1. \u91CD\u542F\u4F60\u7684 AI \u5BA2\u6237\u7AEF (Claude Code / Codex)\u3002\u5B83\u73B0\u5728\u4F1A\u81EA\u52A8\u628A\u672C\u9879\u76EE\u7684\u77E5\u8BC6 surface \u7ED9\u52A9\u624B\u3002\n 2. \u6C89\u6DC0\u77E5\u8BC6: \u6B63\u5E38\u5E72\u6D3B\u5373\u53EF \u2014\u2014 \u5F53\u4F60\u505A\u51B3\u7B56\u6216\u8E29\u5751\u65F6, fabric-archive skill \u4F1A\u63D0\u8BAE\u5165\u5E93; \u6216\u8DD1 fabric-import skill \u4ECE git \u5386\u53F2\u56DE\u704C\u3002\n 3. \u9A8C\u8BC1\u751F\u6548: \u95EE\u4F60\u7684 AI\u300CFabric \u5BF9\u8FD9\u4E2A repo \u77E5\u9053\u4E9B\u4EC0\u4E48?\u300D, \u6216\u8DD1 `fabric doctor` \u67E5\u5065\u5EB7\u3002",
1617
+ "cli.install.restart-banner": "\u91CD\u542F\u63D0\u793A: \u5DF2\u8FD0\u884C\u7684 Claude Code / Codex CLI session \u9700\u91CD\u542F\u624D\u80FD\u52A0\u8F7D\u65B0 MCP server \u914D\u7F6E;\u65B0\u4F1A\u8BDD\u4F1A\u81EA\u52A8\u4F7F\u7528 Fabric tools\u3002",
1618
+ "cli.install.next-steps": "\u4E0B\u4E00\u6B65 \u2014\u2014 \u62FF\u5230\u7B2C\u4E00\u4EFD\u4EF7\u503C:\n 1. \u91CD\u542F\u4F60\u7684 AI \u5BA2\u6237\u7AEF (Claude Code / Codex)\u3002\u5B83\u73B0\u5728\u4F1A\u81EA\u52A8\u628A\u672C\u9879\u76EE\u7684\u77E5\u8BC6 surface (\u4E3B\u52A8\u5448\u73B0) \u7ED9\u52A9\u624B\u3002\n 2. \u6C89\u6DC0\u77E5\u8BC6: \u6B63\u5E38\u5E72\u6D3B\u5373\u53EF \u2014\u2014 \u5F53\u4F60\u505A\u51B3\u7B56\u6216\u8E29\u5751\u65F6, fabric-archive skill \u4F1A\u63D0\u8BAE\u5165\u5E93; \u6216\u8DD1 fabric-import skill \u4ECE git \u5386\u53F2\u56DE\u704C\u3002\n 3. \u9A8C\u8BC1\u751F\u6548: \u95EE\u4F60\u7684 AI\u300CFabric \u5BF9\u8FD9\u4E2A repo \u77E5\u9053\u4E9B\u4EC0\u4E48?\u300D, \u6216\u8DD1 `fabric doctor` \u67E5\u5065\u5EB7\u3002",
1676
1619
  "cli.install.store-bind-nudge": "\u{1F4A1} \u68C0\u6D4B\u5230\u5DF2\u6302\u8F7D\u4F46\u672A\u7ED1\u5B9A\u672C\u9879\u76EE\u7684\u77E5\u8BC6 store: {aliases}\u3002\u8FD0\u884C `fabric store bind {first}` \u628A\u5B83\u7684\u77E5\u8BC6\u63A5\u5165\u672C\u9879\u76EE, \u518D `fabric store switch-write {first}` \u8BBE\u4E3A\u56E2\u961F\u77E5\u8BC6\u7684\u5199\u5165\u76EE\u6807\u3002",
1620
+ // C1/C5: 语义搜索交互文案统一走 t(),英文术语首现加中文 gloss。
1621
+ "cli.install.semantic.prompt": "\u542F\u7528\u5411\u91CF\u8BED\u4E49\u641C\u7D22 (vector semantic search)\uFF1F(\u9996\u6B21\u53EC\u56DE recall \u65F6\u624D\u4F1A\u4E0B\u8F7D\u5D4C\u5165\u6A21\u578B)",
1622
+ "cli.install.semantic.enabled": "\u8BED\u4E49\u641C\u7D22\u5DF2\u542F\u7528 (embed_enabled=true, embed_model={model})\u3002",
1623
+ "cli.install.semantic.already-enabled": "\u8BED\u4E49\u641C\u7D22\u5DF2\u662F\u542F\u7528\u72B6\u6001 (embed_model={model})\uFF0C\u672A\u6539\u52A8 {path}\u3002",
1624
+ "cli.install.semantic.offer-install": "\u73B0\u5728\u5B89\u88C5\u53EF\u9009\u7684 embedder (\u5411\u91CF\u7F16\u7801\u5668) \u5417\uFF1F\u5C06\u8FD0\u884C `npm i -g fastembed`\uFF08\u5DF2\u5B89\u88C5\u5219\u79D2\u8FC7\uFF09\u3002",
1625
+ "cli.install.semantic.installing": "\u6B63\u5728\u8FD0\u884C `npm i -g fastembed` \u2026",
1626
+ "cli.install.semantic.installed": "fastembed \u5B89\u88C5\u5B8C\u6210\u3002\u5D4C\u5165\u6A21\u578B\u4F1A\u5728\u9996\u6B21\u53EC\u56DE (recall) \u65F6\u81EA\u52A8\u4E0B\u8F7D\uFF08\u7EA6\u6570\u5341\u2013\u6570\u767E MB\uFF1B\u4E0D\u4E0A\u4F20\u4EFB\u4F55 KB \u6570\u636E\uFF09\u3002",
1627
+ "cli.install.semantic.install-failed": "\u81EA\u52A8\u5B89\u88C5\u5931\u8D25\uFF08{reason}\uFF09\u3002\u8BF7\u624B\u52A8\u6267\u884C\u4E0B\u9762\u7684\u6B65\u9AA4\uFF1A",
1628
+ "cli.install.semantic.manual-steps": " 1. \u5B89\u88C5\u53EF\u9009 embedder (\u5411\u91CF\u7F16\u7801\u5668\uFF0C\u88C5\u5230 MCP server \u89E3\u6790\u6A21\u5757\u7684\u4F4D\u7F6E \u2014 \u5168\u5C40\u5B89\u88C5\u5373\u5168\u5C40):\n npm i -g fastembed\n 2. \u9884\u70ED\u6A21\u578B\u7F13\u5B58 (\u9996\u8DD1\u4F1A\u8054\u7F51\u4E0B\u8F7D\u6A21\u578B\u6743\u91CD ~\u6570\u5341-\u6570\u767E MB, \u4E0D\u4E0A\u4F20\u4EFB\u4F55 KB \u6570\u636E):\n export FABRIC_EMBED_CACHE_DIR=~/.cache/fabric-embed # \u4E25\u683C\u79BB\u7EBF\u8005\u9884\u5148\u653E\u597D\u6743\u91CD\n \u6CE8: \u5207\u6362 embed_model \u540E\u5DF2\u6709\u5411\u91CF\u7EF4\u5EA6/\u8BED\u4E49\u53D8\u5316, \u4E0B\u6B21 recall \u4F1A\u6309\u65B0\u6A21\u578B\u91CD\u65B0\u5D4C\u5165 (doc \u5411\u91CF\u6309\u6587\u672C\u7F13\u5B58, \u81EA\u52A8\u5931\u914D\u91CD\u7B97)\u3002\n \u5173\u95ED: \u7F16\u8F91 fabric.config.json \u8BBE embed_enabled=false\u3002",
1629
+ // C5: store onboarding 交互文案统一走 t()。
1630
+ "cli.install.store.local-store": "\u672C\u5730 store",
1631
+ "cli.install.store.bind-mounted.prompt": "\u628A\u4E00\u4E2A\u5DF2\u6302\u8F7D\u7684\u77E5\u8BC6 store \u7ED1\u5B9A\u5230\u672C\u9879\u76EE\uFF1F",
1632
+ "cli.install.store.setup.prompt": "\u4E3A\u672C\u9879\u76EE\u8BBE\u7F6E\u77E5\u8BC6 store\uFF1F",
1633
+ "cli.install.store.setup.bind-label": "\u7ED1\u5B9A\u5DF2\u6302\u8F7D: {alias}",
1634
+ "cli.install.store.setup.already-bound": "\u5DF2\u7ED1\u5B9A\u672C\u9879\u76EE: {aliases} \u2713",
1635
+ "cli.install.store.skip-label": "\u8DF3\u8FC7",
1636
+ "cli.install.store.bind-mounted.skip-hint": "\u6682\u4E0D\u7ED1\u5B9A\u5DF2\u6302\u8F7D\u7684 store",
1637
+ "cli.install.store.project-coordinate": "\u5728 store '{store}' \u4E2D\u7684\u9879\u76EE\u5750\u6807 (project coordinate):",
1638
+ "cli.install.store.project-pick.prompt": "store '{store}' \u5DF2\u6709\u5176\u5B83\u9879\u76EE,\u4E14\u4E0E\u672C\u4ED3\u5E93 git \u540D\u4E0D\u5339\u914D \u2014\u2014 \u52A0\u5165\u5DF2\u6709\u9879\u76EE\u8FD8\u662F\u65B0\u5EFA?",
1639
+ "cli.install.store.project-pick.join": "\u52A0\u5165\u5DF2\u6709:{name} ({id})",
1640
+ "cli.install.store.project-pick.new": "\u2795 \u65B0\u5EFA\u9879\u76EE {id}",
1641
+ "cli.install.store.project-pick.new-name": "\u65B0\u9879\u76EE id (project coordinate):",
1642
+ "cli.install.store.bound-success": "\u5DF2\u628A store '{alias}' \u7ED1\u5B9A\u5230\u672C\u9879\u76EE\u5E76\u8BBE\u4E3A\u5199\u5165\u76EE\u6807 (write target)\u3002",
1643
+ "cli.install.store.created-success": "\u5DF2\u521B\u5EFA store '{alias}'\u3001\u7ED1\u5B9A\u5230\u672C\u9879\u76EE\u5E76\u8BBE\u4E3A\u5199\u5165\u76EE\u6807 (write target)\u3002",
1644
+ "cli.install.store.onboard.prompt": "\u4E3A\u672C\u9879\u76EE\u8BBE\u7F6E\u4E00\u4E2A\u56E2\u961F / \u5171\u4EAB\u77E5\u8BC6 store\uFF1F",
1645
+ "cli.install.store.onboard.skip-hint": "\u4EC5\u7528 personal store (\u9ED8\u8BA4)",
1646
+ "cli.install.store.onboard.join-label": "\u52A0\u5165\u5DF2\u6709",
1647
+ "cli.install.store.onboard.join-hint": "\u4ECE git remote \u514B\u9686 + \u7ED1\u5B9A\u4E00\u4E2A\u5171\u4EAB store",
1648
+ "cli.install.store.onboard.create-label": "\u65B0\u5EFA",
1649
+ "cli.install.store.onboard.create-hint": "\u65B0\u5EFA\u4E00\u4E2A\u672C\u5730 store (\u53EF\u9009 remote \u6258\u7BA1)",
1650
+ "cli.install.store.onboard.join-url": "\u5171\u4EAB store \u7684 git remote (url):",
1651
+ "cli.install.store.onboard.alias": "\u65B0 store \u7684\u672C\u5730\u522B\u540D (alias):",
1652
+ "cli.install.store.onboard.remote": "\u7528\u4E8E\u6258\u7BA1\u5B83\u7684 git remote (\u53EF\u9009 \u2014 \u7559\u7A7A\u8DF3\u8FC7):",
1653
+ "cli.install.store.unbound-note": "\u6CE8\u610F: \u4EE5\u4E0B store \u5DF2\u6302\u8F7D\u4F46\u672A\u7ED1\u5B9A\u5230\u672C\u9879\u76EE: {aliases}\u3002",
1654
+ "cli.install.store.unbound-hint": " \u8FD0\u884C 'fabric store bind {first}' \u7ED1\u5B9A\u5176\u4E00\u3002",
1655
+ // C4: personal store clone-or-new。
1656
+ "cli.install.store.personal.prompt": "\u672C\u673A\u8FD8\u6CA1\u6709 personal store (\u4E2A\u4EBA\u77E5\u8BC6\u5E93)\u3002\u65B0\u5EFA\u4E00\u4E2A\uFF0C\u8FD8\u662F\u4ECE remote \u514B\u9686\u4F60\u5DF2\u6709\u7684\uFF1F",
1657
+ "cli.install.store.personal.new-label": "\u65B0\u5EFA\u672C\u5730 (\u9ED8\u8BA4)",
1658
+ "cli.install.store.personal.new-hint": "\u5168\u65B0\u7A7A personal store",
1659
+ "cli.install.store.personal.clone-label": "\u514B\u9686\u5DF2\u6709",
1660
+ "cli.install.store.personal.clone-hint": "\u4ECE git remote \u514B\u9686\u4F60\u5907\u4EFD\u7684 personal store",
1661
+ "cli.install.store.personal.clone-url": "\u4F60\u7684 personal store \u7684 git remote (url):",
1662
+ "cli.install.store.personal.cloned-success": "\u5DF2\u4ECE remote \u514B\u9686 personal store ({uuid})\u3002",
1663
+ "cli.install.store.personal.clone-failed": "\u514B\u9686 personal store \u5931\u8D25\uFF08{reason}\uFF09\uFF0C\u6539\u4E3A\u65B0\u5EFA\u672C\u5730\u7A7A store\u3002",
1677
1664
  "cli.install.capabilities.none": "\u6CA1\u6709\u68C0\u6D4B\u5230\u53EF\u7528\u4E8E bootstrap \u6216 MCP \u540E\u7EED\u63A5\u529B\u7684\u53D7\u652F\u6301\u5BA2\u6237\u7AEF\u3002",
1678
1665
  "cli.install.capabilities.header.client": "\u5BA2\u6237\u7AEF",
1679
1666
  "cli.install.capabilities.header.bootstrap": "Bootstrap",
@@ -1691,7 +1678,7 @@ var zhCNMessages = {
1691
1678
  "cli.install.capabilities.follow-up.ready": "\u53EF\u5728\u5BA2\u6237\u7AEF\u7EE7\u7EED",
1692
1679
  "cli.install.capabilities.follow-up.install": "\u5B89\u88C5\u5BA2\u6237\u7AEF\u8D44\u4EA7",
1693
1680
  "cli.install.capabilities.follow-up.manual": "\u9700\u8981\u624B\u52A8\u540E\u7EED\u5904\u7406",
1694
- "cli.install.next-step.message": "\u8FD0\u884C fabric hooks install \u4EE5\u6DFB\u52A0\u7B2C 4 \u5929\u7684 pre-commit \u6D41\u6C34\u7EBF\u3002",
1681
+ "cli.install.next-step.message": "\u8FD0\u884C fabric install --reapply --yes \u4EE5\u5237\u65B0 Fabric \u7BA1\u7406\u7684 hooks \u4E0E\u5BA2\u6237\u7AEF\u914D\u7F6E\u3002",
1695
1682
  "cli.install.reason-message.installable-body": ".fabric/forensic.json \u5DF2\u5C31\u7EEA\uFF1B\u90E8\u5206\u5DF2\u68C0\u6D4B\u5230\u7684\u5BA2\u6237\u7AEF\u5DF2\u652F\u6301 Fabric \u540E\u7EED\u63A5\u529B\uFF0C\u4F46\u4ECD\u9700\u5B89\u88C5\u5BA2\u6237\u7AEF\u8D44\u4EA7\u3002",
1696
1683
  "cli.install.reason-message.manual-body": ".fabric/forensic.json \u5DF2\u5C31\u7EEA\uFF1B\u90E8\u5206\u5DF2\u68C0\u6D4B\u5230\u7684\u5BA2\u6237\u7AEF\u5C1A\u672A\u5B89\u88C5 Fabric skill\uFF0C\u9700\u8981\u624B\u52A8\u5B8C\u6210\u540E\u7EED\u5B89\u88C5\u3002",
1697
1684
  "cli.install.codex-hooks.created": "{label} {path}\uFF0C\u5E76\u5199\u5165 Codex hooks \u914D\u7F6E\uFF08\u9700\u542F\u7528 features.codex_hooks = true\uFF09\u3002",
@@ -1709,22 +1696,24 @@ var zhCNMessages = {
1709
1696
  "cli.install.diff.canonical": "\u5DE5\u4F5C\u533A\u5DF2\u662F\u89C4\u8303\u72B6\u6001\uFF08\u5DF2\u6821\u9A8C {count} \u4E2A\u6587\u4EF6\uFF09\u3002",
1710
1697
  "cli.install.diff.applying-missing": "\u6B63\u5728\u8865\u9F50 {count} \u4E2A\u7F3A\u5931\u9879\uFF1A{files}",
1711
1698
  "cli.install.diff.drift-abort": "\u68C0\u6D4B\u5230 {path} \u5DF2\u88AB\u4FEE\u6539\u3002\u8FD0\u884C `fabric doctor` \u8FDB\u884C\u68C0\u67E5\uFF0C\u6216 `fabric uninstall && fabric install` \u8FDB\u884C\u91CD\u7F6E\u3002",
1699
+ "cli.install.diff.drift-abort.action-hint": "\u5148\u8FD0\u884C `fabric doctor` \u68C0\u67E5\u6F02\u79FB\uFF1B\u5982\u679C\u9700\u8981\u91CD\u7F6E\u6258\u7BA1\u6587\u4EF6\uFF0C\u8FD0\u884C `fabric uninstall && fabric install`\u3002",
1712
1700
  "cli.install.diff.state.missing": "\u7F3A\u5931",
1713
1701
  "cli.install.diff.state.present-canonical": "\u89C4\u8303",
1714
1702
  "cli.install.diff.state.drifted": "\u6F02\u79FB",
1715
1703
  "cli.install.diff.state.user-modified": "\u7528\u6237\u4FEE\u6539",
1716
- "cli.uninstall.description": "\u4ECE\u76EE\u6807\u9879\u76EE\u4E2D\u5378\u8F7D Fabric\u3002.fabric/knowledge/ \u59CB\u7EC8\u4FDD\u7559\uFF1B~/.fabric/knowledge/ \u6C38\u4E0D\u53D7\u5F71\u54CD\u3002\n\n\u793A\u4F8B\uFF1A\n fabric uninstall \u5728\u5F53\u524D\u9879\u76EE\u4E2D\u4EE5\u4EA4\u4E92\u6A21\u5F0F\u5378\u8F7D\n fabric uninstall --yes \u63A5\u53D7\u9ED8\u8BA4\u503C\uFF0C\u8DF3\u8FC7 TTY \u5411\u5BFC\n fabric uninstall --dry-run \u4EC5\u9884\u89C8\u5378\u8F7D\u8BA1\u5212\uFF0C\u4E0D\u5220\u9664\u6587\u4EF6",
1704
+ "cli.uninstall.description": "\u4ECE\u76EE\u6807\u9879\u76EE\u4E2D\u5378\u8F7D Fabric\u3002\u9879\u76EE\u5378\u8F7D\u6C38\u8FDC\u4E0D\u4F1A\u5220\u9664 ~/.fabric/stores/ \u4E0B\u7684\u5168\u5C40\u77E5\u8BC6 store\u3002\n\n\u793A\u4F8B\uFF1A\n fabric uninstall \u5728\u5F53\u524D\u9879\u76EE\u4E2D\u4EE5\u4EA4\u4E92\u6A21\u5F0F\u5378\u8F7D\n fabric uninstall --yes \u63A5\u53D7\u9ED8\u8BA4\u503C\uFF0C\u8DF3\u8FC7 TTY \u5411\u5BFC\n fabric uninstall --dry-run \u4EC5\u9884\u89C8\u5378\u8F7D\u8BA1\u5212\uFF0C\u4E0D\u5220\u9664\u6587\u4EF6",
1717
1705
  "cli.uninstall.args.target.description": "\u76EE\u6807\u9879\u76EE\u8DEF\u5F84\u3002\u9ED8\u8BA4\u4F9D\u6B21\u4F7F\u7528 --target\u3001EXTERNAL_FIXTURE_PATH\u3001\u5F53\u524D\u76EE\u5F55\u3002",
1718
1706
  "cli.uninstall.args.debug.description": "\u5C06\u76EE\u6807\u89E3\u6790\u7EC6\u8282\u8F93\u51FA\u5230 stderr\u3002",
1719
1707
  "cli.uninstall.args.yes.description": "\u63A5\u53D7\u5F53\u524D\u5378\u8F7D\u8BA1\u5212\u5E76\u8DF3\u8FC7 TTY \u5411\u5BFC\u76F4\u63A5\u6267\u884C\u3002",
1720
1708
  "cli.uninstall.args.dry-run.description": "\u4EC5\u8F93\u51FA\u5378\u8F7D\u8BA1\u5212\uFF0C\u4E0D\u5220\u9664\u6587\u4EF6\u4E5F\u4E0D\u6267\u884C\u540E\u7EED\u9636\u6BB5\u3002",
1721
1709
  "cli.uninstall.plan.title": "Fabric \u5378\u8F7D\u8BA1\u5212",
1710
+ // C3: 镜像 install 的阶段提示 (install 用 "Fabric install 将按 N 个阶段执行")。
1711
+ "cli.uninstall.plan.phase-banner": "Fabric uninstall \u5C06\u6309 {total} \u4E2A\u9636\u6BB5\u6267\u884C",
1722
1712
  "cli.uninstall.plan.target": "\u76EE\u6807\uFF1A{target}",
1723
1713
  "cli.uninstall.plan.actions": "\u8BA1\u5212\uFF1Ascaffold={scaffold} bootstrap={bootstrap} mcp={mcp}",
1724
1714
  "cli.uninstall.plan.detected": "\u68C0\u6D4B\u5230\u7684\u5BA2\u6237\u7AEF\uFF1A{clients}",
1725
1715
  "cli.uninstall.plan.preserves": "\u4FDD\u7559\u9879\uFF1A",
1726
- "cli.uninstall.plan.preserves.knowledge": "\u56E2\u961F\u77E5\u8BC6\u6811\uFF08\u59CB\u7EC8\u4FDD\u7559\uFF09",
1727
- "cli.uninstall.plan.preserves.personal": "\u4E2A\u4EBA\u6839\u76EE\u5F55\uFF0C\u6C38\u4E0D\u89E6\u78B0",
1716
+ "cli.uninstall.plan.preserves.stores": "\u5168\u5C40\u77E5\u8BC6 stores\uFF0C\u9879\u76EE\u5378\u8F7D\u6C38\u4E0D\u5220\u9664",
1728
1717
  "cli.uninstall.plan.preview-title": "Fabric \u5378\u8F7D dry run",
1729
1718
  "cli.uninstall.plan.preview-result": "scaffold={scaffold} bootstrap={bootstrap} mcp={mcp}",
1730
1719
  "cli.uninstall.plan.scaffold-entries.title": "Scaffold \u5F85\u6E05\u7406\u9879\uFF1A",
@@ -1737,53 +1726,18 @@ var zhCNMessages = {
1737
1726
  "cli.uninstall.summary.title": "\u5378\u8F7D\u6458\u8981",
1738
1727
  "cli.uninstall.summary.body": "removed={removed} skipped={skipped} errors={errors}",
1739
1728
  "cli.uninstall.wizard.intro": "\u5378\u8F7D Fabric",
1740
- "cli.uninstall.wizard.overview.title": "\u5378\u8F7D\u6982\u89C8",
1741
- "cli.uninstall.wizard.overview.body": "\u76EE\u6807\uFF1A{target}\n\u8FD9\u4E2A\u5411\u5BFC\u53EA\u8D1F\u8D23\u8C03\u6574\u5378\u8F7D\u8BA1\u5212\uFF1B\u771F\u6B63\u6267\u884C\u4ECD\u7136\u8D70\u73B0\u6709\u7684 Fabric uninstall \u9636\u6BB5\u3002\n.fabric/knowledge/ \u59CB\u7EC8\u4FDD\u7559\uFF1B~/.fabric/knowledge/ \u6C38\u4E0D\u53D7\u5F71\u54CD\u3002",
1742
- "cli.uninstall.wizard.step.target": "\u786E\u8BA4\u76EE\u6807",
1743
- "cli.uninstall.wizard.step.plan": "\u914D\u7F6E\u5378\u8F7D\u8BA1\u5212",
1744
- "cli.uninstall.wizard.step.review": "\u590D\u6838\u6700\u7EC8\u8BA1\u5212",
1745
- "cli.uninstall.wizard.target.confirm": "\u786E\u8BA4\u4ECE {target} \u5378\u8F7D Fabric\uFF1F[Y/n]",
1746
- "cli.uninstall.wizard.stage.scaffold": "\u662F\u5426\u6E05\u7406 scaffold \u4EA7\u7269\uFF1F[{defaultValue}]",
1747
- "cli.uninstall.wizard.stage.bootstrap": "\u662F\u5426\u79FB\u9664 bootstrap\uFF08Skills + hooks\uFF09\uFF1F[{defaultValue}]",
1748
- "cli.uninstall.wizard.stage.mcp": "\u662F\u5426\u53CD\u6CE8\u518C MCP \u5BA2\u6237\u7AEF\uFF1F[{defaultValue}]",
1729
+ "cli.uninstall.wizard.select.prompt": "\u8981\u4ECE {target} \u5378\u8F7D\u54EA\u4E9B\u90E8\u5206\uFF1F(\u7A7A\u683C\u52FE\u9009 / \u56DE\u8F66\u786E\u8BA4\uFF1B~/.fabric/stores/ \u4E0B\u7684\u5168\u5C40\u77E5\u8BC6 store \u6C38\u4E0D\u5220\u9664)",
1730
+ "cli.uninstall.wizard.select.scaffold.label": "scaffold \u4EA7\u7269",
1731
+ "cli.uninstall.wizard.select.scaffold.hint": ".fabric/ \u4E0B\u7684\u811A\u624B\u67B6\u6587\u4EF6",
1732
+ "cli.uninstall.wizard.select.bootstrap.label": "bootstrap (Skills + hooks)",
1733
+ "cli.uninstall.wizard.select.bootstrap.hint": "\u5404\u5BA2\u6237\u7AEF\u7684 skills \u4E0E git hooks",
1734
+ "cli.uninstall.wizard.select.mcp.label": "MCP \u5BA2\u6237\u7AEF\u6CE8\u518C",
1735
+ "cli.uninstall.wizard.select.mcp.hint": "\u4ECE\u5404\u5BA2\u6237\u7AEF\u53CD\u6CE8\u518C fabric MCP server",
1749
1736
  "cli.uninstall.wizard.execute.confirm": "\u73B0\u5728\u6267\u884C\u8BE5\u5378\u8F7D\u8BA1\u5212\uFF1F[Y/n]",
1750
1737
  "cli.uninstall.wizard.outro": "\u5378\u8F7D\u8BA1\u5212\u5DF2\u786E\u8BA4\uFF0C\u5F00\u59CB\u6267\u884C Fabric uninstall...",
1751
1738
  "cli.uninstall.wizard.cancelled": "Fabric \u5378\u8F7D\u5DF2\u5728\u6267\u884C\u524D\u53D6\u6D88\u3002",
1752
1739
  "cli.uninstall.confirm.proceed": "\u786E\u8BA4\u4ECE {target} \u5378\u8F7D Fabric\uFF1F[y/N]",
1753
1740
  "cli.uninstall.errors.target-not-directory": "\u76EE\u6807\u5FC5\u987B\u662F\u5DF2\u5B58\u5728\u7684\u76EE\u5F55\uFF1A{path}",
1754
- "cli.ledger-append.description": "\u5411 Fabric \u610F\u56FE\u65E5\u5FD7\u8FFD\u52A0\u4E00\u6761\u8BB0\u5F55\u3002",
1755
- "cli.ledger-append.args.target.description": "\u76EE\u6807\u9879\u76EE\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u3002",
1756
- "cli.ledger-append.args.staged.description": "\u4ECE\u6682\u5B58\u53D8\u66F4\u63A8\u5BFC\u8BB0\u5F55\uFF08\u7528\u4E8E pre-commit \u9636\u6BB5\uFF09\u3002",
1757
- "cli.ledger-append.requires-staged": "pre-commit \u573A\u666F\u4E0B\u5FC5\u987B\u4F20\u5165 --staged",
1758
- "cli.ledger-append.intent.auto": "\u81EA\u52A8\uFF1A{head}{suffix}",
1759
- "cli.ledger-append.intent.auto-more": " \u7B49 {count} \u9879",
1760
- "cli.pre-commit.description": "\u590D\u5408 pre-commit \u94A9\u5B50\uFF1A\u5728\u5355\u4E2A Node \u8FDB\u7A0B\u4E2D\u4F9D\u6B21\u6267\u884C sync-meta --check-only\u3001human-lint\u3001ledger-append --staged\u3002",
1761
- "cli.pre-commit.args.target.description": "\u9879\u76EE\u6839\u76EE\u5F55\uFF0C\u9ED8\u8BA4\u53D6\u5F53\u524D\u76EE\u5F55\u6216 EXTERNAL_FIXTURE_PATH\u3002",
1762
- "cli.pre-commit.run-failed": "fabric pre-commit\uFF1A{name} \u5931\u8D25 - {message}",
1763
- "cli.scan.description": "\u626B\u63CF\u9879\u76EE\u4EE5\u68C0\u6D4B Fabric \u5F15\u5BFC\u5019\u9009\u6A21\u5757\u3002",
1764
- "cli.scan.args.target.description": "\u76EE\u6807\u7EDD\u5BF9\u8DEF\u5F84\u3002\u9ED8\u8BA4\u4F9D\u6B21\u4F7F\u7528 --target\u3001EXTERNAL_FIXTURE_PATH\u3001\u5F53\u524D\u76EE\u5F55\u3002",
1765
- "cli.scan.args.debug.description": "\u4EE5\u683C\u5F0F\u5316\u8F93\u51FA\u6253\u5370\u68C0\u6D4B\u8BC1\u636E\u3002",
1766
- "cli.scan.args.json.description": "\u4EE5 JSON \u683C\u5F0F\u8F93\u51FA\u8BCA\u65AD\u62A5\u544A\u3002",
1767
- "cli.scan.error.missing-forensic": "\u672A\u627E\u5230 forensic.json\uFF08\u8DEF\u5F84 {path}\uFF09\uFF1B\u8BF7\u5148\u8FD0\u884C `fabric install` \u751F\u6210\u9879\u76EE\u5FEB\u7167\u3002",
1768
- "cli.scan.summary.created": "\u5DF2\u5199\u5165 {count} \u6761\u77E5\u8BC6\u6761\u76EE\u81F3 .fabric/knowledge/\u3002",
1769
- "cli.scan.summary.skipped": "\u65E0\u5DEE\u5F02\uFF1B{count} \u6761\u5DF2\u5B58\u5728\u7684\u6761\u76EE\u4FDD\u6301\u4E0D\u53D8\u3002",
1770
- "cli.scan.report.title": "Fabric \u626B\u63CF\u62A5\u544A",
1771
- "cli.scan.report.target": "\u76EE\u6807",
1772
- "cli.scan.report.framework": "\u6846\u67B6",
1773
- "cli.scan.report.evidence": "\u8BC1\u636E",
1774
- "cli.scan.report.readme-quality": "README \u8D28\u91CF",
1775
- "cli.scan.report.contributing": "CONTRIBUTING.md",
1776
- "cli.scan.report.files-counted": "\u6587\u4EF6\u6570",
1777
- "cli.scan.report.ignored-entries": "\u5FFD\u7565\u9879",
1778
- "cli.scan.report.existing-fabric": "\u73B0\u6709 Fabric \u6587\u4EF6",
1779
- "cli.scan.report.recommendations": "\u5EFA\u8BAE\uFF1A",
1780
- "cli.scan.readme-quality.ok": "\u826F\u597D",
1781
- "cli.scan.readme-quality.stub": "\u8349\u7A3F",
1782
- "cli.scan.recommendation.init": "L0\uFF1A\u8FD0\u884C fabric install\uFF0C\u5728 .fabric/AGENTS.md \u751F\u6210 Fabric \u5F15\u5BFC\u89C4\u8303\u5185\u5BB9\u3002",
1783
- "cli.scan.recommendation.readme": "L0\uFF1A\u5148\u8865\u5145 README.md\uFF0C\u518D\u628A\u9879\u76EE\u4E8B\u5B9E\u6574\u7406\u5230 Fabric \u53C2\u8003\u6587\u4EF6\u4E2D\u3002",
1784
- "cli.scan.recommendation.contributing": "L0\uFF1A\u6DFB\u52A0 CONTRIBUTING.md\uFF0C\u6216\u5728 bootstrap \u4E2D\u7559\u4E0B\u8D21\u732E\u6D41\u7A0B\u7684 TODO \u8BF4\u660E\u3002",
1785
- "cli.scan.recommendation.unknown-framework": "L1\uFF1A\u5F53\u524D\u672A\u68C0\u6D4B\u5230\u6846\u67B6\u6807\u8BB0\uFF0C\u9700\u8981\u624B\u52A8\u8865\u5145\u6280\u672F\u6808\u8BF4\u660E\u3002",
1786
- "cli.scan.recommendation.framework-dirs": "L1\uFF1A\u68C0\u67E5 {framework} \u76EE\u5F55\uFF0C\u540E\u7EED\u4E3A\u5176\u8865\u5145\u5BF9\u5E94\u4F5C\u7528\u57DF\u7684 Fabric \u89C4\u5219\u6587\u4EF6\u3002",
1787
1741
  // v2.0.0-rc.37 Wave A2 Part 2: cli.serve.* + FABRIC_AUTH_TOKEN keys removed
1788
1742
  // alongside `fabric serve` quarantine to packages/server-http-experimental/
1789
1743
  // per [[fabric-serve-quarantine-not-delete]]. Restore from git history when
@@ -1792,16 +1746,7 @@ var zhCNMessages = {
1792
1746
  "cli.onboard-coverage.description": "\u6C47\u603B\u5F53\u524D\u5DE5\u4F5C\u533A\u7684 S5 onboard-slot \u8986\u76D6\u5EA6\u3002fabric-archive Skill \u9996\u8DD1\u9636\u6BB5\u7528\u5B83\u5224\u65AD\u54EA\u4E9B\u9879\u76EE\u8BED\u8C03\u69FD\u4F4D\u5C1A\u672A\u88AB\u8BA4\u9886\u3002",
1793
1747
  "cli.onboard-coverage.args.json.description": "\u8F93\u51FA\u673A\u5668\u53EF\u8BFB\u7684 JSON \u5230 stdout\uFF08\u66FF\u4EE3\u4EBA\u7C7B\u53EF\u8BFB\u7684\u8868\u683C\uFF09\u3002",
1794
1748
  "cli.onboard-coverage.args.target.description": "\u8986\u76D6\u9879\u76EE\u6839\u76EE\u5F55\uFF08\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\uFF09\u3002",
1795
- "cli.update.description": "\u5237\u65B0 MCP \u4E3B\u673A\u914D\u7F6E\u548C git hooks\uFF0C\u4E0D\u91CD\u65B0\u521B\u5EFA Fabric \u6587\u4EF6\u3002",
1796
- "cli.update.args.target.description": "\u76EE\u6807\u9879\u76EE\u8DEF\u5F84\u3002\u9ED8\u8BA4\u4F9D\u6B21\u4F7F\u7528 --target\u3001EXTERNAL_FIXTURE_PATH\u3001\u5F53\u524D\u76EE\u5F55\u3002",
1797
- "cli.update.args.no-mcp.description": "\u8DF3\u8FC7\u91CD\u65B0\u914D\u7F6E MCP \u5BA2\u6237\u7AEF",
1798
- "cli.update.args.no-hooks.description": "\u8DF3\u8FC7\u91CD\u65B0\u5B89\u88C5 git hooks",
1799
- "cli.sync-meta.description": "\u4ECE\u5185\u90E8\u89C4\u5219\u6587\u4EF6\u540C\u6B65 Fabric \u5143\u6570\u636E\u3002",
1800
- "cli.sync-meta.args.target.description": "\u76EE\u6807\u9879\u76EE\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u3002",
1801
- "cli.sync-meta.args.check-only.description": "\u5982\u679C .fabric/agents.meta.json \u5DF2\u8FC7\u671F\uFF0C\u5219\u4EE5\u4EE3\u7801 1 \u9000\u51FA\u3002",
1802
- "cli.sync-meta.drift-detected": "\u68C0\u6D4B\u5230 Fabric \u5143\u6570\u636E\u6F02\u79FB\u3002\u8BF7\u8FD0\u884C fabric sync-meta \u8FDB\u884C\u66F4\u65B0\u3002",
1803
- "cli.sync-meta.updated": "{label} {path}",
1804
- "dashboard.app.nav.aria-label": "\u4EEA\u8868\u76D8\u89C6\u56FE\u5BFC\u822A",
1749
+ "dashboard.app.nav.aria-label": "\u4EEA\u8868\u76D8\u89C6\u56FE",
1805
1750
  "dashboard.app.nav.readiness.label": "\u51C6\u5907\u60C5\u51B5",
1806
1751
  "dashboard.app.nav.readiness.label-bilingual": "\u51C6\u5907\u60C5\u51B5 Readiness",
1807
1752
  "dashboard.app.nav.readiness.subtitle": "\u9879\u76EE\u72B6\u6001",
@@ -2017,12 +1962,6 @@ var zhCNMessages = {
2017
1962
  "cli.store.detached": "\u5DF2\u5206\u79BB '{alias}' \u2014\u2014 \u78C1\u76D8\u4E0A\u7684 store \u76EE\u5F55\u4FDD\u7559 (\u5206\u79BB \u2260 \u5220\u9664)",
2018
1963
  "cli.store.bound": "\u5DF2\u7ED1\u5B9A\u5FC5\u9700 store '{id}' (\u5171 {count} \u4E2A\u5FC5\u9700)",
2019
1964
  "cli.store.switch-write": "\u5DF2\u5C06\u672C\u9879\u76EE\u7684\u6D3B\u52A8\u5199\u5165 store \u8BBE\u4E3A '{alias}'",
2020
- "cli.store.migrate.none": "\u6CA1\u6709\u9700\u8981\u8FC1\u79FB\u7684\u9879\u76EE\u672C\u5730\u77E5\u8BC6 (dual-root \u5DF2\u7A7A)",
2021
- "cli.store.migrate.dry-run-header": "\u8FC1\u79FB\u9884\u89C8 (dry-run, \u4E0D\u5199\u5165\u78C1\u76D8):",
2022
- "cli.store.migrate.applied-header": "\u5DF2\u8FC1\u79FB {count} \u6761\u8FDB store:",
2023
- "cli.store.migrate.committed": "\u5DF2\u5728 store \u4ED3\u5E93\u63D0\u4EA4\u8FC1\u79FB\u53D8\u66F4",
2024
- "cli.store.migrate.remap-note": " \u2191 \u56E0\u76EE\u6807 store id \u51B2\u7A81, {oldId} \u91CD\u6620\u5C04\u4E3A {newId}",
2025
- "cli.store.migrate.skips-header": "\u8DF3\u8FC7 {count} \u9879:",
2026
1965
  "cli.sync.deferred": "{count} \u4E2A store \u79BB\u7EBF \u2014\u2014 push \u5DF2\u5EF6\u540E; \u8054\u7F51\u540E\u91CD\u65B0\u8FD0\u884C `fabric sync`",
2027
1966
  "cli.sync.paused": "sync \u56E0\u51B2\u7A81\u6682\u505C \u2014\u2014 \u89E3\u51B3\u540E\u8FD0\u884C `fabric sync --continue` (\u6216 `--abort`)",
2028
1967
  "cli.metrics.invalid-since": '--since: \u65E0\u6548\u7684\u65F6\u957F "{raw}" (\u793A\u4F8B: 24h\u30017d\u300130m)',
@@ -2035,9 +1974,9 @@ var zhCNMessages = {
2035
1974
  "cli.install.scanning": "\u6B63\u5728\u626B\u63CF\u9879\u76EE\u7684\u5BA2\u6237\u7AEF/\u6846\u67B6\u7279\u5F81\u2026",
2036
1975
  "cli.install.scan-complete": " \u9879\u76EE\u626B\u63CF\u5B8C\u6210",
2037
1976
  // W4-11 (ISS-021): 统一项目扫描推荐(cli forensic + http scan 共用此 i18n key 集)。
2038
- "scan.rec.install": "\u8FD0\u884C `fabric install` \u642D\u5EFA .fabric/ \u77E5\u8BC6\u5C42(decisions/pitfalls/guidelines/models/processes)\u3002",
1977
+ "scan.rec.install": "\u8FD0\u884C `fabric install`\uFF0C\u7136\u540E\u7ED1\u5B9A\u5E76\u9009\u62E9 mounted knowledge store \u6765\u627F\u8F7D decisions/pitfalls/guidelines/models/processes\u3002",
2039
1978
  "scan.rec.readme": "README \u4FE1\u606F\u4E0D\u8DB3,\u5EFA\u8BAE\u5728\u521D\u59CB\u5316\u8BBF\u8C08\u4E2D\u8865\u9F50\u9879\u76EE\u76EE\u6807\u3001\u8FD0\u884C\u65B9\u5F0F\u548C\u7981\u6539\u533A\u57DF\u3002",
2040
- "scan.rec.contributing": "\u8865\u5145 CONTRIBUTING.md,\u6216\u5728 .fabric/knowledge/processes/ \u4E0B\u8BB0\u5F55\u8D21\u732E\u6D41\u7A0B\u3002",
1979
+ "scan.rec.contributing": "\u8865\u5145 CONTRIBUTING.md,\u6216\u5728 mounted store \u7684 knowledge/processes/ \u4E0B\u8BB0\u5F55\u8D21\u732E\u6D41\u7A0B\u3002",
2041
1980
  "scan.rec.cocos.lifecycle": "\u5EFA\u8BAE\u5411\u7528\u6237\u786E\u8BA4 Cocos Creator Component \u751F\u547D\u5468\u671F(onLoad/onEnable/start)\u987A\u5E8F\u3002",
2042
1981
  "scan.rec.cocos.human-protect": "\u5EFA\u8BAE\u8BE2\u95EE assets/prefabs \u548C assets/scenes \u662F\u5426\u5C5E\u4E8E @HUMAN \u4FDD\u62A4\u533A\u57DF\u3002",
2043
1982
  "scan.rec.cocos.meta-lock": "\u68C0\u6D4B\u5230 .meta \u6587\u4EF6,\u5EFA\u8BAE\u5728 @HUMAN \u9501\u5B9A .meta \u4E0D\u88AB AI \u6539\u52A8\u3002",
@@ -2066,73 +2005,15 @@ function createTranslator(locale, messages = defaultMessages) {
2066
2005
  };
2067
2006
  }
2068
2007
 
2069
- // src/i18n/normalize-locale.ts
2070
- function normalizeLocale(raw) {
2071
- if (typeof raw !== "string") {
2072
- return "en";
2073
- }
2074
- const normalized = raw.trim().toLowerCase().replace(/\..*$/, "").replace(/_/g, "-");
2075
- if (normalized.length === 0) {
2076
- return "en";
2077
- }
2078
- if (normalized === "zh" || normalized.startsWith("zh-")) {
2079
- return "zh-CN";
2080
- }
2081
- return "en";
2082
- }
2083
-
2084
- // src/i18n/detect-node-locale.ts
2085
- function detectNodeLocale() {
2086
- const fromFabricEnv = process.env.FAB_LANG;
2087
- if (typeof fromFabricEnv === "string" && fromFabricEnv.trim().length > 0) {
2088
- return normalizeLocale(fromFabricEnv);
2089
- }
2090
- const fromLangEnv = process.env.LANG;
2091
- if (typeof fromLangEnv === "string" && fromLangEnv.trim().length > 0) {
2092
- return normalizeLocale(fromLangEnv);
2093
- }
2094
- return "en";
2095
- }
2096
-
2097
2008
  // src/i18n/resolve-fabric-locale.ts
2098
- import fs from "fs";
2099
- import path from "path";
2100
- function resolveFabricLocale(projectRoot) {
2101
- const configPath = path.join(projectRoot, ".fabric", "fabric-config.json");
2102
- let raw;
2103
- try {
2104
- raw = fs.readFileSync(configPath, "utf8");
2105
- } catch {
2106
- return detectNodeLocale();
2107
- }
2108
- let parsed;
2109
- try {
2110
- parsed = JSON.parse(raw);
2111
- } catch {
2112
- return detectNodeLocale();
2113
- }
2114
- if (typeof parsed !== "object" || parsed === null) {
2115
- return detectNodeLocale();
2116
- }
2117
- const fabricLanguage = parsed.fabric_language;
2118
- if (fabricLanguage === "en" || fabricLanguage === "zh-CN") {
2119
- return fabricLanguage;
2120
- }
2121
- if (fabricLanguage === "zh-CN-hybrid") {
2122
- return "zh-CN";
2123
- }
2124
- if (fabricLanguage === "match-existing") {
2125
- console.warn(
2126
- `[fabric] fabric_language="${fabricLanguage}" is a pre-init placeholder that should have been resolved during 'fabric init' (KT-DEC-9004). Falling back to FAB_LANG / LANG environment detection.`
2127
- );
2128
- return detectNodeLocale();
2129
- }
2130
- return detectNodeLocale();
2009
+ function resolveFabricLocale(_projectRoot) {
2010
+ return resolveGlobalLocale();
2131
2011
  }
2132
2012
 
2133
2013
  // src/i18n/protected-tokens.ts
2134
2014
  var PROTECTED_TOKENS = [
2135
2015
  // v2.0 MCP tool names
2016
+ "fab_recall",
2136
2017
  "fab_plan_context",
2137
2018
  "fab_get_knowledge_sections",
2138
2019
  "fab_extract_knowledge",
@@ -2141,10 +2022,9 @@ var PROTECTED_TOKENS = [
2141
2022
  "AGENTS.md",
2142
2023
  ".fabric/agents/",
2143
2024
  ".fabric/agents/_cross/",
2144
- ".fabric/agents.meta.json",
2145
2025
  ".fabric/human-lock.json",
2146
2026
  ".fabric/events.jsonl",
2147
- ".fabric/knowledge/",
2027
+ "knowledge/pending",
2148
2028
  // Event types templates reference verbatim
2149
2029
  "knowledge_proposed",
2150
2030
  // fabric-archive Phase 1.5 contract surface (rc.9 — bare `scope` was renamed)
@@ -2176,8 +2056,6 @@ export {
2176
2056
  zhCNMessages,
2177
2057
  defaultMessages,
2178
2058
  createTranslator,
2179
- normalizeLocale,
2180
- detectNodeLocale,
2181
2059
  resolveFabricLocale,
2182
2060
  PROTECTED_TOKENS
2183
2061
  };