@fenglimg/fabric-shared 2.2.0-rc.1 → 2.2.0-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-JEXTOQVV.js → chunk-355LUDLW.js} +92 -8
- package/dist/chunk-4N6DMOOW.js +128 -0
- package/dist/{chunk-TX2XZ7AW.js → chunk-AFT7DB4P.js} +6 -5
- package/dist/{chunk-7TZ2PMVH.js → chunk-KUYCTRFI.js} +87 -3
- package/dist/{chunk-3SZRB42B.js → chunk-VDSM73PK.js} +8 -0
- package/dist/errors/index.d.ts +7 -1
- package/dist/errors/index.js +7 -3
- package/dist/i18n/index.js +1 -1
- package/dist/{index-J3Xn5h2J.d.ts → index-BqA89S9q.d.ts} +28 -3
- package/dist/index.d.ts +348 -10
- package/dist/index.js +367 -24
- package/dist/node/atomic-write.js +6 -106
- package/dist/node/mcp-payload-guard.js +1 -1
- package/dist/schemas/api-contracts.d.ts +140 -18
- package/dist/schemas/api-contracts.js +1 -1
- package/dist/templates/bootstrap-canonical.d.ts +1 -1
- package/dist/templates/bootstrap-canonical.js +1 -1
- package/dist/types/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -134,7 +134,13 @@ var planContextOutputSchema = z2.object({
|
|
|
134
134
|
// the new id before issuing fab_get_knowledge_sections / fab_recall. Empty
|
|
135
135
|
// (field omitted) when no actionable redirects exist for the surfaced
|
|
136
136
|
// candidate set. See packages/server/src/services/id-redirect.ts.
|
|
137
|
-
redirects: z2.record(z2.string()).optional()
|
|
137
|
+
redirects: z2.record(z2.string()).optional(),
|
|
138
|
+
// lifecycle-refactor W3-T2 (§7 图谱消费): related-expansion provenance map
|
|
139
|
+
// (appended id → surfaced source id). Present only when `include_related` was
|
|
140
|
+
// requested AND at least one in-corpus one-hop neighbour was appended. Omitted
|
|
141
|
+
// on the graph-empty / steady-state path. Additive — declare it here or zod
|
|
142
|
+
// strips it on output validation.
|
|
143
|
+
related_appended: z2.record(z2.string()).optional()
|
|
138
144
|
});
|
|
139
145
|
var planContextAnnotations = {
|
|
140
146
|
readOnlyHint: true,
|
|
@@ -161,7 +167,9 @@ var knowledgeSectionsInputSchema = z2.object({
|
|
|
161
167
|
ai_selected_stable_ids: z2.array(z2.string()).describe(
|
|
162
168
|
"Stable ids picked from fab_plan_context candidates[].stable_id; choose 1..N to fetch bodies for"
|
|
163
169
|
),
|
|
164
|
-
ai_selection_reasons: z2.record(z2.string().min(1)).describe(
|
|
170
|
+
ai_selection_reasons: z2.record(z2.string().min(1)).optional().default({}).describe(
|
|
171
|
+
"Optional reason for each AI-selected L1 stable_id (audit telemetry). Omit to fetch bodies without annotating \u2014 server defaults to {} rather than rejecting the documented two-step call."
|
|
172
|
+
),
|
|
165
173
|
correlation_id: z2.string().optional().describe("Optional caller-provided correlation id for Event Ledger records"),
|
|
166
174
|
session_id: z2.string().optional().describe("Optional caller-provided session id for Event Ledger records"),
|
|
167
175
|
// v2.0 rc.5 TASK-014 (C5): optional client identity hash propagated into
|
|
@@ -196,7 +204,7 @@ var knowledgeSectionsOutputSchema = z2.object({
|
|
|
196
204
|
// for un-migrated v1.x entries (no knowledge_type AND no knowledge_layer
|
|
197
205
|
// in frontmatter). Does NOT block selection.
|
|
198
206
|
z2.object({
|
|
199
|
-
code: z2.
|
|
207
|
+
code: z2.enum(["missing_knowledge_metadata", "unresolved_selected_id"]),
|
|
200
208
|
severity: z2.literal("warn"),
|
|
201
209
|
stable_id: z2.string(),
|
|
202
210
|
message: z2.string()
|
|
@@ -279,13 +287,21 @@ var recallOutputSchema = z2.object({
|
|
|
279
287
|
stable_id: z2.string(),
|
|
280
288
|
level: z2.enum(["L0", "L1", "L2"]),
|
|
281
289
|
path: z2.string(),
|
|
282
|
-
body: z2.string()
|
|
290
|
+
body: z2.string(),
|
|
291
|
+
// lifecycle-refactor W3-T4 (§2 store 轴 / store-qualified 观测 / D7 物理 store
|
|
292
|
+
// 边界对 AI 可见): per-rule store provenance so the caller can trace which
|
|
293
|
+
// store each recalled entry came from. cross-store-recall already prefixes
|
|
294
|
+
// store entries `<alias>:<stable_id>`; this surfaces that as a structured
|
|
295
|
+
// field (`{ alias }`) instead of forcing the caller to parse the id. Omitted
|
|
296
|
+
// for project-local entries (no alias prefix). Additive — declare it or zod
|
|
297
|
+
// strips it on output validation.
|
|
298
|
+
store: z2.object({ alias: z2.string() }).optional()
|
|
283
299
|
})
|
|
284
300
|
),
|
|
285
301
|
selected_stable_ids: z2.array(z2.string()),
|
|
286
302
|
diagnostics: z2.array(
|
|
287
303
|
z2.object({
|
|
288
|
-
code: z2.
|
|
304
|
+
code: z2.enum(["missing_knowledge_metadata", "unresolved_selected_id"]),
|
|
289
305
|
severity: z2.literal("warn"),
|
|
290
306
|
stable_id: z2.string(),
|
|
291
307
|
message: z2.string()
|
|
@@ -371,8 +387,12 @@ var PROPOSED_REASON_DESCRIPTIONS = {
|
|
|
371
387
|
var _sourceSessionsField = z2.array(z2.string().min(1)).min(1);
|
|
372
388
|
var _FabExtractKnowledgeInputBaseSchema = z2.object({
|
|
373
389
|
// v2.0.0-rc.7 T5: array form. rc.23 dropped the legacy single-string alias.
|
|
374
|
-
|
|
375
|
-
|
|
390
|
+
// v2.2 全砍 F13: REQUIRED in the base schema (was `.optional()`) so the MCP
|
|
391
|
+
// tool's advertised inputSchema (registerTool reads `.shape`) matches the
|
|
392
|
+
// requirement the superRefine enforces. Previously a caller reading the schema
|
|
393
|
+
// saw it optional, omitted it, and got rejected at parse — a contract lie.
|
|
394
|
+
source_sessions: _sourceSessionsField.describe(
|
|
395
|
+
"Originating session ids (REQUIRED, non-empty array); correlates with Event Ledger records. Array form (T5+, rc.23 made it the sole accepted shape)."
|
|
376
396
|
),
|
|
377
397
|
recent_paths: z2.array(z2.string()).describe("Workspace paths recently touched in the source session \u2014 used as scope hints"),
|
|
378
398
|
user_messages_summary: z2.string().describe("Skill-side summary of the user's intent/messages, kept compact"),
|
|
@@ -804,7 +824,71 @@ var citeCoverageReportSchema = z2.object({
|
|
|
804
824
|
// expected_but_missed. >0 typically means a stale pre-session_id hook is
|
|
805
825
|
// installed (run `fabric install`). Surfaced so the denominator gap is
|
|
806
826
|
// visible rather than a silent 100% confound.
|
|
807
|
-
uncorrelatable_edits: z2.number().int().nonnegative().optional()
|
|
827
|
+
uncorrelatable_edits: z2.number().int().nonnegative().optional(),
|
|
828
|
+
// v2.1 ⑤ cite-redesign (P5): recall-based coverage口径. The redesign infers
|
|
829
|
+
// a citation from real behavior — an in-session fab_recall
|
|
830
|
+
// (knowledge_context_planned) whose target_paths overlap a subsequently
|
|
831
|
+
// edited file IS the citation, no hand-written `KB:` line required.
|
|
832
|
+
// recall_backed_edits = correlatable edits preceded (within the recall
|
|
833
|
+
// window) by such an overlapping recall. recall_coverage_rate =
|
|
834
|
+
// recall_backed_edits / edits_touched (null when no edits). Additive — the
|
|
835
|
+
// legacy first-line-`KB:` metrics above are unchanged (back-compat).
|
|
836
|
+
recall_backed_edits: z2.number().int().nonnegative().optional(),
|
|
837
|
+
recall_coverage_rate: z2.number().min(0).max(1).nullable().optional(),
|
|
838
|
+
// v2.2.0-rc.1 W1-T3 (cite 诚实拆分 / lifecycle §3): exposed_and_mutated is a
|
|
839
|
+
// WEAK auxiliary signal — strictly SEPARATE from cite_compliance_rate (which
|
|
840
|
+
// is the true explicit-adherence rate, currently ~2.5%). It MUST NOT be
|
|
841
|
+
// merged into compliance: it estimates "a narrow PreToolUse-surfaced KB id
|
|
842
|
+
// whose contract-specific glob was subsequently edited (mutated) in the same
|
|
843
|
+
// session, and was not [dismissed] that round". It credits NOTHING toward the
|
|
844
|
+
// real `KB:`-line compliance — it is an observational hint that surfaced
|
|
845
|
+
// knowledge influenced an edit, surfaced ONLY as its own field so the renderer
|
|
846
|
+
// can label it "weak signal, NOT counted toward true adherence". Three
|
|
847
|
+
// conditions (all required): (1) id came from a `hook_surface_emitted` with
|
|
848
|
+
// hook_name === "knowledge-hint-narrow"; (2) the id's contract glob is
|
|
849
|
+
// SPECIFIC (excludes `**/*` wildcards and generic guideline-type entries);
|
|
850
|
+
// (3) the id was not [dismissed] in the same session. `count` = number of
|
|
851
|
+
// distinct (session_id, stable_id) pairs satisfying all three; `ids` =
|
|
852
|
+
// sorted distinct stable_ids (capped, diagnostics only). Always >= 0; null/
|
|
853
|
+
// absent on degraded/skipped reports.
|
|
854
|
+
exposed_and_mutated: z2.object({
|
|
855
|
+
count: z2.number().int().nonnegative(),
|
|
856
|
+
ids: z2.array(z2.string()).optional()
|
|
857
|
+
}).optional(),
|
|
858
|
+
// lifecycle-refactor W2-T4 (§5 row7 PostToolUse / §0 下沉 doctor): mutation
|
|
859
|
+
// funnel rebuilt offline from the new `file_mutated` PostToolUse marker —
|
|
860
|
+
// the权威 signal that a mutation actually completed (path + tool_call_id),
|
|
861
|
+
// distinct from the PreToolUse `edit_intent_checked` EDIT-INTENT signal that
|
|
862
|
+
// feeds `edits_touched`. mutations_observed.count = number of distinct
|
|
863
|
+
// `file_mutated` events in window (per-call tool_call_id dedup guards the
|
|
864
|
+
// PostToolUse parallel-fire race). Strictly ADDITIVE — never folded into
|
|
865
|
+
// cite_compliance_rate (honesty 铁律, mirrors exposed_and_mutated). Absent on
|
|
866
|
+
// degraded/skipped reports.
|
|
867
|
+
mutations_observed: z2.object({
|
|
868
|
+
count: z2.number().int().nonnegative()
|
|
869
|
+
}).optional(),
|
|
870
|
+
// lifecycle-refactor W2-T4 (§5 row7 mutation_pool + downgrade): low-confidence
|
|
871
|
+
// mutation attribution pool. A `file_mutated` event is `attributed` ONLY when
|
|
872
|
+
// its `source_event_id` links back to a `hook_surface_emitted` (surfaced/cited
|
|
873
|
+
// knowledge) in window — attribution key = store_id + stable_id +
|
|
874
|
+
// source_event_id (distinct dedup so multi-store never double-counts). Every
|
|
875
|
+
// other mutation (no source_event_id, or a source_event_id that does not
|
|
876
|
+
// resolve to a surfaced event) downgrades to `unattributed_workspace_dirty`.
|
|
877
|
+
// NOTE: this is the events.jsonl-only attribution. The §9 git-diff fallback
|
|
878
|
+
// (升 fallback via session shell event + baseline) is a SPECULATIVE
|
|
879
|
+
// implementation note — deliberately NOT run here (doctor stays read-only,
|
|
880
|
+
// no git diff / no disk write). Additive; absent on degraded/skipped reports.
|
|
881
|
+
mutation_pool: z2.object({
|
|
882
|
+
attributed: z2.number().int().nonnegative(),
|
|
883
|
+
unattributed_workspace_dirty: z2.number().int().nonnegative()
|
|
884
|
+
}).optional(),
|
|
885
|
+
// lifecycle-refactor W2-T4 (§5 row2 SessionEnd funnel 对账下沉 doctor): the
|
|
886
|
+
// SessionEnd hook only O(1)-appends a `session_ended` marker; this counts the
|
|
887
|
+
// distinct sessions that emitted one (funnel "closed" boundary). Purely an
|
|
888
|
+
// observability marker — not joined into any rate. Additive.
|
|
889
|
+
sessions_closed: z2.object({
|
|
890
|
+
count: z2.number().int().nonnegative()
|
|
891
|
+
}).optional()
|
|
808
892
|
}),
|
|
809
893
|
per_client: z2.record(
|
|
810
894
|
z2.string(),
|
|
@@ -0,0 +1,128 @@
|
|
|
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
|
+
try {
|
|
12
|
+
if (opts?.fsync) {
|
|
13
|
+
const fd = await open(tmpPath, "w");
|
|
14
|
+
try {
|
|
15
|
+
await fd.writeFile(content, "utf8");
|
|
16
|
+
await fd.datasync();
|
|
17
|
+
} finally {
|
|
18
|
+
await fd.close();
|
|
19
|
+
}
|
|
20
|
+
} else {
|
|
21
|
+
await writeFile(tmpPath, content, "utf8");
|
|
22
|
+
}
|
|
23
|
+
await rename(tmpPath, path);
|
|
24
|
+
} catch (err) {
|
|
25
|
+
try {
|
|
26
|
+
await unlink(tmpPath);
|
|
27
|
+
} catch {
|
|
28
|
+
}
|
|
29
|
+
throw err;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function atomicWriteJson(path, value, opts) {
|
|
33
|
+
const indent = opts?.indent ?? 2;
|
|
34
|
+
const content = JSON.stringify(value, null, indent) + "\n";
|
|
35
|
+
await atomicWriteText(path, content, { fsync: opts?.fsync });
|
|
36
|
+
}
|
|
37
|
+
function isErrnoException(err) {
|
|
38
|
+
return err instanceof Error && typeof err.code === "string";
|
|
39
|
+
}
|
|
40
|
+
function sleep(ms) {
|
|
41
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
42
|
+
}
|
|
43
|
+
async function withFileLock(lockPath, fn, opts = {}) {
|
|
44
|
+
const staleMs = opts.staleMs ?? 1e4;
|
|
45
|
+
const retryDelayMs = opts.retryDelayMs ?? 20;
|
|
46
|
+
const maxWaitMs = opts.maxWaitMs ?? 1e4;
|
|
47
|
+
await mkdir(dirname(lockPath), { recursive: true });
|
|
48
|
+
const token = `${process.pid}.${randomUUID()}`;
|
|
49
|
+
const start = Date.now();
|
|
50
|
+
for (; ; ) {
|
|
51
|
+
let handle;
|
|
52
|
+
try {
|
|
53
|
+
handle = await open(lockPath, "wx");
|
|
54
|
+
} catch (err) {
|
|
55
|
+
if (!isErrnoException(err) || err.code !== "EEXIST") throw err;
|
|
56
|
+
try {
|
|
57
|
+
const st = await stat(lockPath);
|
|
58
|
+
if (Date.now() - st.mtimeMs > staleMs) {
|
|
59
|
+
const staleToken = await readFile(lockPath, "utf8").catch(() => null);
|
|
60
|
+
if (staleToken !== null) {
|
|
61
|
+
await unlinkIfToken(lockPath, staleToken);
|
|
62
|
+
}
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
} catch {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (Date.now() - start > maxWaitMs) {
|
|
69
|
+
throw new Error(`withFileLock: timed out acquiring ${lockPath} after ${maxWaitMs}ms`);
|
|
70
|
+
}
|
|
71
|
+
await sleep(retryDelayMs);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
await handle.writeFile(token, "utf8");
|
|
76
|
+
await handle.close();
|
|
77
|
+
return await fn();
|
|
78
|
+
} finally {
|
|
79
|
+
await unlinkIfToken(lockPath, token);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function unlinkIfToken(lockPath, expected) {
|
|
84
|
+
try {
|
|
85
|
+
const current = await readFile(lockPath, "utf8");
|
|
86
|
+
if (current === expected) {
|
|
87
|
+
await unlink(lockPath).catch(() => void 0);
|
|
88
|
+
}
|
|
89
|
+
} catch {
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function createLedgerWriteQueue() {
|
|
93
|
+
const chains = /* @__PURE__ */ new Map();
|
|
94
|
+
async function doAppend(path, line) {
|
|
95
|
+
const normalized = line.endsWith("\n") ? line : line + "\n";
|
|
96
|
+
await appendFile(path, normalized, "utf8");
|
|
97
|
+
}
|
|
98
|
+
function enqueue(path, work) {
|
|
99
|
+
const prev = chains.get(path) ?? Promise.resolve();
|
|
100
|
+
const result = prev.catch(() => void 0).then(() => work());
|
|
101
|
+
const chainSlot = result.then(
|
|
102
|
+
() => void 0,
|
|
103
|
+
() => void 0
|
|
104
|
+
);
|
|
105
|
+
chains.set(path, chainSlot);
|
|
106
|
+
chainSlot.finally(() => {
|
|
107
|
+
if (chains.get(path) === chainSlot) {
|
|
108
|
+
chains.delete(path);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
append(path, line) {
|
|
115
|
+
return enqueue(path, () => doAppend(path, line));
|
|
116
|
+
},
|
|
117
|
+
runExclusive(path, fn) {
|
|
118
|
+
return enqueue(path, fn);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export {
|
|
124
|
+
atomicWriteText,
|
|
125
|
+
atomicWriteJson,
|
|
126
|
+
withFileLock,
|
|
127
|
+
createLedgerWriteQueue
|
|
128
|
+
};
|
|
@@ -42,9 +42,9 @@ var BOOTSTRAP_CANONICAL = `# Fabric Bootstrap
|
|
|
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
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
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
|
+
- **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
|
|
46
46
|
- **Language**:\u6E32\u67D3\u6309 \`.fabric/fabric-config.json\` \u7684 \`fabric_language\` \u5B57\u6BB5\u3002
|
|
47
|
-
- **Archive cadence nudge** (rc.36): \u6BCF\u5B8C\u6210
|
|
47
|
+
- **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
|
|
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
50
|
## Self-archive policy (v2.0.0-rc.37 NEW-2: \u7B80\u5316 4 \u4FE1\u53F7 \u2192 2 \u5927\u7C7B)
|
|
@@ -75,10 +75,11 @@ var BOOTSTRAP_CANONICAL = `# Fabric Bootstrap
|
|
|
75
75
|
|
|
76
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
|
|
77
77
|
|
|
78
|
-
## Cite policy (v2.
|
|
78
|
+
## Cite policy (v2.1 \u2464 recall-based: \u81EA\u52A8\u8BB0\u8D26\u4F18\u5148, \u9996\u884C KB: \u53EF\u9009 override)
|
|
79
79
|
|
|
80
|
-
- **\
|
|
81
|
-
-
|
|
80
|
+
- **\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
|
|
81
|
+
- **\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
|
|
82
|
+
- **\`[applied]\` \u9A8C\u8BC1\u4E49\u52A1**: \u5F15\u7528\u4EFB\u4F55 id(\u81EA\u52A8\u6216\u624B\u5199)\u7684\u524D\u63D0\u662F\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
83
|
- **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
|
|
83
84
|
- **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
|
|
84
85
|
- **skip reason \u8BCD\u5178**: \`sequencing | conditional | semantic | aesthetic | architectural | other:<text>\`\u3002
|
|
@@ -116,6 +116,18 @@ var enMessages = {
|
|
|
116
116
|
"doctor.cite.metric.complianceRate": "cite compliance rate (incl. KB:none[reason])",
|
|
117
117
|
"doctor.cite.metric.complianceNA": "N/A (no cite-expected turns)",
|
|
118
118
|
"doctor.cite.metric.uncorrelatableEdits": "Uncorrelatable edits (no session_id \u2014 stale hook? run `fabric install`)",
|
|
119
|
+
"doctor.cite.metric.recallCoverage": "recall coverage (edits preceded by a relevant fab_recall)",
|
|
120
|
+
"doctor.cite.metric.recallCoverageNA": "N/A (no correlatable edits)",
|
|
121
|
+
// v2.2.0-rc.1 W1-T3 (cite 诚实拆分): WEAK auxiliary signal, rendered separately
|
|
122
|
+
// from the compliance rate. The parenthetical MUST state it is not counted
|
|
123
|
+
// toward true adherence (honesty 铁律).
|
|
124
|
+
"doctor.cite.metric.exposedAndMutated": "exposed & mutated (weak auxiliary signal \u2014 NOT counted toward true adherence)",
|
|
125
|
+
// lifecycle-refactor W2-T4 (§5 row7/row2): PostToolUse mutation funnel +
|
|
126
|
+
// SessionEnd boundary. Observability markers, NOT folded into adherence.
|
|
127
|
+
"doctor.cite.metric.mutationsObserved": "mutations observed (PostToolUse file_mutated \u2014 authoritative, NOT counted toward adherence)",
|
|
128
|
+
"doctor.cite.metric.mutationPool": "mutation pool (low-confidence attribution via source_event_id)",
|
|
129
|
+
"doctor.cite.metric.sessionsClosed": "sessions closed (SessionEnd markers \u2014 funnel boundary)",
|
|
130
|
+
"doctor.cite.metric.byStore": "qualifying cites by store (diagnostic split \u2014 NOT counted toward adherence; 'local' = project)",
|
|
119
131
|
"doctor.cite.section.perClient": "Per-client",
|
|
120
132
|
"doctor.cite.section.dismissedReasons": "Dismissed reasons",
|
|
121
133
|
"doctor.cite.dismissed.scope-mismatch": "Scope mismatch",
|
|
@@ -180,6 +192,16 @@ var enMessages = {
|
|
|
180
192
|
// v2.0.0-rc.24 TASK-10: --layer filters cite contract audit by KB layer (team|personal|all).
|
|
181
193
|
"cli.doctor.args.layer.description": "Filter cite contract audit by KB layer (team|personal|all)",
|
|
182
194
|
"cli.doctor.errors.cite-coverage-mutex": "--cite-coverage cannot be combined with --fix or --fix-knowledge",
|
|
195
|
+
"cli.doctor.errors.lint-conflicts-mutex": "--lint-conflicts cannot be combined with --fix, --fix-knowledge or --cite-coverage",
|
|
196
|
+
"cli.doctor.args.lint-conflicts.description": "Lint the knowledge base for conflicting/duplicate entry pairs (bm25 candidates)",
|
|
197
|
+
"cli.doctor.args.deep.description": "With --lint-conflicts: run the LLM judge over candidates (cold-eval seam)",
|
|
198
|
+
"doctor.conflict.header": "Knowledge conflict lint",
|
|
199
|
+
"doctor.conflict.none": "No candidate conflicting/duplicate pairs found",
|
|
200
|
+
"doctor.conflict.summary": "{candidates} candidate pair(s), {conflicts} judged conflict(s) (similarity \u2265 {threshold})",
|
|
201
|
+
"doctor.conflict.deep_no_judge": "--deep requested but no LLM judge is wired (run the cold-eval review manually); showing cheap candidates",
|
|
202
|
+
"doctor.conflict.verdict.conflict": "conflict",
|
|
203
|
+
"doctor.conflict.verdict.similar": "similar (possible duplicate)",
|
|
204
|
+
"doctor.conflict.verdict.unknown": "review (possible duplicate or conflict)",
|
|
183
205
|
"cli.doctor.errors.invalid-since": "Invalid --since value: {input}. Expected duration like 7d, 24h, 30m or epoch ms.",
|
|
184
206
|
"cli.doctor.errors.invalid-client": "Invalid --client value: {input}. Expected cc, codex, cursor, or all.",
|
|
185
207
|
"cli.doctor.errors.invalid-layer": "Invalid --layer value: {input}. Expected team, personal, or all.",
|
|
@@ -281,7 +303,7 @@ var enMessages = {
|
|
|
281
303
|
"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
304
|
"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
305
|
"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`
|
|
306
|
+
"doctor.check.events_jsonl_health.remediation": "Run `fabric doctor --fix` \u2014 it triggers a rotation AND flushes metrics.jsonl (rc.2 F16: clears idle-buffered metric counters without a server restart). If the warning persists, restart the MCP server so startMetricsFlush + startRotationTick reschedule. If metric_leak fires, audit recent code changes for direct appendEventLedgerEvent calls bypassing bumpCounter for one of the 4 metric-managed event_types.",
|
|
285
307
|
"doctor.check.mcp_config_in_wrong_file.name": "Claude MCP config location",
|
|
286
308
|
"doctor.check.mcp_config_in_wrong_file.message": ".claude/settings.json contains mcpServers.fabric \u2014 this file is for hooks/permissions only. Run --fix to remove it, then re-run fabric install to write .mcp.json.",
|
|
287
309
|
"doctor.check.mcp_config_in_wrong_file.remediation": "Run `fabric doctor --fix` to remove mcpServers.fabric from .claude/settings.json, then run `fabric install` to write .mcp.json.",
|
|
@@ -368,6 +390,11 @@ var enMessages = {
|
|
|
368
390
|
"doctor.check.counter_desync.message.plural": "{count} knowledge counters desynced from observed stable_ids. {counterPath} = {current} but observed {observedId}. Run `fabric doctor --fix` to bump counters.",
|
|
369
391
|
"doctor.check.counter_desync.remediation": "Run `fabric doctor --fix` to bump agents.meta.json counters to the maximum observed counter value.",
|
|
370
392
|
"doctor.check.counter_desync.ok": "agents.meta.json counters envelope is consistent with observed stable_ids.",
|
|
393
|
+
"doctor.check.store_counter_drift.name": "Store counter drift",
|
|
394
|
+
"doctor.check.store_counter_drift.message.singular": "{count} store counter is below its on-disk max stable_id ({detail}). The next allocation in that store would re-mint an existing id. Run `fabric doctor --fix` to floor the store counters.json.",
|
|
395
|
+
"doctor.check.store_counter_drift.message.plural": "{count} store counters are below their on-disk max stable_id ({detail}). The next allocation in those stores would re-mint an existing id. Run `fabric doctor --fix` to floor the store counters.json.",
|
|
396
|
+
"doctor.check.store_counter_drift.remediation": "Run `fabric doctor --fix` to floor each store's counters.json at the highest stable_id observed on disk (the floor never lowers \u2014 KT-DEC-0004 monotonic invariant).",
|
|
397
|
+
"doctor.check.store_counter_drift.ok": "Every read-set store's counters.json is floored at its on-disk max stable_id.",
|
|
371
398
|
"doctor.check.preexisting_root_files.name": "Preexisting root markdown",
|
|
372
399
|
"doctor.check.preexisting_root_files.ok": "No CLAUDE.md or AGENTS.md detected at project root.",
|
|
373
400
|
"doctor.check.preexisting_root_files.message": "{files} detected at project root. These root files are not auto-loaded by Fabric MCP.",
|
|
@@ -507,6 +534,11 @@ var enMessages = {
|
|
|
507
534
|
"doctor.check.knowledge_summary_opaque.ok": "{opaque}/{total} entries have summary == stable_id; opacity ratio is within the healthy band.",
|
|
508
535
|
"doctor.check.knowledge_summary_opaque.message.warn": "{opaque}/{total} entries ({pct}%) have description.summary equal to their stable_id, exceeding the {threshold}% threshold. Narrow-hint output renders as `<id> \xB7 <id>`, signaling nothing useful, and AI clients skip the fetch. First opaque: {sample}.",
|
|
509
536
|
"doctor.check.knowledge_summary_opaque.remediation": "Run the fabric-review skill to rewrite opaque summaries with one short human-readable phrase. The rc.35 hint renderer fallback (TASK-06) will also synthesize a temporary summary from the entry's `## Summary` section.",
|
|
537
|
+
// v2.2 W4 (G-GUARD / A6): store scope lint.
|
|
538
|
+
"doctor.check.store_scope_lint.name": "Store scope lint",
|
|
539
|
+
"doctor.check.store_scope_lint.ok": "All read-set store entries carry valid scope metadata (semantic_scope + visibility_store, no personal leak, no dangling project).",
|
|
540
|
+
"doctor.check.store_scope_lint.message": "{total} store scope issue(s): {breakdown}. e.g. {sample}.",
|
|
541
|
+
"doctor.check.store_scope_lint.remediation": "Run `fabric store backfill-scope` to add missing semantic_scope/visibility_store; `fabric store re-scope` to fix a dangling project: coordinate; move any personal-scope entry out of a shared store (personal knowledge lives only in your personal store, R5#3).",
|
|
510
542
|
"doctor.check.skill_md_yaml_invalid.name": "Skill markdown YAML",
|
|
511
543
|
"doctor.check.skill_md_yaml_invalid.ok": "All .claude/.codex SKILL.md frontmatter values parse as strict YAML.",
|
|
512
544
|
"doctor.check.skill_md_yaml_invalid.message.singular": "{count} SKILL.md frontmatter value contains an unquoted ': ' that strict YAML parsers reject (Claude Code tolerates it; Codex CLI drops the skill at load). First: {detail}.",
|
|
@@ -554,6 +586,8 @@ var enMessages = {
|
|
|
554
586
|
"cli.install.args.debug.description": "Print target resolution details to stderr.",
|
|
555
587
|
"cli.install.args.yes.description": "Accept the current install plan and run without the TTY wizard",
|
|
556
588
|
"cli.install.args.dry-run.description": "Print the install plan without writing files or running follow-up stages",
|
|
589
|
+
"cli.install.args.enable-embed.description": "Opt in to vector semantic search (sets embed_enabled + embed_model; prints fastembed install steps)",
|
|
590
|
+
"cli.install.args.embed-model.description": "With --enable-embed: override the pinned embed model (default fast-bge-small-zh-v1.5)",
|
|
557
591
|
// rc.35 TASK-08 (P0-5/6): --force-skills-only.
|
|
558
592
|
"cli.install.args.force-skills-only.description": "Skip bootstrap / MCP / hooks / settings; refresh ONLY the fabric Skill template copies (.claude/.codex/.cursor/skills/*).",
|
|
559
593
|
"cli.install.force-skills-only.banner": "Refreshing fabric Skill templates only",
|
|
@@ -628,6 +662,7 @@ var enMessages = {
|
|
|
628
662
|
// sessions won't pick up the new mcp config until they restart.
|
|
629
663
|
"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
664
|
"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.',
|
|
665
|
+
"cli.install.store-bind-nudge": "\u{1F4A1} Mounted store(s) not bound to this project: {aliases}. Run `fabric store bind {first}` to read their knowledge here, then `fabric store switch-write {first}` to write team knowledge into it.",
|
|
631
666
|
"cli.install.capabilities.none": "No supported client was detected for bootstrap or MCP follow-up.",
|
|
632
667
|
"cli.install.capabilities.header.client": "Client",
|
|
633
668
|
"cli.install.capabilities.header.bootstrap": "Bootstrap",
|
|
@@ -972,6 +1007,12 @@ var enMessages = {
|
|
|
972
1007
|
"cli.store.detached": "detached '{alias}' \u2014 on-disk store tree left intact (detach \u2260 delete)",
|
|
973
1008
|
"cli.store.bound": "bound required store '{id}' ({count} required)",
|
|
974
1009
|
"cli.store.switch-write": "active write store set to '{alias}' for this project",
|
|
1010
|
+
"cli.store.migrate.none": "no project-local knowledge to migrate (dual-root is empty)",
|
|
1011
|
+
"cli.store.migrate.dry-run-header": "migration preview (dry-run, nothing written):",
|
|
1012
|
+
"cli.store.migrate.applied-header": "migrated {count} entries into stores:",
|
|
1013
|
+
"cli.store.migrate.committed": "committed migration changes in the store repo",
|
|
1014
|
+
"cli.store.migrate.remap-note": " \u2191 remapped {oldId} \u2192 {newId} (target store id collision)",
|
|
1015
|
+
"cli.store.migrate.skips-header": "skipped {count} item(s):",
|
|
975
1016
|
"cli.sync.deferred": "{count} store(s) offline \u2014 push deferred; re-run `fabric sync` when online",
|
|
976
1017
|
"cli.sync.paused": "sync paused on a conflict \u2014 resolve it, then run `fabric sync --continue` (or `--abort`)",
|
|
977
1018
|
"cli.metrics.invalid-since": '--since: invalid duration "{raw}" (expected e.g. 24h, 7d, 30m)',
|
|
@@ -1113,6 +1154,17 @@ var zhCNMessages = {
|
|
|
1113
1154
|
"doctor.cite.metric.complianceRate": "cite \u5408\u89C4\u7387 (\u542B KB:none[reason])",
|
|
1114
1155
|
"doctor.cite.metric.complianceNA": "N/A (\u65E0\u5E94 cite \u56DE\u5408)",
|
|
1115
1156
|
"doctor.cite.metric.uncorrelatableEdits": "\u65E0\u6CD5\u5173\u8054\u7684 edit (\u7F3A session_id \u2014 hook \u8FC7\u671F? \u8BF7\u8DD1 `fabric install`)",
|
|
1157
|
+
"doctor.cite.metric.recallCoverage": "recall \u8986\u76D6\u7387 (\u6539\u524D\u6709\u76F8\u5173 fab_recall \u7684 edit \u5360\u6BD4)",
|
|
1158
|
+
"doctor.cite.metric.recallCoverageNA": "N/A (\u65E0\u53EF\u5173\u8054 edit)",
|
|
1159
|
+
// v2.2.0-rc.1 W1-T3 (cite 诚实拆分): 弱辅助信号, 与真遵循率分列展示。括注必须
|
|
1160
|
+
// 明确「不计入真遵循度」(诚实铁律)。
|
|
1161
|
+
"doctor.cite.metric.exposedAndMutated": "\u66DD\u5149\u4E14\u8DEF\u5F84\u53D8\u66F4 (\u5F31\u8F85\u52A9\u4FE1\u53F7 \u2014 \u4E0D\u8BA1\u5165\u771F\u9075\u5FAA\u5EA6)",
|
|
1162
|
+
// lifecycle-refactor W2-T4 (§5 row7/row2): PostToolUse mutation funnel +
|
|
1163
|
+
// SessionEnd 边界。均为可观测性 marker, 不计入真遵循度。
|
|
1164
|
+
"doctor.cite.metric.mutationsObserved": "mutation \u89C2\u6D4B\u6570 (PostToolUse file_mutated \u2014 \u6743\u5A01\u4FE1\u53F7, \u4E0D\u8BA1\u5165\u771F\u9075\u5FAA\u5EA6)",
|
|
1165
|
+
"doctor.cite.metric.mutationPool": "mutation \u5F52\u56E0\u6C60 (\u7ECF source_event_id \u7684 low-confidence \u5F52\u56E0)",
|
|
1166
|
+
"doctor.cite.metric.sessionsClosed": "\u5DF2\u95ED\u5408 session \u6570 (SessionEnd marker \u2014 funnel \u8FB9\u754C)",
|
|
1167
|
+
"doctor.cite.metric.byStore": "\u6309 store \u62C6\u5206\u7684\u5408\u89C4 cite \u6570 (\u8BCA\u65AD\u62C6\u5206 \u2014 \u4E0D\u8BA1\u5165\u771F\u9075\u5FAA\u5EA6; 'local' = \u672C\u9879\u76EE)",
|
|
1116
1168
|
"doctor.cite.section.perClient": "\u6309\u5BA2\u6237\u7AEF\u62C6\u5206",
|
|
1117
1169
|
"doctor.cite.section.dismissedReasons": "\u9A73\u56DE\u539F\u56E0\u5206\u5E03",
|
|
1118
1170
|
"doctor.cite.dismissed.scope-mismatch": "\u8303\u56F4\u4E0D\u7B26",
|
|
@@ -1175,6 +1227,16 @@ var zhCNMessages = {
|
|
|
1175
1227
|
// v2.0.0-rc.24 TASK-10: --layer 过滤 cite 合约审计的知识层 (team|personal|all)。
|
|
1176
1228
|
"cli.doctor.args.layer.description": "\u6309\u77E5\u8BC6\u5C42\u8FC7\u6EE4 cite \u5408\u7EA6\u5BA1\u8BA1 (team|personal|all)",
|
|
1177
1229
|
"cli.doctor.errors.cite-coverage-mutex": "--cite-coverage \u4E0D\u80FD\u4E0E --fix \u6216 --fix-knowledge \u540C\u65F6\u4F7F\u7528",
|
|
1230
|
+
"cli.doctor.errors.lint-conflicts-mutex": "--lint-conflicts \u4E0D\u80FD\u4E0E --fix / --fix-knowledge / --cite-coverage \u540C\u65F6\u4F7F\u7528",
|
|
1231
|
+
"cli.doctor.args.lint-conflicts.description": "\u4F53\u68C0\u77E5\u8BC6\u5E93\u4E2D\u4E92\u76F8\u77DB\u76FE/\u91CD\u590D\u7684\u6761\u76EE\u5BF9 (bm25 \u5019\u9009)",
|
|
1232
|
+
"cli.doctor.args.deep.description": "\u914D\u5408 --lint-conflicts: \u5BF9\u5019\u9009\u5BF9\u8DD1 LLM \u5224\u5B9A (\u51B7\u8BC4 seam)",
|
|
1233
|
+
"doctor.conflict.header": "\u77E5\u8BC6\u51B2\u7A81\u4F53\u68C0",
|
|
1234
|
+
"doctor.conflict.none": "\u672A\u53D1\u73B0\u53EF\u7591\u7684\u77DB\u76FE/\u91CD\u590D\u6761\u76EE\u5BF9",
|
|
1235
|
+
"doctor.conflict.summary": "{candidates} \u4E2A\u5019\u9009\u5BF9, {conflicts} \u4E2A\u5224\u5B9A\u4E3A\u77DB\u76FE (\u76F8\u4F3C\u5EA6 \u2265 {threshold})",
|
|
1236
|
+
"doctor.conflict.deep_no_judge": "\u5DF2\u8BF7\u6C42 --deep \u4F46\u672A\u63A5\u5165 LLM judge (\u8BF7\u624B\u52A8\u8DD1\u51B7\u8BC4 review);\u5148\u5C55\u793A\u4FBF\u5B9C\u5019\u9009",
|
|
1237
|
+
"doctor.conflict.verdict.conflict": "\u77DB\u76FE",
|
|
1238
|
+
"doctor.conflict.verdict.similar": "\u76F8\u4F3C (\u53EF\u80FD\u91CD\u590D)",
|
|
1239
|
+
"doctor.conflict.verdict.unknown": "\u5F85\u5BA1 (\u53EF\u80FD\u91CD\u590D\u6216\u77DB\u76FE)",
|
|
1178
1240
|
"cli.doctor.errors.invalid-since": "--since \u53D6\u503C\u65E0\u6548: {input}\u3002\u9884\u671F\u683C\u5F0F 7d / 24h / 30m \u6216 epoch ms\u3002",
|
|
1179
1241
|
"cli.doctor.errors.invalid-client": "--client \u53D6\u503C\u65E0\u6548: {input}\u3002\u9884\u671F cc / codex / cursor / all\u3002",
|
|
1180
1242
|
"cli.doctor.errors.invalid-layer": "--layer \u53D6\u503C\u65E0\u6548: {input}\u3002\u9884\u671F team / personal / all\u3002",
|
|
@@ -1274,7 +1336,7 @@ var zhCNMessages = {
|
|
|
1274
1336
|
"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",
|
|
1275
1337
|
"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",
|
|
1276
1338
|
"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",
|
|
1277
|
-
"doctor.check.events_jsonl_health.remediation": "\u8FD0\u884C `fabric doctor --fix` \u89E6\u53D1 rotation
|
|
1339
|
+
"doctor.check.events_jsonl_health.remediation": "\u8FD0\u884C `fabric doctor --fix` \u2014\u2014 \u5B83\u4F1A\u89E6\u53D1 rotation \u5E76 flush metrics.jsonl(rc.2 F16: \u65E0\u9700\u91CD\u542F server \u5373\u53EF\u6E05\u51FA idle \u671F\u672A\u5237\u7684 metric counter)\u3002\u82E5\u544A\u8B66\u4ECD\u6301\u7EED, \u518D\u91CD\u542F MCP server \u8BA9 startMetricsFlush + startRotationTick \u91CD\u65B0\u8C03\u5EA6\u3002\u82E5 metric_leak \u547D\u4E2D, \u68C0\u67E5\u6700\u8FD1\u4EE3\u7801\u6539\u52A8\u662F\u5426\u7ED5\u8FC7 bumpCounter API \u76F4\u63A5 appendEventLedgerEvent \u5199\u4E86 4 \u4E2A metric-managed event_type \u4E4B\u4E00\u3002",
|
|
1278
1340
|
"doctor.check.mcp_config_in_wrong_file.name": "Claude MCP config \u4F4D\u7F6E",
|
|
1279
1341
|
"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",
|
|
1280
1342
|
"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",
|
|
@@ -1361,6 +1423,11 @@ var zhCNMessages = {
|
|
|
1361
1423
|
"doctor.check.counter_desync.message.plural": "{count} \u4E2A knowledge counters \u4E0E\u89C2\u6D4B\u5230\u7684 stable_ids \u4E0D\u540C\u6B65\u3002{counterPath} = {current}\uFF0C\u4F46\u68C0\u6D4B\u5230 {observedId}\u3002\u8FD0\u884C `fabric doctor --fix` bump counters\u3002",
|
|
1362
1424
|
"doctor.check.counter_desync.remediation": "\u8FD0\u884C `fabric doctor --fix` \u5C06 agents.meta.json counters \u63D0\u5347\u5230\u89C2\u6D4B\u5230\u7684\u6700\u5927 counter \u503C\u3002",
|
|
1363
1425
|
"doctor.check.counter_desync.ok": "agents.meta.json counters envelope \u4E0E\u89C2\u6D4B\u5230\u7684 stable_ids \u4E00\u81F4\u3002",
|
|
1426
|
+
"doctor.check.store_counter_drift.name": "Store counter drift",
|
|
1427
|
+
"doctor.check.store_counter_drift.message.singular": "{count} \u4E2A store counter \u4F4E\u4E8E\u78C1\u76D8\u4E0A\u7684\u6700\u5927 stable_id\uFF08{detail}\uFF09\u3002\u8BE5 store \u4E0B\u4E00\u6B21\u94F8\u53F7\u4F1A\u590D\u7528\u5DF2\u5B58\u5728\u7684 id\u3002\u8FD0\u884C `fabric doctor --fix` \u5C06 store counters.json \u63D0\u5347\u5230\u78C1\u76D8\u6700\u5927\u503C\u3002",
|
|
1428
|
+
"doctor.check.store_counter_drift.message.plural": "{count} \u4E2A store counter \u4F4E\u4E8E\u78C1\u76D8\u4E0A\u7684\u6700\u5927 stable_id\uFF08{detail}\uFF09\u3002\u8FD9\u4E9B store \u4E0B\u4E00\u6B21\u94F8\u53F7\u4F1A\u590D\u7528\u5DF2\u5B58\u5728\u7684 id\u3002\u8FD0\u884C `fabric doctor --fix` \u5C06 store counters.json \u63D0\u5347\u5230\u78C1\u76D8\u6700\u5927\u503C\u3002",
|
|
1429
|
+
"doctor.check.store_counter_drift.remediation": "\u8FD0\u884C `fabric doctor --fix` \u5C06\u6BCF\u4E2A store \u7684 counters.json \u63D0\u5347\uFF08floor\uFF09\u5230\u78C1\u76D8\u4E0A\u89C2\u6D4B\u5230\u7684\u6700\u5927 stable_id\uFF08floor \u53EA\u5347\u4E0D\u964D\u2014\u2014KT-DEC-0004 \u5355\u8C03\u4E0D\u53D8\u91CF\uFF09\u3002",
|
|
1430
|
+
"doctor.check.store_counter_drift.ok": "read-set \u5185\u6BCF\u4E2A store \u7684 counters.json \u90FD\u5DF2 floor \u5230\u78C1\u76D8\u6700\u5927 stable_id\u3002",
|
|
1364
1431
|
"doctor.check.preexisting_root_files.name": "Preexisting root markdown",
|
|
1365
1432
|
"doctor.check.preexisting_root_files.ok": "project root \u672A\u68C0\u6D4B\u5230 CLAUDE.md \u6216 AGENTS.md\u3002",
|
|
1366
1433
|
"doctor.check.preexisting_root_files.message": "project root \u68C0\u6D4B\u5230 {files}\u3002\u8FD9\u4E9B root files \u4E0D\u4F1A\u88AB Fabric MCP \u81EA\u52A8\u52A0\u8F7D\u3002",
|
|
@@ -1500,6 +1567,11 @@ var zhCNMessages = {
|
|
|
1500
1567
|
"doctor.check.knowledge_summary_opaque.ok": "{opaque}/{total} \u4E2A entry \u7684 summary == stable_id\uFF0C\u6BD4\u4F8B\u5728\u5065\u5EB7\u8303\u56F4\u5185\u3002",
|
|
1501
1568
|
"doctor.check.knowledge_summary_opaque.message.warn": "{opaque}/{total} \u4E2A entry ({pct}%) \u7684 description.summary \u7B49\u4E8E stable_id\uFF0C\u8D85\u8FC7 {threshold}% \u9608\u503C\u3002narrow hint \u8F93\u51FA\u4F1A\u53D8\u6210 `<id> \xB7 <id>` \u800C\u975E\u771F\u5B9E\u6982\u8981\uFF0CAI \u770B\u4E0D\u5230\u4FE1\u606F\u4F1A\u4E3B\u52A8\u8DF3\u8FC7 fetch\u3002\u9996\u6279\u4E0D\u900F\u660E: {sample}\u3002",
|
|
1502
1569
|
"doctor.check.knowledge_summary_opaque.remediation": "\u8C03 fabric-review skill \u91CD\u5199\u4E0D\u900F\u660E summary \u4E3A\u4E00\u53E5\u4EBA\u7C7B\u53EF\u8BFB\u7684\u6982\u8981\u3002rc.35 hint renderer fallback (TASK-06) \u4E5F\u4F1A\u4ECE entry \u7684 `## Summary` \u6BB5\u81EA\u52A8\u5408\u6210\u4E34\u65F6 summary\u3002",
|
|
1570
|
+
// v2.2 W4 (G-GUARD / A6): store scope lint。
|
|
1571
|
+
"doctor.check.store_scope_lint.name": "Store scope lint",
|
|
1572
|
+
"doctor.check.store_scope_lint.ok": "read-set \u5185\u6240\u6709 store \u6761\u76EE scope \u5143\u6570\u636E\u9F50\u5907(semantic_scope + visibility_store,\u65E0 personal \u6CC4\u6F0F,\u65E0 dangling project)\u3002",
|
|
1573
|
+
"doctor.check.store_scope_lint.message": "{total} \u4E2A store scope \u95EE\u9898: {breakdown}\u3002\u4F8B\u5982 {sample}\u3002",
|
|
1574
|
+
"doctor.check.store_scope_lint.remediation": "\u8C03 `fabric store backfill-scope` \u8865\u7F3A\u5931\u7684 semantic_scope/visibility_store;`fabric store re-scope` \u4FEE dangling \u7684 project: \u5750\u6807;\u628A personal-scope \u6761\u76EE\u79FB\u51FA shared store(personal \u77E5\u8BC6\u53EA\u5B58\u4E2A\u4EBA store,R5#3)\u3002",
|
|
1503
1575
|
"doctor.check.skill_md_yaml_invalid.name": "Skill markdown YAML",
|
|
1504
1576
|
"doctor.check.skill_md_yaml_invalid.ok": "\u6240\u6709 .claude/.codex SKILL.md frontmatter values \u90FD\u80FD\u6309 strict YAML \u89E3\u6790\u3002",
|
|
1505
1577
|
"doctor.check.skill_md_yaml_invalid.message.singular": "{count} \u4E2A SKILL.md frontmatter value \u5305\u542B\u672A\u52A0\u5F15\u53F7\u7684 ': '\uFF0Cstrict YAML parsers \u4F1A\u62D2\u7EDD\uFF08Claude Code tolerates it\uFF1BCodex CLI drops the skill at load\uFF09\u3002\u9996\u4E2A\uFF1A{detail}\u3002",
|
|
@@ -1545,6 +1617,8 @@ var zhCNMessages = {
|
|
|
1545
1617
|
"cli.install.args.debug.description": "\u5C06\u76EE\u6807\u89E3\u6790\u7EC6\u8282\u8F93\u51FA\u5230 stderr\u3002",
|
|
1546
1618
|
"cli.install.args.yes.description": "\u63A5\u53D7\u5F53\u524D\u5B89\u88C5\u8BA1\u5212\u5E76\u8DF3\u8FC7 TTY \u5411\u5BFC\u76F4\u63A5\u6267\u884C",
|
|
1547
1619
|
"cli.install.args.dry-run.description": "\u4EC5\u8F93\u51FA\u5B89\u88C5\u8BA1\u5212\uFF0C\u4E0D\u5199\u6587\u4EF6\u4E5F\u4E0D\u6267\u884C\u540E\u7EED\u9636\u6BB5",
|
|
1620
|
+
"cli.install.args.enable-embed.description": "\u542F\u7528\u5411\u91CF\u8BED\u4E49\u641C\u7D22 (\u8BBE embed_enabled + embed_model;\u6253\u5370 fastembed \u5B89\u88C5\u6B65\u9AA4)",
|
|
1621
|
+
"cli.install.args.embed-model.description": "\u914D\u5408 --enable-embed:\u8986\u76D6\u56FA\u5B9A\u7684 embed \u6A21\u578B (\u9ED8\u8BA4 fast-bge-small-zh-v1.5)",
|
|
1548
1622
|
// rc.35 TASK-08 (P0-5/6): --force-skills-only。
|
|
1549
1623
|
"cli.install.args.force-skills-only.description": "\u8DF3\u8FC7 bootstrap / MCP / hooks / settings,\u53EA\u91CD\u65B0\u5237\u65B0 fabric Skill \u6A21\u677F (.claude/.codex/.cursor/skills/*)\u3002",
|
|
1550
1624
|
"cli.install.force-skills-only.banner": "\u53EA\u5237\u65B0 fabric Skill \u6A21\u677F",
|
|
@@ -1619,6 +1693,7 @@ var zhCNMessages = {
|
|
|
1619
1693
|
// 新 mcp config — 必须重启才能拿到 Fabric tools。
|
|
1620
1694
|
"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",
|
|
1621
1695
|
"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",
|
|
1696
|
+
"cli.install.store-bind-nudge": "\u{1F4A1} \u68C0\u6D4B\u5230\u5DF2\u6302\u8F7D\u4F46\u672A\u7ED1\u5B9A\u672C\u9879\u76EE\u7684\u77E5\u8BC6 store: {aliases}\u3002\u8FD0\u884C `fabric store bind {first}` \u628A\u5B83\u7684\u77E5\u8BC6\u63A5\u5165\u672C\u9879\u76EE, \u518D `fabric store switch-write {first}` \u8BBE\u4E3A\u56E2\u961F\u77E5\u8BC6\u7684\u5199\u5165\u76EE\u6807\u3002",
|
|
1622
1697
|
"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",
|
|
1623
1698
|
"cli.install.capabilities.header.client": "\u5BA2\u6237\u7AEF",
|
|
1624
1699
|
"cli.install.capabilities.header.bootstrap": "Bootstrap",
|
|
@@ -1962,6 +2037,12 @@ var zhCNMessages = {
|
|
|
1962
2037
|
"cli.store.detached": "\u5DF2\u5206\u79BB '{alias}' \u2014\u2014 \u78C1\u76D8\u4E0A\u7684 store \u76EE\u5F55\u4FDD\u7559 (\u5206\u79BB \u2260 \u5220\u9664)",
|
|
1963
2038
|
"cli.store.bound": "\u5DF2\u7ED1\u5B9A\u5FC5\u9700 store '{id}' (\u5171 {count} \u4E2A\u5FC5\u9700)",
|
|
1964
2039
|
"cli.store.switch-write": "\u5DF2\u5C06\u672C\u9879\u76EE\u7684\u6D3B\u52A8\u5199\u5165 store \u8BBE\u4E3A '{alias}'",
|
|
2040
|
+
"cli.store.migrate.none": "\u6CA1\u6709\u9700\u8981\u8FC1\u79FB\u7684\u9879\u76EE\u672C\u5730\u77E5\u8BC6 (dual-root \u5DF2\u7A7A)",
|
|
2041
|
+
"cli.store.migrate.dry-run-header": "\u8FC1\u79FB\u9884\u89C8 (dry-run, \u4E0D\u5199\u5165\u78C1\u76D8):",
|
|
2042
|
+
"cli.store.migrate.applied-header": "\u5DF2\u8FC1\u79FB {count} \u6761\u8FDB store:",
|
|
2043
|
+
"cli.store.migrate.committed": "\u5DF2\u5728 store \u4ED3\u5E93\u63D0\u4EA4\u8FC1\u79FB\u53D8\u66F4",
|
|
2044
|
+
"cli.store.migrate.remap-note": " \u2191 \u56E0\u76EE\u6807 store id \u51B2\u7A81, {oldId} \u91CD\u6620\u5C04\u4E3A {newId}",
|
|
2045
|
+
"cli.store.migrate.skips-header": "\u8DF3\u8FC7 {count} \u9879:",
|
|
1965
2046
|
"cli.sync.deferred": "{count} \u4E2A store \u79BB\u7EBF \u2014\u2014 push \u5DF2\u5EF6\u540E; \u8054\u7F51\u540E\u91CD\u65B0\u8FD0\u884C `fabric sync`",
|
|
1966
2047
|
"cli.sync.paused": "sync \u56E0\u51B2\u7A81\u6682\u505C \u2014\u2014 \u89E3\u51B3\u540E\u8FD0\u884C `fabric sync --continue` (\u6216 `--abort`)",
|
|
1967
2048
|
"cli.metrics.invalid-since": '--since: \u65E0\u6548\u7684\u65F6\u957F "{raw}" (\u793A\u4F8B: 24h\u30017d\u300130m)',
|
|
@@ -2057,7 +2138,10 @@ function resolveFabricLocale(projectRoot) {
|
|
|
2057
2138
|
if (fabricLanguage === "en" || fabricLanguage === "zh-CN") {
|
|
2058
2139
|
return fabricLanguage;
|
|
2059
2140
|
}
|
|
2060
|
-
if (fabricLanguage === "
|
|
2141
|
+
if (fabricLanguage === "zh-CN-hybrid") {
|
|
2142
|
+
return "zh-CN";
|
|
2143
|
+
}
|
|
2144
|
+
if (fabricLanguage === "match-existing") {
|
|
2061
2145
|
console.warn(
|
|
2062
2146
|
`[fabric] fabric_language="${fabricLanguage}" is a pre-init placeholder that should have been resolved during 'fabric init' (KT-DEC-9004). Falling back to FAB_LANG / LANG environment detection.`
|
|
2063
2147
|
);
|
|
@@ -36,6 +36,12 @@ var ConfigPathInvalidError = class extends ConfigError {
|
|
|
36
36
|
var GenericConfigError = class extends ConfigError {
|
|
37
37
|
code = "config_error";
|
|
38
38
|
};
|
|
39
|
+
var StoreWriteTargetUnresolvedError = class extends ConfigError {
|
|
40
|
+
code = "store_write_target_unresolved";
|
|
41
|
+
};
|
|
42
|
+
var PersonalScopeLeakError = class extends ConfigError {
|
|
43
|
+
code = "personal_scope_leak";
|
|
44
|
+
};
|
|
39
45
|
|
|
40
46
|
// src/errors/rule-error.ts
|
|
41
47
|
var RuleError = class extends FabricError {
|
|
@@ -78,6 +84,8 @@ export {
|
|
|
78
84
|
ConfigError,
|
|
79
85
|
ConfigPathInvalidError,
|
|
80
86
|
GenericConfigError,
|
|
87
|
+
StoreWriteTargetUnresolvedError,
|
|
88
|
+
PersonalScopeLeakError,
|
|
81
89
|
RuleError,
|
|
82
90
|
RuleValidationError,
|
|
83
91
|
IOFabricError,
|
package/dist/errors/index.d.ts
CHANGED
|
@@ -28,6 +28,12 @@ declare class ConfigPathInvalidError extends ConfigError {
|
|
|
28
28
|
declare class GenericConfigError extends ConfigError {
|
|
29
29
|
readonly code = "config_error";
|
|
30
30
|
}
|
|
31
|
+
declare class StoreWriteTargetUnresolvedError extends ConfigError {
|
|
32
|
+
readonly code = "store_write_target_unresolved";
|
|
33
|
+
}
|
|
34
|
+
declare class PersonalScopeLeakError extends ConfigError {
|
|
35
|
+
readonly code = "personal_scope_leak";
|
|
36
|
+
}
|
|
31
37
|
|
|
32
38
|
declare abstract class RuleError extends FabricError {
|
|
33
39
|
readonly httpStatus: number;
|
|
@@ -62,4 +68,4 @@ declare class InitFrameworkUnknownError extends InitError {
|
|
|
62
68
|
readonly code = "init_framework_unknown";
|
|
63
69
|
}
|
|
64
70
|
|
|
65
|
-
export { ConfigError, ConfigPathInvalidError, FabricError, GenericConfigError, GenericIOError, IOFabricError, InitError, InitFrameworkUnknownError, MCPError, McpToolError, PathEscapeError, RuleError, RuleValidationError };
|
|
71
|
+
export { ConfigError, ConfigPathInvalidError, FabricError, GenericConfigError, GenericIOError, IOFabricError, InitError, InitFrameworkUnknownError, MCPError, McpToolError, PathEscapeError, PersonalScopeLeakError, RuleError, RuleValidationError, StoreWriteTargetUnresolvedError };
|
package/dist/errors/index.js
CHANGED
|
@@ -10,9 +10,11 @@ import {
|
|
|
10
10
|
MCPError,
|
|
11
11
|
McpToolError,
|
|
12
12
|
PathEscapeError,
|
|
13
|
+
PersonalScopeLeakError,
|
|
13
14
|
RuleError,
|
|
14
|
-
RuleValidationError
|
|
15
|
-
|
|
15
|
+
RuleValidationError,
|
|
16
|
+
StoreWriteTargetUnresolvedError
|
|
17
|
+
} from "../chunk-VDSM73PK.js";
|
|
16
18
|
export {
|
|
17
19
|
ConfigError,
|
|
18
20
|
ConfigPathInvalidError,
|
|
@@ -25,6 +27,8 @@ export {
|
|
|
25
27
|
MCPError,
|
|
26
28
|
McpToolError,
|
|
27
29
|
PathEscapeError,
|
|
30
|
+
PersonalScopeLeakError,
|
|
28
31
|
RuleError,
|
|
29
|
-
RuleValidationError
|
|
32
|
+
RuleValidationError,
|
|
33
|
+
StoreWriteTargetUnresolvedError
|
|
30
34
|
};
|