@fenglimg/fabric-shared 2.0.0-rc.36 → 2.0.0-rc.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wangzhichao (fenglimg)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,13 @@
1
+ # @fenglimg/fabric-shared
2
+
3
+ Shared types, Zod schemas, i18n bundle, atomic-write helpers, MCP payload guards, and error classes consumed by [`@fenglimg/fabric-server`](https://www.npmjs.com/package/@fenglimg/fabric-server) and [`@fenglimg/fabric-cli`](https://www.npmjs.com/package/@fenglimg/fabric-cli).
4
+
5
+ End users should not depend on this package directly — it ships as a workspace dependency of the server + CLI. Pinned versions are not part of Fabric's public API.
6
+
7
+ ## Repo
8
+
9
+ Source + issues + roadmap: <https://github.com/fenglimg/fabric-v2>
10
+
11
+ ## License
12
+
13
+ MIT — see [LICENSE](./LICENSE).
@@ -1,6 +1,6 @@
1
1
  // src/i18n/locales/en.ts
2
2
  var enMessages = {
3
- "cli.main.description": "Fabric CLI - AI agent collaboration framework.\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",
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",
4
4
  "cli.shared.created": "Created",
5
5
  "cli.shared.skipped": "Skipped",
6
6
  "cli.shared.next": "Next",
@@ -113,6 +113,9 @@ var enMessages = {
113
113
  "doctor.cite.metric.recalledUnverified": "Recalled but not verified",
114
114
  "doctor.cite.metric.expectedButMissed": "Expected cite missing",
115
115
  "doctor.cite.metric.totalTurns": "Total turns",
116
+ "doctor.cite.metric.complianceRate": "cite compliance rate (incl. KB:none[reason])",
117
+ "doctor.cite.metric.complianceNA": "N/A (no cite-expected turns)",
118
+ "doctor.cite.metric.uncorrelatableEdits": "Uncorrelatable edits (no session_id \u2014 stale hook? run `fabric install`)",
116
119
  "doctor.cite.section.perClient": "Per-client",
117
120
  "doctor.cite.section.dismissedReasons": "Dismissed reasons",
118
121
  "doctor.cite.dismissed.scope-mismatch": "Scope mismatch",
@@ -269,6 +272,16 @@ var enMessages = {
269
272
  // v2.0.0-rc.33 W3-1 (P0-6): archive-history mode — direct users to mv the broken ledger into events.archive/ before recreating, preserving history rather than rm'ing it. Mirrors rotateEventLedgerIfNeeded's events-rotated-YYYY-MM-DD.jsonl naming convention (events-corrupted-YYYY-MM-DD.jsonl distinguishes this archive cause from sliding-window rotation).
270
273
  "doctor.check.event_ledger.remediation.invalid": "Archive history first (`mkdir -p .fabric/events.archive && mv .fabric/events.jsonl .fabric/events.archive/events-corrupted-$(date +%Y-%m-%d).jsonl`), then run `fabric doctor --fix` to create a new empty ledger. Historical events are preserved under events.archive/.",
271
274
  "doctor.check.event_ledger.ok": ".fabric/events.jsonl exists, is writable, and is parseable.",
275
+ // v2.0.0-rc.37 Wave B (B5): composite hard-gate check for events.jsonl /
276
+ // metrics.jsonl health (G7 size / G8 metric_leak / G9 metrics_stale /
277
+ // G10 rotation_overdue).
278
+ "doctor.check.events_jsonl_health.name": "Events ledger health (rc.37 Plan B 5 hard gate)",
279
+ "doctor.check.events_jsonl_health.ok": ".fabric/events.jsonl size, freshness, and metric isolation all healthy.",
280
+ "doctor.check.events_jsonl_health.message.size": ".fabric/events.jsonl is {sizeMb} MB, above the 10 MB threshold.",
281
+ "doctor.check.events_jsonl_health.message.metric_leak": ".fabric/events.jsonl contains {count} rows with metric-counter event_types ({samples}). Those events should be aggregated in metrics.jsonl, not in the audit ledger.",
282
+ "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.",
283
+ "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.",
284
+ "doctor.check.events_jsonl_health.remediation": "Run `fabric doctor --fix` to trigger a rotation; 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.",
272
285
  "doctor.check.mcp_config_in_wrong_file.name": "Claude MCP config location",
273
286
  "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.",
274
287
  "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.",
@@ -314,6 +327,12 @@ var enMessages = {
314
327
  "doctor.check.draft_backlog.ok": "draft-maturity entry ratio is healthy (< 50%, or workspace too small to compute).",
315
328
  "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%).",
316
329
  "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.",
330
+ // rc.37 NEW-38: knowledge auto-promote (info surface; --fix applies).
331
+ "doctor.check.draft_auto_promote.name": "Knowledge auto-promote",
332
+ "doctor.check.draft_auto_promote.ok": "No settled drafts awaiting auto-promote (drafts are younger than 14 days or flagged drifted).",
333
+ "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.",
334
+ "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.",
335
+ "doctor.check.draft_auto_promote.fixed": "Auto-promoted {count} settled draft entries \u2192 verified.",
317
336
  // rc.36 TASK-05 (P0-8): empty-tags ratio warn.
318
337
  "doctor.check.knowledge_tags_empty.name": "Knowledge tags coverage",
319
338
  "doctor.check.knowledge_tags_empty.ok": "empty-tag ratio is healthy (\u2264 50%, or workspace too small to compute).",
@@ -323,7 +342,7 @@ var enMessages = {
323
342
  "doctor.check.drift_unconsumed.name": "Knowledge drift unconsumed",
324
343
  "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.",
325
344
  "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.",
326
- "doctor.check.drift_unconsumed.remediation": "rc.36 has no auto-demote pipeline; act manually: run `fabric doctor --fix` to trigger orphan-demote / stale-archive auto-heal, or invoke `/fabric-review` to manually triage drift-flagged entries. Automatic 14-day demote is planned for rc.37.",
345
+ "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.",
327
346
  "doctor.check.meta_manually_diverged.name": "Meta manual divergence",
328
347
  "doctor.check.meta_manually_diverged.ok.unreadable": "agents.meta.json not readable; skipping divergence check.",
329
348
  "doctor.check.meta_manually_diverged.message.extra.singular": "agents.meta.json has {count} entry with no backing file on disk. Run --fix to reconcile.",
@@ -399,7 +418,7 @@ var enMessages = {
399
418
  "doctor.check.narrow_no_paths.ok": "No narrow-scope canonical entries have an empty relevance_paths array.",
400
419
  "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}.",
401
420
  "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}.",
402
- "doctor.check.narrow_no_paths.remediation": "Either add path anchors to relevance_paths or widen the entry's relevance_scope to broad.",
421
+ "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.",
403
422
  "doctor.check.relevance_paths_dangling.name": "Knowledge relevance_paths dangling",
404
423
  "doctor.check.relevance_paths_dangling.ok": "All relevance_paths globs resolve to at least one file under the workspace root.",
405
424
  "doctor.check.relevance_paths_dangling.message.singular": "{count} relevance_paths glob resolves to zero files in the current workspace. First: {detail}.",
@@ -411,6 +430,16 @@ var enMessages = {
411
430
  "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}.",
412
431
  "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}.",
413
432
  "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.",
433
+ "doctor.check.personal_layer_path_misclassify.name": "Personal-layer path misclassify",
434
+ "doctor.check.personal_layer_path_misclassify.ok": "No personal-layer entries declare relevance_paths that resolve against the current project.",
435
+ "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}.",
436
+ "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}.",
437
+ "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).',
438
+ "doctor.check.suspicious_kb.name": "Suspicious KB injection",
439
+ "doctor.check.suspicious_kb.ok": "No canonical knowledge bodies match known prompt-injection patterns.",
440
+ "doctor.check.suspicious_kb.message.singular": "{count} canonical entry body contains tokens matching prompt-injection patterns (likely legacy pre-NEW-31 archive). First: {detail}.",
441
+ "doctor.check.suspicious_kb.message.plural": "{count} canonical entry bodies contain tokens matching prompt-injection patterns (likely legacy pre-NEW-31 archive). First: {detail}.",
442
+ "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.",
414
443
  "doctor.check.narrow_too_few.name": "Knowledge narrow too few",
415
444
  "doctor.check.narrow_too_few.ok": "Narrow-with-paths ratio {ratioPct}% ({narrowCount}/{totalCount}); {teleNote}.",
416
445
  "doctor.check.narrow_too_few.message.telemetry_skipped": "telemetry skipped (no edit-counter fires in window)",
@@ -445,6 +474,20 @@ var enMessages = {
445
474
  "doctor.check.hooks_wired.message.missing_settings": ".claude/ exists but .claude/settings.json is absent or unparseable; fabric install may have never run successfully, or the file was wiped externally.",
446
475
  "doctor.check.hooks_wired.message.incomplete": ".claude/settings.json is missing fabric hook injections: {missing}. fabric install dry-run report does not match actual state (rc.30 audit BUG-M3 / NEW-4).",
447
476
  "doctor.check.hooks_wired.remediation": "Run `fabric install` to re-inject hooks (idempotent; only fills missing slots). If hooks config was accidentally wiped, back up .claude/settings.json before running.",
477
+ // v2.0.0-rc.37 NEW-20: hooks_runtime — shebang + Node.js syntax validity
478
+ // of installed *.cjs hook files (one layer below hooks_wired).
479
+ "doctor.check.hooks_runtime.name": "Hooks runtime health",
480
+ "doctor.check.hooks_runtime.ok.skipped": "No installed hook files found under .claude/hooks/ / .codex/hooks/ / .cursor/hooks/; skipping hooks_runtime check.",
481
+ "doctor.check.hooks_runtime.ok.healthy": "Scanned {count} hook .cjs file(s); shebang and Node.js syntax parse all pass.",
482
+ "doctor.check.hooks_runtime.message.singular": "{count} hook file is unhealthy at runtime; first: {first_path} ({first_detail}).",
483
+ "doctor.check.hooks_runtime.message.plural": "{count} hook files are unhealthy at runtime; first: {first_path} ({first_detail}).",
484
+ "doctor.check.hooks_runtime.remediation": "Run `fabric install` to overwrite broken hook files (idempotent). If a hook was corrupted by an external process, confirm the cause before re-running install.",
485
+ // v2.0.0-rc.37 NEW-27: hooks_content_drift — cross-client sha256 parity.
486
+ "doctor.check.hooks_content_drift.name": "Hooks cross-client content parity",
487
+ "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.",
488
+ "doctor.check.hooks_content_drift.ok.aligned": "Scanned {count} hook copies; sha256 of every basename matches across .claude / .codex / .cursor.",
489
+ "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.",
490
+ "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.",
448
491
  // rc.31 BUG-G2/G5: promote-ledger invariant check.
449
492
  "doctor.check.promote_ledger_invariant.name": "Promote ledger invariant",
450
493
  "doctor.check.promote_ledger_invariant.ok": "knowledge_proposed={proposed} >= knowledge_promote_started={started} >= knowledge_promoted={promoted}; ledger invariant holds.",
@@ -485,6 +528,12 @@ var enMessages = {
485
528
  "doctor.archive-history.table.outcome": "Outcome",
486
529
  "doctor.archive-history.table.candidates": "Candidates",
487
530
  "doctor.archive-history.table.coveredGap": "Covered gap",
531
+ // rc.37 NEW-33: unified --history <mode> view (archive | fix | all).
532
+ "cli.doctor.args.history.description": "Render unified per-day history (mode: archive | fix | all). Read-only; mutex with --fix / --fix-knowledge / --cite-coverage / --enrich-descriptions / --archive-history.",
533
+ "cli.doctor.errors.history-mutex": "--history cannot be combined with --fix, --fix-knowledge, --cite-coverage, --enrich-descriptions, or --archive-history. Run them separately.",
534
+ "cli.doctor.errors.invalid-history-mode": "Invalid --history mode '{input}'. Use archive | fix | all.",
535
+ "doctor.history.header": "Doctor history (mode={mode}, last {sinceLabel}, {days} day(s))",
536
+ "doctor.history.empty": "No doctor or archive activity within the --since={sinceLabel} window (mode={mode}).",
488
537
  "cli.hooks.description": "Manage Fabric Git hook templates.",
489
538
  "cli.hooks.install.description": "Install the Fabric Husky pre-commit hook template.",
490
539
  "cli.hooks.install.args.target.description": "Target project path, default is the current working directory.",
@@ -511,6 +560,12 @@ var enMessages = {
511
560
  "cli.install.force-skills-only.uninitialised.message": "fabric install --force-skills-only: project is not initialised (.fabric/agents.meta.json is missing).",
512
561
  "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.",
513
562
  "cli.install.force-skills-only.summary": "Skills refresh complete \u2014 written: {written}, skipped: {skipped}, errors: {errors}",
563
+ // v2.0.0-rc.37 NEW-26: --force-hooks-only mirror of --force-skills-only.
564
+ "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/*).",
565
+ "cli.install.force-hooks-only.banner": "Refreshing fabric hooks only",
566
+ "cli.install.force-hooks-only.uninitialised.message": "fabric install --force-hooks-only: project not initialised (.fabric/agents.meta.json missing).",
567
+ "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.",
568
+ "cli.install.force-hooks-only.summary": "Hooks refresh complete \u2014 written: {written}, skipped: {skipped}, errors: {errors}",
514
569
  "cli.install.mcp.install.global": "Using globally-installed @fenglimg/fabric-server",
515
570
  "cli.install.mcp.install.local": "Installing @fenglimg/fabric-server to project devDependencies",
516
571
  "cli.install.mcp.local.installing": "Running {manager} add -D @fenglimg/fabric-server...",
@@ -568,6 +623,11 @@ var enMessages = {
568
623
  "cli.install.wizard.invalid-select": "Invalid value. Use one of: {options}.",
569
624
  "cli.install.wizard.cancelled": "Fabric install cancelled before execution.",
570
625
  "cli.install.capabilities.title": "Client capability summary",
626
+ // v2.0.0-rc.37 NEW-22: post-install restart banner. The MCP server is
627
+ // spawned by the client; already-running Claude Code / Cursor / Codex
628
+ // sessions won't pick up the new mcp config until they restart.
629
+ "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.",
630
+ "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.',
571
631
  "cli.install.capabilities.none": "No supported client was detected for bootstrap or MCP follow-up.",
572
632
  "cli.install.capabilities.header.client": "Client",
573
633
  "cli.install.capabilities.header.bootstrap": "Bootstrap",
@@ -678,17 +738,10 @@ var enMessages = {
678
738
  "cli.scan.recommendation.contributing": "L0: Add CONTRIBUTING.md or leave a bootstrap TODO reference for contribution flow.",
679
739
  "cli.scan.recommendation.unknown-framework": "L1: Add tech-stack TODOs manually because no framework marker was detected.",
680
740
  "cli.scan.recommendation.framework-dirs": "L1: Review {framework} directories for future scoped Fabric rule files.",
681
- "cli.serve.description": "Start the local Fabric MCP HTTP service.\n\nExamples:\n fabric serve bind 127.0.0.1:7373 (default)\n fabric serve --port 8787 use a custom port\n FABRIC_AUTH_TOKEN=<token> fabric serve --host 0.0.0.0 bind non-loopback with Bearer auth",
682
- "cli.serve.args.port.description": "Listen port, default 7373.",
683
- "cli.serve.args.host.description": "Listen host, default 127.0.0.1. Non-loopback hosts (e.g. 0.0.0.0) require FABRIC_AUTH_TOKEN to enable Bearer auth, otherwise serve falls back to 127.0.0.1.",
684
- "cli.serve.args.target.description": "Target project path. Defaults to --target, then EXTERNAL_FIXTURE_PATH, then cwd.",
685
- "cli.serve.args.debug.description": "Print target resolution details to stderr.",
686
- "cli.serve.args.allow-loopback-no-auth.description": "Opt in to running the loopback HTTP server without Bearer auth (default-deny). Use only on a trusted single-user machine; any local process can then read your knowledge ledger.",
687
- "cli.serve.ready.title": "Fabric Dashboard",
688
- "cli.serve.lock-held.action-hint": "A `fabric serve` instance (PID {pid}) is holding the workspace lock. Stop it (Ctrl-C in that terminal or `kill {pid}`) before running this command.",
689
- "cli.serve.warning.host-fallback": "--host {host} requires FABRIC_AUTH_TOKEN for non-loopback exposure; falling back to 127.0.0.1. To bind {host}, run: FABRIC_AUTH_TOKEN=<token> fabric serve --host {host}",
690
- "cli.serve.warning.loopback-deny-default": "FABRIC_AUTH_TOKEN is not set: /api /events /mcp will return 401 by default (any local process could otherwise read .fabric/agents.meta.json + forensic.json + events.jsonl). Set FABRIC_AUTH_TOKEN=<secret> or pass --allow-loopback-no-auth to opt in.",
691
- "cli.serve.error.port-in-use": "Port {port} in use - try --port {nextPort}",
741
+ // v2.0.0-rc.37 Wave A2 Part 2: cli.serve.* + FABRIC_AUTH_TOKEN keys removed
742
+ // alongside `fabric serve` quarantine to packages/server-http-experimental/
743
+ // per [[fabric-serve-quarantine-not-delete]]. Restore from git history when
744
+ // the web UI surface is re-enabled.
692
745
  // v2.0.0-rc.29 TASK-008 (BUG-L2): onboard-coverage i18n keys.
693
746
  "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.",
694
747
  "cli.onboard-coverage.args.json.description": "Emit machine-readable JSON to stdout instead of the human table.",
@@ -907,7 +960,7 @@ var enMessages = {
907
960
 
908
961
  // src/i18n/locales/zh-CN.ts
909
962
  var zhCNMessages = {
910
- "cli.main.description": "Fabric CLI - AI \u667A\u80FD\u4F53\u534F\u4F5C\u6846\u67B6\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",
963
+ "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",
911
964
  "cli.shared.created": "\u5DF2\u521B\u5EFA",
912
965
  "cli.shared.skipped": "\u5DF2\u8DF3\u8FC7",
913
966
  "cli.shared.next": "\u4E0B\u4E00\u6B65",
@@ -1018,6 +1071,9 @@ var zhCNMessages = {
1018
1071
  "doctor.cite.metric.recalledUnverified": "recalled \u4F46\u672A\u9A8C\u8BC1",
1019
1072
  "doctor.cite.metric.expectedButMissed": "\u5E94\u67E5\u6CA1\u67E5",
1020
1073
  "doctor.cite.metric.totalTurns": "\u603B\u56DE\u5408\u6570",
1074
+ "doctor.cite.metric.complianceRate": "cite \u5408\u89C4\u7387 (\u542B KB:none[reason])",
1075
+ "doctor.cite.metric.complianceNA": "N/A (\u65E0\u5E94 cite \u56DE\u5408)",
1076
+ "doctor.cite.metric.uncorrelatableEdits": "\u65E0\u6CD5\u5173\u8054\u7684 edit (\u7F3A session_id \u2014 hook \u8FC7\u671F? \u8BF7\u8DD1 `fabric install`)",
1021
1077
  "doctor.cite.section.perClient": "\u6309\u5BA2\u6237\u7AEF\u62C6\u5206",
1022
1078
  "doctor.cite.section.dismissedReasons": "\u9A73\u56DE\u539F\u56E0\u5206\u5E03",
1023
1079
  "doctor.cite.dismissed.scope-mismatch": "\u8303\u56F4\u4E0D\u7B26",
@@ -1171,6 +1227,15 @@ var zhCNMessages = {
1171
1227
  // v2.0.0-rc.33 W3-1 (P0-6): archive-history 模式 — 引导用户先 mv 备份到 events.archive/ 保留历史, 再跑 --fix 重建空 ledger。与 rotateEventLedgerIfNeeded 的命名约定一致 (events-rotated-YYYY-MM-DD.jsonl 是滑窗 rotation; events-corrupted-YYYY-MM-DD.jsonl 是 invalid-fix 归档)。
1172
1228
  "doctor.check.event_ledger.remediation.invalid": "\u5148\u5F52\u6863\u5386\u53F2 (`mkdir -p .fabric/events.archive && mv .fabric/events.jsonl .fabric/events.archive/events-corrupted-$(date +%Y-%m-%d).jsonl`), \u518D\u8FD0\u884C `fabric doctor --fix` \u521B\u5EFA\u65B0\u7A7A ledger\u3002\u5386\u53F2\u4E8B\u4EF6\u4FDD\u7559\u5728 events.archive/ \u4E0D\u4E22\u3002",
1173
1229
  "doctor.check.event_ledger.ok": ".fabric/events.jsonl \u5DF2\u5B58\u5728\uFF0C\u53EF\u5199\uFF0C\u4E14\u53EF\u89E3\u6790\u3002",
1230
+ // v2.0.0-rc.37 Wave B (B5): 复合 hard-gate 检查 events.jsonl/metrics.jsonl 健康
1231
+ // (G7 size / G8 metric_leak / G9 metrics_stale / G10 rotation_overdue)。
1232
+ "doctor.check.events_jsonl_health.name": "Events ledger \u5065\u5EB7 (rc.37 Plan B 5 hard gate)",
1233
+ "doctor.check.events_jsonl_health.ok": ".fabric/events.jsonl \u5927\u5C0F\u3001\u65B0\u9C9C\u5EA6\u3001metric \u9694\u79BB\u5168\u90E8\u6B63\u5E38\u3002",
1234
+ "doctor.check.events_jsonl_health.message.size": ".fabric/events.jsonl \u5DF2 {sizeMb} MB\uFF0C\u8D85\u8FC7 10 MB \u9608\u503C\u3002",
1235
+ "doctor.check.events_jsonl_health.message.metric_leak": ".fabric/events.jsonl \u542B {count} \u884C metric-counter \u7C7B event_type ({samples})\u3002\u8FD9\u4E9B event \u5E94\u7531 metrics.jsonl \u8BA1\u6570, \u4E0D\u518D\u8FDB\u5165 audit ledger\u3002",
1236
+ "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",
1237
+ "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",
1238
+ "doctor.check.events_jsonl_health.remediation": "\u8FD0\u884C `fabric doctor --fix` \u89E6\u53D1 rotation; \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",
1174
1239
  "doctor.check.mcp_config_in_wrong_file.name": "Claude MCP config \u4F4D\u7F6E",
1175
1240
  "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",
1176
1241
  "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",
@@ -1216,6 +1281,12 @@ var zhCNMessages = {
1216
1281
  "doctor.check.draft_backlog.ok": "canonical knowledge entries \u4E2D draft \u5360\u6BD4\u6B63\u5E38 (< 50%, \u6216 workspace \u592A\u5C0F\u4E0D\u8BC4)\u3002",
1217
1282
  "doctor.check.draft_backlog.message": "{draftCount}/{totalCount} ({pct}%) canonical knowledge entries \u5361\u5728 draft maturity \u2014 promote \u65AD\u6D41 (rc.32 baseline 92%)\u3002",
1218
1283
  "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",
1284
+ // rc.37 NEW-38: knowledge auto-promote (info surface; --fix 执行).
1285
+ "doctor.check.draft_auto_promote.name": "Knowledge auto-promote",
1286
+ "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",
1287
+ "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",
1288
+ "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",
1289
+ "doctor.check.draft_auto_promote.fixed": "\u81EA\u52A8 promote {count} \u4E2A settled draft entries \u2192 verified\u3002",
1219
1290
  // rc.36 TASK-05 (P0-8): empty-tags ratio warn.
1220
1291
  "doctor.check.knowledge_tags_empty.name": "Knowledge tags coverage",
1221
1292
  "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",
@@ -1225,7 +1296,7 @@ var zhCNMessages = {
1225
1296
  "doctor.check.drift_unconsumed.name": "Knowledge drift unconsumed",
1226
1297
  "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",
1227
1298
  "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",
1228
- "doctor.check.drift_unconsumed.remediation": "rc.36 \u6CA1\u6709 auto-demote pipeline,\u9700\u624B\u52A8\u5904\u7406:\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\u3002rc.37 \u8BA1\u5212\u4E0A\u7EBF\u81EA\u52A8 14-day demote\u3002",
1299
+ "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",
1229
1300
  "doctor.check.meta_manually_diverged.name": "Meta manual divergence",
1230
1301
  "doctor.check.meta_manually_diverged.ok.unreadable": "agents.meta.json \u4E0D\u53EF\u8BFB\uFF0C\u8DF3\u8FC7 divergence \u68C0\u67E5\u3002",
1231
1302
  "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",
@@ -1301,7 +1372,7 @@ var zhCNMessages = {
1301
1372
  "doctor.check.narrow_no_paths.ok": "\u6CA1\u6709 narrow-scope canonical entries \u7684 relevance_paths array \u4E3A\u7A7A\u3002",
1302
1373
  "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",
1303
1374
  "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",
1304
- "doctor.check.narrow_no_paths.remediation": "\u4E3A relevance_paths \u6DFB\u52A0 path anchors\uFF0C\u6216\u5C06 entry \u7684 relevance_scope \u653E\u5BBD\u5230 broad\u3002",
1375
+ "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",
1305
1376
  "doctor.check.relevance_paths_dangling.name": "Knowledge relevance_paths dangling",
1306
1377
  "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",
1307
1378
  "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",
@@ -1313,6 +1384,16 @@ var zhCNMessages = {
1313
1384
  "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",
1314
1385
  "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",
1315
1386
  "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",
1387
+ "doctor.check.personal_layer_path_misclassify.name": "Personal-layer path misclassify",
1388
+ "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",
1389
+ "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",
1390
+ "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",
1391
+ "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",
1392
+ "doctor.check.suspicious_kb.name": "Suspicious KB injection",
1393
+ "doctor.check.suspicious_kb.ok": "\u6240\u6709 canonical knowledge body \u5747\u672A\u547D\u4E2D\u5DF2\u77E5 prompt-injection \u6A21\u5F0F\u3002",
1394
+ "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",
1395
+ "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",
1396
+ "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",
1316
1397
  "doctor.check.narrow_too_few.name": "Knowledge narrow too few",
1317
1398
  "doctor.check.narrow_too_few.ok": "Narrow-with-paths ratio {ratioPct}%\uFF08{narrowCount}/{totalCount}\uFF09\uFF1B{teleNote}\u3002",
1318
1399
  "doctor.check.narrow_too_few.message.telemetry_skipped": "telemetry skipped\uFF08no edit-counter fires in window\uFF09",
@@ -1347,6 +1428,20 @@ var zhCNMessages = {
1347
1428
  "doctor.check.hooks_wired.message.missing_settings": ".claude/ \u76EE\u5F55\u5B58\u5728\u4F46 .claude/settings.json \u7F3A\u5931\u6216\u65E0\u6CD5\u89E3\u6790\uFF1Bfabric install \u53EF\u80FD\u4ECE\u672A\u8DD1\u6210\u529F\uFF0C\u6216\u6587\u4EF6\u88AB\u5916\u90E8\u6E05\u7A7A\u3002",
1348
1429
  "doctor.check.hooks_wired.message.incomplete": ".claude/settings.json \u7F3A\u5C11 fabric hook \u6CE8\u5165\uFF1A{missing}\u3002fabric install \u7684 dry-run \u62A5\u544A\u4E0E\u5B9E\u9645\u72B6\u6001\u4E0D\u4E00\u81F4\uFF08rc.30 audit BUG-M3 / NEW-4\uFF09\u3002",
1349
1430
  "doctor.check.hooks_wired.remediation": "\u8FD0\u884C `fabric install` \u91CD\u65B0\u6CE8\u5165 hooks\uFF08\u5E42\u7B49\uFF1B\u53EA\u8865\u7F3A\u5931\u9879\uFF09\u3002\u82E5\u610F\u5916\u8986\u76D6\u4E86 hooks \u914D\u7F6E\uFF0C\u5148\u5907\u4EFD .claude/settings.json \u518D\u8DD1\u3002",
1431
+ // v2.0.0-rc.37 NEW-20: hooks_runtime — shebang + Node.js syntax validity
1432
+ // of installed *.cjs hook files (one layer below hooks_wired).
1433
+ "doctor.check.hooks_runtime.name": "Hooks \u8FD0\u884C\u65F6\u5065\u5EB7",
1434
+ "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",
1435
+ "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",
1436
+ "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",
1437
+ "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",
1438
+ "doctor.check.hooks_runtime.remediation": "\u8FD0\u884C `fabric install` \u91CD\u5199\u635F\u574F\u7684 hook \u6587\u4EF6\uFF08\u8986\u76D6\u5F0F\uFF0C\u5E42\u7B49\uFF09\u3002\u82E5\u6587\u4EF6\u662F\u88AB\u5916\u90E8\u8FDB\u7A0B\u7834\u574F\u7684\uFF0C\u786E\u8BA4\u6E90\u5934\u518D\u8DD1 install\u3002",
1439
+ // v2.0.0-rc.37 NEW-27: hooks_content_drift — cross-client sha256 parity.
1440
+ "doctor.check.hooks_content_drift.name": "Hooks \u8DE8\u5BA2\u6237\u7AEF\u5185\u5BB9\u4E00\u81F4\u6027",
1441
+ "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",
1442
+ "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",
1443
+ "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",
1444
+ "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",
1350
1445
  // rc.31 BUG-G2/G5: promote-ledger invariant check.
1351
1446
  "doctor.check.promote_ledger_invariant.name": "Promote ledger invariant",
1352
1447
  "doctor.check.promote_ledger_invariant.ok": "knowledge_proposed={proposed} \u2265 knowledge_promote_started={started} \u2265 knowledge_promoted={promoted}\uFF0Cledger \u4E0D\u53D8\u91CF\u6301\u6709\u3002",
@@ -1385,6 +1480,12 @@ var zhCNMessages = {
1385
1480
  "doctor.archive-history.table.outcome": "\u7ED3\u679C",
1386
1481
  "doctor.archive-history.table.candidates": "\u5019\u9009\u6570",
1387
1482
  "doctor.archive-history.table.coveredGap": "\u8986\u76D6\u8DDD\u4ECA",
1483
+ // rc.37 NEW-33: 统一 --history <mode> 视图 (archive | fix | all)。
1484
+ "cli.doctor.args.history.description": "\u6E32\u67D3\u7EDF\u4E00\u7684\u9010\u65E5 doctor / archive \u5386\u53F2 (mode: archive | fix | all)\u3002\u53EA\u8BFB;\u4E0E --fix / --fix-knowledge / --cite-coverage / --enrich-descriptions / --archive-history \u4E92\u65A5\u3002",
1485
+ "cli.doctor.errors.history-mutex": "--history \u4E0D\u80FD\u4E0E --fix / --fix-knowledge / --cite-coverage / --enrich-descriptions / --archive-history \u7EC4\u5408\u3002\u8BF7\u5206\u522B\u8FD0\u884C\u3002",
1486
+ "cli.doctor.errors.invalid-history-mode": "\u65E0\u6548\u7684 --history mode '{input}'\u3002\u53EF\u9009: archive | fix | all\u3002",
1487
+ "doctor.history.header": "Doctor \u5386\u53F2 (mode={mode}, \u8FD1 {sinceLabel}, \u5171 {days} \u5929)",
1488
+ "doctor.history.empty": "--since={sinceLabel} \u7A97\u53E3\u5185\u65E0 doctor \u6216 archive \u6D3B\u52A8 (mode={mode})\u3002",
1388
1489
  "cli.hooks.description": "\u7BA1\u7406 Fabric Git \u94A9\u5B50\u6A21\u677F\u3002",
1389
1490
  "cli.hooks.install.description": "\u5B89\u88C5 Fabric Husky pre-commit \u94A9\u5B50\u6A21\u677F\u3002",
1390
1491
  "cli.hooks.install.args.target.description": "\u76EE\u6807\u9879\u76EE\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u3002",
@@ -1411,6 +1512,12 @@ var zhCNMessages = {
1411
1512
  "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",
1412
1513
  "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",
1413
1514
  "cli.install.force-skills-only.summary": "Skill \u5237\u65B0\u5B8C\u6210 \u2014 \u5199\u5165: {written}, \u8DF3\u8FC7: {skipped}, \u9519\u8BEF: {errors}",
1515
+ // v2.0.0-rc.37 NEW-26: --force-hooks-only mirror of --force-skills-only。
1516
+ "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",
1517
+ "cli.install.force-hooks-only.banner": "\u53EA\u5237\u65B0 fabric hooks",
1518
+ "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",
1519
+ "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",
1520
+ "cli.install.force-hooks-only.summary": "Hooks \u5237\u65B0\u5B8C\u6210 \u2014 \u5199\u5165: {written}, \u8DF3\u8FC7: {skipped}, \u9519\u8BEF: {errors}",
1414
1521
  "cli.install.mcp.install.global": "\u4F7F\u7528\u5168\u5C40\u5B89\u88C5\u7684 @fenglimg/fabric-server",
1415
1522
  "cli.install.mcp.install.local": "\u5C06 @fenglimg/fabric-server \u5B89\u88C5\u5230\u9879\u76EE devDependencies",
1416
1523
  "cli.install.mcp.local.installing": "\u6B63\u5728\u8FD0\u884C {manager} add -D @fenglimg/fabric-server...",
@@ -1468,6 +1575,11 @@ var zhCNMessages = {
1468
1575
  "cli.install.wizard.invalid-select": "\u65E0\u6548\u8F93\u5165\u3002\u53EF\u9009\u503C\uFF1A{options}\u3002",
1469
1576
  "cli.install.wizard.cancelled": "Fabric \u5B89\u88C5\u5DF2\u5728\u6267\u884C\u524D\u53D6\u6D88\u3002",
1470
1577
  "cli.install.capabilities.title": "\u5BA2\u6237\u7AEF\u80FD\u529B\u6458\u8981",
1578
+ // v2.0.0-rc.37 NEW-22: post-install 重启提示。MCP server 在 client 启动
1579
+ // 时 spawn, 已运行的 Claude Code / Cursor / Codex session 不会自动加载
1580
+ // 新 mcp config — 必须重启才能拿到 Fabric tools。
1581
+ "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",
1582
+ "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",
1471
1583
  "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",
1472
1584
  "cli.install.capabilities.header.client": "\u5BA2\u6237\u7AEF",
1473
1585
  "cli.install.capabilities.header.bootstrap": "Bootstrap",
@@ -1578,17 +1690,10 @@ var zhCNMessages = {
1578
1690
  "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",
1579
1691
  "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",
1580
1692
  "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",
1581
- "cli.serve.description": "\u542F\u52A8\u672C\u5730 Fabric MCP HTTP \u670D\u52A1\u3002\n\n\u793A\u4F8B\uFF1A\n fabric serve \u7ED1\u5B9A 127.0.0.1:7373\uFF08\u9ED8\u8BA4\uFF09\n fabric serve --port 8787 \u4F7F\u7528\u81EA\u5B9A\u4E49\u7AEF\u53E3\n FABRIC_AUTH_TOKEN=<token> fabric serve --host 0.0.0.0 \u7ED1\u5B9A\u975E loopback \u5E76\u542F\u7528 Bearer \u9274\u6743",
1582
- "cli.serve.args.port.description": "\u76D1\u542C\u7AEF\u53E3\uFF0C\u9ED8\u8BA4 7373\u3002",
1583
- "cli.serve.args.host.description": "\u76D1\u542C\u4E3B\u673A\uFF0C\u9ED8\u8BA4 127.0.0.1\u3002\u7ED1\u5B9A\u975E loopback \u4E3B\u673A\uFF08\u5982 0.0.0.0\uFF09\u5FC5\u987B\u8BBE\u7F6E FABRIC_AUTH_TOKEN \u542F\u7528 Bearer \u9274\u6743\uFF0C\u5426\u5219\u5C06\u81EA\u52A8\u56DE\u9000\u5230 127.0.0.1\u3002",
1584
- "cli.serve.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",
1585
- "cli.serve.args.debug.description": "\u5C06\u76EE\u6807\u89E3\u6790\u7EC6\u8282\u8F93\u51FA\u5230 stderr\u3002",
1586
- "cli.serve.args.allow-loopback-no-auth.description": "\u663E\u5F0F\u5141\u8BB8\u5728 loopback \u4E0A\u4EE5\u65E0\u9274\u6743\u65B9\u5F0F\u8FD0\u884C\uFF08\u9ED8\u8BA4 default-deny\uFF09\u3002\u4EC5\u5728\u53EF\u4FE1\u5355\u7528\u6237\u673A\u5668\u4E0A\u4F7F\u7528\u2014\u2014\u5426\u5219\u4EFB\u4F55\u672C\u673A\u8FDB\u7A0B\u90FD\u80FD\u8BFB\u53D6\u4F60\u7684\u77E5\u8BC6\u5E93\u8D26\u672C\u3002",
1587
- "cli.serve.ready.title": "Fabric \u4EEA\u8868\u76D8",
1588
- "cli.serve.lock-held.action-hint": "\u53E6\u4E00\u4E2A `fabric serve` \u8FDB\u7A0B (PID {pid}) \u6B63\u5360\u7528\u5DE5\u4F5C\u533A\u9501\u3002\u8BF7\u5148\u505C\u6B62\u5B83 (\u5728\u8BE5\u7EC8\u7AEF\u6309 Ctrl-C \u6216\u8FD0\u884C `kill {pid}`) \u518D\u6267\u884C\u6B64\u547D\u4EE4\u3002",
1589
- "cli.serve.warning.host-fallback": "--host {host} \u9700\u8981\u8BBE\u7F6E FABRIC_AUTH_TOKEN \u624D\u80FD\u5BF9\u5916\u66B4\u9732\uFF1B\u5DF2\u56DE\u9000\u5230 127.0.0.1\u3002\u5982\u9700\u7ED1\u5B9A {host}\uFF0C\u8BF7\u8FD0\u884C\uFF1AFABRIC_AUTH_TOKEN=<token> fabric serve --host {host}",
1590
- "cli.serve.warning.loopback-deny-default": "\u672A\u8BBE\u7F6E FABRIC_AUTH_TOKEN\uFF1A/api /events /mcp \u9ED8\u8BA4\u8FD4\u56DE 401\uFF08\u5426\u5219\u4EFB\u4F55\u672C\u673A\u8FDB\u7A0B\u90FD\u80FD\u8BFB\u53D6 .fabric/agents.meta.json + forensic.json + events.jsonl\uFF09\u3002\u8BF7\u8BBE\u7F6E FABRIC_AUTH_TOKEN=<secret>\uFF0C\u6216\u4F20\u5165 --allow-loopback-no-auth \u663E\u5F0F\u653E\u884C\u3002",
1591
- "cli.serve.error.port-in-use": "\u7AEF\u53E3 {port} \u5DF2\u88AB\u5360\u7528\uFF0C\u53EF\u5C1D\u8BD5 --port {nextPort}",
1693
+ // v2.0.0-rc.37 Wave A2 Part 2: cli.serve.* + FABRIC_AUTH_TOKEN keys removed
1694
+ // alongside `fabric serve` quarantine to packages/server-http-experimental/
1695
+ // per [[fabric-serve-quarantine-not-delete]]. Restore from git history when
1696
+ // the web UI surface is re-enabled.
1592
1697
  // v2.0.0-rc.29 TASK-008 (BUG-L2): onboard-coverage 国际化键。
1593
1698
  "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",
1594
1699
  "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",
@@ -35,55 +35,58 @@ var BOOTSTRAP_CANONICAL = `# Fabric Bootstrap
35
35
  \u5B8C\u6574 maintainer \u7248\u89C1 \`docs/USER-QUICKSTART.md\`\u3002
36
36
 
37
37
  ## \u884C\u4E3A\u89C4\u5219
38
- - **\u4FEE\u6539\u4EFB\u4F55\u6587\u4EF6\u524D**:\u4E24\u6B65\u8C03\u7528\u2014\u2014\u5148 \`fab_plan_context(paths=[<\u88AB\u6539\u6587\u4EF6>])\` \u62FF\u5230 \`selection_token\` \u4E0E\u5019\u9009 \`entries\`(\u6311 \`selectable===true\` \u7684 \`stable_id\`),\u518D \`fab_get_knowledge_sections({ selection_token, ai_selected_stable_ids: [<id>...] })\` \u53D6\u89C4\u5219\u6B63\u6587\u3002
38
+ - **\u4FEE\u6539\u4EFB\u4F55\u6587\u4EF6\u524D**:\u4F18\u5148\u5355\u6B65 \`fab_recall(paths=[<\u88AB\u6539\u6587\u4EF6>])\` \u2014\u2014 \u4E00\u6B21\u8C03\u7528\u76F4\u63A5\u62FF\u56DE\u6240\u6709\u76F8\u5173 KB \u6B63\u6587(rc.37+ \u9ED8\u8BA4\u8DEF\u5F84,\u7701\u6389\u624B\u52A8\u6311 id \u7684\u73AF\u8282)\u3002**\u4EC5\u5F53\u5355\u6B65\u62C9\u56DE\u7684\u6B63\u6587\u8FC7\u591A\u3001\u5BFC\u81F4\u4E0A\u4E0B\u6587\u8FC7\u8F7D\u9700\u7CBE\u786E\u88C1\u526A\u566A\u97F3\u65F6**\u624D\u8D70\u4E24\u6B65:\u5148 \`fab_plan_context(paths=[...])\` \u62FF \`selection_token\` + \u9876\u5C42 \`candidates[]\`(\u4ECE \`candidates[].stable_id\` \u6311),\u518D \`fab_get_knowledge_sections({ selection_token, ai_selected_stable_ids: [<id>...] })\` \u53D6\u6B63\u6587\u3002
39
39
  - **\`.fabric/agents.meta.json\` \u4E25\u7981\u624B\u52A8\u7F16\u8F91**;engine \u4F1A\u81EA\u52A8\u540C\u6B65\u6D3E\u751F\u72B6\u6001,\u663E\u5F0F reconcile \u8DD1 \`fabric doctor --fix\`\u3002
40
40
 
41
41
  ## \u77E5\u8BC6\u5E93(KB)
42
42
  - **Discovery**:SessionStart hook \u5217 broad-scoped \u6761\u76EE(\u542B personal layer \`KP-*\` \u6761\u76EE,\u5F15\u7528\u65B9\u5F0F\u76F8\u540C);edit \u6587\u4EF6\u65F6 PreToolUse hook \u53EF\u80FD\u89E6\u53D1 narrow hint\u3002
43
- - **Usage**:\u4E24\u6B65\u5F0F\u2014\u2014\`fab_plan_context(paths=[...])\` \u8FD4\u56DE \`selection_token\` + \u5019\u9009 entries,\u518D \`fab_get_knowledge_sections({ selection_token, ai_selected_stable_ids: [<id>...] })\` \u62C9\u5168\u6587;\`selection_token\` \u5FC5\u987B\u6765\u81EA\u6700\u8FD1\u4E00\u6B21 \`fab_plan_context\`,\u4E0D\u53EF\u51ED\u7A7A\u7F16\u9020\u3002
44
- - **session_id**: \u8C03\u7528 \`fab_plan_context\` \u65F6, \u52A1\u5FC5\u628A\u5F53\u524D client session id \u4F5C\u4E3A \`session_id\` \u53C2\u6570\u4F20\u5165(Claude Code \u7684 session id \u5728 stdin payload \u4E2D, Codex \u7684\u5BF9\u5E94 identifier \u540C\u7406)\u3002\u8FD9\u80FD\u8BA9 \`fabric doctor --archive-history\` \u4E0E archive-hint hook \u51C6\u786E\u8BC6\u522B\u8DE8\u4F1A\u8BDD debt \u72B6\u6001\u3002
43
+ - **Usage**:\u5E38\u6001\u8D70\u5355\u6B65 \`fab_recall(paths=[...])\` \u4E00\u6B21\u62FF\u56DE\u76F8\u5173 KB \u6B63\u6587\u3002\u4EC5\u5F53\u5355\u6B65\u6B63\u6587\u8FC7\u591A\u81F4\u4E0A\u4E0B\u6587\u8FC7\u8F7D\u3001\u9700\u7CBE\u786E\u88C1\u526A\u566A\u97F3\u65F6\u624D\u4E24\u6B65:\`fab_plan_context(paths=[...])\` \u8FD4\u56DE \`selection_token\` + \u9876\u5C42 \`candidates[]\`,\u518D \`fab_get_knowledge_sections({ selection_token, ai_selected_stable_ids: [<\u4ECE candidates[].stable_id \u6311>...] })\` \u62C9\u5168\u6587;\`selection_token\` \u5FC5\u987B\u6765\u81EA\u6700\u8FD1\u4E00\u6B21 \`fab_plan_context\`,\u4E0D\u53EF\u51ED\u7A7A\u7F16\u9020\u3002
44
+ - **session_id**: \u8C03\u7528 \`fab_recall\` / \`fab_plan_context\` \u65F6, \u52A1\u5FC5\u628A\u5F53\u524D client session id \u4F5C\u4E3A \`session_id\` \u53C2\u6570\u4F20\u5165(Claude Code \u7684 session id \u5728 stdin payload \u4E2D, Codex \u7684\u5BF9\u5E94 identifier \u540C\u7406)\u3002\u8FD9\u80FD\u8BA9 \`fabric doctor --archive-history\` \u4E0E archive-hint hook \u51C6\u786E\u8BC6\u522B\u8DE8\u4F1A\u8BDD debt \u72B6\u6001\u3002
45
45
  - **Write flows**:\`fabric-archive\` / \`fabric-review\` / \`fabric-import\` \u4E09\u4E2A Skills\u3002
46
46
  - **Language**:\u6E32\u67D3\u6309 \`.fabric/fabric-config.json\` \u7684 \`fabric_language\` \u5B57\u6BB5\u3002
47
47
  - **Archive cadence nudge** (rc.36): \u6BCF\u5B8C\u6210 5+ \u6B21 Edit / \u663E\u8457 decision \u540E,\u5728\u5408\u9002\u56DE\u5408\u4E3B\u52A8 propose \u8C03 \`fabric-archive\` skill \u2014 archive \u6CA1\u5EFA\u7ACB\u9891\u7387\u4F1A\u8BA9 KB \u6162\u901F\u6B7B\u6389\u3002
48
48
  - **Review backlog nudge** (rc.36): \`.fabric/knowledge/pending/\` \u7D2F\u79EF >10 \u6761\u65F6,\u5728\u5408\u9002\u56DE\u5408\u4E3B\u52A8 propose \u8C03 \`fabric-review\` skill \u6279\u91CF\u5BA1,\u907F\u514D draft \u5361\u6B7B\u3002
49
49
 
50
- ## Self-archive policy
50
+ ## Self-archive policy (v2.0.0-rc.37 NEW-2: \u7B80\u5316 4 \u4FE1\u53F7 \u2192 2 \u5927\u7C7B)
51
51
 
52
- - **\u89E6\u53D1**: \u672C\u4F1A\u8BDD\u51FA\u73B0\u4EE5\u4E0B\u4EFB\u4E00\u4FE1\u53F7, \u5728\u8BE5 turn \u56DE\u590D\u672B\u5C3E\u81EA\u4E3B\u8C03\u7528 \`fabric-archive\` skill (E3-strong mode):
53
- 1. **Normative \u8BED\u8A00** \u2014 \u7528\u6237\u6D88\u606F\u51FA\u73B0 \`\u4EE5\u540E\` / \`always\` / \`never\` / \`from now on\` / \`\u4E0B\u6B21\u6CE8\u610F\` / \`\u8BB0\u4E00\u4E0B\` / \`\u6C38\u8FDC\u4E0D\u8981\`
54
- 2. **Wrong-turn-and-revert** \u2014 AI \u5C1D\u8BD5 path X, \u53CD\u601D\u540E\u6539\u8D70 path Y (\u5C24\u5176\u5F53 path X \u662F\u975E\u663E\u7136\u8E29\u5751)
55
- 3. **Decision confirmation** \u2014 \u7528\u6237\u5728 \u22652 \u5019\u9009\u4E2D\u6743\u8861\u540E\u7ED9\u51FA rationale \u9501\u5B9A\u65B9\u5411
56
- 4. **Explicit dismissal with reason** \u2014 \u7528\u6237\u62D2\u4E86\u67D0\u5EFA\u8BAE**\u5E76**\u8BF4\u4E86\u539F\u56E0
52
+ - **\u89E6\u53D1** (\u672C\u4F1A\u8BDD\u51FA\u73B0\u4EE5\u4E0B\u4EFB\u4E00\u4FE1\u53F7, \u5728\u8BE5 turn \u56DE\u590D\u672B\u5C3E\u81EA\u4E3B\u8C03\u7528 \`fabric-archive\` skill, \u8D70 AI \u81EA\u89E6\u53D1\u5165\u53E3 E3_ai_self_trigger):
53
+ 1. **User-driven normative** \u2014 \u7528\u6237\u6D88\u606F\u4E2D\u663E\u5F0F\u8868\u8FBE normative \u610F\u56FE: \`\u4EE5\u540E\` / \`always\` / \`never\` / \`from now on\` / \`\u4E0B\u6B21\u6CE8\u610F\` / \`\u8BB0\u4E00\u4E0B\` / \`\u6C38\u8FDC\u4E0D\u8981\`, OR \u7528\u6237\u5728 \u22652 \u5019\u9009\u95F4\u6743\u8861\u540E\u7ED9\u51FA rationale \u9501\u5B9A\u65B9\u5411, OR \u7528\u6237\u62D2\u4E86\u67D0\u5EFA\u8BAE**\u5E76**\u8BF4\u4E86\u539F\u56E0 (\u62D2\u7EDD\u7406\u7531\u672C\u8EAB\u662F\u77E5\u8BC6)
54
+ 2. **Wrong-turn-and-revert** \u2014 AI \u5C1D\u8BD5 path X, \u53CD\u601D\u540E\u6539\u8D70 path Y (\u5C24\u5176\u5F53 path X \u662F\u975E\u663E\u7136\u8E29\u5751); \u6DB5\u76D6\u6280\u672F\u51B3\u7B56\u53CD\u8F6C + \u5DE5\u5177/\u8303\u5F0F\u5207\u6362 + \u5931\u8D25\u91CD\u8BD5\u3002Anchor: \u4E00\u5B9A\u6709"\u5426\u5B9A+\u66FF\u4EE3"\u7684\u4E24\u6B65\u7ED3\u6784, \u4E0D\u662F\u5355\u7EAF\u63A2\u7D22\u5931\u8D25
55
+
56
+ \u8001 4-state (Normative / Decision-confirmation / Explicit-dismissal / Wrong-turn) \u73B0\u5408\u5E76: \u524D 3 \u4E2A\u5168\u662F"\u7528\u6237\u6D88\u606F\u4E2D\u663E\u5F0F\u8868\u8FBE"\u6027\u8D28, \u6298\u6210 1 \u7C7B; \u7B2C 4 \u662F"AI \u81EA\u5DF1\u7684\u53CD\u601D\u8DEF\u5F84", \u72EC\u7ACB 1 \u7C7B\u3002\u4E24\u7C7B\u5404\u81EA\u7684\u672C\u8D28\u5224\u522B\u4E0D\u53D8, \u89E6\u53D1\u9762\u6CA1\u53D8\u7A84\u3002
57
57
 
58
58
  - **Anti-trigger** (\u660E\u786E\u4E0D\u89E6\u53D1):
59
59
  - \u7528\u6237\u7EAF\u8BE2\u95EE (\u65E0 normative \u8868\u8FBE)
60
60
  - \u7B80\u5355 refactor / typo fix
61
- - AI \u81EA\u5DF1\u4EA7\u751F\u7684'\u6D1E\u5BDF' (\u5FC5\u987B\u7531\u7528\u6237\u6D88\u606F\u4E2D\u4FE1\u53F7\u89E6\u53D1)
61
+ - AI \u81EA\u5DF1\u4EA7\u751F\u7684'\u6D1E\u5BDF' (\u5FC5\u987B\u7531\u7528\u6237\u6D88\u606F\u4E2D\u4FE1\u53F7\u6216 AI \u81EA\u5DF1\u7684 wrong-turn \u89E6\u53D1, \u4E0D\u662F\u51ED\u7A7A"\u6211\u5B66\u5230\u4E86"\u6027\u8D28)
62
62
 
63
63
  - **Anti-loop \u4E09\u6761\u9632\u62A4**:
64
64
  - \u540C turn \u6700\u591A\u81EA\u8C03 1 \u6B21
65
65
  - \u540C session \u540C outcome \u4E0D\u91CD\u590D (\u82E5 user_dismissed, \u672C\u4F1A\u8BDD\u4E0D\u518D\u81EA\u8C03\u76F8\u540C\u4E3B\u9898)
66
- - Phase 0.5 viability gate \u515C\u5E95 (skill \u5185\u90E8\u4ECD\u8DD1 gate, AI \u5224\u9519\u4E0D\u4F1A\u4E71\u5199 pending)
66
+ - Phase 2.5 viability gate \u515C\u5E95 (skill \u5185\u90E8\u4ECD\u8DD1 gate, AI \u5224\u9519\u4E0D\u4F1A\u4E71\u5199 pending)
67
67
 
68
- - **\u5448\u73B0\u6A21\u677F** (turn \u672B\u5C3E\u63D2\u5165, \u4E24\u884C: \u5148 marker \u884C\u4F9B Phase 0.4 \u68C0\u6D4B, \u518D user-facing \u63D0\u793A):
68
+ - **\u5448\u73B0\u6A21\u677F** (turn \u672B\u5C3E\u63D2\u5165, \u4E24\u884C: \u5148 marker \u884C\u4F9B Phase 1.5 \u68C0\u6D4B, \u518D user-facing \u63D0\u793A):
69
69
  \`\`\`
70
- self-archive policy triggered by signal: <Normative|Wrong-turn-and-revert|Decision confirmation|Explicit dismissal>
70
+ self-archive policy triggered by signal: <User-driven normative|Wrong-turn-and-revert>
71
71
  \u987A\u624B\u5F52\u6863: \u6CE8\u610F\u5230\u4F60\u8BF4 \`<\u89E6\u53D1\u77ED\u8BED>\`, \u5DF2\u8C03\u7528 fabric-archive \u6293 N \u6761\u5019\u9009 \u2192 .fabric/knowledge/pending/...
72
72
  \u82E5\u4E0D\u8BE5\u8BB0, \u7B54 '\u64A4\u9500' \u6211\u4F1A\u8C03 fab_review reject\u3002
73
73
  \`\`\`
74
- \u7B2C\u4E00\u884C\u662F Phase 0.4 Trigger Gate \u7528\u6765\u8BC6\u522B E3 \u5165\u53E3\u7684 structured marker (verbatim \u5B57\u7B26\u4E32 \`self-archive policy triggered by signal\`, \u540E\u63A5\u5192\u53F7 + \u89E6\u53D1\u4FE1\u53F7\u540D)\u3002\u7B2C\u4E8C\u884C\u8D77\u662F\u7ED9\u7528\u6237\u770B\u7684\u4E2D\u6587\u63D0\u793A\u3002\u4E24\u884C\u90FD\u5FC5\u987B\u51FA\u73B0; \u7F3A marker \u884C Phase 0.4 \u65E0\u6CD5\u8DEF\u7531\u5230 E3_ai_self_trigger\u3002
74
+ \u7B2C\u4E00\u884C\u662F Phase 1.5 Trigger Gate \u8BC6\u522B E3 \u5165\u53E3\u7684 structured marker (verbatim \u5B57\u7B26\u4E32 \`self-archive policy triggered by signal\`, \u540E\u63A5\u5192\u53F7 + \u89E6\u53D1\u4FE1\u53F7\u540D)\u3002\u7B2C\u4E8C\u884C\u8D77\u662F\u7ED9\u7528\u6237\u770B\u7684\u4E2D\u6587\u63D0\u793A\u3002\u4E24\u884C\u90FD\u5FC5\u987B\u51FA\u73B0; \u7F3A marker \u884C Phase 1.5 \u65E0\u6CD5\u8DEF\u7531\u5230 E3_ai_self_trigger\u3002
75
+
76
+ Backward compat: Phase 1.5 entry-point regex \u540C\u65F6\u8BC6\u522B\u8001 4 \u4E2A\u4FE1\u53F7\u540D (Normative / Wrong-turn-and-revert / Decision confirmation / Explicit dismissal) \u4E0E\u65B0 2 \u5927\u7C7B\u540D, \u65E7 session marker \u4ECD\u80FD\u6B63\u786E\u8DEF\u7531\u3002
75
77
 
76
- ## Cite policy
78
+ ## Cite policy (v2.0.0-rc.37 NEW-1: \u7B80\u5316 4-state \u2192 2-state)
77
79
 
78
- - **\u89E6\u53D1**: \u505A edit / decide / propose plan \u4E4B\u524D,**\u56DE\u590D\u9996\u884C**\u5FC5\u987B\u5199 \`KB: <id> (<\u22648\u5B57 \u7528\u6CD5>) [planned|recalled|chained-from <id>|dismissed:<reason>]\` \u6216 \`KB: none [<reason>]\`\u3002
79
- - **\`[recalled]\` \u9A8C\u8BC1**: \u5FC5\u987B\u7D27\u8DDF\u4E24\u6B65\u8C03\u7528\u2014\u2014\u5148 \`fab_plan_context(paths=[...])\` \u62FF \`selection_token\`,\u518D \`fab_get_knowledge_sections({ selection_token, ai_selected_stable_ids: [<id>] })\`,\u9632\u6B62\u7F16\u9020 id\u3002
80
- - **contract \u8BED\u6CD5**: decisions/pitfalls \u7C7B\u5F15\u7528\u5FC5\u987B\u5728\u5C3E\u6BB5\u52A0 contract: \`\u2192 <operator> [<operator> ...]\`,operator \u2208 {\`edit:<glob>\` \`!edit:<glob>\` \`require:<symbol>\` \`forbid:<symbol>\` \`skip:<reason>\`}\u3002\u4F8B:\`KB: K-001 (auth) [planned] \u2192 edit:src/auth/**/*.ts !edit:src/legacy/**\`\u3002
80
+ - **\u89E6\u53D1**: \u505A edit / decide / propose plan \u4E4B\u524D,**\u56DE\u590D\u9996\u884C**\u5FC5\u987B\u5199 \`KB: <id> (<\u22648\u5B57 \u7528\u6CD5>) [applied|dismissed:<reason>]\` \u6216 \`KB: none [<reason>]\`\u3002
81
+ - **\`[applied]\` \u9A8C\u8BC1\u4E49\u52A1**: \u5F15\u7528\u4EFB\u4F55 id \u524D\u5FC5\u987B\u5148\u7528 fab_recall (\u6216\u4E24\u6B65 fab_plan_context \u2192 fab_get_knowledge_sections) \u5B9E\u9645\u6293 KB body, \u9632\u6B62\u7F16\u9020 id\u3002\u9A8C\u8BC1\u4E0D\u901A\u8FC7 = \u4E0D\u80FD cite\u3002
82
+ - **contract \u8BED\u6CD5**: decisions/pitfalls \u7C7B \`[applied]\` cite \u5C3E\u6BB5\u52A0 contract: \`\u2192 <operator> [<operator> ...]\`,operator \u2208 {\`edit:<glob>\` \`!edit:<glob>\` \`require:<symbol>\` \`forbid:<symbol>\` \`skip:<reason>\`}\u3002\u4F8B:\`KB: K-001 (auth) [applied] \u2192 edit:src/auth/**/*.ts !edit:src/legacy/**\`\u3002
81
83
  - **skip reason \u8BCD\u5178**: \`sequencing | conditional | semantic | aesthetic | architectural | other:<text>\`\u3002
82
84
  - **type \u8DEF\u7531**: models \u7C7B\u5F15\u7528\u4E3A reference cite,\u4E0D\u9700\u8981 contract;guidelines/processes \u7C7B\u6682\u4E0D\u5F3A\u5236,\u63A8\u540E LLM-judge\u3002
83
- - **\u7528\u6237\u53E3\u5934\u63D0\u89C4\u5219\u6CA1\u7ED9 id**: \u5148\u8C03 \`fab_extract_knowledge\` \u6216 \`search_context\` \u53CD\u67E5\u3002
85
+ - **\u7528\u6237\u53E3\u5934\u63D0\u89C4\u5219\u6CA1\u7ED9 id**: \u5148\u8C03 \`fab_recall(paths)\` \u6216 \`fab_extract_knowledge\` \u53CD\u67E5\u3002
84
86
  - **dismissed reason**: \u679A\u4E3E \`scope-mismatch | outdated | not-applicable | other:<text>\`\u3002
85
- - **\`KB: none\` sentinel**: \u679A\u4E3E\u4E24\u79CD\u5408\u89C4\u7406\u7531\u2014\u2014\`[no-relevant]\` \u5DF2\u8C03 \`fab_plan_context\`(\u6216 hook \u8F93\u51FA\u53EF\u89C1)\u4F46\u65E0\u53EF\u7528\u6761\u76EE;\`[not-applicable]\` \u5F53\u524D\u52A8\u4F5C\u4E0D\u5728 cite \u8303\u56F4(\u7EAF\u63A2\u7D22 / Bash \u53EA\u8BFB / \u7528\u6237\u95EE\u7B54)\u3002\u88F8 \`KB: none\`(\u65E0\u540E\u7F00)\u4ECD\u7136 valid,\u5F52\u7C7B\u4E3A \`[unspecified]\`(legacy \u517C\u5BB9,\u9F13\u52B1\u540E\u7EED\u8865\u6CE8)\u3002
87
+ - **\`KB: none\` sentinel**: \u679A\u4E3E\u4E24\u79CD\u5408\u89C4\u7406\u7531\u2014\u2014\`[no-relevant]\` \u5DF2\u8C03 \`fab_recall\` / \`fab_plan_context\`(\u6216 hook \u8F93\u51FA\u53EF\u89C1)\u4F46\u65E0\u53EF\u7528\u6761\u76EE;\`[not-applicable]\` \u5F53\u524D\u52A8\u4F5C\u4E0D\u5728 cite \u8303\u56F4(\u7EAF\u63A2\u7D22 / Bash \u53EA\u8BFB / \u7528\u6237\u95EE\u7B54)\u3002\u88F8 \`KB: none\`(\u65E0\u540E\u7F00)\u4ECD\u7136 valid,\u5F52\u7C7B\u4E3A \`[unspecified]\`(legacy \u517C\u5BB9,\u9F13\u52B1\u540E\u7EED\u8865\u6CE8)\u3002
86
88
  - **\u7A3D\u6838**: \`fabric doctor --cite-coverage [--since=7d] [--client=cc|codex|all]\` \u8F93\u51FA cite \u8986\u76D6\u7387,\u542B \`KB: none\` sentinel \u62C6\u5206\u3002\u672C\u89C4\u5219\u4E0D\u963B\u65AD\u4F60\u5DE5\u4F5C,\u53EA\u8BB0\u5F55\u3002
89
+ - **Backward compat**: \u89E3\u6790\u5668\u540C\u65F6\u63A5\u53D7\u8001 4-state tags (\`planned\` / \`recalled\` / \`chained-from <id>\`) \u2014 \u90FD\u6620\u5C04\u5230 \`[applied]\` \u8BED\u4E49,gradually \u8FC1\u5230\u65B0\u7B80\u5316\u5F62\u6001\u5373\u53EF,\u65E7 session \u7559\u4E0B\u7684 cite \u4ECD\u7136\u8BA1\u5165 cite-coverage\u3002
87
90
  `;
88
91
 
89
92
  export {