@fenglimg/fabric-shared 2.0.0-rc.1 → 2.0.0

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.
@@ -52,11 +52,15 @@ var enMessages = {
52
52
  "doctor.section.fixable": "Fixable errors:",
53
53
  "doctor.section.manual": "Manual errors:",
54
54
  "doctor.section.warnings": "Warnings:",
55
+ "doctor.section.apply-lint-mutations": "Apply-lint mutations:",
55
56
  "cli.doctor.args.target.description": "Target project path. Defaults to CLI arg, EXTERNAL_FIXTURE_PATH, fabric.config.json, then cwd.",
56
- "cli.doctor.args.fix.description": "Repair deterministic derived Fabric state, including meta, rule-test index, bootstrap, and events ledger.",
57
+ "cli.doctor.args.fix.description": "Repair deterministic derived Fabric state, including meta, knowledge-test index, bootstrap, and events ledger.",
57
58
  "cli.doctor.args.json.description": "Print the doctor report as JSON.",
58
59
  "cli.doctor.args.strict.description": "Treat warnings as failures.",
59
60
  "cli.doctor.args.force.description": "Run even if a serve process appears to hold the lock.",
61
+ "cli.doctor.args.apply-lint.description": "Apply lint mutations: demote orphaned canonical entries, archive stale drafts, and bump drifted index counters. Emits knowledge_demoted / knowledge_archived events. Default doctor invocation remains report-only.",
62
+ "cli.doctor.args.yes.description": "Skip the --apply-lint safety confirm. Required for non-tty invocations unless FABRIC_NONINTERACTIVE=1 is set in the environment.",
63
+ "cli.doctor.errors.apply-lint-fix-mutually-exclusive": "--apply-lint and --fix cannot be combined. --apply-lint mutates user knowledge state (demote/archive); --fix repairs derived state (meta/index). Run them separately.",
60
64
  "cli.hooks.description": "Manage Fabric Git hook templates.",
61
65
  "cli.hooks.install.description": "Install the Fabric Husky pre-commit hook template.",
62
66
  "cli.hooks.install.args.target.description": "Target project path, default is the current working directory.",
@@ -487,11 +491,15 @@ var zhCNMessages = {
487
491
  "doctor.section.fixable": "\u53EF\u4FEE\u590D\u9519\u8BEF\uFF1A",
488
492
  "doctor.section.manual": "\u9700\u624B\u52A8\u4FEE\u590D\uFF1A",
489
493
  "doctor.section.warnings": "\u8B66\u544A\uFF1A",
494
+ "doctor.section.apply-lint-mutations": "Apply-lint \u53D8\u66F4\uFF1A",
490
495
  "cli.doctor.args.target.description": "\u76EE\u6807\u9879\u76EE\u8DEF\u5F84\u3002\u9ED8\u8BA4\u4F9D\u6B21\u4F7F\u7528 CLI \u53C2\u6570\u3001EXTERNAL_FIXTURE_PATH\u3001fabric.config.json\u3001\u5F53\u524D\u76EE\u5F55\u3002",
491
- "cli.doctor.args.fix.description": "\u4FEE\u590D\u786E\u5B9A\u6027\u6D3E\u751F\u7684 Fabric \u72B6\u6001\uFF0C\u5305\u62EC meta\u3001rule-test index\u3001bootstrap \u548C events ledger\u3002",
496
+ "cli.doctor.args.fix.description": "\u4FEE\u590D\u786E\u5B9A\u6027\u6D3E\u751F\u7684 Fabric \u72B6\u6001\uFF0C\u5305\u62EC meta\u3001knowledge-test \u7D22\u5F15\u3001bootstrap \u548C events ledger\u3002",
492
497
  "cli.doctor.args.json.description": "\u4EE5 JSON \u8F93\u51FA doctor \u62A5\u544A\u3002",
493
498
  "cli.doctor.args.strict.description": "\u5C06 warning \u4E5F\u89C6\u4E3A\u5931\u8D25\u3002",
494
499
  "cli.doctor.args.force.description": "\u5373\u4F7F serve \u8FDB\u7A0B\u6301\u6709\u9501\uFF0C\u4E5F\u5F3A\u5236\u8FD0\u884C\u3002",
500
+ "cli.doctor.args.apply-lint.description": "\u5E94\u7528 lint \u53D8\u66F4\uFF1A\u964D\u7EA7\u5B64\u7ACB\u7684\u89C4\u8303\u6761\u76EE\u3001\u5F52\u6863\u9648\u65E7 draft\u3001\u4FEE\u6B63\u6F02\u79FB\u7684\u7D22\u5F15\u8BA1\u6570\u5668\uFF1B\u5199\u5165 knowledge_demoted / knowledge_archived \u4E8B\u4EF6\u3002\u9ED8\u8BA4\u8FD0\u884C\u4ECD\u7136\u53EA\u8BFB\u3002",
501
+ "cli.doctor.args.yes.description": "\u8DF3\u8FC7 --apply-lint \u7684\u5B89\u5168\u786E\u8BA4\uFF1B\u975E tty \u8C03\u7528\u5FC5\u987B\u663E\u5F0F\u8BBE\u7F6E\u8BE5\u6807\u8BB0\uFF0C\u6216\u5728\u73AF\u5883\u53D8\u91CF\u4E2D\u8BBE\u7F6E FABRIC_NONINTERACTIVE=1\u3002",
502
+ "cli.doctor.errors.apply-lint-fix-mutually-exclusive": "--apply-lint \u4E0E --fix \u4E0D\u53EF\u540C\u65F6\u4F7F\u7528\u3002--apply-lint \u4FEE\u6539\u7528\u6237\u77E5\u8BC6\u72B6\u6001\uFF08\u964D\u7EA7/\u5F52\u6863\uFF09\uFF1B--fix \u4FEE\u590D\u6D3E\u751F\u72B6\u6001\uFF08meta/\u7D22\u5F15\uFF09\u3002\u8BF7\u5206\u522B\u8FD0\u884C\u3002",
495
503
  "cli.hooks.description": "\u7BA1\u7406 Fabric Git \u94A9\u5B50\u6A21\u677F\u3002",
496
504
  "cli.hooks.install.description": "\u5B89\u88C5 Fabric Husky pre-commit \u94A9\u5B50\u6A21\u677F\u3002",
497
505
  "cli.hooks.install.args.target.description": "\u76EE\u6807\u9879\u76EE\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u4E3A\u5F53\u524D\u5DE5\u4F5C\u76EE\u5F55\u3002",
@@ -917,27 +925,24 @@ function detectNodeLocale() {
917
925
 
918
926
  // src/i18n/protected-tokens.ts
919
927
  var PROTECTED_TOKENS = [
928
+ // v2.0 MCP tool names
920
929
  "fab_plan_context",
921
- "fab_get_rule_sections",
922
- "fabric_rules",
923
- "ledger_entry",
924
- "ledger_entry_id",
925
- "agent_meta",
930
+ "fab_get_knowledge_sections",
931
+ "fab_extract_knowledge",
932
+ "fab_review",
933
+ // Project convergence point + knowledge tree paths
926
934
  "AGENTS.md",
927
- "FABRIC.md",
928
935
  ".fabric/agents/",
929
936
  ".fabric/agents/_cross/",
930
937
  ".fabric/agents.meta.json",
931
938
  ".fabric/human-lock.json",
932
- ".fabric/init-context.json",
933
- ".fabric/forensic.json",
934
- ".fabric/.intent-ledger.jsonl",
935
939
  ".fabric/events.jsonl",
940
+ ".fabric/knowledge/",
941
+ // Event types templates reference verbatim
942
+ "knowledge_proposed",
943
+ // Human-lock marker
936
944
  "@HUMAN",
937
- "shadow constraints",
938
- "Shadow Mirroring",
939
- "CORE RULES",
940
- "DO NOT TRANSLATE",
945
+ // Hard-rule keywords AI clients rely on for compliance
941
946
  "MUST",
942
947
  "NEVER"
943
948
  ];
@@ -0,0 +1,555 @@
1
+ // src/schemas/api-contracts.ts
2
+ import { z } from "zod";
3
+ var structuredWarningSchema = z.object({
4
+ code: z.string(),
5
+ file: z.string(),
6
+ line: z.number().optional(),
7
+ action_hint: z.string()
8
+ });
9
+ var _knowledgeTypeEnum = z.enum(["model", "decision", "guideline", "pitfall", "process"]);
10
+ var _maturityEnum = z.enum(["draft", "verified", "proven"]);
11
+ var _layerEnum = z.enum(["personal", "team"]);
12
+ var _ruleDescriptionSchema = z.object({
13
+ summary: z.string(),
14
+ intent_clues: z.array(z.string()),
15
+ tech_stack: z.array(z.string()),
16
+ impact: z.array(z.string()),
17
+ must_read_if: z.string(),
18
+ entities: z.array(z.string()).optional(),
19
+ // v2.0: optional knowledge-entry fields. Absent for v1.x rules; present for
20
+ // entries that declare frontmatter `id/type/maturity/layer`.
21
+ id: z.string().optional(),
22
+ knowledge_type: _knowledgeTypeEnum.optional(),
23
+ maturity: _maturityEnum.optional(),
24
+ knowledge_layer: _layerEnum.optional(),
25
+ layer_reason: z.string().optional(),
26
+ created_at: z.string().optional()
27
+ });
28
+ var _descriptionIndexItemSchema = z.object({
29
+ stable_id: z.string(),
30
+ level: z.enum(["L0", "L1", "L2"]),
31
+ required: z.boolean(),
32
+ selectable: z.boolean(),
33
+ description: _ruleDescriptionSchema,
34
+ // v2.0: top-level knowledge surface for client-side filtering. Mirrors
35
+ // description.* — exposed here so MCP clients can filter without reaching
36
+ // into the nested payload.
37
+ type: _knowledgeTypeEnum.optional(),
38
+ maturity: _maturityEnum.optional(),
39
+ layer: _layerEnum.optional(),
40
+ layer_reason: z.string().optional(),
41
+ // v2/rc.2: tag list shipped via frontmatter (commit a85121a). Exposed at
42
+ // the API surface so MCP clients can filter without re-parsing the
43
+ // description payload. Absent on legacy entries; consumers should treat
44
+ // missing as [].
45
+ tags: z.array(z.string()).optional(),
46
+ // v2.0-rc.5 (C1): relevance scope/paths drive plan-context-hint narrowing.
47
+ // Exposed at the API surface so MCP clients (and the `fabric
48
+ // plan-context-hint` CLI from D1) can filter without re-parsing the
49
+ // description payload. Defaults applied at the parse layer
50
+ // (knowledge-meta-builder + agentsMetaNodeBaseSchema):
51
+ // relevance_scope → 'broad' (always-surface, safe default)
52
+ // relevance_paths → [] (no path anchors)
53
+ // Consumers should treat missing fields as broad/[]. Optional on the wire
54
+ // so older servers without rc.5 schemas remain wire-compatible.
55
+ relevance_scope: z.enum(["narrow", "broad"]).optional(),
56
+ relevance_paths: z.array(z.string()).optional()
57
+ });
58
+ var _requirementProfileSchema = z.object({
59
+ target_path: z.string(),
60
+ path_segments: z.array(z.string()),
61
+ extension: z.string(),
62
+ known_tech: z.array(z.string()),
63
+ user_intent: z.string(),
64
+ detected_entities: z.array(z.string())
65
+ });
66
+ var planContextInputSchema = z.object({
67
+ paths: z.array(z.string()).min(1).describe("Candidate file paths to build neutral rule selection context for"),
68
+ intent: z.string().optional().describe("User-stated requirement or implementation intent; used only to build a neutral requirement profile"),
69
+ known_tech: z.array(z.string()).optional().describe("Known technologies involved in the requirement profile"),
70
+ detected_entities: z.record(z.array(z.string())).optional().describe("Optional path-keyed detected entities for the requirement profile"),
71
+ client_hash: z.string().optional().describe("Revision hash from a prior fab_plan_context response; enables stale detection"),
72
+ correlation_id: z.string().optional().describe("Optional caller-provided correlation id for Event Ledger records"),
73
+ session_id: z.string().optional().describe("Optional caller-provided session id for Event Ledger records"),
74
+ // v2.0-rc.5 A3 (TASK-007): `include_deprecated` removed — it was a no-op
75
+ // placeholder (MaturitySchema has no `deprecated` value). When the maturity
76
+ // enum widens we re-introduce the flag as part of that protocol bump.
77
+ // v2/rc.2 (Q6): client-supplied layer scope. When omitted, the server
78
+ // falls back to fabric-config.default_layer_filter (TASK-002) so a single
79
+ // workspace policy controls the default. Explicit values override.
80
+ layer_filter: z.enum(["team", "personal", "both"]).optional().describe(
81
+ "Restrict description_index to the named layer. Default: fabric-config.default_layer_filter (TASK-002)."
82
+ ),
83
+ // v2.0-rc.5 C3 (TASK-012): explicit path context for `narrow` relevance
84
+ // filtering. When omitted, the server falls back to `paths` so existing
85
+ // callers see narrowing against the requested paths. When the resolved
86
+ // list is empty, the narrow filter fails open (every narrow entry passes).
87
+ target_paths: z.array(z.string()).optional().describe(
88
+ "Path context for narrow-scope relevance filtering. Defaults to `paths`; empty = no filter."
89
+ )
90
+ });
91
+ var planContextOutputSchema = z.object({
92
+ revision_hash: z.string(),
93
+ stale: z.boolean(),
94
+ selection_token: z.string(),
95
+ entries: z.array(
96
+ z.object({
97
+ path: z.string(),
98
+ requirement_profile: _requirementProfileSchema,
99
+ description_index: z.array(_descriptionIndexItemSchema)
100
+ })
101
+ ),
102
+ shared: z.object({
103
+ description_index: z.array(_descriptionIndexItemSchema),
104
+ preflight_diagnostics: z.array(
105
+ z.object({
106
+ code: z.literal("missing_description"),
107
+ severity: z.literal("warn"),
108
+ message: z.string(),
109
+ stable_ids: z.array(z.string()).optional(),
110
+ path: z.string().optional()
111
+ })
112
+ )
113
+ }),
114
+ warnings: z.array(structuredWarningSchema).optional()
115
+ });
116
+ var planContextAnnotations = {
117
+ readOnlyHint: true,
118
+ idempotentHint: true,
119
+ destructiveHint: false,
120
+ openWorldHint: false,
121
+ title: "Plan rule context"
122
+ };
123
+ var planContextHintNarrowEntrySchema = z.object({
124
+ id: z.string(),
125
+ type: z.string(),
126
+ maturity: z.string(),
127
+ summary: z.string()
128
+ });
129
+ var planContextHintOutputSchema = z.object({
130
+ version: z.literal(1),
131
+ revision_hash: z.string(),
132
+ target_paths: z.array(z.string()),
133
+ narrow: z.array(planContextHintNarrowEntrySchema),
134
+ broad_count: z.number().int().nonnegative()
135
+ });
136
+ var _knowledgeEntrySchema = z.object({ path: z.string(), content: z.string() });
137
+ var _humanLockedSchema = z.object({ file: z.string(), excerpt: z.string() });
138
+ var _descriptionStubSchema = z.object({ path: z.string(), description: z.string() });
139
+ var getKnowledgeInputSchema = z.object({
140
+ path: z.string().describe("Target file path to query rules for"),
141
+ client_hash: z.string().optional().describe("Revision hash from prior fab_get_rules response; enables stale detection"),
142
+ correlation_id: z.string().optional().describe("Optional caller-provided correlation id for Event Ledger records"),
143
+ session_id: z.string().optional().describe("Optional caller-provided session id for Event Ledger records")
144
+ });
145
+ var getKnowledgeOutputSchema = z.object({
146
+ revision_hash: z.string(),
147
+ stale: z.boolean(),
148
+ rules: z.object({
149
+ L0: z.string(),
150
+ L1: z.array(_knowledgeEntrySchema),
151
+ L2: z.array(_knowledgeEntrySchema),
152
+ human_locked_nearby: z.array(_humanLockedSchema),
153
+ description_stubs: z.array(_descriptionStubSchema).optional()
154
+ }),
155
+ warnings: z.array(structuredWarningSchema).optional()
156
+ });
157
+ var getKnowledgeAnnotations = {
158
+ readOnlyHint: true,
159
+ idempotentHint: true,
160
+ destructiveHint: false,
161
+ openWorldHint: false,
162
+ title: "Get rule content"
163
+ };
164
+ var KNOWLEDGE_SECTION_NAMES_TUPLE = ["MISSION_STATEMENT", "MANDATORY_INJECTION", "BUSINESS_LOGIC_CHUNKS", "CONTEXT_INFO"];
165
+ var knowledgeSectionsInputSchema = z.object({
166
+ selection_token: z.string().min(1).describe("Selection token returned by fab_plan_context"),
167
+ sections: z.array(z.enum(KNOWLEDGE_SECTION_NAMES_TUPLE)).min(1).describe("Structured rule sections to fetch"),
168
+ ai_selected_stable_ids: z.array(z.string()).describe("AI-selected L1 stable_ids chosen from fab_plan_context ai_selectable_stable_ids"),
169
+ ai_selection_reasons: z.record(z.string().min(1)).describe("Reason for each AI-selected L1 stable_id"),
170
+ correlation_id: z.string().optional().describe("Optional caller-provided correlation id for Event Ledger records"),
171
+ session_id: z.string().optional().describe("Optional caller-provided session id for Event Ledger records"),
172
+ // v2.0 rc.5 TASK-014 (C5): optional client identity hash propagated into
173
+ // knowledge_consumed events. Falls back to empty string when unset — full
174
+ // client-identity propagation deferred to rc.6.
175
+ client_hash: z.string().optional().describe("Optional caller-provided client hash propagated into knowledge_consumed events")
176
+ });
177
+ var knowledgeSectionsOutputSchema = z.object({
178
+ revision_hash: z.string(),
179
+ precedence: z.tuple([z.literal("L2"), z.literal("L1"), z.literal("L0")]),
180
+ selected_stable_ids: z.array(z.string()),
181
+ rules: z.array(
182
+ z.object({
183
+ stable_id: z.string(),
184
+ level: z.enum(["L0", "L1", "L2"]),
185
+ path: z.string(),
186
+ sections: z.record(z.string())
187
+ })
188
+ ),
189
+ diagnostics: z.array(
190
+ z.discriminatedUnion("code", [
191
+ z.object({
192
+ code: z.literal("missing_section"),
193
+ severity: z.literal("warn"),
194
+ stable_id: z.string(),
195
+ section: z.enum(KNOWLEDGE_SECTION_NAMES_TUPLE),
196
+ message: z.string()
197
+ }),
198
+ // v2.0: warn-level diagnostic for un-migrated v1.x entries (no
199
+ // knowledge_type and no knowledge_layer). Does NOT block selection.
200
+ z.object({
201
+ code: z.literal("missing_knowledge_metadata"),
202
+ severity: z.literal("warn"),
203
+ stable_id: z.string(),
204
+ message: z.string()
205
+ })
206
+ ])
207
+ ),
208
+ // v2/rc.3 (Q6): present iff a layer-flip in fab_review/modify changed the
209
+ // canonical stable_id since the caller's selection_token was minted.
210
+ // Clients should retry against `redirect_to.stable_id`.
211
+ redirect_to: z.object({ stable_id: z.string() }).optional().describe(
212
+ "Post-layer-flip redirect. Populated when stable_id changed after token mint (rc.3 fab_review/modify)."
213
+ ),
214
+ warnings: z.array(structuredWarningSchema).optional()
215
+ });
216
+ var knowledgeSectionsAnnotations = {
217
+ readOnlyHint: true,
218
+ idempotentHint: true,
219
+ destructiveHint: false,
220
+ openWorldHint: false,
221
+ title: "Filter rule sections"
222
+ };
223
+ var ProposedReasonSchema = z.enum([
224
+ "explicit-user-mark",
225
+ "diagnostic-then-fix",
226
+ "decision-confirmation",
227
+ "wrong-turn-revert",
228
+ "new-dependency-or-pattern",
229
+ "dismissal-with-reason"
230
+ ]);
231
+ var PROPOSED_REASON_DESCRIPTIONS = {
232
+ "explicit-user-mark": "\u7528\u6237\u663E\u5F0F\u6807\u8BB0\u9700\u5F52\u6863\uFF08always / never / \u4E0B\u6B21\u6CE8\u610F \u7B49\u89C4\u8303\u6027\u8BED\u8A00\uFF09\u3002",
233
+ "diagnostic-then-fix": "\u8BCA\u65AD\u8FC7\u7A0B\u53D1\u73B0\u65B0\u6A21\u5F0F\u6216\u8E29\u5751\uFF0C\u4FEE\u590D\u540E\u503C\u5F97\u6C89\u6DC0\u3002",
234
+ "decision-confirmation": "\u22652 \u5019\u9009\u65B9\u6848\u7ECF\u6743\u8861\u540E\u786E\u8BA4\u9009\u578B\uFF0C\u9700\u4FDD\u7559 rationale\u3002",
235
+ "wrong-turn-revert": "\u5C1D\u8BD5\u67D0\u8DEF\u5F84\u540E\u56DE\u9000\uFF0C\u9519\u8BEF\u8DEF\u5F84\u672C\u8EAB\u662F\u503C\u5F97\u8BB0\u5F55\u7684 pitfall\u3002",
236
+ "new-dependency-or-pattern": "\u5F15\u5165\u65B0\u4F9D\u8D56 / \u65B0\u6A21\u5F0F / \u65B0\u547D\u540D\u7EA6\u5B9A\u3002",
237
+ "dismissal-with-reason": "\u7528\u6237\u660E\u786E\u62D2\u7EDD\u67D0\u65B9\u6848\u5E76\u7ED9\u51FA\u539F\u56E0\uFF0C\u539F\u56E0\u5373\u53EF\u5F52\u6863\u77E5\u8BC6\u3002"
238
+ };
239
+ var _sourceSessionsField = z.preprocess(
240
+ (value) => {
241
+ if (typeof value === "string") return [value];
242
+ return value;
243
+ },
244
+ z.array(z.string().min(1)).min(1)
245
+ );
246
+ var _FabExtractKnowledgeInputBaseSchema = z.object({
247
+ // v2.0.0-rc.7 T5: array form. Legacy single-string callers are accepted
248
+ // via the preprocess shim above. The optional pre-T5 alias `source_session`
249
+ // is kept as an accepted alternative below for in-flight integrations
250
+ // (Zod parses one or the other — see refinement).
251
+ source_sessions: _sourceSessionsField.optional().describe(
252
+ "Originating session ids; correlates with Event Ledger records. Array form (T5). Single string accepted via back-compat shim."
253
+ ),
254
+ // Pre-T5 alias. When set and source_sessions is missing, the handler maps
255
+ // it to [source_session]. Marked optional so new callers can drop it.
256
+ source_session: z.string().min(1).optional().describe(
257
+ "DEPRECATED \u2014 pre-T5 alias for source_sessions. Use source_sessions: string[]. Single string still accepted for back-compat."
258
+ ),
259
+ recent_paths: z.array(z.string()).describe("Workspace paths recently touched in the source session \u2014 used as scope hints"),
260
+ user_messages_summary: z.string().describe("Skill-side summary of the user's intent/messages, kept compact"),
261
+ type: z.enum(["decisions", "pitfalls", "guidelines", "models", "processes"]).describe("Knowledge type bucket (plural form, mirrors directory layout)"),
262
+ slug: z.string().describe("URL-safe short identifier proposed by the Skill; server may sanitize"),
263
+ // rc.5 B1: dual pending root. When 'personal', the server writes to
264
+ // ~/.fabric/knowledge/pending/<type>/; otherwise to .fabric/knowledge/pending/<type>/.
265
+ // Defaults to 'team' to preserve existing call sites (Skill bumps as needed).
266
+ layer: z.enum(["team", "personal"]).optional().describe(
267
+ "Storage layer for the pending entry. 'team' writes under the workspace; 'personal' writes under the user's home. Defaults to 'team'."
268
+ ),
269
+ // v2.0.0-rc.7 T6: proposed_reason — required enum that drives `## Why
270
+ // proposed` rendering. Skills (archive / import / review) infer the
271
+ // appropriate reason per their semantics (see each SKILL.md).
272
+ proposed_reason: ProposedReasonSchema.describe(
273
+ "Why this entry is being proposed. Drives `## Why proposed` rendering and enables future maturity-promotion scoring."
274
+ ),
275
+ // v2.0.0-rc.7 T6: session_context — required 3-5 line markdown blob that
276
+ // captures the session goal + key turning point. Future-self review reads
277
+ // this without conversation transcript access. Min length guards against
278
+ // empty placeholders; cap is soft (no max), Skill caps at ~600 chars.
279
+ session_context: z.string().min(20, { message: "session_context must be \u226520 chars (3-5 lines describing goal + turning point)" }).describe(
280
+ "3-5 line markdown blob \u2014 session goal + key turning point. Reviewed by future-self without transcript access."
281
+ )
282
+ });
283
+ var FabExtractKnowledgeInputSchema = _FabExtractKnowledgeInputBaseSchema.superRefine(
284
+ (value, ctx) => {
285
+ const hasArray = Array.isArray(value.source_sessions) && value.source_sessions.length > 0;
286
+ const hasString = typeof value.source_session === "string" && value.source_session.length > 0;
287
+ if (!hasArray && !hasString) {
288
+ ctx.addIssue({
289
+ code: z.ZodIssueCode.custom,
290
+ message: "either source_sessions (array, preferred) or source_session (legacy single string) must be provided",
291
+ path: ["source_sessions"]
292
+ });
293
+ }
294
+ }
295
+ );
296
+ var FabExtractKnowledgeInputShape = _FabExtractKnowledgeInputBaseSchema.shape;
297
+ var FabExtractKnowledgeOutputSchema = z.object({
298
+ pending_path: z.string().describe("Workspace-relative path to the persisted pending entry"),
299
+ idempotency_key: z.string().describe("Stable key derived from inputs; identical inputs yield identical key")
300
+ });
301
+ var fabExtractKnowledgeAnnotations = {
302
+ readOnlyHint: false,
303
+ idempotentHint: true,
304
+ destructiveHint: false,
305
+ openWorldHint: false,
306
+ title: "Extract pending knowledge entry"
307
+ };
308
+ var _fabReviewFiltersSchema = z.object({
309
+ type: z.enum(["decisions", "pitfalls", "guidelines", "models", "processes"]).optional(),
310
+ layer: z.enum(["team", "personal", "both"]).optional(),
311
+ maturity: z.enum(["draft", "verified", "proven"]).optional(),
312
+ tags: z.array(z.string()).optional(),
313
+ // rc.4 TASK-006 fix (c): ISO-8601 lower bound on entry created_at; entries
314
+ // strictly older than this threshold are excluded from list / search
315
+ // results. Additive optional field — existing callers unaffected.
316
+ created_after: z.string().datetime().optional()
317
+ }).optional();
318
+ var _fabReviewModifyChangesSchema = z.object({
319
+ title: z.string().optional(),
320
+ summary: z.string().optional(),
321
+ // Q7: writing `layer` here triggers a layer-flip; downstream callers may
322
+ // observe a redirect_to in fab_get_knowledge_sections if stable_id changes.
323
+ layer: z.enum(["team", "personal"]).optional(),
324
+ maturity: z.enum(["draft", "verified", "proven"]).optional(),
325
+ tags: z.array(z.string()).optional(),
326
+ // v2.0-rc.5 C3 (TASK-012): relevance scope/paths patches. Applied to
327
+ // pending AND canonical entries. When an explicit team→personal layer flip
328
+ // arrives on a narrow entry, the server auto-degrades to broad + [] and
329
+ // emits a `knowledge_scope_degraded` event regardless of what the caller
330
+ // sent in these fields (personal-implies-broad).
331
+ relevance_scope: z.enum(["narrow", "broad"]).optional(),
332
+ relevance_paths: z.array(z.string()).optional()
333
+ });
334
+ var FabReviewInputSchema = z.discriminatedUnion("action", [
335
+ z.object({
336
+ action: z.literal("list"),
337
+ filters: _fabReviewFiltersSchema
338
+ }),
339
+ z.object({
340
+ action: z.literal("approve"),
341
+ pending_paths: z.array(z.string()).min(1)
342
+ }),
343
+ z.object({
344
+ action: z.literal("reject"),
345
+ pending_paths: z.array(z.string()).min(1),
346
+ reason: z.string().min(1)
347
+ }),
348
+ z.object({
349
+ action: z.literal("modify"),
350
+ pending_path: z.string().min(1),
351
+ changes: _fabReviewModifyChangesSchema
352
+ }),
353
+ z.object({
354
+ action: z.literal("search"),
355
+ query: z.string().min(1),
356
+ filters: _fabReviewFiltersSchema
357
+ }),
358
+ z.object({
359
+ action: z.literal("defer"),
360
+ pending_paths: z.array(z.string()).min(1),
361
+ until: z.string().datetime().optional(),
362
+ reason: z.string().optional()
363
+ })
364
+ ]);
365
+ var _fabReviewListItemSchema = z.object({
366
+ pending_path: z.string(),
367
+ type: z.enum(["decisions", "pitfalls", "guidelines", "models", "processes"]),
368
+ layer: z.enum(["team", "personal"]),
369
+ maturity: z.enum(["draft", "verified", "proven"]),
370
+ tags: z.array(z.string()).optional(),
371
+ title: z.string().optional(),
372
+ summary: z.string().optional(),
373
+ // rc.5 B1: dual pending root. 'team' = workspace .fabric/knowledge/pending,
374
+ // 'personal' = ~/.fabric/knowledge/pending. Distinct from `layer` (frontmatter):
375
+ // origin reflects where the pending file actually lives on disk; layer reflects
376
+ // the declared classification that will drive the approve destination.
377
+ origin: z.enum(["team", "personal"]).optional()
378
+ });
379
+ var FabReviewOutputSchema = z.discriminatedUnion("action", [
380
+ z.object({
381
+ action: z.literal("list"),
382
+ items: z.array(_fabReviewListItemSchema)
383
+ }),
384
+ z.object({
385
+ action: z.literal("approve"),
386
+ approved: z.array(z.object({ pending_path: z.string(), stable_id: z.string() }))
387
+ }),
388
+ z.object({
389
+ action: z.literal("reject"),
390
+ rejected: z.array(z.string())
391
+ }),
392
+ z.object({
393
+ action: z.literal("modify"),
394
+ pending_path: z.string(),
395
+ // When a layer-flip occurred, prior_stable_id and new_stable_id differ.
396
+ prior_stable_id: z.string().optional(),
397
+ new_stable_id: z.string().optional()
398
+ }),
399
+ z.object({
400
+ action: z.literal("search"),
401
+ items: z.array(_fabReviewListItemSchema)
402
+ }),
403
+ z.object({
404
+ action: z.literal("defer"),
405
+ deferred: z.array(z.string())
406
+ })
407
+ ]);
408
+ var fabReviewAnnotations = {
409
+ readOnlyHint: false,
410
+ idempotentHint: false,
411
+ destructiveHint: false,
412
+ openWorldHint: false,
413
+ title: "Review pending knowledge entries"
414
+ };
415
+ var ledgerSourceSchema = z.enum(["ai", "human"]);
416
+ var timestampFilterSchema = z.preprocess((value) => {
417
+ if (value === void 0 || value === null || value === "") {
418
+ return void 0;
419
+ }
420
+ if (typeof value === "number") {
421
+ return value;
422
+ }
423
+ if (typeof value === "string") {
424
+ const trimmed = value.trim();
425
+ if (trimmed.length === 0) {
426
+ return void 0;
427
+ }
428
+ if (/^\d+$/.test(trimmed)) {
429
+ return Number.parseInt(trimmed, 10);
430
+ }
431
+ const parsed = Date.parse(trimmed);
432
+ return Number.isNaN(parsed) ? value : parsed;
433
+ }
434
+ return value;
435
+ }, z.number().int().nonnegative());
436
+ var ledgerQuerySchema = z.object({
437
+ source: ledgerSourceSchema.optional(),
438
+ since: timestampFilterSchema.optional()
439
+ });
440
+ var historyStateQuerySchema = z.object({
441
+ ledger_id: z.string().trim().min(1).optional(),
442
+ ts: timestampFilterSchema.optional()
443
+ }).superRefine((value, ctx) => {
444
+ const provided = [value.ledger_id, value.ts].filter((entry) => entry !== void 0);
445
+ if (provided.length !== 1) {
446
+ ctx.addIssue({
447
+ code: z.ZodIssueCode.custom,
448
+ message: "Provide exactly one of ledger_id or ts.",
449
+ path: ["ledger_id"]
450
+ });
451
+ }
452
+ });
453
+ var humanLockApproveRequestSchema = z.object({
454
+ file: z.string().min(1),
455
+ start_line: z.number().int().positive(),
456
+ end_line: z.number().int().positive(),
457
+ new_hash: z.string().min(1)
458
+ });
459
+ var humanLockFileParamsSchema = z.object({
460
+ file: z.string().min(1)
461
+ });
462
+ var annotateIntentRequestSchema = z.object({
463
+ ledger_entry_id: z.string().min(1),
464
+ annotation: z.string().trim().min(1)
465
+ });
466
+ var KnowledgeTypeSchema = z.enum([
467
+ "model",
468
+ // entities, data structures, relationships
469
+ "decision",
470
+ // architectural/technical choices with rationale
471
+ "guideline",
472
+ // recommended practices (recommend) or anti-patterns (avoid)
473
+ "pitfall",
474
+ // known risks, failure modes, troubleshooting
475
+ "process"
476
+ // workflows, state machines, operational steps
477
+ ]);
478
+ var MaturitySchema = z.enum(["draft", "verified", "proven"]);
479
+ var LayerSchema = z.enum(["personal", "team"]);
480
+ var StableIdSchema = z.string().regex(/^K[PT]-(MOD|DEC|GLD|PIT|PRO)-\d{4,}$/);
481
+ var KnowledgeEntryFrontmatterSchema = z.object({
482
+ id: StableIdSchema,
483
+ // e.g., "KT-DEC-0042"
484
+ type: KnowledgeTypeSchema,
485
+ // one of 5 types
486
+ maturity: MaturitySchema,
487
+ // draft | verified | proven
488
+ layer: LayerSchema,
489
+ // personal | team
490
+ layer_reason: z.string().optional(),
491
+ // why this layer (for ambiguous cases)
492
+ created_at: z.string()
493
+ // ISO 8601 timestamp
494
+ // Note: 'tags' and other fields can be added later but core schema is these 6
495
+ });
496
+ var KNOWLEDGE_TYPE_CODES = {
497
+ model: "MOD",
498
+ decision: "DEC",
499
+ guideline: "GLD",
500
+ pitfall: "PIT",
501
+ process: "PRO"
502
+ };
503
+ function formatKnowledgeId(layer, type, counter) {
504
+ const layerPrefix = layer === "personal" ? "KP" : "KT";
505
+ const typeCode = KNOWLEDGE_TYPE_CODES[type];
506
+ return `${layerPrefix}-${typeCode}-${String(counter).padStart(4, "0")}`;
507
+ }
508
+ function parseKnowledgeId(id) {
509
+ const match = id.match(/^(KP|KT)-(MOD|DEC|GLD|PIT|PRO)-(\d+)$/);
510
+ if (!match) return null;
511
+ const layer = match[1] === "KP" ? "personal" : "team";
512
+ const typeCode = match[2];
513
+ const entry = Object.entries(KNOWLEDGE_TYPE_CODES).find(([, code]) => code === typeCode);
514
+ if (!entry) return null;
515
+ const type = entry[0];
516
+ return { layer, type, counter: parseInt(match[3], 10) };
517
+ }
518
+
519
+ export {
520
+ structuredWarningSchema,
521
+ planContextInputSchema,
522
+ planContextOutputSchema,
523
+ planContextAnnotations,
524
+ planContextHintNarrowEntrySchema,
525
+ planContextHintOutputSchema,
526
+ getKnowledgeInputSchema,
527
+ getKnowledgeOutputSchema,
528
+ getKnowledgeAnnotations,
529
+ knowledgeSectionsInputSchema,
530
+ knowledgeSectionsOutputSchema,
531
+ knowledgeSectionsAnnotations,
532
+ ProposedReasonSchema,
533
+ PROPOSED_REASON_DESCRIPTIONS,
534
+ FabExtractKnowledgeInputSchema,
535
+ FabExtractKnowledgeInputShape,
536
+ FabExtractKnowledgeOutputSchema,
537
+ fabExtractKnowledgeAnnotations,
538
+ FabReviewInputSchema,
539
+ FabReviewOutputSchema,
540
+ fabReviewAnnotations,
541
+ ledgerSourceSchema,
542
+ ledgerQuerySchema,
543
+ historyStateQuerySchema,
544
+ humanLockApproveRequestSchema,
545
+ humanLockFileParamsSchema,
546
+ annotateIntentRequestSchema,
547
+ KnowledgeTypeSchema,
548
+ MaturitySchema,
549
+ LayerSchema,
550
+ StableIdSchema,
551
+ KnowledgeEntryFrontmatterSchema,
552
+ KNOWLEDGE_TYPE_CODES,
553
+ formatKnowledgeId,
554
+ parseKnowledgeId
555
+ };
@@ -12,7 +12,7 @@ declare function detectNodeLocale(): Locale;
12
12
 
13
13
  declare function normalizeLocale(raw: string | null | undefined): Locale;
14
14
 
15
- declare const PROTECTED_TOKENS: readonly ["fab_plan_context", "fab_get_rule_sections", "fabric_rules", "ledger_entry", "ledger_entry_id", "agent_meta", "AGENTS.md", "FABRIC.md", ".fabric/agents/", ".fabric/agents/_cross/", ".fabric/agents.meta.json", ".fabric/human-lock.json", ".fabric/init-context.json", ".fabric/forensic.json", ".fabric/.intent-ledger.jsonl", ".fabric/events.jsonl", "@HUMAN", "shadow constraints", "Shadow Mirroring", "CORE RULES", "DO NOT TRANSLATE", "MUST", "NEVER"];
15
+ 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", "@HUMAN", "MUST", "NEVER"];
16
16
  type ProtectedToken = (typeof PROTECTED_TOKENS)[number];
17
17
 
18
18
  declare const enMessages: Messages;
@@ -6,7 +6,7 @@ import {
6
6
  enMessages,
7
7
  normalizeLocale,
8
8
  zhCNMessages
9
- } from "../chunk-KHIM6MWS.js";
9
+ } from "../chunk-U2SR2M4L.js";
10
10
  export {
11
11
  PROTECTED_TOKENS,
12
12
  createTranslator,