@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.
@@ -0,0 +1,206 @@
1
+ import {
2
+ resolveGlobalLocale
3
+ } from "./chunk-2GLIAZ5M.js";
4
+
5
+ // src/templates/bootstrap-canonical.ts
6
+ var BOOTSTRAP_MARKER_BEGIN = "<!-- fabric:bootstrap:begin -->";
7
+ var BOOTSTRAP_MARKER_END = "<!-- fabric:bootstrap:end -->";
8
+ var BOOTSTRAP_REGEX = /(?:\r?\n){0,2}<!-- fabric:bootstrap:begin -->[\s\S]*?<!-- fabric:bootstrap:end -->/;
9
+ var BOOTSTRAP_CANONICAL_ZH = `# Fabric Bootstrap
10
+
11
+ \u672C\u9879\u76EE\u4F7F\u7528 Fabric \u7BA1\u7406\u8DE8\u5BA2\u6237\u7AEF AI \u77E5\u8BC6\u4E0E\u884C\u4E3A\u89C4\u5219\u3002\u672C\u6587\u4EF6\u7531 \`fabric install\` \u540C\u6B65\u5230\u4E24\u7AEF managed block,**\u4E0D\u8981\u624B\u52A8\u7F16\u8F91\u4E24\u7AEF\u7684 block**,\u53EA\u6539\u8FD9\u91CC + \u91CD\u8DD1 \`fabric install\`\u3002
12
+
13
+ ## For Developers
14
+
15
+ \u8FD9\u4E2A\u6587\u4EF6\u662F **AI \u5BA2\u6237\u7AEF\u7684\u7B56\u7565\u4E0E\u89C4\u7EA6\u914D\u7F6E**,\u4E0D\u662F dev onboarding\u3002\u4F60\u4E0D\u9700\u8981\u8BFB Self-archive / Cite / Phase 0.4 \u7B49\u7EC6\u8282\u3002
16
+ \u4F5C\u4E3A dev \u4F60\u53EA\u9700\u8981:\u5728\u6BCF\u4E2A repo \u8DD1\u4E00\u6B21 \`fabric install\`,\u7528 \`fabric store bind <alias>\` / \`fabric store switch-write <alias>\` \u63A5\u5165\u5199\u5165 store,\u51FA\u95EE\u9898\u8DD1 \`fabric doctor\`\u3002
17
+ **\u4E25\u7981\u624B\u52A8\u7F16\u8F91 \`.fabric/agents.meta.json\`** \u2014 \u6D3E\u751F\u72B6\u6001\u7531 engine \u91CD\u5EFA\u3002
18
+
19
+ ## 5 \u5206\u949F\u4E0A\u624B (Dev Quickstart)
20
+
21
+ **Fabric \u662F\u4EC0\u4E48**:\u8DE8\u5BA2\u6237\u7AEF(Claude Code / Codex CLI)\u7684 AI \u77E5\u8BC6\u5C42\u3002\u628A\u56E2\u961F/\u9879\u76EE\u7684 **decisions / pitfalls / guidelines / models / processes** \u5B58\u4E3A markdown,hook \u81EA\u52A8 surface \u7ED9 AI,\u8BA9 AI \u4E0D\u7528\u6BCF\u6B21\u91CD\u5B66\u3002
22
+
23
+ **\u4F60\u8981\u505A\u7684 (DO)** vs **engine \u81EA\u52A8\u7684 (DON'T \u624B\u52A8)**:
24
+
25
+ | \u4F60 DO | \u4F60 DON'T |
26
+ | --- | --- |
27
+ | \u6BCF\u4E2A repo \u8DD1\u4E00\u6B21 \`fabric install\` | \u624B\u7F16 \`.fabric/agents.meta.json\` |
28
+ | \u5F02\u5E38\u65F6\u8DD1 \`fabric doctor\` (--fix \u81EA\u6108) | \u624B\u7F16 \`.claude/hooks/\` \u4E0B \`.cjs\` |
29
+ | \u7528 \`fabric-archive\` / \`fabric-review\` / \`fabric store ...\` \u7BA1\u7406 store-backed knowledge | \u624B\u5199\u4EFB\u4F55\u975E store knowledge \u6839 |
30
+ | \`npm install -g @fenglimg/fabric-cli@latest\` \u5347\u7EA7 | \u80CC 35 \u6761 doctor lint \u4EE3\u7801 |
31
+
32
+ **4 \u6B65\u5FAA\u73AF**: \`fabric install\` (\u4E00\u6B21) \u2192 \u7ED1\u5B9A\u5E76\u9009\u62E9\u5199\u5165 store \u2192 AI \u6B63\u5E38\u5DE5\u4F5C (hook on session start + edit) \u2192 AI \u901A\u8FC7 MCP \u5199\u5165\u5F53\u524D write store \u7684 pending \u6761\u76EE\u5E76\u8FD4\u56DE \`pending_path\` \u2192 \u7528 \`fabric-review\` skill \u5BA1\u6838\u3002
33
+
34
+ **\u771F\u4F8B**:\u67D0 sprite \u9ED1\u8FB9 root cause \u662F \`atlas.premultiplyAlpha\` flag \u53CD\u5411 \u2014 \u5F52\u6863\u8FDB store \u7684 \`knowledge/pitfalls/\` \u540E,\u4E0B\u6B21\u540C\u7C7B\u95EE\u9898 AI \u81EA\u52A8 reference\u3002
35
+
36
+ \u5B8C\u6574 maintainer \u7248\u89C1 \`docs/USER-QUICKSTART.md\`\u3002
37
+
38
+ ## \u884C\u4E3A\u89C4\u5219
39
+ - **\u4FEE\u6539\u4EFB\u4F55\u6587\u4EF6\u524D**:\u5148 \`fab_recall(paths=[<\u88AB\u6539\u6587\u4EF6>])\` \u2014\u2014 \u4E00\u6B21\u8C03\u7528\u62FF\u56DE\u76F8\u5173 KB \u7684\u63CF\u8FF0 + \u539F\u751F\u8BFB\u53D6\u8DEF\u5F84(\`paths[].path\`)\u3002\`fab_recall\` \u4E0D\u518D\u6295\u9012\u6B63\u6587;\u9700\u8981\u67D0\u6761\u6B63\u6587\u65F6\u76F4\u63A5\u5BF9\u5176 \`paths[].path\` \u505A\u539F\u751F Read(\`Read <store>/knowledge/<type>/<id>--*.md\`),\u8FD9\u4F1A\u88AB PostToolUse hook \u8BB0\u4E3A \`knowledge_body_read\`\u3002lean \u9ED8\u8BA4:\u63CF\u8FF0+\u7D22\u5F15\u5DF2\u591F\u53D1\u73B0\u6761\u76EE,\u6B63\u6587\u6309\u9700\u8BFB\u4E00\u6B21,\u4E0D\u6BCF\u8F6E\u91CD\u704C(KT-GLD-0005)\u3002
40
+ - **\`.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
41
+
42
+ ## \u77E5\u8BC6\u5E93(KB)
43
+ - **Discovery**:SessionStart hook \u5217 broad-scoped \u6761\u76EE(\u6761\u76EE\u6309 \`semantic_scope\` \u5206\u4E09\u5C42:\`team\` \u56E2\u961F\u901A\u7528 / \`project:<id>\` \u672C\u9879\u76EE\u4E13\u5C5E(\u4EC5\u5728\u7ED1\u5B9A\u8BE5\u9879\u76EE\u7684\u4ED3\u5E93\u6D6E\u73B0)/ \`personal\` \u4E2A\u4EBA \`KP-*\`,\u4E09\u8005\u5F15\u7528\u65B9\u5F0F\u76F8\u540C);edit \u6587\u4EF6\u65F6 PreToolUse hook \u53EF\u80FD\u89E6\u53D1 narrow hint\u3002
44
+ - **Usage**:\u8D70\u5355\u6B65 \`fab_recall(paths=[...])\` \u4E00\u6B21\u62FF\u56DE\u76F8\u5173 KB \u7684\u63CF\u8FF0 + \u8BFB\u53D6\u8DEF\u5F84;\u9700\u8981\u67D0\u6761\u6B63\u6587\u65F6\u5BF9\u5176 \`paths[].path\` \u505A\u539F\u751F Read \u53D6\u56DE(\u4E0D\u518D\u8D70 MCP \u4E8C\u6B21\u53D6\u6B63\u6587)\u3002
45
+ - **session_id**: \u8C03\u7528 \`fab_recall\` \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 \`fabric-hint.cjs\` Stop hook \u51C6\u786E\u8BC6\u522B\u8DE8\u4F1A\u8BDD debt \u72B6\u6001\u3002
46
+ - **Skills (7)**:\u5199\u6D41\u7A0B \`fabric-archive\` / \`fabric-review\` / \`fabric-import\`;store \u6D41\u7A0B \`fabric-store\` / \`fabric-sync\` / \`fabric-connect\`;\u8BCA\u65AD \`fabric-audit\`\u3002
47
+ - **Language**:\u6E32\u67D3\u6309 \`.fabric/fabric-config.json\` \u7684 \`fabric_language\` \u5B57\u6BB5\u3002
48
+ - **Archive cadence nudge** (rc.36): \u6BCF\u5B8C\u6210\u4E00\u6279 Edit(\u9ED8\u8BA4 ~20 \u6B21, \u4E0E Stop hook \u9608\u503C config \`archive_edit_threshold\` \u4E00\u81F4)/ \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
49
+ - **Review backlog nudge** (rc.36): \u9700\u8981\u5224\u65AD pending backlog \u65F6\u8D70 \`fab_review action="list"\` \u6216 \`fabric-review\` \u8FD4\u56DE\u7684 \`pending_path\`;\u4E0D\u8981 glob \u9879\u76EE\u672C\u5730 \`.fabric/knowledge/pending\`\u3002\u5F53\u53EF\u89C1 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
50
+
51
+ ## Self-archive policy (v2.0.0-rc.37 NEW-2: \u7B80\u5316 4 \u4FE1\u53F7 \u2192 2 \u5927\u7C7B)
52
+
53
+ - **\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):
54
+ 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)
55
+ 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
56
+
57
+ \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
58
+
59
+ - **Anti-trigger** (\u660E\u786E\u4E0D\u89E6\u53D1):
60
+ - \u7528\u6237\u7EAF\u8BE2\u95EE (\u65E0 normative \u8868\u8FBE)
61
+ - \u7B80\u5355 refactor / typo fix
62
+ - 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)
63
+
64
+ - **Anti-loop \u4E09\u6761\u9632\u62A4**:
65
+ - \u540C turn \u6700\u591A\u81EA\u8C03 1 \u6B21
66
+ - \u540C session \u540C outcome \u4E0D\u91CD\u590D (\u82E5 user_dismissed, \u672C\u4F1A\u8BDD\u4E0D\u518D\u81EA\u8C03\u76F8\u540C\u4E3B\u9898)
67
+ - Phase 2.5 viability gate \u515C\u5E95 (skill \u5185\u90E8\u4ECD\u8DD1 gate, AI \u5224\u9519\u4E0D\u4F1A\u4E71\u5199 pending)
68
+
69
+ - **\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):
70
+ \`\`\`
71
+ self-archive policy triggered by signal: <User-driven normative|Wrong-turn-and-revert>
72
+ \u987A\u624B\u5F52\u6863: \u6CE8\u610F\u5230\u4F60\u8BF4 \`<\u89E6\u53D1\u77ED\u8BED>\`, \u5DF2\u8C03\u7528 fabric-archive \u6293 N \u6761\u5019\u9009 \u2192 \u5F53\u524D write store \u7684 knowledge/pending/...
73
+ \u82E5\u4E0D\u8BE5\u8BB0, \u7B54 '\u64A4\u9500' \u6211\u4F1A\u8C03 fab_review reject\u3002
74
+ \`\`\`
75
+ \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
76
+
77
+ 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
78
+
79
+ ## Cite policy (v2.1 \u2464 recall-based: \u81EA\u52A8\u8BB0\u8D26\u4F18\u5148, \u9996\u884C KB: \u53EF\u9009 override)
80
+
81
+ - **\u6838\u5FC3 (recall-first \u81EA\u52A8\u8BB0\u8D26)**: \u6539\u4EFB\u4F55\u6587\u4EF6\u524D\u5148 \`fab_recall(paths=[<\u88AB\u6539\u6587\u4EF6>])\`\u3002\u7CFB\u7EDF\u6309"\u672C session \u8FD1\u671F recall \u547D\u4E2D\u7684 path \u4E0E\u7F16\u8F91\u76EE\u6807\u91CD\u53E0"\u81EA\u52A8\u628A\u53EC\u56DE\u7684 KB \u5173\u8054\u4E3A\u8BE5\u6B21 edit \u7684\u5F15\u7528 \u2014\u2014 **\u65E0\u9700\u624B\u5199\u56DE\u590D\u9996\u884C**\u3002PreToolUse hook \u5728\u68C0\u6D4B\u4E0D\u5230\u76F8\u5173 recall \u65F6\u7ED9\u4E00\u6761\u8F6F nudge(nudge \u975E gate,\u5B88 KT-DEC-0007);\u6539\u524D recall \u8FC7(\u6216\u5DF2\u624B\u5199 cite)\u5373\u9759\u9ED8\u3002\u4E3A\u4EC0\u4E48\u4E0D\u518D\u903C\u9996\u884C:\u5148\u60F3\u540E\u8BF4,recall \u624D\u662F\u5F15\u7528\u53D1\u751F\u7684\u771F\u5B9E\u4FE1\u53F7,\u624B\u5199\u9996\u884C\u8FDD\u80CC CoT \u4E14 \`KB: none\` \u9003\u9038\u4F7F\u65E7\u89C4\u5219\u5F62\u540C\u865A\u8BBE\u3002
82
+ - **\u53EF\u9009 override (\u9996\u884C KB:)**: \u4ECD\u53EF\u5728\u56DE\u590D\u9996\u884C\u624B\u5199 \`KB: <id> (<\u22648\u5B57 \u7528\u6CD5>) [applied|dismissed:<reason>]\` \u6216 \`KB: none [<reason>]\` \u6765\u663E\u5F0F\u6807\u6CE8/\u7CBE\u786E\u5316\u5F15\u7528;cite-line \u89E3\u6790\u5668\u4FDD\u7559(\u5411\u540E\u517C\u5BB9),\u65E7\u4E60\u60EF\u4E0D\u7834\u3002
83
+ - **\`[applied]\` \u9A8C\u8BC1\u4E49\u52A1**: \u5F15\u7528\u4EFB\u4F55 id(\u81EA\u52A8\u6216\u624B\u5199)\u7684\u524D\u63D0\u662F\u5148\u7528 fab_recall \u5B9E\u9645\u6293\u56DE KB(\u5E76\u6309\u9700\u5BF9\u5176\u6B63\u6587\u8DEF\u5F84\u505A\u539F\u751F Read), \u9632\u6B62\u7F16\u9020 id\u3002\u9A8C\u8BC1\u4E0D\u901A\u8FC7 = \u4E0D\u80FD cite\u3002
84
+ - **store \u524D\u7F00 (v2.1, \u591A store)**: \u5F53 read-set \u542B\u591A\u4E2A store \u4E14\u540C\u4E00 local id \u5728\u591A store \u95F4 shadow \u65F6,cite \u5FC5\u987B store-qualified: \`KB: <store-alias>:<id> ...\`(\u5982 \`KB: team:KT-DEC-0001 (auth) [applied]\`);alias \u7528\u6237\u81EA\u5B9A/canonical,\u5E95\u5C42 UUID\u3002\u5355 store \u6216\u65E0\u6B67\u4E49\u65F6\u88F8 \`KB: <id>\` \u4ECD valid\u3002personal-only \u6761\u76EE cite \u8FDB\u56E2\u961F\u4EA7\u7269=\u5F3A warning(\u63A5 P2 \u5199\u8DEF\u5F84\u9632\u6CC4\u6F0F R5#3)\u3002
85
+ - **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
86
+ - **skip reason \u8BCD\u5178**: \`sequencing | conditional | semantic | aesthetic | architectural | other:<text>\`\u3002
87
+ - **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
88
+ - **\u7528\u6237\u53E3\u5934\u63D0\u89C4\u5219\u6CA1\u7ED9 id**: \u5148\u8C03 \`fab_recall(paths)\` \u6216 \`fab_extract_knowledge\` \u53CD\u67E5\u3002
89
+ - **dismissed reason**: \u679A\u4E3E \`scope-mismatch | outdated | not-applicable | other:<text>\`\u3002
90
+ - **\`KB: none\` sentinel**: \u679A\u4E3E\u4E24\u79CD\u5408\u89C4\u7406\u7531\u2014\u2014\`[no-relevant]\` \u5DF2\u8C03 \`fab_recall\`(\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
91
+ - **\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
92
+ - **Clean-slate (\u65E0 backward compat)**: \u89E3\u6790\u5668\u53EA\u8BA4 \`applied\` / \`dismissed\` / \`none\` \u4E09\u6001;\u4EFB\u4F55\u65E0\u6CD5\u8BC6\u522B\u7684\u8001 tag (\`planned\` / \`recalled\` / \`chained-from <id>\`) \u4E00\u5F8B\u964D\u7EA7\u4E3A \`none\`(\`chained-from\` \u7684\u5185\u5D4C id \u4ECD\u88AB\u62A2\u6551\u4E3A sibling cite_id)\u3002\u65E7 session \u7559\u4E0B\u7684 legacy cite \u4EE5 \`none\` \u8BA1\u5165 cite-coverage\u3002
93
+ - **\u5B8C\u6574\u53C2\u8003\u4E0B\u6C89** (v2.2 SK5): contract operator / skip\xB7dismissed \u8BCD\u5178 / \u7C7B\u578B\u8DEF\u7531 / \u7A3D\u6838\u53E3\u5F84 / **\u88C1\u51B3\u9636\u68AF** (AI\u81EA\u51B3 \u2192 \u591A-LLM \u542B\u96F6\u4E0A\u4E0B\u6587\u51B7\u8BC4 \u2192 \u975E\u963B\u585E\u961F\u5217) \u7684\u6743\u5A01\u8BE6\u53C2\u5728 \`fabric-review\` skill \u7684 \`ref/cite-contract.md\` \u2014\u2014 bootstrap \u53EA\u7559\u53EF\u6267\u884C core,\u6CBB\u7406\u7EC6\u8282\u5F52 ref \u4E0D\u518D\u6491\u5927 bootstrap\u3002
94
+ `;
95
+ var BOOTSTRAP_CANONICAL_EN = `# Fabric Bootstrap
96
+
97
+ This project uses Fabric to manage cross-client AI knowledge and behavior rules. This file is synced into the managed block on both clients by \`fabric install\` \u2014 **do not hand-edit the block on any client**; edit here + re-run \`fabric install\`.
98
+
99
+ ## For Developers
100
+
101
+ This file is the **AI client's policy & convention config**, not dev onboarding. You don't need to read the Self-archive / Cite / Phase 0.4 details.
102
+ As a dev you only need to: run \`fabric install\` once per repo, use \`fabric store bind <alias>\` / \`fabric store switch-write <alias>\` to wire up a write store, and run \`fabric doctor\` when something breaks.
103
+ **Never hand-edit \`.fabric/agents.meta.json\`** \u2014 derived state is rebuilt by the engine.
104
+
105
+ ## Dev Quickstart
106
+
107
+ **What Fabric is**: a cross-client (Claude Code / Codex CLI) AI knowledge layer. Store the team/project **decisions / pitfalls / guidelines / models / processes** as markdown; hooks surface them to the AI automatically so it doesn't re-learn every time.
108
+
109
+ **What you DO** vs **what the engine does (DON'T hand-edit)**:
110
+
111
+ | You DO | You DON'T |
112
+ | --- | --- |
113
+ | Run \`fabric install\` once per repo | Hand-edit \`.fabric/agents.meta.json\` |
114
+ | Run \`fabric doctor\` (--fix self-heals) on trouble | Hand-edit \`.cjs\` under \`.claude/hooks/\` |
115
+ | Use \`fabric-archive\` / \`fabric-review\` / \`fabric store ...\` to manage store-backed knowledge | Hand-write any non-store knowledge root |
116
+ | \`npm install -g @fenglimg/fabric-cli@latest\` to upgrade | Memorize the 35 doctor lint codes |
117
+
118
+ **4-step loop**: \`fabric install\` (once) \u2192 bind and pick a write store \u2192 AI works normally (hook on session start + edit) \u2192 the AI writes pending entries into the current write store via MCP and returns a \`pending_path\` \u2192 review with the \`fabric-review\` skill.
119
+
120
+ **Real example**: a sprite black-edge root cause was the \`atlas.premultiplyAlpha\` flag being inverted \u2014 once archived into the store's \`knowledge/pitfalls/\`, the AI auto-references it next time a similar issue shows up.
121
+
122
+ See \`docs/USER-QUICKSTART.md\` for the full maintainer version.
123
+
124
+ ## Behavior Rules
125
+ - **Before modifying any file**: first \`fab_recall(paths=[<file-being-edited>])\` \u2014\u2014 a single call returns the relevant KB descriptions + native read paths (\`paths[].path\`). \`fab_recall\` no longer delivers bodies; when you need a body, do a native Read of its \`paths[].path\` (\`Read <store>/knowledge/<type>/<id>--*.md\`), which the PostToolUse hook records as \`knowledge_body_read\`. Lean default: descriptions + index already suffice to discover entries; read a body once on demand, don't re-inject it every turn (KT-GLD-0005).
126
+ - **Never hand-edit \`.fabric/agents.meta.json\`**; the engine syncs derived state automatically \u2014 run \`fabric doctor --fix\` for an explicit reconcile.
127
+
128
+ ## Knowledge Base (KB)
129
+ - **Discovery**: the SessionStart hook lists broad-scoped entries (scoped by \`semantic_scope\` across three tiers: \`team\` team-wide / \`project:<id>\` this-project-only (surfaces only in repos bound to that project) / \`personal\` \`KP-*\`, all three referenced the same way); editing a file may trigger a narrow hint via the PreToolUse hook.
130
+ - **Usage**: go one-step \`fab_recall(paths=[...])\` to fetch the relevant KB descriptions + read paths in one call; when you need a body, do a native Read of its \`paths[].path\` (no second MCP round-trip for the body).
131
+ - **session_id**: when calling \`fab_recall\`, always pass the current client session id as the \`session_id\` argument (Claude Code's session id is in the stdin payload; Codex's corresponding identifier likewise). This lets \`fabric doctor --archive-history\` and the \`fabric-hint.cjs\` Stop hook track cross-session debt accurately.
132
+ - **Skills (7)**: write flow \`fabric-archive\` / \`fabric-review\` / \`fabric-import\`; store flow \`fabric-store\` / \`fabric-sync\` / \`fabric-connect\`; diagnostics \`fabric-audit\`.
133
+ - **Language**: rendered per the \`fabric_language\` field in \`.fabric/fabric-config.json\`.
134
+ - **Archive cadence nudge** (rc.36): after each batch of edits (default ~20, matching the Stop hook threshold config \`archive_edit_threshold\`) / a significant decision, proactively propose the \`fabric-archive\` skill at a suitable turn \u2014 without an archive cadence the KB slowly dies.
135
+ - **Review backlog nudge** (rc.36): to judge the pending backlog, go through \`fab_review action="list"\` or the \`pending_path\` returned by \`fabric-review\`; don't glob the project-local \`.fabric/knowledge/pending\`. When the visible pending count exceeds 10, proactively propose the \`fabric-review\` skill at a suitable turn to batch-review and avoid draft deadlock.
136
+
137
+ ## Self-archive policy (v2.0.0-rc.37 NEW-2: simplified 4 signals \u2192 2 classes)
138
+
139
+ - **Trigger** (when any of the following signals appears this session, autonomously invoke the \`fabric-archive\` skill at the end of that turn, via the AI self-trigger entry E3_ai_self_trigger):
140
+ 1. **User-driven normative** \u2014 the user's message explicitly expresses normative intent: \`\u4EE5\u540E\` / \`always\` / \`never\` / \`from now on\` / \`\u4E0B\u6B21\u6CE8\u610F\` / \`\u8BB0\u4E00\u4E0B\` / \`\u6C38\u8FDC\u4E0D\u8981\`, OR the user locks a direction with rationale after weighing \u22652 candidates, OR the user rejects a suggestion **and** states a reason (the rejection reason itself is knowledge)
141
+ 2. **Wrong-turn-and-revert** \u2014 the AI tries path X, then after reflection switches to path Y (especially when path X is a non-obvious pitfall); covers technical-decision reversals + tool/paradigm switches + failed retries. Anchor: there is always a two-step "negate + replace" structure, not mere exploratory failure
142
+
143
+ The old 4-state set (Normative / Decision-confirmation / Explicit-dismissal / Wrong-turn) is now merged: the first 3 are all "explicitly expressed in the user's message" and fold into 1 class; the 4th is "the AI's own reflective path" and stands alone as 1 class. Each class's underlying test is unchanged; the trigger surface did not narrow.
144
+
145
+ - **Anti-trigger** (explicitly does NOT trigger):
146
+ - Pure user questions (no normative expression)
147
+ - Simple refactor / typo fix
148
+ - AI's own 'insights' (must be triggered by a signal in the user's message or the AI's own wrong-turn, not a baseless "I learned something")
149
+
150
+ - **Anti-loop, 3 guards**:
151
+ - At most 1 self-invocation per turn
152
+ - No repeat for the same outcome in the same session (if user_dismissed, don't self-invoke the same topic again this session)
153
+ - Phase 2.5 viability gate as backstop (the skill still runs the gate internally, so a misjudgment won't write junk pending)
154
+
155
+ - **Presentation template** (insert at the end of the turn, two lines: first the marker line for Phase 1.5 detection, then the user-facing prompt):
156
+ \`\`\`
157
+ self-archive policy triggered by signal: <User-driven normative|Wrong-turn-and-revert>
158
+ Archived along the way: noticed you said \`<trigger phrase>\`, invoked fabric-archive to capture N candidates \u2192 the current write store's knowledge/pending/...
159
+ If this shouldn't be recorded, reply 'undo' and I'll call fab_review reject.
160
+ \`\`\`
161
+ The first line is the structured marker the Phase 1.5 Trigger Gate uses to route the E3 entry (verbatim string \`self-archive policy triggered by signal\`, followed by a colon + the trigger signal name). From the second line on it's the user-facing prompt. Both lines MUST appear; without the marker line Phase 1.5 cannot route to E3_ai_self_trigger.
162
+
163
+ Backward compat: the Phase 1.5 entry-point regex recognises both the old 4 signal names (Normative / Wrong-turn-and-revert / Decision confirmation / Explicit dismissal) and the new 2 class names, so markers from old sessions still route correctly.
164
+
165
+ ## Cite policy (v2.1 \u2464 recall-based: auto-accounting first, optional first-line KB: override)
166
+
167
+ - **Core (recall-first auto-accounting)**: before changing any file, run \`fab_recall(paths=[<file-being-edited>])\` first. The system auto-associates the recalled KB as that edit's citation by "paths recall-hit recently this session overlap the edit target" \u2014\u2014 **no need to hand-write a first reply line**. The PreToolUse hook gives a soft nudge when it detects no relevant recall (nudge, not a gate, per KT-DEC-0007); having recalled before the edit (or already hand-written a cite) keeps it silent. Why no longer force a first line: think-then-speak, recall is the real signal that a citation happened, hand-writing a first line violates CoT and the \`KB: none\` escape hatch made the old rule toothless.
168
+ - **Optional override (first-line KB:)**: you may still hand-write \`KB: <id> (<\u22648-char usage>) [applied|dismissed:<reason>]\` or \`KB: none [<reason>]\` as the first reply line to explicitly annotate/refine the citation; the cite-line parser is retained (backward compatible), old habits aren't broken.
169
+ - **\`[applied]\` verification duty**: citing any id (auto or hand-written) requires first actually fetching the KB via fab_recall (and a native Read of its body path when needed), to prevent fabricated ids. Verification failing = you cannot cite.
170
+ - **store prefix (v2.1, multi-store)**: when the read-set spans multiple stores and the same local id is shadowed across stores, the cite MUST be store-qualified: \`KB: <store-alias>:<id> ...\` (e.g. \`KB: team:KT-DEC-0001 (auth) [applied]\`); the alias is user-defined/canonical, the underlying id a UUID. A bare \`KB: <id>\` is still valid for a single store or no ambiguity. Citing a personal-only entry into a team artifact = strong warning (ties into the P2 write-path leak guard R5#3).
171
+ - **contract syntax**: for decisions/pitfalls-type \`[applied]\` cites, append a contract tail: \`\u2192 <operator> [<operator> ...]\`, operator \u2208 {\`edit:<glob>\` \`!edit:<glob>\` \`require:<symbol>\` \`forbid:<symbol>\` \`skip:<reason>\`}. E.g. \`KB: K-001 (auth) [applied] \u2192 edit:src/auth/**/*.ts !edit:src/legacy/**\`.
172
+ - **skip reason dictionary**: \`sequencing | conditional | semantic | aesthetic | architectural | other:<text>\`.
173
+ - **type routing**: a models-type citation is a reference cite, no contract needed; guidelines/processes types are not yet enforced, deferred to an LLM-judge.
174
+ - **user mentions a rule verbally without an id**: first call \`fab_recall(paths)\` or \`fab_extract_knowledge\` to look it up.
175
+ - **dismissed reason**: enum \`scope-mismatch | outdated | not-applicable | other:<text>\`.
176
+ - **\`KB: none\` sentinel**: two compliant reasons \u2014\u2014 \`[no-relevant]\` you called \`fab_recall\` (or hook output is visible) but no usable entry; \`[not-applicable]\` the current action is not in cite scope (pure exploration / read-only Bash / user Q&A). A bare \`KB: none\` (no suffix) is still valid, classified as \`[unspecified]\` (legacy compatible, annotating later is encouraged).
177
+ - **audit**: \`fabric doctor --cite-coverage [--since=7d] [--client=cc|codex|all]\` reports cite coverage, including the \`KB: none\` sentinel breakdown. This rule does not block your work, it only records.
178
+ - **Clean-slate (no backward compat)**: the parser recognises only the three states \`applied\` / \`dismissed\` / \`none\`; any unrecognised legacy tag (\`planned\` / \`recalled\` / \`chained-from <id>\`) degrades to \`none\` (\`chained-from\`'s embedded id is still rescued as a sibling cite_id). Legacy cites left by old sessions count toward cite-coverage as \`none\`.
179
+ - **Full reference offloaded** (v2.2 SK5): the authoritative details for contract operators / skip\xB7dismissed dictionaries / type routing / audit semantics / **adjudication ladder** (AI self-decide \u2192 multi-LLM incl. zero-context cold review \u2192 non-blocking queue) live in the \`fabric-review\` skill's \`ref/cite-contract.md\` \u2014\u2014 bootstrap keeps only the executable core, governance detail goes to ref so it doesn't bloat bootstrap.
180
+ `;
181
+ var BOOTSTRAP_CANONICAL_BY_LOCALE = {
182
+ "zh-CN": BOOTSTRAP_CANONICAL_ZH,
183
+ en: BOOTSTRAP_CANONICAL_EN
184
+ };
185
+ function resolveBootstrapCanonical(locale) {
186
+ return BOOTSTRAP_CANONICAL_BY_LOCALE[locale ?? resolveGlobalLocale()];
187
+ }
188
+ function matchBootstrapCanonicalLocale(body) {
189
+ for (const locale of Object.keys(BOOTSTRAP_CANONICAL_BY_LOCALE)) {
190
+ if (BOOTSTRAP_CANONICAL_BY_LOCALE[locale] === body) {
191
+ return locale;
192
+ }
193
+ }
194
+ return null;
195
+ }
196
+
197
+ export {
198
+ BOOTSTRAP_MARKER_BEGIN,
199
+ BOOTSTRAP_MARKER_END,
200
+ BOOTSTRAP_REGEX,
201
+ BOOTSTRAP_CANONICAL_ZH,
202
+ BOOTSTRAP_CANONICAL_EN,
203
+ BOOTSTRAP_CANONICAL_BY_LOCALE,
204
+ resolveBootstrapCanonical,
205
+ matchBootstrapCanonicalLocale
206
+ };
@@ -0,0 +1,129 @@
1
+ // src/node/atomic-write.ts
2
+ import { appendFile, mkdir, open, readFile, rename, stat, unlink, writeFile } from "fs/promises";
3
+ import { dirname } from "path";
4
+ import { randomUUID } from "crypto";
5
+ function makeTmpSuffix() {
6
+ const rand = Math.floor(Math.random() * 65535).toString(16).padStart(4, "0");
7
+ return `.${process.pid}.${Date.now()}.${rand}.tmp`;
8
+ }
9
+ async function atomicWriteText(path, content, opts) {
10
+ const tmpPath = path + makeTmpSuffix();
11
+ const shouldFsync = opts?.fsync ?? true;
12
+ try {
13
+ if (shouldFsync) {
14
+ const fd = await open(tmpPath, "w");
15
+ try {
16
+ await fd.writeFile(content, "utf8");
17
+ await fd.datasync();
18
+ } finally {
19
+ await fd.close();
20
+ }
21
+ } else {
22
+ await writeFile(tmpPath, content, "utf8");
23
+ }
24
+ await rename(tmpPath, path);
25
+ } catch (err) {
26
+ try {
27
+ await unlink(tmpPath);
28
+ } catch {
29
+ }
30
+ throw err;
31
+ }
32
+ }
33
+ async function atomicWriteJson(path, value, opts) {
34
+ const indent = opts?.indent ?? 2;
35
+ const content = JSON.stringify(value, null, indent) + "\n";
36
+ await atomicWriteText(path, content, { fsync: opts?.fsync });
37
+ }
38
+ function isErrnoException(err) {
39
+ return err instanceof Error && typeof err.code === "string";
40
+ }
41
+ function sleep(ms) {
42
+ return new Promise((resolve) => setTimeout(resolve, ms));
43
+ }
44
+ async function withFileLock(lockPath, fn, opts = {}) {
45
+ const staleMs = opts.staleMs ?? 1e4;
46
+ const retryDelayMs = opts.retryDelayMs ?? 20;
47
+ const maxWaitMs = opts.maxWaitMs ?? 1e4;
48
+ await mkdir(dirname(lockPath), { recursive: true });
49
+ const token = `${process.pid}.${randomUUID()}`;
50
+ const start = Date.now();
51
+ for (; ; ) {
52
+ let handle;
53
+ try {
54
+ handle = await open(lockPath, "wx");
55
+ } catch (err) {
56
+ if (!isErrnoException(err) || err.code !== "EEXIST") throw err;
57
+ try {
58
+ const st = await stat(lockPath);
59
+ if (Date.now() - st.mtimeMs > staleMs) {
60
+ const staleToken = await readFile(lockPath, "utf8").catch(() => null);
61
+ if (staleToken !== null) {
62
+ await unlinkIfToken(lockPath, staleToken);
63
+ }
64
+ continue;
65
+ }
66
+ } catch {
67
+ continue;
68
+ }
69
+ if (Date.now() - start > maxWaitMs) {
70
+ throw new Error(`withFileLock: timed out acquiring ${lockPath} after ${maxWaitMs}ms`);
71
+ }
72
+ await sleep(retryDelayMs);
73
+ continue;
74
+ }
75
+ try {
76
+ await handle.writeFile(token, "utf8");
77
+ await handle.close();
78
+ return await fn();
79
+ } finally {
80
+ await unlinkIfToken(lockPath, token);
81
+ }
82
+ }
83
+ }
84
+ async function unlinkIfToken(lockPath, expected) {
85
+ try {
86
+ const current = await readFile(lockPath, "utf8");
87
+ if (current === expected) {
88
+ await unlink(lockPath).catch(() => void 0);
89
+ }
90
+ } catch {
91
+ }
92
+ }
93
+ function createLedgerWriteQueue() {
94
+ const chains = /* @__PURE__ */ new Map();
95
+ async function doAppend(path, line) {
96
+ const normalized = line.endsWith("\n") ? line : line + "\n";
97
+ await appendFile(path, normalized, "utf8");
98
+ }
99
+ function enqueue(path, work) {
100
+ const prev = chains.get(path) ?? Promise.resolve();
101
+ const result = prev.catch(() => void 0).then(() => work());
102
+ const chainSlot = result.then(
103
+ () => void 0,
104
+ () => void 0
105
+ );
106
+ chains.set(path, chainSlot);
107
+ chainSlot.finally(() => {
108
+ if (chains.get(path) === chainSlot) {
109
+ chains.delete(path);
110
+ }
111
+ });
112
+ return result;
113
+ }
114
+ return {
115
+ append(path, line) {
116
+ return enqueue(path, () => doAppend(path, line));
117
+ },
118
+ runExclusive(path, fn) {
119
+ return enqueue(path, fn);
120
+ }
121
+ };
122
+ }
123
+
124
+ export {
125
+ atomicWriteText,
126
+ atomicWriteJson,
127
+ withFileLock,
128
+ createLedgerWriteQueue
129
+ };
@@ -25,6 +25,11 @@ var FabricError = class extends Error {
25
25
  };
26
26
  }
27
27
  };
28
+ function hasActionHint(err) {
29
+ if (err === null || typeof err !== "object") return false;
30
+ const candidate = err;
31
+ return typeof candidate.message === "string" && candidate.message.length > 0 && typeof candidate.actionHint === "string" && candidate.actionHint.length > 0;
32
+ }
28
33
 
29
34
  // src/errors/config-error.ts
30
35
  var ConfigError = class extends FabricError {
@@ -39,6 +44,9 @@ var GenericConfigError = class extends ConfigError {
39
44
  var StoreWriteTargetUnresolvedError = class extends ConfigError {
40
45
  code = "store_write_target_unresolved";
41
46
  };
47
+ var PersonalScopeLeakError = class extends ConfigError {
48
+ code = "personal_scope_leak";
49
+ };
42
50
 
43
51
  // src/errors/rule-error.ts
44
52
  var RuleError = class extends FabricError {
@@ -78,10 +86,12 @@ var InitFrameworkUnknownError = class extends InitError {
78
86
 
79
87
  export {
80
88
  FabricError,
89
+ hasActionHint,
81
90
  ConfigError,
82
91
  ConfigPathInvalidError,
83
92
  GenericConfigError,
84
93
  StoreWriteTargetUnresolvedError,
94
+ PersonalScopeLeakError,
85
95
  RuleError,
86
96
  RuleValidationError,
87
97
  IOFabricError,
@@ -18,6 +18,11 @@ declare abstract class FabricError extends Error {
18
18
  fixable: boolean;
19
19
  };
20
20
  }
21
+ type FabricErrorShape = {
22
+ message: string;
23
+ actionHint: string;
24
+ };
25
+ declare function hasActionHint(err: unknown): err is FabricErrorShape;
21
26
 
22
27
  declare abstract class ConfigError extends FabricError {
23
28
  readonly httpStatus = 400;
@@ -31,6 +36,9 @@ declare class GenericConfigError extends ConfigError {
31
36
  declare class StoreWriteTargetUnresolvedError extends ConfigError {
32
37
  readonly code = "store_write_target_unresolved";
33
38
  }
39
+ declare class PersonalScopeLeakError extends ConfigError {
40
+ readonly code = "personal_scope_leak";
41
+ }
34
42
 
35
43
  declare abstract class RuleError extends FabricError {
36
44
  readonly httpStatus: number;
@@ -65,4 +73,4 @@ declare class InitFrameworkUnknownError extends InitError {
65
73
  readonly code = "init_framework_unknown";
66
74
  }
67
75
 
68
- export { ConfigError, ConfigPathInvalidError, FabricError, GenericConfigError, GenericIOError, IOFabricError, InitError, InitFrameworkUnknownError, MCPError, McpToolError, PathEscapeError, RuleError, RuleValidationError, StoreWriteTargetUnresolvedError };
76
+ export { ConfigError, ConfigPathInvalidError, FabricError, type FabricErrorShape, GenericConfigError, GenericIOError, IOFabricError, InitError, InitFrameworkUnknownError, MCPError, McpToolError, PathEscapeError, PersonalScopeLeakError, RuleError, RuleValidationError, StoreWriteTargetUnresolvedError, hasActionHint };
@@ -10,10 +10,12 @@ import {
10
10
  MCPError,
11
11
  McpToolError,
12
12
  PathEscapeError,
13
+ PersonalScopeLeakError,
13
14
  RuleError,
14
15
  RuleValidationError,
15
- StoreWriteTargetUnresolvedError
16
- } from "../chunk-VW5QGPIN.js";
16
+ StoreWriteTargetUnresolvedError,
17
+ hasActionHint
18
+ } from "../chunk-O6GIHZF3.js";
17
19
  export {
18
20
  ConfigError,
19
21
  ConfigPathInvalidError,
@@ -26,7 +28,9 @@ export {
26
28
  MCPError,
27
29
  McpToolError,
28
30
  PathEscapeError,
31
+ PersonalScopeLeakError,
29
32
  RuleError,
30
33
  RuleValidationError,
31
- StoreWriteTargetUnresolvedError
34
+ StoreWriteTargetUnresolvedError,
35
+ hasActionHint
32
36
  };
@@ -1,9 +1,5 @@
1
- type Locale = "en" | "zh-CN";
2
- interface Messages {
3
- [key: string]: string;
4
- }
5
- type TranslationKey = string;
6
- type Translator = (key: TranslationKey, vars?: Record<string, string>) => string;
1
+ import { L as Locale, M as Messages, T as Translator } from '../types-qg4xXVuT.js';
2
+ export { a as TranslationKey } from '../types-qg4xXVuT.js';
7
3
 
8
4
  declare const defaultMessages: Record<Locale, Messages>;
9
5
  declare function createTranslator(locale: Locale, messages?: Record<Locale, Messages>): Translator;
@@ -11,32 +7,42 @@ declare function createTranslator(locale: Locale, messages?: Record<Locale, Mess
11
7
  declare function detectNodeLocale(): Locale;
12
8
 
13
9
  /**
14
- * Resolve the effective runtime locale for a given project root.
10
+ * Resolve the effective runtime locale for a project-scoped command.
15
11
  *
16
- * Resolution order (rc.26 closes KT-DEC-9004 runtime gap):
17
- * 1. Read `<projectRoot>/.fabric/fabric-config.json` and inspect
18
- * `fabric_language`.
19
- * 2. If the value is `"en"` or `"zh-CN"` (the two concrete Locale members),
20
- * return it verbatim this is the eager-resolved value `fabric init` is
21
- * supposed to write back per KT-DEC-9004.
22
- * 3. If the value is `"match-existing"` or `"zh-CN-hybrid"` (placeholders
23
- * that should NEVER survive `fabric init` per KT-DEC-9004's invariant),
24
- * emit a `console.warn` and fall through to `detectNodeLocale()`.
25
- * 4. If the file is missing, unreadable, malformed JSON, or `fabric_language`
26
- * is absent / has any other shape, silently fall through to
27
- * `detectNodeLocale()` (env-driven: `FAB_LANG` → `LANG` → `"en"`).
12
+ * grill-6fixes (D1): language is now a SINGLE machine-wide base tone held in
13
+ * `~/.fabric/fabric-global.json` `language`. The old per-project
14
+ * `fabric_language` field and the README/docs content-detection path were
15
+ * removed, so the `projectRoot` argument is no longer consulted it is kept
16
+ * only so the existing call sites need no signature change. Everything now
17
+ * delegates to {@link resolveGlobalLocale} (global language → env fallback).
28
18
  *
29
- * Never throws — all failure paths degrade to `detectNodeLocale()`.
19
+ * Never throws.
30
20
  */
31
- declare function resolveFabricLocale(projectRoot: string): Locale;
21
+ declare function resolveFabricLocale(_projectRoot?: string): Locale;
22
+
23
+ /**
24
+ * Resolve the effective runtime locale from the single machine-wide language
25
+ * base tone (grill-6fixes D1).
26
+ *
27
+ * Resolution order:
28
+ * 1. `~/.fabric/fabric-global.json` → `language` (`"zh-CN"` | `"en"`), the
29
+ * value the install language selector wrote. This governs BOTH CLI
30
+ * display and knowledge authoring — there is no per-project override.
31
+ * 2. Otherwise fall through to `detectNodeLocale()` (env-driven:
32
+ * `FAB_LANG` → `LANG` → `"en"`), covering the pre-install window and any
33
+ * machine where the user never picked a language.
34
+ *
35
+ * Never throws — every failure path degrades to `detectNodeLocale()`.
36
+ */
37
+ declare function resolveGlobalLocale(globalRoot?: string): Locale;
32
38
 
33
39
  declare function normalizeLocale(raw: string | null | undefined): Locale;
34
40
 
35
- declare const PROTECTED_TOKENS: readonly ["fab_plan_context", "fab_get_knowledge_sections", "fab_extract_knowledge", "fab_review", "AGENTS.md", ".fabric/agents/", ".fabric/agents/_cross/", ".fabric/agents.meta.json", ".fabric/human-lock.json", ".fabric/events.jsonl", ".fabric/knowledge/", "knowledge_proposed", "relevance_scope", "relevance_paths", "narrow", "broad", "source_sessions", "proposed_reason", "session_context", "layer", "team", "personal", "pending_path", "knowledge_scope_degraded", "@HUMAN", "MUST", "NEVER"];
41
+ declare const PROTECTED_TOKENS: readonly ["fab_recall", "fab_plan_context", "fab_get_knowledge_sections", "fab_extract_knowledge", "fab_review", "AGENTS.md", ".fabric/agents/", ".fabric/agents/_cross/", ".fabric/human-lock.json", ".fabric/events.jsonl", "knowledge/pending", "knowledge_proposed", "relevance_scope", "relevance_paths", "narrow", "broad", "source_sessions", "proposed_reason", "session_context", "layer", "team", "personal", "pending_path", "knowledge_scope_degraded", "@HUMAN", "MUST", "NEVER"];
36
42
  type ProtectedToken = (typeof PROTECTED_TOKENS)[number];
37
43
 
38
44
  declare const enMessages: Messages;
39
45
 
40
46
  declare const zhCNMessages: Messages;
41
47
 
42
- export { type Locale, type Messages, PROTECTED_TOKENS, type ProtectedToken, type TranslationKey, type Translator, createTranslator, defaultMessages, detectNodeLocale, enMessages, normalizeLocale, resolveFabricLocale, zhCNMessages };
48
+ export { Locale, Messages, PROTECTED_TOKENS, type ProtectedToken, Translator, createTranslator, defaultMessages, detectNodeLocale, enMessages, normalizeLocale, resolveFabricLocale, resolveGlobalLocale, zhCNMessages };
@@ -2,12 +2,15 @@ import {
2
2
  PROTECTED_TOKENS,
3
3
  createTranslator,
4
4
  defaultMessages,
5
- detectNodeLocale,
6
5
  enMessages,
7
- normalizeLocale,
8
6
  resolveFabricLocale,
9
7
  zhCNMessages
10
- } from "../chunk-QSD4PN4W.js";
8
+ } from "../chunk-B2N3I7UX.js";
9
+ import {
10
+ detectNodeLocale,
11
+ normalizeLocale,
12
+ resolveGlobalLocale
13
+ } from "../chunk-2GLIAZ5M.js";
11
14
  export {
12
15
  PROTECTED_TOKENS,
13
16
  createTranslator,
@@ -16,5 +19,6 @@ export {
16
19
  enMessages,
17
20
  normalizeLocale,
18
21
  resolveFabricLocale,
22
+ resolveGlobalLocale,
19
23
  zhCNMessages
20
24
  };