@fenglimg/fabric-shared 2.2.0-rc.1 → 2.2.0-rc.10
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-2GLIAZ5M.js +251 -0
- package/dist/{chunk-JEXTOQVV.js → chunk-5AKCRBKJ.js} +541 -401
- package/dist/{chunk-7TZ2PMVH.js → chunk-AQMDXC6J.js} +471 -519
- package/dist/chunk-BDJQIOQO.js +206 -0
- package/dist/chunk-C7WZPYZE.js +129 -0
- package/dist/{chunk-3SZRB42B.js → chunk-O6GIHZF3.js} +14 -0
- package/dist/errors/index.d.ts +12 -1
- package/dist/errors/index.js +9 -3
- package/dist/i18n/index.d.ts +29 -23
- package/dist/i18n/index.js +7 -3
- package/dist/{index-J3Xn5h2J.d.ts → index-D_gT1CEA.d.ts} +108 -34
- package/dist/index.d.ts +829 -582
- package/dist/index.js +1495 -955
- package/dist/node/atomic-write.js +6 -106
- package/dist/node/mcp-payload-guard.js +1 -1
- package/dist/node.d.ts +10 -1
- package/dist/node.js +32 -1
- package/dist/schemas/api-contracts.d.ts +290 -118
- package/dist/schemas/api-contracts.js +3 -3
- package/dist/templates/bootstrap-canonical.d.ts +50 -23
- package/dist/templates/bootstrap-canonical.js +12 -9
- package/dist/types/index.d.ts +1 -1
- package/dist/types-qg4xXVuT.d.ts +8 -0
- package/package.json +3 -2
- package/dist/chunk-TX2XZ7AW.js +0 -102
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/schemas/api-contracts.ts
|
|
2
|
-
import { z as
|
|
2
|
+
import { z as z3 } from "zod";
|
|
3
3
|
|
|
4
4
|
// src/onboard-slots.ts
|
|
5
5
|
import { z } from "zod";
|
|
@@ -13,63 +13,91 @@ var ONBOARD_SLOT_NAMES = [
|
|
|
13
13
|
var onboardSlotSchema = z.enum(ONBOARD_SLOT_NAMES);
|
|
14
14
|
var ONBOARD_SLOT_TOTAL = ONBOARD_SLOT_NAMES.length;
|
|
15
15
|
|
|
16
|
+
// src/schemas/scope.ts
|
|
17
|
+
import { z as z2 } from "zod";
|
|
18
|
+
var PERSONAL_SCOPE = "personal";
|
|
19
|
+
var KNOWN_SCOPE_PREFIXES = ["personal", "team", "project", "org"];
|
|
20
|
+
var SCOPE_COORDINATE_PATTERN = /^[a-z0-9_-]+(:[a-z0-9_-]+)*$/u;
|
|
21
|
+
var scopeCoordinateSchema = z2.string().min(1).regex(
|
|
22
|
+
SCOPE_COORDINATE_PATTERN,
|
|
23
|
+
"scope coordinate must be ':'-joined lowercase [a-z0-9_-] segments"
|
|
24
|
+
);
|
|
25
|
+
function scopeRoot(coordinate) {
|
|
26
|
+
const colon = coordinate.indexOf(":");
|
|
27
|
+
return colon === -1 ? coordinate : coordinate.slice(0, colon);
|
|
28
|
+
}
|
|
29
|
+
function isPersonalScope(coordinate) {
|
|
30
|
+
return scopeRoot(coordinate) === PERSONAL_SCOPE;
|
|
31
|
+
}
|
|
32
|
+
var entryScopeMetadataSchema = z2.object({
|
|
33
|
+
semantic_scope: scopeCoordinateSchema,
|
|
34
|
+
// Store alias or UUID. Validated as a non-empty string here; the resolver
|
|
35
|
+
// (P0.6) maps alias→UUID and verifies the store is in the read-set.
|
|
36
|
+
visibility_store: z2.string().min(1)
|
|
37
|
+
}).strict();
|
|
38
|
+
|
|
16
39
|
// src/schemas/api-contracts.ts
|
|
17
|
-
var structuredWarningSchema =
|
|
18
|
-
code:
|
|
19
|
-
file:
|
|
20
|
-
line:
|
|
21
|
-
|
|
40
|
+
var structuredWarningSchema = z3.object({
|
|
41
|
+
code: z3.string(),
|
|
42
|
+
file: z3.string(),
|
|
43
|
+
line: z3.number().optional(),
|
|
44
|
+
message: z3.string().optional(),
|
|
45
|
+
action_hint: z3.string()
|
|
22
46
|
});
|
|
23
|
-
var _knowledgeTypeEnum =
|
|
24
|
-
var _maturityEnum =
|
|
25
|
-
var _layerEnum =
|
|
26
|
-
var _ruleDescriptionSchema =
|
|
27
|
-
summary:
|
|
28
|
-
intent_clues:
|
|
29
|
-
tech_stack:
|
|
30
|
-
impact:
|
|
31
|
-
must_read_if:
|
|
32
|
-
entities:
|
|
47
|
+
var _knowledgeTypeEnum = z3.enum(["models", "decisions", "guidelines", "pitfalls", "processes"]);
|
|
48
|
+
var _maturityEnum = z3.enum(["draft", "verified", "proven"]);
|
|
49
|
+
var _layerEnum = z3.enum(["personal", "team"]);
|
|
50
|
+
var _ruleDescriptionSchema = z3.object({
|
|
51
|
+
summary: z3.string(),
|
|
52
|
+
intent_clues: z3.array(z3.string()),
|
|
53
|
+
tech_stack: z3.array(z3.string()),
|
|
54
|
+
impact: z3.array(z3.string()),
|
|
55
|
+
must_read_if: z3.string(),
|
|
56
|
+
entities: z3.array(z3.string()).optional(),
|
|
33
57
|
// v2.0: optional knowledge-entry fields. Absent for v1.x rules; present for
|
|
34
58
|
// entries that declare frontmatter `id/type/maturity/layer`.
|
|
35
|
-
id:
|
|
59
|
+
id: z3.string().optional(),
|
|
36
60
|
knowledge_type: _knowledgeTypeEnum.optional(),
|
|
37
61
|
maturity: _maturityEnum.optional(),
|
|
38
62
|
knowledge_layer: _layerEnum.optional(),
|
|
39
|
-
layer_reason:
|
|
40
|
-
created_at:
|
|
63
|
+
layer_reason: z3.string().optional(),
|
|
64
|
+
created_at: z3.string().optional(),
|
|
41
65
|
// v2.0.0-rc.38 UX-3 (D-MCP fold ③): these three were previously carried ONLY
|
|
42
66
|
// as top-level mirrors on the index item. With the mirrors removed,
|
|
43
67
|
// `description` becomes their canonical (and only) home, so the schema must
|
|
44
68
|
// validate them here. Optional + default-safe (tags/[]/broad) so legacy
|
|
45
69
|
// entries without frontmatter still parse.
|
|
46
|
-
tags:
|
|
47
|
-
relevance_scope:
|
|
48
|
-
relevance_paths:
|
|
70
|
+
tags: z3.array(z3.string()).optional(),
|
|
71
|
+
relevance_scope: z3.enum(["narrow", "broad"]).optional(),
|
|
72
|
+
relevance_paths: z3.array(z3.string()).optional(),
|
|
49
73
|
// v2.2 H2-related (W1-T7) — W1-REVIEW codex HIGH-2: the MCP-facing description
|
|
50
74
|
// schema must also carry `related`, else zod strips the graph edges on output
|
|
51
75
|
// validation and they never reach the client (MC1 include_related / fabric-
|
|
52
76
|
// connect would see nothing). Mirrors the agents-meta ruleDescriptionSchema.
|
|
53
|
-
related:
|
|
77
|
+
related: z3.array(z3.string()).optional()
|
|
54
78
|
});
|
|
55
|
-
var _descriptionIndexItemSchema =
|
|
56
|
-
stable_id:
|
|
57
|
-
description: _ruleDescriptionSchema
|
|
79
|
+
var _descriptionIndexItemSchema = z3.object({
|
|
80
|
+
stable_id: z3.string(),
|
|
81
|
+
description: _ruleDescriptionSchema,
|
|
82
|
+
// recall dedupe marker: true when this candidate is ALSO injected in full at
|
|
83
|
+
// SessionStart ("ALWAYS-ACTIVE RULES" = broad model/guideline). MUST be
|
|
84
|
+
// declared here or zod .strip() drops it at the MCP boundary (KT-PIT-0005),
|
|
85
|
+
// silently breaking the marker even though recall() sets it. Only ever true.
|
|
86
|
+
always_active: z3.boolean().optional()
|
|
58
87
|
});
|
|
59
|
-
var _requirementProfileSchema =
|
|
60
|
-
target_path:
|
|
61
|
-
known_tech:
|
|
62
|
-
|
|
63
|
-
detected_entities: z2.array(z2.string())
|
|
88
|
+
var _requirementProfileSchema = z3.object({
|
|
89
|
+
target_path: z3.string(),
|
|
90
|
+
known_tech: z3.array(z3.string()),
|
|
91
|
+
detected_entities: z3.array(z3.string())
|
|
64
92
|
});
|
|
65
|
-
var planContextInputSchema =
|
|
66
|
-
paths:
|
|
67
|
-
intent:
|
|
68
|
-
known_tech:
|
|
69
|
-
detected_entities:
|
|
70
|
-
client_hash:
|
|
71
|
-
correlation_id:
|
|
72
|
-
session_id:
|
|
93
|
+
var planContextInputSchema = z3.object({
|
|
94
|
+
paths: z3.array(z3.string()).min(1).describe("Candidate file paths to build neutral rule selection context for"),
|
|
95
|
+
intent: z3.string().optional().describe("User-stated requirement or implementation intent; used only to build a neutral requirement profile"),
|
|
96
|
+
known_tech: z3.array(z3.string()).optional().describe("Known technologies involved in the requirement profile"),
|
|
97
|
+
detected_entities: z3.record(z3.array(z3.string())).optional().describe("Optional path-keyed detected entities for the requirement profile"),
|
|
98
|
+
client_hash: z3.string().optional().describe("Revision hash from a prior fab_plan_context response; enables stale detection"),
|
|
99
|
+
correlation_id: z3.string().optional().describe("Optional caller-provided correlation id for Event Ledger records"),
|
|
100
|
+
session_id: z3.string().optional().describe(
|
|
73
101
|
"Recommended: pass the current client session id (Claude Code: $session_id; Codex: corresponding identifier) \u2014 enables cross-session debt tracking in fabric doctor and accurate archive-hint cross-session count. Falls back gracefully if omitted."
|
|
74
102
|
),
|
|
75
103
|
// v2.0-rc.5 A3 (TASK-007): `include_deprecated` removed — it was a no-op
|
|
@@ -78,55 +106,58 @@ var planContextInputSchema = z2.object({
|
|
|
78
106
|
// v2/rc.2 (Q6): client-supplied layer scope. When omitted, the server
|
|
79
107
|
// falls back to fabric-config.default_layer_filter (TASK-002) so a single
|
|
80
108
|
// workspace policy controls the default. Explicit values override.
|
|
81
|
-
layer_filter:
|
|
109
|
+
layer_filter: z3.enum(["team", "personal", "both"]).optional().describe(
|
|
82
110
|
"Restrict description_index to the named layer. Default: fabric-config.default_layer_filter (TASK-002)."
|
|
83
111
|
),
|
|
84
112
|
// v2.0-rc.5 C3 (TASK-012): explicit path context for `narrow` relevance
|
|
85
113
|
// filtering. When omitted, the server falls back to `paths` so existing
|
|
86
114
|
// callers see narrowing against the requested paths. When the resolved
|
|
87
115
|
// list is empty, the narrow filter fails open (every narrow entry passes).
|
|
88
|
-
target_paths:
|
|
116
|
+
target_paths: z3.array(z3.string()).optional().describe(
|
|
89
117
|
"Path context for narrow-scope relevance filtering. Defaults to `paths`; empty = no filter."
|
|
90
118
|
)
|
|
91
119
|
});
|
|
92
|
-
var _preflightDiagnosticSchema =
|
|
120
|
+
var _preflightDiagnosticSchema = z3.object({
|
|
93
121
|
// v2.0.0-rc.38 UX-2: `empty_shell_suppressed` surfaces draft entries whose
|
|
94
122
|
// description carries no selection signal (summary === stable_id + empty
|
|
95
123
|
// intent_clues/tech_stack/impact). They are filtered out of `candidates` to
|
|
96
124
|
// cut noise; this diagnostic names them so `fabric doctor` /
|
|
97
125
|
// --enrich-descriptions can prompt enrichment.
|
|
98
|
-
code:
|
|
99
|
-
severity:
|
|
100
|
-
message:
|
|
101
|
-
stable_ids:
|
|
102
|
-
path:
|
|
126
|
+
code: z3.enum(["missing_description", "empty_shell_suppressed"]),
|
|
127
|
+
severity: z3.literal("warn"),
|
|
128
|
+
message: z3.string(),
|
|
129
|
+
stable_ids: z3.array(z3.string()).optional(),
|
|
130
|
+
path: z3.string().optional()
|
|
103
131
|
});
|
|
104
|
-
var planContextOutputSchema =
|
|
105
|
-
revision_hash:
|
|
106
|
-
stale:
|
|
107
|
-
selection_token:
|
|
108
|
-
entries:
|
|
109
|
-
|
|
110
|
-
path:
|
|
132
|
+
var planContextOutputSchema = z3.object({
|
|
133
|
+
revision_hash: z3.string(),
|
|
134
|
+
stale: z3.boolean(),
|
|
135
|
+
selection_token: z3.string(),
|
|
136
|
+
entries: z3.array(
|
|
137
|
+
z3.object({
|
|
138
|
+
path: z3.string(),
|
|
111
139
|
requirement_profile: _requirementProfileSchema
|
|
112
140
|
})
|
|
113
141
|
),
|
|
114
|
-
|
|
142
|
+
// v2.2 payload de-dup: single top-level echo of the caller's `intent` (was
|
|
143
|
+
// duplicated into every entry's requirement_profile). Omitted when no intent.
|
|
144
|
+
intent: z3.string().optional(),
|
|
145
|
+
candidates: z3.array(_descriptionIndexItemSchema),
|
|
115
146
|
// v2.2 A-INFRA-3 (W1-T3-TOPK) / MC4-payload-budget (W1-T4): number of
|
|
116
147
|
// lower-ranked candidates dropped by the unified truncation chain (top_k cap
|
|
117
148
|
// + payload-budget trim). Present and > 0 ONLY when truncation fired, so the
|
|
118
149
|
// steady-state wire shape is unchanged. Lets the LLM know the returned set is
|
|
119
150
|
// not exhaustive ("N more exist; narrow your intent").
|
|
120
|
-
omitted_candidate_count:
|
|
121
|
-
preflight_diagnostics:
|
|
122
|
-
warnings:
|
|
151
|
+
omitted_candidate_count: z3.number().int().nonnegative().optional(),
|
|
152
|
+
preflight_diagnostics: z3.array(_preflightDiagnosticSchema),
|
|
153
|
+
warnings: z3.array(structuredWarningSchema).optional(),
|
|
123
154
|
// v2.0.0-rc.22 Scope D T-D2: optional auto-heal banner fields. Surfaced
|
|
124
155
|
// ONLY when the loadActiveMetaOrStale call detected drift and rebuilt the
|
|
125
156
|
// meta in-place. Downstream CLI / hint renderers use this pair to render a
|
|
126
157
|
// "knowledge meta auto-healed (was <prev>, now <curr>)" notice without
|
|
127
158
|
// having to query the event ledger.
|
|
128
|
-
auto_healed:
|
|
129
|
-
previous_revision_hash:
|
|
159
|
+
auto_healed: z3.boolean().optional(),
|
|
160
|
+
previous_revision_hash: z3.string().optional(),
|
|
130
161
|
// v2.0.0-rc.37 NEW-24: stale-id redirect map. Populated when one or more
|
|
131
162
|
// recent fab_review modify-layer flips reassigned a canonical stable_id
|
|
132
163
|
// and the NEW id is in this response's description_index. Callers that
|
|
@@ -134,7 +165,13 @@ var planContextOutputSchema = z2.object({
|
|
|
134
165
|
// the new id before issuing fab_get_knowledge_sections / fab_recall. Empty
|
|
135
166
|
// (field omitted) when no actionable redirects exist for the surfaced
|
|
136
167
|
// candidate set. See packages/server/src/services/id-redirect.ts.
|
|
137
|
-
redirects:
|
|
168
|
+
redirects: z3.record(z3.string()).optional(),
|
|
169
|
+
// lifecycle-refactor W3-T2 (§7 图谱消费): related-expansion provenance map
|
|
170
|
+
// (appended id → surfaced source id). Present only when `include_related` was
|
|
171
|
+
// requested AND at least one in-corpus one-hop neighbour was appended. Omitted
|
|
172
|
+
// on the graph-empty / steady-state path. Additive — declare it here or zod
|
|
173
|
+
// strips it on output validation.
|
|
174
|
+
related_appended: z3.record(z3.string()).optional()
|
|
138
175
|
});
|
|
139
176
|
var planContextAnnotations = {
|
|
140
177
|
readOnlyHint: true,
|
|
@@ -143,63 +180,69 @@ var planContextAnnotations = {
|
|
|
143
180
|
openWorldHint: false,
|
|
144
181
|
title: "Plan rule context"
|
|
145
182
|
};
|
|
146
|
-
var planContextHintNarrowEntrySchema =
|
|
147
|
-
id:
|
|
148
|
-
type:
|
|
149
|
-
maturity:
|
|
150
|
-
summary:
|
|
183
|
+
var planContextHintNarrowEntrySchema = z3.object({
|
|
184
|
+
id: z3.string(),
|
|
185
|
+
type: z3.string(),
|
|
186
|
+
maturity: z3.string(),
|
|
187
|
+
summary: z3.string(),
|
|
188
|
+
// W2-2 (KT-DEC-0027): the entry's must_read_if trigger hook, forwarded for the
|
|
189
|
+
// SessionStart REFERENCE rendering (decision/pitfall/process → title + hook).
|
|
190
|
+
// Optional — omitted when the frontmatter declares none.
|
|
191
|
+
must_read_if: z3.string().optional()
|
|
151
192
|
});
|
|
152
|
-
var planContextHintOutputSchema =
|
|
153
|
-
version:
|
|
154
|
-
revision_hash:
|
|
155
|
-
target_paths:
|
|
156
|
-
narrow:
|
|
157
|
-
broad_count:
|
|
193
|
+
var planContextHintOutputSchema = z3.object({
|
|
194
|
+
version: z3.literal(1),
|
|
195
|
+
revision_hash: z3.string(),
|
|
196
|
+
target_paths: z3.array(z3.string()),
|
|
197
|
+
narrow: z3.array(planContextHintNarrowEntrySchema),
|
|
198
|
+
broad_count: z3.number().int().nonnegative()
|
|
158
199
|
});
|
|
159
|
-
var knowledgeSectionsInputSchema =
|
|
160
|
-
selection_token:
|
|
161
|
-
ai_selected_stable_ids:
|
|
200
|
+
var knowledgeSectionsInputSchema = z3.object({
|
|
201
|
+
selection_token: z3.string().min(1).describe("Selection token returned by fab_plan_context"),
|
|
202
|
+
ai_selected_stable_ids: z3.array(z3.string()).describe(
|
|
162
203
|
"Stable ids picked from fab_plan_context candidates[].stable_id; choose 1..N to fetch bodies for"
|
|
163
204
|
),
|
|
164
|
-
ai_selection_reasons:
|
|
165
|
-
|
|
166
|
-
|
|
205
|
+
ai_selection_reasons: z3.record(z3.string().min(1)).optional().default({}).describe(
|
|
206
|
+
"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."
|
|
207
|
+
),
|
|
208
|
+
correlation_id: z3.string().optional().describe("Optional caller-provided correlation id for Event Ledger records"),
|
|
209
|
+
session_id: z3.string().optional().describe("Optional caller-provided session id for Event Ledger records"),
|
|
167
210
|
// v2.0 rc.5 TASK-014 (C5): optional client identity hash propagated into
|
|
168
211
|
// knowledge_consumed events. Falls back to empty string when unset — full
|
|
169
212
|
// client-identity propagation deferred to rc.6.
|
|
170
|
-
client_hash:
|
|
213
|
+
client_hash: z3.string().optional().describe("Optional caller-provided client hash propagated into knowledge_consumed events")
|
|
171
214
|
});
|
|
172
|
-
var knowledgeSectionsOutputSchema =
|
|
173
|
-
revision_hash:
|
|
215
|
+
var knowledgeSectionsOutputSchema = z3.object({
|
|
216
|
+
revision_hash: z3.string(),
|
|
174
217
|
// v2.0.0-rc.38 UX-13 (D-MCP step-2 audit): the deprecated `precedence`
|
|
175
218
|
// L2/L1/L0 tuple (flagged "removed in rc.24" but still emitted) is gone — it
|
|
176
219
|
// was a constant 3-string field on every response read by no production
|
|
177
|
-
// consumer.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
path:
|
|
220
|
+
// consumer. v2.0.0-rc.38 Goal B: the dead L0/L1/L2 `level` axis was retired
|
|
221
|
+
// too (dead-write — no consumer ordered by it).
|
|
222
|
+
selected_stable_ids: z3.array(z3.string()),
|
|
223
|
+
rules: z3.array(
|
|
224
|
+
z3.object({
|
|
225
|
+
stable_id: z3.string(),
|
|
226
|
+
path: z3.string(),
|
|
184
227
|
// v2.0.0-rc.23 TASK-013 (F8b): replaced the legacy
|
|
185
228
|
// `sections: Record<string,string>` (keyed by the 4-element A-set enum)
|
|
186
229
|
// with the full markdown body (frontmatter stripped). Callers scan the
|
|
187
230
|
// body for whichever B-set heading they need (Summary / Why proposed /
|
|
188
231
|
// Session context / Evidence) — section-name discipline is now a writer
|
|
189
232
|
// convention, not an API contract.
|
|
190
|
-
body:
|
|
233
|
+
body: z3.string()
|
|
191
234
|
})
|
|
192
235
|
),
|
|
193
|
-
diagnostics:
|
|
236
|
+
diagnostics: z3.array(
|
|
194
237
|
// v2.0.0-rc.23 TASK-013 (F8b): `missing_section` was removed alongside the
|
|
195
238
|
// A-set enum. `missing_knowledge_metadata` stays as the warn-level signal
|
|
196
239
|
// for un-migrated v1.x entries (no knowledge_type AND no knowledge_layer
|
|
197
240
|
// in frontmatter). Does NOT block selection.
|
|
198
|
-
|
|
199
|
-
code:
|
|
200
|
-
severity:
|
|
201
|
-
stable_id:
|
|
202
|
-
message:
|
|
241
|
+
z3.object({
|
|
242
|
+
code: z3.enum(["missing_knowledge_metadata", "unresolved_selected_id"]),
|
|
243
|
+
severity: z3.literal("warn"),
|
|
244
|
+
stable_id: z3.string(),
|
|
245
|
+
message: z3.string()
|
|
203
246
|
})
|
|
204
247
|
),
|
|
205
248
|
// v2/rc.3 (Q6) + v2.0.0-rc.37 NEW-24: present iff at least one stable_id in
|
|
@@ -209,105 +252,96 @@ var knowledgeSectionsOutputSchema = z2.object({
|
|
|
209
252
|
// (old_id → new_id) when multiple rewrites fire in one fetch. Both shapes
|
|
210
253
|
// are accepted for forward-compat; readers should branch on shape and
|
|
211
254
|
// refresh their cached ids accordingly.
|
|
212
|
-
redirect_to:
|
|
213
|
-
|
|
214
|
-
|
|
255
|
+
redirect_to: z3.union([
|
|
256
|
+
z3.object({ stable_id: z3.string() }),
|
|
257
|
+
z3.record(z3.string())
|
|
215
258
|
]).optional().describe(
|
|
216
259
|
"Post-layer-flip redirect. Pre-rc.37: { stable_id } shape from rc.3 fab_review/modify. rc.37+: also accepts a (old_id \u2192 new_id) map for fab_get_knowledge_sections / fab_recall transparent rewrite."
|
|
217
260
|
),
|
|
218
|
-
warnings:
|
|
261
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
219
262
|
});
|
|
220
263
|
var knowledgeSectionsAnnotations = {
|
|
221
264
|
readOnlyHint: true,
|
|
222
265
|
idempotentHint: true,
|
|
223
266
|
destructiveHint: false,
|
|
224
267
|
openWorldHint: false,
|
|
225
|
-
title: "
|
|
268
|
+
title: "Fetch knowledge entry bodies"
|
|
226
269
|
};
|
|
227
|
-
var recallInputSchema =
|
|
228
|
-
paths:
|
|
229
|
-
"Candidate file paths to recall Fabric
|
|
230
|
-
),
|
|
231
|
-
intent:
|
|
232
|
-
known_tech:
|
|
233
|
-
detected_entities:
|
|
234
|
-
client_hash:
|
|
235
|
-
correlation_id:
|
|
236
|
-
session_id:
|
|
270
|
+
var recallInputSchema = z3.object({
|
|
271
|
+
paths: z3.array(z3.string()).min(1).describe(
|
|
272
|
+
"Candidate file paths to recall Fabric knowledge entries for. Same semantics as fab_plan_context.paths."
|
|
273
|
+
),
|
|
274
|
+
intent: z3.string().optional().describe("User-stated requirement or implementation intent; used to build a neutral requirement profile."),
|
|
275
|
+
known_tech: z3.array(z3.string()).optional().describe("Known technologies involved."),
|
|
276
|
+
detected_entities: z3.record(z3.array(z3.string())).optional().describe("Optional path-keyed detected entities."),
|
|
277
|
+
client_hash: z3.string().optional().describe("Revision hash from a prior call; enables stale detection."),
|
|
278
|
+
correlation_id: z3.string().optional().describe("Optional caller-provided correlation id for Event Ledger records."),
|
|
279
|
+
session_id: z3.string().optional().describe(
|
|
237
280
|
"Current client session id (Claude Code: $session_id; Codex: corresponding identifier). Enables cross-session debt tracking. Falls back gracefully if omitted."
|
|
238
281
|
),
|
|
239
|
-
layer_filter:
|
|
282
|
+
layer_filter: z3.enum(["team", "personal", "both"]).optional().describe(
|
|
240
283
|
"Restrict recall to the named layer. Default: fabric-config.default_layer_filter."
|
|
241
284
|
),
|
|
242
|
-
target_paths:
|
|
285
|
+
target_paths: z3.array(z3.string()).optional().describe(
|
|
243
286
|
"Path context for narrow-scope relevance filtering. Defaults to `paths`; empty = no filter."
|
|
244
287
|
),
|
|
245
|
-
ids:
|
|
246
|
-
"Optional explicit stable_ids to
|
|
288
|
+
ids: z3.array(z3.string()).optional().describe(
|
|
289
|
+
"Optional explicit stable_ids to SCOPE the returned read paths. When omitted, `paths` carries one read path per surfaced candidate. The candidate DESCRIPTION index is always returned in full for discovery \u2014 `ids` only narrows which read paths are surfaced (e.g. when you already know which entries to Read). Stale ids are redirect-rewritten before matching."
|
|
247
290
|
),
|
|
248
|
-
//
|
|
249
|
-
include_related:
|
|
250
|
-
"When true, also
|
|
291
|
+
// W1-3 / KT-DEC-0031: graph expansion (surface related read paths, no body).
|
|
292
|
+
include_related: z3.boolean().optional().describe(
|
|
293
|
+
"When true, also surface the one-hop `related` graph neighbours (of the surfaced entries) that are present in the candidate set \u2014 their descriptions and read paths, NOT their bodies."
|
|
251
294
|
)
|
|
252
295
|
});
|
|
253
|
-
var recallOutputSchema =
|
|
254
|
-
revision_hash:
|
|
255
|
-
stale:
|
|
256
|
-
// Selection token surfaced for callers who want to continue the conversation
|
|
257
|
-
// with fab_get_knowledge_sections (e.g. fetch additional ids later) — every
|
|
258
|
-
// recall response is still token-backed internally.
|
|
259
|
-
selection_token: z2.string(),
|
|
296
|
+
var recallOutputSchema = z3.object({
|
|
297
|
+
revision_hash: z3.string(),
|
|
298
|
+
stale: z3.boolean(),
|
|
260
299
|
// v2.0.0-rc.38 UX-1/UX-4: mirrors planContextOutputSchema fold ① — per-path
|
|
261
300
|
// description_index collapsed into a single top-level `candidates`, and
|
|
262
301
|
// `preflight_diagnostics` lifted out of the removed `shared` wrapper.
|
|
263
|
-
entries:
|
|
264
|
-
|
|
265
|
-
path:
|
|
302
|
+
entries: z3.array(
|
|
303
|
+
z3.object({
|
|
304
|
+
path: z3.string(),
|
|
266
305
|
requirement_profile: _requirementProfileSchema
|
|
267
306
|
})
|
|
268
307
|
),
|
|
269
|
-
|
|
270
|
-
//
|
|
271
|
-
|
|
272
|
-
//
|
|
273
|
-
//
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
//
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
),
|
|
285
|
-
selected_stable_ids: z2.array(z2.string()),
|
|
286
|
-
diagnostics: z2.array(
|
|
287
|
-
z2.object({
|
|
288
|
-
code: z2.literal("missing_knowledge_metadata"),
|
|
289
|
-
severity: z2.literal("warn"),
|
|
290
|
-
stable_id: z2.string(),
|
|
291
|
-
message: z2.string()
|
|
308
|
+
// v2.2 payload de-dup: single top-level echo of the caller's `intent` (was
|
|
309
|
+
// duplicated into every entry's requirement_profile). Omitted when no intent.
|
|
310
|
+
intent: z3.string().optional(),
|
|
311
|
+
// W1 (KT-DEC-0026): the discovery index — every surfaced candidate's
|
|
312
|
+
// DESCRIPTION (summary / intent_clues / must_read_if / related ...). No body.
|
|
313
|
+
candidates: z3.array(_descriptionIndexItemSchema),
|
|
314
|
+
// W1 (KT-DEC-0026): the read-path index — one entry per surfaced candidate
|
|
315
|
+
// (scoped by `ids` when provided), in ranked order. `path` is the on-disk
|
|
316
|
+
// knowledge file the agent Reads to load the body on demand; `store` is the
|
|
317
|
+
// originating store alias (omitted for unqualified entries).
|
|
318
|
+
paths: z3.array(
|
|
319
|
+
z3.object({
|
|
320
|
+
stable_id: z3.string(),
|
|
321
|
+
path: z3.string(),
|
|
322
|
+
store: z3.object({ alias: z3.string() }).optional()
|
|
292
323
|
})
|
|
293
324
|
),
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
// v2.
|
|
303
|
-
//
|
|
304
|
-
//
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
325
|
+
// Number of lower-ranked candidates dropped by the retrieval budget. Present
|
|
326
|
+
// (and > 0) ONLY when truncation fired — keeps the steady-state wire shape
|
|
327
|
+
// unchanged while signalling "more exist; narrow your intent".
|
|
328
|
+
omitted_candidate_count: z3.number().int().nonnegative().optional(),
|
|
329
|
+
preflight_diagnostics: z3.array(_preflightDiagnosticSchema),
|
|
330
|
+
warnings: z3.array(structuredWarningSchema).optional(),
|
|
331
|
+
auto_healed: z3.boolean().optional(),
|
|
332
|
+
previous_revision_hash: z3.string().optional(),
|
|
333
|
+
// v2.0.0-rc.37 NEW-24: parallel to planContextOutputSchema.redirects — stale
|
|
334
|
+
// (pre layer-flip) ids in `ids` are redirect-rewritten before matching; the
|
|
335
|
+
// surfaced map exposes the substitution so callers refresh cached state.
|
|
336
|
+
redirects: z3.record(z3.string()).optional(),
|
|
337
|
+
// lifecycle-refactor W3-T2 (§7 图谱消费): related-expansion provenance map
|
|
338
|
+
// (appended id → surfaced source id). Present only when include_related
|
|
339
|
+
// appended an in-corpus neighbour. Omitted on the steady-state path.
|
|
340
|
+
related_appended: z3.record(z3.string()).optional(),
|
|
341
|
+
// v2.2 MC1-recall-pack: standing behavioral directive (cite-before-edit) +
|
|
342
|
+
// dynamic discovery hints, so the one-call recall is self-describing.
|
|
343
|
+
directive: z3.string(),
|
|
344
|
+
next_steps: z3.array(z3.string()).optional()
|
|
311
345
|
});
|
|
312
346
|
var recallAnnotations = {
|
|
313
347
|
readOnlyHint: true,
|
|
@@ -316,34 +350,34 @@ var recallAnnotations = {
|
|
|
316
350
|
openWorldHint: false,
|
|
317
351
|
title: "Recall Fabric knowledge (one-call)"
|
|
318
352
|
};
|
|
319
|
-
var archiveScanInputSchema =
|
|
320
|
-
range:
|
|
353
|
+
var archiveScanInputSchema = z3.object({
|
|
354
|
+
range: z3.union([z3.array(z3.string()).min(1), z3.literal("all")]).optional().describe(
|
|
321
355
|
"Phase 0 scope: explicit session_id[] to constrain the scan, or the 'all' sentinel. Omitted = scan everything since the last knowledge_proposed anchor."
|
|
322
356
|
),
|
|
323
|
-
now_ms:
|
|
324
|
-
correlation_id:
|
|
325
|
-
session_id:
|
|
357
|
+
now_ms: z3.number().int().nonnegative().optional().describe("Override for the anti-loop cooldown clock (testing). Defaults to Date.now()."),
|
|
358
|
+
correlation_id: z3.string().optional().describe("Optional caller-provided correlation id for Event Ledger records."),
|
|
359
|
+
session_id: z3.string().optional().describe("Current client session id; recorded for cross-session debt tracking.")
|
|
326
360
|
});
|
|
327
|
-
var archiveScanOutputSchema =
|
|
361
|
+
var archiveScanOutputSchema = z3.object({
|
|
328
362
|
// ts of the most recent knowledge_proposed event (the lower bound), or null
|
|
329
363
|
// when the workspace has never archived (scan everything).
|
|
330
|
-
anchor_ts:
|
|
364
|
+
anchor_ts: z3.number().nullable(),
|
|
331
365
|
// Distinct session_ids since the anchor that survived the outcome filter,
|
|
332
366
|
// in first-seen order — ready for the Skill to load digests + stitch.
|
|
333
|
-
session_ids:
|
|
367
|
+
session_ids: z3.array(z3.string()),
|
|
334
368
|
// Sessions dropped by the filter, with the rule that fired (audit/debug).
|
|
335
|
-
dropped:
|
|
336
|
-
|
|
337
|
-
session_id:
|
|
338
|
-
reason:
|
|
369
|
+
dropped: z3.array(
|
|
370
|
+
z3.object({
|
|
371
|
+
session_id: z3.string(),
|
|
372
|
+
reason: z3.enum(["user_dismissed", "cooldown", "no_new_signal"])
|
|
339
373
|
})
|
|
340
374
|
),
|
|
341
375
|
// max ts examined across the scan — becomes the next covered_through_ts.
|
|
342
|
-
covered_through_ts:
|
|
376
|
+
covered_through_ts: z3.number().nullable(),
|
|
343
377
|
// Idempotency keys already proposed by prior archive runs but not yet
|
|
344
378
|
// reviewed (Phase 4.5 cross-session pending dedupe). Drop matching candidates.
|
|
345
|
-
already_proposed_keys:
|
|
346
|
-
warnings:
|
|
379
|
+
already_proposed_keys: z3.array(z3.string()),
|
|
380
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
347
381
|
});
|
|
348
382
|
var archiveScanAnnotations = {
|
|
349
383
|
readOnlyHint: true,
|
|
@@ -352,7 +386,7 @@ var archiveScanAnnotations = {
|
|
|
352
386
|
openWorldHint: false,
|
|
353
387
|
title: "Scan event ledger for archive candidates (deterministic)"
|
|
354
388
|
};
|
|
355
|
-
var ProposedReasonSchema =
|
|
389
|
+
var ProposedReasonSchema = z3.enum([
|
|
356
390
|
"explicit-user-mark",
|
|
357
391
|
"diagnostic-then-fix",
|
|
358
392
|
"decision-confirmation",
|
|
@@ -360,7 +394,7 @@ var ProposedReasonSchema = z2.enum([
|
|
|
360
394
|
"new-dependency-or-pattern",
|
|
361
395
|
"dismissal-with-reason"
|
|
362
396
|
]);
|
|
363
|
-
var
|
|
397
|
+
var PROPOSED_REASON_DESCRIPTIONS_ZH = {
|
|
364
398
|
"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",
|
|
365
399
|
"diagnostic-then-fix": "\u8BCA\u65AD\u8FC7\u7A0B\u53D1\u73B0\u65B0\u6A21\u5F0F\u6216\u8E29\u5751\uFF0C\u4FEE\u590D\u540E\u503C\u5F97\u6C89\u6DC0\u3002",
|
|
366
400
|
"decision-confirmation": "\u22652 \u5019\u9009\u65B9\u6848\u7ECF\u6743\u8861\u540E\u786E\u8BA4\u9009\u578B\uFF0C\u9700\u4FDD\u7559 rationale\u3002",
|
|
@@ -368,21 +402,41 @@ var PROPOSED_REASON_DESCRIPTIONS = {
|
|
|
368
402
|
"new-dependency-or-pattern": "\u5F15\u5165\u65B0\u4F9D\u8D56 / \u65B0\u6A21\u5F0F / \u65B0\u547D\u540D\u7EA6\u5B9A\u3002",
|
|
369
403
|
"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"
|
|
370
404
|
};
|
|
371
|
-
var
|
|
372
|
-
|
|
405
|
+
var PROPOSED_REASON_DESCRIPTIONS_EN = {
|
|
406
|
+
"explicit-user-mark": "User explicitly marked this for archival (normative language: always / never / next time, etc.).",
|
|
407
|
+
"diagnostic-then-fix": "A new pattern or pitfall surfaced during diagnosis and is worth retaining after the fix.",
|
|
408
|
+
"decision-confirmation": "A choice was confirmed after weighing \u22652 candidate approaches; the rationale must be preserved.",
|
|
409
|
+
"wrong-turn-revert": "A path was tried then reverted; the wrong turn itself is a pitfall worth recording.",
|
|
410
|
+
"new-dependency-or-pattern": "Introduces a new dependency / pattern / naming convention.",
|
|
411
|
+
"dismissal-with-reason": "The user explicitly rejected an approach and gave a reason; the reason is archivable knowledge."
|
|
412
|
+
};
|
|
413
|
+
var PROPOSED_REASON_DESCRIPTIONS_BY_LOCALE = {
|
|
414
|
+
"zh-CN": PROPOSED_REASON_DESCRIPTIONS_ZH,
|
|
415
|
+
en: PROPOSED_REASON_DESCRIPTIONS_EN
|
|
416
|
+
};
|
|
417
|
+
var _sourceSessionsField = z3.array(z3.string().min(1)).min(1);
|
|
418
|
+
var _FabExtractKnowledgeInputBaseSchema = z3.object({
|
|
373
419
|
// v2.0.0-rc.7 T5: array form. rc.23 dropped the legacy single-string alias.
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
420
|
+
// v2.2 全砍 F13: REQUIRED in the base schema (was `.optional()`) so the MCP
|
|
421
|
+
// tool's advertised inputSchema (registerTool reads `.shape`) matches the
|
|
422
|
+
// requirement the superRefine enforces. Previously a caller reading the schema
|
|
423
|
+
// saw it optional, omitted it, and got rejected at parse — a contract lie.
|
|
424
|
+
source_sessions: _sourceSessionsField.describe(
|
|
425
|
+
"Originating session ids (REQUIRED, non-empty array); correlates with Event Ledger records. Array form (T5+, rc.23 made it the sole accepted shape)."
|
|
426
|
+
),
|
|
427
|
+
recent_paths: z3.array(z3.string()).describe("Workspace paths recently touched in the source session \u2014 used as scope hints"),
|
|
428
|
+
user_messages_summary: z3.string().describe("Skill-side summary of the user's intent/messages, kept compact"),
|
|
429
|
+
type: z3.enum(["decisions", "pitfalls", "guidelines", "models", "processes"]).describe("Knowledge type bucket (plural form, mirrors directory layout)"),
|
|
430
|
+
slug: z3.string().describe("URL-safe short identifier proposed by the Skill; server may sanitize"),
|
|
431
|
+
// Store-only cutover: layer is a compatibility audience hint. The server
|
|
432
|
+
// resolves the actual write target through semantic_scope/write_routes and
|
|
433
|
+
// writes to the selected mounted store's knowledge/pending/<type>/ tree.
|
|
383
434
|
// Defaults to 'team' to preserve existing call sites (Skill bumps as needed).
|
|
384
|
-
layer:
|
|
385
|
-
"
|
|
435
|
+
layer: z3.enum(["team", "personal"]).optional().describe(
|
|
436
|
+
"Compatibility storage audience. 'personal' writes to the personal store; non-personal writes resolve by semantic_scope/write_routes. Defaults to 'team'."
|
|
437
|
+
),
|
|
438
|
+
semantic_scope: z3.string().regex(SCOPE_COORDINATE_PATTERN).optional().describe(
|
|
439
|
+
"Logical audience/write route coordinate for this pending entry, e.g. personal, team, project:fabric-v2, org:acme:team:platform. Server validates and resolves it through write_routes."
|
|
386
440
|
),
|
|
387
441
|
// v2.0.0-rc.7 T6: proposed_reason — required enum that drives `## Why
|
|
388
442
|
// proposed` rendering. Skills (archive / import / review) infer the
|
|
@@ -394,7 +448,7 @@ var _FabExtractKnowledgeInputBaseSchema = z2.object({
|
|
|
394
448
|
// captures the session goal + key turning point. Future-self review reads
|
|
395
449
|
// this without conversation transcript access. Min length guards against
|
|
396
450
|
// empty placeholders; cap is soft (no max), Skill caps at ~600 chars.
|
|
397
|
-
session_context:
|
|
451
|
+
session_context: z3.string().min(20, { message: "session_context must be \u226520 chars (3-5 lines describing goal + turning point)" }).describe(
|
|
398
452
|
"3-5 line markdown blob \u2014 session goal + key turning point. Reviewed by future-self without transcript access."
|
|
399
453
|
),
|
|
400
454
|
// v2.0.0-rc.8 A1 (skill-contract-fix): relevance scope/paths on the
|
|
@@ -408,10 +462,10 @@ var _FabExtractKnowledgeInputBaseSchema = z2.object({
|
|
|
408
462
|
// a `knowledge_scope_degraded` event keyed by `pending:<idempotency_key>`.
|
|
409
463
|
// NOTE: these fields MUST NOT be part of the idempotency hash inputs at
|
|
410
464
|
// extract-knowledge.ts:78 — preserves rc.5→rc.7 collision detection.
|
|
411
|
-
relevance_scope:
|
|
465
|
+
relevance_scope: z3.enum(["narrow", "broad"]).optional().describe(
|
|
412
466
|
"Optional relevance scope. 'narrow' restricts plan-context-hint surfacing to relevance_paths; 'broad' always surfaces. Omit to let the meta-builder default to 'broad'. Personal + narrow is silently degraded to broad + []."
|
|
413
467
|
),
|
|
414
|
-
relevance_paths:
|
|
468
|
+
relevance_paths: z3.array(z3.string()).optional().describe(
|
|
415
469
|
"Optional path anchors for narrow scope. Workspace-relative globs or paths. Omit to let the meta-builder default to []. Ignored when scope is broad (server preserves the array for audit)."
|
|
416
470
|
),
|
|
417
471
|
// v2.0.0-rc.23 TASK-006 (a-C1): four optional structured fields that the
|
|
@@ -428,16 +482,16 @@ var _FabExtractKnowledgeInputBaseSchema = z2.object({
|
|
|
428
482
|
// relevance_paths follow the same rule). Including them would let an LLM
|
|
429
483
|
// re-roll of the same observation create a second pending file just because
|
|
430
484
|
// its inferred metadata wording drifted.
|
|
431
|
-
intent_clues:
|
|
485
|
+
intent_clues: z3.array(z3.string()).optional().describe(
|
|
432
486
|
"Short LLM-readable triggers describing when this rule should fire and when it should not. Each item \u226480 chars, imperative phrasing (e.g. 'when editing Cocos UI batch code', 'NOT for non-batch contexts'). Optional \u2014 omit when the skill cannot infer cleanly."
|
|
433
487
|
),
|
|
434
|
-
tech_stack:
|
|
488
|
+
tech_stack: z3.array(z3.string()).optional().describe(
|
|
435
489
|
"Tech stack / languages / frameworks the rule applies to (e.g. ['typescript', 'cocos-creator', 'nodejs']). Inferred from recent_paths file extensions and manifest files. Optional \u2014 omit when the rule is stack-agnostic."
|
|
436
490
|
),
|
|
437
|
-
impact:
|
|
491
|
+
impact: z3.array(z3.string()).optional().describe(
|
|
438
492
|
"Consequences of ignoring this rule, used by the LLM to weight relevance vs cost. Each item \u2264120 chars (e.g. 'O(n\xB2) re-render on every frame', 'silent data loss on collision'). Optional \u2014 omit when impact is not observable."
|
|
439
493
|
),
|
|
440
|
-
must_read_if:
|
|
494
|
+
must_read_if: z3.string().optional().describe(
|
|
441
495
|
"One-line strong trigger; when this condition holds the entry is considered required reading. Single line \u2264160 chars (e.g. 'touching anything under packages/cli/src/commands/hooks.ts'). Optional \u2014 omit when no single strong trigger fits."
|
|
442
496
|
),
|
|
443
497
|
// v2.0.0-rc.37 NEW-37 (werewolf dogfood remediation): optional tags array.
|
|
@@ -448,7 +502,7 @@ var _FabExtractKnowledgeInputBaseSchema = z2.object({
|
|
|
448
502
|
// IDEMPOTENCY: tags MUST NOT 参与 idempotency_key hash(同 relevance_*
|
|
449
503
|
// / intent_clues 等可变字段一致),re-extract 时 tags 调整不应产生重复
|
|
450
504
|
// pending file。
|
|
451
|
-
tags:
|
|
505
|
+
tags: z3.array(z3.string()).optional().describe(
|
|
452
506
|
"Optional topic tags (2-4 kebab-case strings recommended). Drives cross-entry retrieval + topic clustering. Skill-inferred from session content; omit when not confidently inferable. Empty array allowed but discouraged (degrades narrow hint topic signal)."
|
|
453
507
|
),
|
|
454
508
|
// v2.0.0-rc.23 TASK-014 (F8c): optional onboard-slot tag. The S5 slot
|
|
@@ -483,7 +537,7 @@ var _FabExtractKnowledgeInputBaseSchema = z2.object({
|
|
|
483
537
|
// signal was captured. Like relevance_paths it MUST NOT participate in
|
|
484
538
|
// the idempotency_key hash (an idempotent re-extract may surface a
|
|
485
539
|
// slightly different read set without spawning a duplicate pending).
|
|
486
|
-
evidence_paths:
|
|
540
|
+
evidence_paths: z3.array(z3.string()).optional().describe(
|
|
487
541
|
"Workspace-relative paths the agent CONSULTED (read but never modified) while building this knowledge. Documents context without affecting activation. Lifted from the legacy body ## Evidence markdown block into structured frontmatter so plan-context retrieval can read it as data."
|
|
488
542
|
)
|
|
489
543
|
});
|
|
@@ -492,7 +546,7 @@ var FabExtractKnowledgeInputSchema = _FabExtractKnowledgeInputBaseSchema.superRe
|
|
|
492
546
|
const hasArray = Array.isArray(value.source_sessions) && value.source_sessions.length > 0;
|
|
493
547
|
if (!hasArray) {
|
|
494
548
|
ctx.addIssue({
|
|
495
|
-
code:
|
|
549
|
+
code: z3.ZodIssueCode.custom,
|
|
496
550
|
message: "source_sessions (non-empty string array) is required",
|
|
497
551
|
path: ["source_sessions"]
|
|
498
552
|
});
|
|
@@ -500,12 +554,12 @@ var FabExtractKnowledgeInputSchema = _FabExtractKnowledgeInputBaseSchema.superRe
|
|
|
500
554
|
}
|
|
501
555
|
);
|
|
502
556
|
var FabExtractKnowledgeInputShape = _FabExtractKnowledgeInputBaseSchema.shape;
|
|
503
|
-
var FabExtractKnowledgeOutputSchema =
|
|
504
|
-
pending_path:
|
|
505
|
-
idempotency_key:
|
|
557
|
+
var FabExtractKnowledgeOutputSchema = z3.object({
|
|
558
|
+
pending_path: z3.string().describe("Workspace-relative path to the persisted pending entry"),
|
|
559
|
+
idempotency_key: z3.string().describe("Stable key derived from inputs; identical inputs yield identical key"),
|
|
506
560
|
// v2.0.0-rc.23 TASK-009 (d): optional warnings surface for the first-reconcile
|
|
507
561
|
// gate (`meta_stale` / `reconcile_failed`). Absent on the steady-state path.
|
|
508
|
-
warnings:
|
|
562
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
509
563
|
});
|
|
510
564
|
var fabExtractKnowledgeAnnotations = {
|
|
511
565
|
readOnlyHint: false,
|
|
@@ -514,21 +568,21 @@ var fabExtractKnowledgeAnnotations = {
|
|
|
514
568
|
openWorldHint: false,
|
|
515
569
|
title: "Extract pending knowledge entry"
|
|
516
570
|
};
|
|
517
|
-
var _fabReviewFiltersSchema =
|
|
518
|
-
type:
|
|
519
|
-
layer:
|
|
520
|
-
maturity:
|
|
521
|
-
tags:
|
|
571
|
+
var _fabReviewFiltersSchema = z3.object({
|
|
572
|
+
type: z3.enum(["decisions", "pitfalls", "guidelines", "models", "processes"]).optional(),
|
|
573
|
+
layer: z3.enum(["team", "personal", "both"]).optional(),
|
|
574
|
+
maturity: z3.enum(["draft", "verified", "proven"]).optional(),
|
|
575
|
+
tags: z3.array(z3.string()).optional(),
|
|
522
576
|
// rc.4 TASK-006 fix (c): ISO-8601 lower bound on entry created_at; entries
|
|
523
577
|
// strictly older than this threshold are excluded from list / search
|
|
524
578
|
// results. Additive optional field — existing callers unaffected.
|
|
525
|
-
created_after:
|
|
579
|
+
created_after: z3.string().datetime().optional(),
|
|
526
580
|
// v2.0.0-rc.27 TASK-001 (§2.2/§2.3): opt-in surfacing of lifecycle-filtered
|
|
527
581
|
// entries. Default (omit both) hides rejected entries and deferred entries
|
|
528
582
|
// whose deferred_until is in the future. Pass true to include them — e.g.
|
|
529
583
|
// for vacuum tooling, audit dashboards, or "show me what I parked" UX.
|
|
530
|
-
include_rejected:
|
|
531
|
-
include_deferred:
|
|
584
|
+
include_rejected: z3.boolean().optional(),
|
|
585
|
+
include_deferred: z3.boolean().optional(),
|
|
532
586
|
// v2.0.0-rc.27 TASK-006 (audit §2.23): opt-in body inspection. Default
|
|
533
587
|
// list/search return only frontmatter-derived fields — a malicious
|
|
534
588
|
// pending entry could hide a prompt-injection payload under `## Evidence`
|
|
@@ -538,41 +592,57 @@ var _fabReviewFiltersSchema = z2.object({
|
|
|
538
592
|
// default-off design keeps the wire payload small for routine list
|
|
539
593
|
// calls; reviewer workflows pass `true` before approving so the body
|
|
540
594
|
// is rendered into the reviewer's UI for visual scan.
|
|
541
|
-
include_body:
|
|
595
|
+
include_body: z3.boolean().optional()
|
|
542
596
|
}).optional();
|
|
543
|
-
var _fabReviewModifyChangesSchema =
|
|
544
|
-
title:
|
|
545
|
-
summary:
|
|
597
|
+
var _fabReviewModifyChangesSchema = z3.object({
|
|
598
|
+
title: z3.string().optional(),
|
|
599
|
+
summary: z3.string().optional(),
|
|
546
600
|
// Q7: writing `layer` here triggers a layer-flip; downstream callers may
|
|
547
601
|
// observe a redirect_to in fab_get_knowledge_sections if stable_id changes.
|
|
548
|
-
layer:
|
|
549
|
-
maturity:
|
|
550
|
-
tags:
|
|
602
|
+
layer: z3.enum(["team", "personal"]).optional(),
|
|
603
|
+
maturity: z3.enum(["draft", "verified", "proven"]).optional(),
|
|
604
|
+
tags: z3.array(z3.string()).optional(),
|
|
551
605
|
// v2.0-rc.5 C3 (TASK-012): relevance scope/paths patches. Applied to
|
|
552
606
|
// pending AND canonical entries. When an explicit team→personal layer flip
|
|
553
607
|
// arrives on a narrow entry, the server auto-degrades to broad + [] and
|
|
554
608
|
// emits a `knowledge_scope_degraded` event regardless of what the caller
|
|
555
609
|
// sent in these fields (personal-implies-broad).
|
|
556
|
-
relevance_scope:
|
|
557
|
-
relevance_paths:
|
|
610
|
+
relevance_scope: z3.enum(["narrow", "broad"]).optional(),
|
|
611
|
+
relevance_paths: z3.array(z3.string()).optional(),
|
|
612
|
+
// v2.2 project-scope migration: re-scope an existing entry's resolution
|
|
613
|
+
// coordinate (e.g. team → project:fabric-v2) WITHOUT moving stores
|
|
614
|
+
// (scope ⊥ store, S42/A2). The in-place modify path keeps visibility_store
|
|
615
|
+
// intact, so a team→project flip just relabels who recall surfaces it to
|
|
616
|
+
// (G-FILTER, cross-store-recall.ts) — the entry stays physically in the
|
|
617
|
+
// same shared store. A personal-root coordinate is rejected here: landing
|
|
618
|
+
// an entry in the personal store is a store move, which is the dedicated
|
|
619
|
+
// modify-layer path (R5#3 privacy boundary), never an in-place scalar edit.
|
|
620
|
+
semantic_scope: z3.string().regex(SCOPE_COORDINATE_PATTERN).optional(),
|
|
621
|
+
// v2.2 graph edges (KT-DEC-0031 wiki seam): write the `related` H2 adjacency
|
|
622
|
+
// (bare or store-qualified stable_ids this entry points at). REPLACE semantics
|
|
623
|
+
// mirror tags/relevance_paths — the caller (fabric-connect) reads existing
|
|
624
|
+
// edges via fab_recall and sends the merged set. Absent this field the modify
|
|
625
|
+
// path silently dropped `related` via zod .strip() (KT-PIT-0005 recurrence),
|
|
626
|
+
// leaving the only programmatic related-write path non-functional.
|
|
627
|
+
related: z3.array(z3.string()).optional()
|
|
558
628
|
});
|
|
559
|
-
var FabReviewInputSchema =
|
|
560
|
-
|
|
561
|
-
action:
|
|
629
|
+
var FabReviewInputSchema = z3.discriminatedUnion("action", [
|
|
630
|
+
z3.object({
|
|
631
|
+
action: z3.literal("list"),
|
|
562
632
|
filters: _fabReviewFiltersSchema
|
|
563
633
|
}),
|
|
564
|
-
|
|
565
|
-
action:
|
|
566
|
-
pending_paths:
|
|
634
|
+
z3.object({
|
|
635
|
+
action: z3.literal("approve"),
|
|
636
|
+
pending_paths: z3.array(z3.string()).min(1)
|
|
567
637
|
}),
|
|
568
|
-
|
|
569
|
-
action:
|
|
570
|
-
pending_paths:
|
|
571
|
-
reason:
|
|
638
|
+
z3.object({
|
|
639
|
+
action: z3.literal("reject"),
|
|
640
|
+
pending_paths: z3.array(z3.string()).min(1),
|
|
641
|
+
reason: z3.string().min(1)
|
|
572
642
|
}),
|
|
573
|
-
|
|
574
|
-
action:
|
|
575
|
-
pending_path:
|
|
643
|
+
z3.object({
|
|
644
|
+
action: z3.literal("modify"),
|
|
645
|
+
pending_path: z3.string().min(1),
|
|
576
646
|
changes: _fabReviewModifyChangesSchema
|
|
577
647
|
}),
|
|
578
648
|
// v2.0.0-rc.37 NEW-12: explicit modify split. `modify-content` edits scalar
|
|
@@ -581,177 +651,176 @@ var FabReviewInputSchema = z2.discriminatedUnion("action", [
|
|
|
581
651
|
// (changes.layer REQUIRED) which may reallocate the stable_id + emit an
|
|
582
652
|
// id-redirect (rc.37 NEW-24). Legacy `modify` stays for back-compat and
|
|
583
653
|
// routes by whether changes.layer is present.
|
|
584
|
-
|
|
585
|
-
action:
|
|
586
|
-
pending_path:
|
|
654
|
+
z3.object({
|
|
655
|
+
action: z3.literal("modify-content"),
|
|
656
|
+
pending_path: z3.string().min(1),
|
|
587
657
|
changes: _fabReviewModifyChangesSchema
|
|
588
658
|
}),
|
|
589
|
-
|
|
590
|
-
action:
|
|
591
|
-
pending_path:
|
|
659
|
+
z3.object({
|
|
660
|
+
action: z3.literal("modify-layer"),
|
|
661
|
+
pending_path: z3.string().min(1),
|
|
592
662
|
changes: _fabReviewModifyChangesSchema.extend({
|
|
593
|
-
layer:
|
|
663
|
+
layer: z3.enum(["team", "personal"])
|
|
594
664
|
})
|
|
595
665
|
}),
|
|
596
|
-
|
|
597
|
-
action:
|
|
598
|
-
query:
|
|
666
|
+
z3.object({
|
|
667
|
+
action: z3.literal("search"),
|
|
668
|
+
query: z3.string().min(1),
|
|
599
669
|
filters: _fabReviewFiltersSchema
|
|
600
670
|
}),
|
|
601
|
-
|
|
602
|
-
action:
|
|
603
|
-
pending_paths:
|
|
604
|
-
until:
|
|
605
|
-
reason:
|
|
671
|
+
z3.object({
|
|
672
|
+
action: z3.literal("defer"),
|
|
673
|
+
pending_paths: z3.array(z3.string()).min(1),
|
|
674
|
+
until: z3.string().datetime().optional(),
|
|
675
|
+
reason: z3.string().optional()
|
|
606
676
|
})
|
|
607
677
|
]);
|
|
608
678
|
var FabReviewInputShape = {
|
|
609
|
-
action:
|
|
679
|
+
action: z3.enum(["list", "approve", "reject", "modify", "modify-content", "modify-layer", "search", "defer"]).describe(
|
|
610
680
|
"Action selector. Discriminates the per-action fields below; required. modify-content edits scalars (no layer); modify-layer is the layer-flip path (changes.layer required); modify is the legacy combined alias."
|
|
611
681
|
),
|
|
612
682
|
filters: _fabReviewFiltersSchema.describe(
|
|
613
683
|
"Optional filters (type/layer/maturity/tags/created_after). Used by action=list and action=search."
|
|
614
684
|
),
|
|
615
|
-
pending_paths:
|
|
685
|
+
pending_paths: z3.array(z3.string()).min(1).optional().describe(
|
|
616
686
|
"Workspace-relative pending entry paths. Required when action=approve|reject|defer (non-empty array)."
|
|
617
687
|
),
|
|
618
|
-
pending_path:
|
|
688
|
+
pending_path: z3.string().min(1).optional().describe(
|
|
619
689
|
"Workspace-relative pending OR canonical entry path. Required when action=modify."
|
|
620
690
|
),
|
|
621
|
-
reason:
|
|
691
|
+
reason: z3.string().optional().describe(
|
|
622
692
|
"Reason string. Required (non-empty) when action=reject; optional when action=defer."
|
|
623
693
|
),
|
|
624
694
|
changes: _fabReviewModifyChangesSchema.optional().describe(
|
|
625
|
-
"Frontmatter scalar patches (title/summary/layer/maturity/tags/relevance_
|
|
695
|
+
"Frontmatter scalar patches (title/summary/layer/maturity/tags/relevance_*/semantic_scope/related). Required when action=modify. semantic_scope re-scopes the entry's resolution coordinate in place (e.g. team \u2192 project:<id>) without moving stores; personal-root coordinates are rejected (use modify-layer)."
|
|
626
696
|
),
|
|
627
|
-
query:
|
|
697
|
+
query: z3.string().min(1).optional().describe(
|
|
628
698
|
"Substring query against title/summary/tags/path. Required (non-empty) when action=search."
|
|
629
699
|
),
|
|
630
|
-
until:
|
|
700
|
+
until: z3.string().datetime().optional().describe(
|
|
631
701
|
"ISO-8601 datetime upper bound for the deferral. Optional; used only when action=defer."
|
|
632
702
|
)
|
|
633
703
|
};
|
|
634
|
-
var _fabReviewListItemSchema =
|
|
635
|
-
pending_path:
|
|
704
|
+
var _fabReviewListItemSchema = z3.object({
|
|
705
|
+
pending_path: z3.string(),
|
|
636
706
|
// v2.0.0-rc.27 TASK-001 (§2.12): for personal-layer entries `pending_path`
|
|
637
707
|
// carries the human-friendly `~/...` form (legacy contract) while
|
|
638
708
|
// `pending_path_absolute` carries the os-expanded absolute path. Programmatic
|
|
639
709
|
// consumers (Read tool, fs.readFile, downstream MCP servers) should prefer
|
|
640
710
|
// the absolute variant — the `~` is a shell-only sigil that breaks every
|
|
641
711
|
// non-shell consumer. Team entries omit this field because their
|
|
642
|
-
// `pending_path` is already
|
|
643
|
-
pending_path_absolute:
|
|
644
|
-
type:
|
|
645
|
-
layer:
|
|
646
|
-
maturity:
|
|
647
|
-
tags:
|
|
648
|
-
title:
|
|
649
|
-
summary:
|
|
650
|
-
//
|
|
651
|
-
//
|
|
652
|
-
//
|
|
653
|
-
|
|
654
|
-
origin: z2.enum(["team", "personal"]).optional(),
|
|
712
|
+
// `pending_path` is already store-resolved and unambiguous.
|
|
713
|
+
pending_path_absolute: z3.string().optional(),
|
|
714
|
+
type: z3.enum(["decisions", "pitfalls", "guidelines", "models", "processes"]),
|
|
715
|
+
layer: z3.enum(["team", "personal"]),
|
|
716
|
+
maturity: z3.enum(["draft", "verified", "proven"]),
|
|
717
|
+
tags: z3.array(z3.string()).optional(),
|
|
718
|
+
title: z3.string().optional(),
|
|
719
|
+
summary: z3.string().optional(),
|
|
720
|
+
// Store-only cutover: origin reflects the resolved store audience where the
|
|
721
|
+
// pending file lives; layer reflects the declared classification that will
|
|
722
|
+
// drive approval semantics.
|
|
723
|
+
origin: z3.enum(["team", "personal"]).optional(),
|
|
655
724
|
// v2.0.0-rc.27 TASK-001 (§2.2/§2.3): frontmatter status markers. Default
|
|
656
725
|
// "active" (or absent). `rejected` entries are excluded from list/search
|
|
657
726
|
// unless filters.include_rejected=true; `deferred` entries are excluded
|
|
658
727
|
// when deferred_until is in the future. Authored by reject/defer write
|
|
659
728
|
// paths — never by extract or approve.
|
|
660
|
-
status:
|
|
661
|
-
deferred_until:
|
|
729
|
+
status: z3.enum(["active", "rejected", "deferred"]).optional(),
|
|
730
|
+
deferred_until: z3.string().datetime().optional(),
|
|
662
731
|
// v2.0.0-rc.27 TASK-006 (audit §2.23): full body content (everything
|
|
663
732
|
// after the closing `---` of frontmatter). Surfaced only when caller
|
|
664
733
|
// passes `filters.include_body: true`. Default-omitted to keep payload
|
|
665
734
|
// small for routine list calls.
|
|
666
|
-
body:
|
|
735
|
+
body: z3.string().optional()
|
|
667
736
|
});
|
|
668
|
-
var _fabReviewSearchItemSchema =
|
|
669
|
-
// Search hits live in one of two trees:
|
|
670
|
-
// - "pending" →
|
|
671
|
-
// - "canonical" →
|
|
672
|
-
area:
|
|
673
|
-
path:
|
|
674
|
-
path_absolute:
|
|
675
|
-
type:
|
|
676
|
-
layer:
|
|
677
|
-
maturity:
|
|
678
|
-
tags:
|
|
679
|
-
title:
|
|
680
|
-
summary:
|
|
681
|
-
origin:
|
|
682
|
-
status:
|
|
683
|
-
deferred_until:
|
|
684
|
-
body:
|
|
737
|
+
var _fabReviewSearchItemSchema = z3.object({
|
|
738
|
+
// Search hits live in one of two store trees:
|
|
739
|
+
// - "pending" → mounted store `knowledge/pending/`
|
|
740
|
+
// - "canonical" → mounted store `knowledge/{decisions,pitfalls,...}`
|
|
741
|
+
area: z3.enum(["pending", "canonical"]),
|
|
742
|
+
path: z3.string(),
|
|
743
|
+
path_absolute: z3.string().optional(),
|
|
744
|
+
type: z3.enum(["decisions", "pitfalls", "guidelines", "models", "processes"]),
|
|
745
|
+
layer: z3.enum(["team", "personal"]),
|
|
746
|
+
maturity: z3.enum(["draft", "verified", "proven"]),
|
|
747
|
+
tags: z3.array(z3.string()).optional(),
|
|
748
|
+
title: z3.string().optional(),
|
|
749
|
+
summary: z3.string().optional(),
|
|
750
|
+
origin: z3.enum(["team", "personal"]).optional(),
|
|
751
|
+
status: z3.enum(["active", "rejected", "deferred"]).optional(),
|
|
752
|
+
deferred_until: z3.string().datetime().optional(),
|
|
753
|
+
body: z3.string().optional(),
|
|
685
754
|
// For pending hits the upstream stable_id may still be unassigned — keep it
|
|
686
755
|
// optional so canonical hits (which always have one) parse alongside pending
|
|
687
756
|
// hits in the same array.
|
|
688
|
-
stable_id:
|
|
757
|
+
stable_id: z3.string().optional()
|
|
689
758
|
});
|
|
690
|
-
var FabReviewOutputSchema =
|
|
691
|
-
|
|
692
|
-
action:
|
|
693
|
-
items:
|
|
694
|
-
warnings:
|
|
759
|
+
var FabReviewOutputSchema = z3.discriminatedUnion("action", [
|
|
760
|
+
z3.object({
|
|
761
|
+
action: z3.literal("list"),
|
|
762
|
+
items: z3.array(_fabReviewListItemSchema),
|
|
763
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
695
764
|
}),
|
|
696
|
-
|
|
697
|
-
action:
|
|
698
|
-
approved:
|
|
699
|
-
warnings:
|
|
765
|
+
z3.object({
|
|
766
|
+
action: z3.literal("approve"),
|
|
767
|
+
approved: z3.array(z3.object({ pending_path: z3.string(), stable_id: z3.string() })),
|
|
768
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
700
769
|
}),
|
|
701
|
-
|
|
702
|
-
action:
|
|
703
|
-
rejected:
|
|
704
|
-
warnings:
|
|
770
|
+
z3.object({
|
|
771
|
+
action: z3.literal("reject"),
|
|
772
|
+
rejected: z3.array(z3.string()),
|
|
773
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
705
774
|
}),
|
|
706
|
-
|
|
707
|
-
action:
|
|
708
|
-
pending_path:
|
|
775
|
+
z3.object({
|
|
776
|
+
action: z3.literal("modify"),
|
|
777
|
+
pending_path: z3.string(),
|
|
709
778
|
// When a layer-flip occurred, prior_stable_id and new_stable_id differ.
|
|
710
|
-
prior_stable_id:
|
|
711
|
-
new_stable_id:
|
|
712
|
-
warnings:
|
|
779
|
+
prior_stable_id: z3.string().optional(),
|
|
780
|
+
new_stable_id: z3.string().optional(),
|
|
781
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
713
782
|
}),
|
|
714
|
-
|
|
715
|
-
action:
|
|
783
|
+
z3.object({
|
|
784
|
+
action: z3.literal("search"),
|
|
716
785
|
// v2.0.0-rc.29 TASK-007 (BUG-M4): search returns the new search-item
|
|
717
786
|
// shape with `area` discriminator + neutrally-named `path` field.
|
|
718
|
-
items:
|
|
719
|
-
warnings:
|
|
787
|
+
items: z3.array(_fabReviewSearchItemSchema),
|
|
788
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
720
789
|
}),
|
|
721
|
-
|
|
722
|
-
action:
|
|
723
|
-
deferred:
|
|
724
|
-
warnings:
|
|
790
|
+
z3.object({
|
|
791
|
+
action: z3.literal("defer"),
|
|
792
|
+
deferred: z3.array(z3.string()),
|
|
793
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
725
794
|
})
|
|
726
795
|
]);
|
|
727
796
|
var FabReviewOutputShape = {
|
|
728
|
-
action:
|
|
797
|
+
action: z3.enum(["list", "approve", "reject", "modify", "search", "defer"]).describe(
|
|
729
798
|
"Echoes the input action; clients can switch on it for per-variant fields below."
|
|
730
799
|
),
|
|
731
|
-
items:
|
|
800
|
+
items: z3.array(z3.union([_fabReviewListItemSchema, _fabReviewSearchItemSchema])).optional().describe(
|
|
732
801
|
"Pending entries (action=list, `pending_path` shape) or pending+canonical entries (action=search, `area`+`path` shape)."
|
|
733
802
|
),
|
|
734
|
-
approved:
|
|
803
|
+
approved: z3.array(z3.object({ pending_path: z3.string(), stable_id: z3.string() })).optional().describe(
|
|
735
804
|
"Allocated stable ids paired with their original pending paths. Present when action=approve."
|
|
736
805
|
),
|
|
737
|
-
rejected:
|
|
806
|
+
rejected: z3.array(z3.string()).optional().describe(
|
|
738
807
|
"Pending paths that were rejected (files retained on disk; doctor owns vacuum). Present when action=reject."
|
|
739
808
|
),
|
|
740
|
-
pending_path:
|
|
809
|
+
pending_path: z3.string().optional().describe(
|
|
741
810
|
"Echoed target path for the modification. Present when action=modify."
|
|
742
811
|
),
|
|
743
|
-
prior_stable_id:
|
|
812
|
+
prior_stable_id: z3.string().optional().describe(
|
|
744
813
|
"Prior stable id. Present when action=modify AND a layer-flip reallocated the id."
|
|
745
814
|
),
|
|
746
|
-
new_stable_id:
|
|
815
|
+
new_stable_id: z3.string().optional().describe(
|
|
747
816
|
"New stable id after reallocation. Present when action=modify AND a layer-flip reallocated the id."
|
|
748
817
|
),
|
|
749
|
-
deferred:
|
|
818
|
+
deferred: z3.array(z3.string()).optional().describe(
|
|
750
819
|
"Pending paths that were deferred (files retained on disk). Present when action=defer."
|
|
751
820
|
),
|
|
752
821
|
// v2.0.0-rc.23 TASK-009 (d): optional warnings surface for the first-reconcile
|
|
753
822
|
// gate (`meta_stale` / `reconcile_failed`). Absent on the steady-state path.
|
|
754
|
-
warnings:
|
|
823
|
+
warnings: z3.array(structuredWarningSchema).optional()
|
|
755
824
|
};
|
|
756
825
|
var fabReviewAnnotations = {
|
|
757
826
|
readOnlyHint: false,
|
|
@@ -760,35 +829,35 @@ var fabReviewAnnotations = {
|
|
|
760
829
|
openWorldHint: false,
|
|
761
830
|
title: "Review pending knowledge entries"
|
|
762
831
|
};
|
|
763
|
-
var citeContractMetricsSchema =
|
|
764
|
-
decisions_cited:
|
|
765
|
-
pitfalls_cited:
|
|
766
|
-
contract_with:
|
|
767
|
-
contract_missing:
|
|
768
|
-
hard_violated:
|
|
769
|
-
cite_id_unresolved:
|
|
770
|
-
skip_count:
|
|
832
|
+
var citeContractMetricsSchema = z3.object({
|
|
833
|
+
decisions_cited: z3.number().int().nonnegative(),
|
|
834
|
+
pitfalls_cited: z3.number().int().nonnegative(),
|
|
835
|
+
contract_with: z3.number().int().nonnegative(),
|
|
836
|
+
contract_missing: z3.number().int().nonnegative(),
|
|
837
|
+
hard_violated: z3.number().int().nonnegative(),
|
|
838
|
+
cite_id_unresolved: z3.number().int().nonnegative(),
|
|
839
|
+
skip_count: z3.record(z3.string(), z3.number().int().nonnegative())
|
|
771
840
|
});
|
|
772
|
-
var citeLayerTypeBreakdownSchema =
|
|
773
|
-
team:
|
|
774
|
-
personal:
|
|
841
|
+
var citeLayerTypeBreakdownSchema = z3.object({
|
|
842
|
+
team: z3.record(z3.string(), z3.number().int().nonnegative()),
|
|
843
|
+
personal: z3.record(z3.string(), z3.number().int().nonnegative())
|
|
775
844
|
});
|
|
776
|
-
var citeCoverageReportSchema =
|
|
777
|
-
status:
|
|
778
|
-
marker_ts:
|
|
779
|
-
marker_emitted_now:
|
|
780
|
-
since_ts:
|
|
781
|
-
client_filter:
|
|
845
|
+
var citeCoverageReportSchema = z3.object({
|
|
846
|
+
status: z3.enum(["ok", "skipped"]),
|
|
847
|
+
marker_ts: z3.number().int().nonnegative(),
|
|
848
|
+
marker_emitted_now: z3.boolean(),
|
|
849
|
+
since_ts: z3.number().int().nonnegative(),
|
|
850
|
+
client_filter: z3.enum(["cc", "codex", "all"]),
|
|
782
851
|
// v2.0.0-rc.24 TASK-08: layer filter discriminator. Optional so pre-TASK-10
|
|
783
852
|
// CLI callers (which never set the flag) still parse. Defaults to "all" at
|
|
784
853
|
// the service layer.
|
|
785
|
-
layer_filter:
|
|
786
|
-
metrics:
|
|
787
|
-
edits_touched:
|
|
788
|
-
qualifying_cites:
|
|
789
|
-
recalled_unverified:
|
|
790
|
-
expected_but_missed:
|
|
791
|
-
total_turns:
|
|
854
|
+
layer_filter: z3.enum(["team", "personal", "all"]).optional(),
|
|
855
|
+
metrics: z3.object({
|
|
856
|
+
edits_touched: z3.number().int().nonnegative(),
|
|
857
|
+
qualifying_cites: z3.number().int().nonnegative(),
|
|
858
|
+
recalled_unverified: z3.number().int().nonnegative(),
|
|
859
|
+
expected_but_missed: z3.number().int().nonnegative(),
|
|
860
|
+
total_turns: z3.number().int().nonnegative(),
|
|
792
861
|
// v2.0.0-rc.38 UX-8 (C, user-authorized): cite-policy COMPLIANCE rate —
|
|
793
862
|
// the corrected G-CITE semantic. The legacy qualifying_cites/edits ratio
|
|
794
863
|
// measured "how often an applicable KB id existed" (a function of corpus
|
|
@@ -797,38 +866,102 @@ var citeCoverageReportSchema = z2.object({
|
|
|
797
866
|
// `KB: none [reason]` (the policy explicitly allows the none sentinel) —
|
|
798
867
|
// over the turns where a cite was expected. null when no cite-expected
|
|
799
868
|
// turns observed (avoids a misleading 0/0 → 0). Range [0,1].
|
|
800
|
-
cite_compliance_rate:
|
|
801
|
-
compliant_cites:
|
|
802
|
-
noncompliant_cites:
|
|
869
|
+
cite_compliance_rate: z3.number().min(0).max(1).nullable().optional(),
|
|
870
|
+
compliant_cites: z3.number().int().nonnegative().optional(),
|
|
871
|
+
noncompliant_cites: z3.number().int().nonnegative().optional(),
|
|
803
872
|
// Edit signals lacking session_id → uncorrelatable, silently excluded from
|
|
804
873
|
// expected_but_missed. >0 typically means a stale pre-session_id hook is
|
|
805
874
|
// installed (run `fabric install`). Surfaced so the denominator gap is
|
|
806
875
|
// visible rather than a silent 100% confound.
|
|
807
|
-
uncorrelatable_edits:
|
|
876
|
+
uncorrelatable_edits: z3.number().int().nonnegative().optional(),
|
|
877
|
+
// v2.1 ⑤ cite-redesign (P5): recall-based coverage口径. The redesign infers
|
|
878
|
+
// a citation from real behavior — an in-session fab_recall
|
|
879
|
+
// (knowledge_context_planned) whose target_paths overlap a subsequently
|
|
880
|
+
// edited file IS the citation, no hand-written `KB:` line required.
|
|
881
|
+
// recall_backed_edits = correlatable edits preceded (within the recall
|
|
882
|
+
// window) by such an overlapping recall. recall_coverage_rate =
|
|
883
|
+
// recall_backed_edits / edits_touched (null when no edits). Additive — the
|
|
884
|
+
// legacy first-line-`KB:` metrics above are unchanged (back-compat).
|
|
885
|
+
recall_backed_edits: z3.number().int().nonnegative().optional(),
|
|
886
|
+
recall_coverage_rate: z3.number().min(0).max(1).nullable().optional(),
|
|
887
|
+
// v2.2.0-rc.1 W1-T3 (cite 诚实拆分 / lifecycle §3): exposed_and_mutated is a
|
|
888
|
+
// WEAK auxiliary signal — strictly SEPARATE from cite_compliance_rate (which
|
|
889
|
+
// is the true explicit-adherence rate, currently ~2.5%). It MUST NOT be
|
|
890
|
+
// merged into compliance: it estimates "a narrow PreToolUse-surfaced KB id
|
|
891
|
+
// whose contract-specific glob was subsequently edited (mutated) in the same
|
|
892
|
+
// session, and was not [dismissed] that round". It credits NOTHING toward the
|
|
893
|
+
// real `KB:`-line compliance — it is an observational hint that surfaced
|
|
894
|
+
// knowledge influenced an edit, surfaced ONLY as its own field so the renderer
|
|
895
|
+
// can label it "weak signal, NOT counted toward true adherence". Three
|
|
896
|
+
// conditions (all required): (1) id came from a `hook_surface_emitted` with
|
|
897
|
+
// hook_name === "knowledge-hint-narrow"; (2) the id's contract glob is
|
|
898
|
+
// SPECIFIC (excludes `**/*` wildcards and generic guideline-type entries);
|
|
899
|
+
// (3) the id was not [dismissed] in the same session. `count` = number of
|
|
900
|
+
// distinct (session_id, stable_id) pairs satisfying all three; `ids` =
|
|
901
|
+
// sorted distinct stable_ids (capped, diagnostics only). Always >= 0; null/
|
|
902
|
+
// absent on degraded/skipped reports.
|
|
903
|
+
exposed_and_mutated: z3.object({
|
|
904
|
+
count: z3.number().int().nonnegative(),
|
|
905
|
+
ids: z3.array(z3.string()).optional()
|
|
906
|
+
}).optional(),
|
|
907
|
+
// lifecycle-refactor W2-T4 (§5 row7 PostToolUse / §0 下沉 doctor): mutation
|
|
908
|
+
// funnel rebuilt offline from the new `file_mutated` PostToolUse marker —
|
|
909
|
+
// the权威 signal that a mutation actually completed (path + tool_call_id),
|
|
910
|
+
// distinct from the PreToolUse `edit_intent_checked` EDIT-INTENT signal that
|
|
911
|
+
// feeds `edits_touched`. mutations_observed.count = number of distinct
|
|
912
|
+
// `file_mutated` events in window (per-call tool_call_id dedup guards the
|
|
913
|
+
// PostToolUse parallel-fire race). Strictly ADDITIVE — never folded into
|
|
914
|
+
// cite_compliance_rate (honesty 铁律, mirrors exposed_and_mutated). Absent on
|
|
915
|
+
// degraded/skipped reports.
|
|
916
|
+
mutations_observed: z3.object({
|
|
917
|
+
count: z3.number().int().nonnegative()
|
|
918
|
+
}).optional(),
|
|
919
|
+
// lifecycle-refactor W2-T4 (§5 row7 mutation_pool + downgrade): low-confidence
|
|
920
|
+
// mutation attribution pool. A `file_mutated` event is `attributed` ONLY when
|
|
921
|
+
// its `source_event_id` links back to a `hook_surface_emitted` (surfaced/cited
|
|
922
|
+
// knowledge) in window — attribution key = store_id + stable_id +
|
|
923
|
+
// source_event_id (distinct dedup so multi-store never double-counts). Every
|
|
924
|
+
// other mutation (no source_event_id, or a source_event_id that does not
|
|
925
|
+
// resolve to a surfaced event) downgrades to `unattributed_workspace_dirty`.
|
|
926
|
+
// NOTE: this is the events.jsonl-only attribution. The §9 git-diff fallback
|
|
927
|
+
// (升 fallback via session shell event + baseline) is a SPECULATIVE
|
|
928
|
+
// implementation note — deliberately NOT run here (doctor stays read-only,
|
|
929
|
+
// no git diff / no disk write). Additive; absent on degraded/skipped reports.
|
|
930
|
+
mutation_pool: z3.object({
|
|
931
|
+
attributed: z3.number().int().nonnegative(),
|
|
932
|
+
unattributed_workspace_dirty: z3.number().int().nonnegative()
|
|
933
|
+
}).optional(),
|
|
934
|
+
// lifecycle-refactor W2-T4 (§5 row2 SessionEnd funnel 对账下沉 doctor): the
|
|
935
|
+
// SessionEnd hook only O(1)-appends a `session_ended` marker; this counts the
|
|
936
|
+
// distinct sessions that emitted one (funnel "closed" boundary). Purely an
|
|
937
|
+
// observability marker — not joined into any rate. Additive.
|
|
938
|
+
sessions_closed: z3.object({
|
|
939
|
+
count: z3.number().int().nonnegative()
|
|
940
|
+
}).optional()
|
|
808
941
|
}),
|
|
809
|
-
per_client:
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
edits_touched:
|
|
813
|
-
qualifying_cites:
|
|
814
|
-
recalled_unverified:
|
|
815
|
-
expected_but_missed:
|
|
816
|
-
total_turns:
|
|
942
|
+
per_client: z3.record(
|
|
943
|
+
z3.string(),
|
|
944
|
+
z3.object({
|
|
945
|
+
edits_touched: z3.number().int().nonnegative().optional(),
|
|
946
|
+
qualifying_cites: z3.number().int().nonnegative().optional(),
|
|
947
|
+
recalled_unverified: z3.number().int().nonnegative().optional(),
|
|
948
|
+
expected_but_missed: z3.number().int().nonnegative().optional(),
|
|
949
|
+
total_turns: z3.number().int().nonnegative().optional()
|
|
817
950
|
})
|
|
818
951
|
).optional(),
|
|
819
|
-
dismissed_reason_histogram:
|
|
820
|
-
none_reason_histogram:
|
|
952
|
+
dismissed_reason_histogram: z3.record(z3.string(), z3.number().int().nonnegative()).optional(),
|
|
953
|
+
none_reason_histogram: z3.record(z3.string(), z3.number().int().nonnegative()).optional(),
|
|
821
954
|
// v2.0.0-rc.24 TASK-08: contract-policy audit metrics. Status discriminates
|
|
822
955
|
// populated vs degraded modes. contract_metrics + per_layer_type are emitted
|
|
823
956
|
// (zeroed) in degraded modes so the renderer iterates one stable shape.
|
|
824
|
-
contract_metrics_status:
|
|
957
|
+
contract_metrics_status: z3.enum(["ok", "skipped:bootstrap_drift", "awaiting_marker"]).optional(),
|
|
825
958
|
contract_metrics: citeContractMetricsSchema.optional(),
|
|
826
959
|
per_layer_type: citeLayerTypeBreakdownSchema.optional(),
|
|
827
|
-
contract_marker_ts:
|
|
828
|
-
generated_at:
|
|
960
|
+
contract_marker_ts: z3.number().int().nonnegative().optional(),
|
|
961
|
+
generated_at: z3.string()
|
|
829
962
|
});
|
|
830
|
-
var ledgerSourceSchema =
|
|
831
|
-
var timestampFilterSchema =
|
|
963
|
+
var ledgerSourceSchema = z3.enum(["ai", "human"]);
|
|
964
|
+
var timestampFilterSchema = z3.preprocess((value) => {
|
|
832
965
|
if (value === void 0 || value === null || value === "") {
|
|
833
966
|
return void 0;
|
|
834
967
|
}
|
|
@@ -847,38 +980,38 @@ var timestampFilterSchema = z2.preprocess((value) => {
|
|
|
847
980
|
return Number.isNaN(parsed) ? value : parsed;
|
|
848
981
|
}
|
|
849
982
|
return value;
|
|
850
|
-
},
|
|
851
|
-
var ledgerQuerySchema =
|
|
983
|
+
}, z3.number().int().nonnegative());
|
|
984
|
+
var ledgerQuerySchema = z3.object({
|
|
852
985
|
source: ledgerSourceSchema.optional(),
|
|
853
986
|
since: timestampFilterSchema.optional()
|
|
854
987
|
});
|
|
855
|
-
var historyStateQuerySchema =
|
|
856
|
-
ledger_id:
|
|
988
|
+
var historyStateQuerySchema = z3.object({
|
|
989
|
+
ledger_id: z3.string().trim().min(1).optional(),
|
|
857
990
|
ts: timestampFilterSchema.optional()
|
|
858
991
|
}).superRefine((value, ctx) => {
|
|
859
992
|
const provided = [value.ledger_id, value.ts].filter((entry) => entry !== void 0);
|
|
860
993
|
if (provided.length !== 1) {
|
|
861
994
|
ctx.addIssue({
|
|
862
|
-
code:
|
|
995
|
+
code: z3.ZodIssueCode.custom,
|
|
863
996
|
message: "Provide exactly one of ledger_id or ts.",
|
|
864
997
|
path: ["ledger_id"]
|
|
865
998
|
});
|
|
866
999
|
}
|
|
867
1000
|
});
|
|
868
|
-
var humanLockApproveRequestSchema =
|
|
869
|
-
file:
|
|
870
|
-
start_line:
|
|
871
|
-
end_line:
|
|
872
|
-
new_hash:
|
|
1001
|
+
var humanLockApproveRequestSchema = z3.object({
|
|
1002
|
+
file: z3.string().min(1),
|
|
1003
|
+
start_line: z3.number().int().positive(),
|
|
1004
|
+
end_line: z3.number().int().positive(),
|
|
1005
|
+
new_hash: z3.string().min(1)
|
|
873
1006
|
});
|
|
874
|
-
var humanLockFileParamsSchema =
|
|
875
|
-
file:
|
|
1007
|
+
var humanLockFileParamsSchema = z3.object({
|
|
1008
|
+
file: z3.string().min(1)
|
|
876
1009
|
});
|
|
877
|
-
var annotateIntentRequestSchema =
|
|
878
|
-
ledger_entry_id:
|
|
879
|
-
annotation:
|
|
1010
|
+
var annotateIntentRequestSchema = z3.object({
|
|
1011
|
+
ledger_entry_id: z3.string().min(1),
|
|
1012
|
+
annotation: z3.string().trim().min(1)
|
|
880
1013
|
});
|
|
881
|
-
var KnowledgeTypeSchema =
|
|
1014
|
+
var KnowledgeTypeSchema = z3.enum([
|
|
882
1015
|
"models",
|
|
883
1016
|
// entities, data structures, relationships
|
|
884
1017
|
"decisions",
|
|
@@ -890,10 +1023,10 @@ var KnowledgeTypeSchema = z2.enum([
|
|
|
890
1023
|
"processes"
|
|
891
1024
|
// workflows, state machines, operational steps
|
|
892
1025
|
]);
|
|
893
|
-
var MaturitySchema =
|
|
894
|
-
var LayerSchema =
|
|
895
|
-
var StableIdSchema =
|
|
896
|
-
var KnowledgeEntryFrontmatterSchema =
|
|
1026
|
+
var MaturitySchema = z3.enum(["draft", "verified", "proven"]);
|
|
1027
|
+
var LayerSchema = z3.enum(["personal", "team"]);
|
|
1028
|
+
var StableIdSchema = z3.string().regex(/^K[PT]-(MOD|DEC|GLD|PIT|PRO)-\d{4,}$/);
|
|
1029
|
+
var KnowledgeEntryFrontmatterSchema = z3.object({
|
|
897
1030
|
id: StableIdSchema,
|
|
898
1031
|
// e.g., "KT-DEC-0042"
|
|
899
1032
|
type: KnowledgeTypeSchema,
|
|
@@ -902,9 +1035,9 @@ var KnowledgeEntryFrontmatterSchema = z2.object({
|
|
|
902
1035
|
// draft | verified | proven
|
|
903
1036
|
layer: LayerSchema,
|
|
904
1037
|
// personal | team
|
|
905
|
-
layer_reason:
|
|
1038
|
+
layer_reason: z3.string().optional(),
|
|
906
1039
|
// why this layer (for ambiguous cases)
|
|
907
|
-
created_at:
|
|
1040
|
+
created_at: z3.string()
|
|
908
1041
|
// ISO 8601 timestamp
|
|
909
1042
|
// Note: 'tags' and other fields can be added later but core schema is these 6
|
|
910
1043
|
});
|
|
@@ -935,6 +1068,13 @@ export {
|
|
|
935
1068
|
ONBOARD_SLOT_NAMES,
|
|
936
1069
|
onboardSlotSchema,
|
|
937
1070
|
ONBOARD_SLOT_TOTAL,
|
|
1071
|
+
PERSONAL_SCOPE,
|
|
1072
|
+
KNOWN_SCOPE_PREFIXES,
|
|
1073
|
+
SCOPE_COORDINATE_PATTERN,
|
|
1074
|
+
scopeCoordinateSchema,
|
|
1075
|
+
scopeRoot,
|
|
1076
|
+
isPersonalScope,
|
|
1077
|
+
entryScopeMetadataSchema,
|
|
938
1078
|
structuredWarningSchema,
|
|
939
1079
|
planContextInputSchema,
|
|
940
1080
|
planContextOutputSchema,
|
|
@@ -951,7 +1091,7 @@ export {
|
|
|
951
1091
|
archiveScanOutputSchema,
|
|
952
1092
|
archiveScanAnnotations,
|
|
953
1093
|
ProposedReasonSchema,
|
|
954
|
-
|
|
1094
|
+
PROPOSED_REASON_DESCRIPTIONS_BY_LOCALE,
|
|
955
1095
|
FabExtractKnowledgeInputSchema,
|
|
956
1096
|
FabExtractKnowledgeInputShape,
|
|
957
1097
|
FabExtractKnowledgeOutputSchema,
|