@fenglimg/fabric-shared 2.1.0-rc.2 → 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-WVPDH4BF.js → chunk-5AKCRBKJ.js} +551 -382
- package/dist/{chunk-R2J7DAED.js → chunk-AQMDXC6J.js} +545 -517
- 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-GQpaWTm-.d.ts → index-D_gT1CEA.d.ts} +125 -28
- package/dist/index.d.ts +2348 -1187
- package/dist/index.js +1675 -835
- package/dist/node/atomic-write.d.ts +26 -1
- package/dist/node/atomic-write.js +8 -65
- package/dist/node/mcp-payload-guard.d.ts +32 -1
- package/dist/node/mcp-payload-guard.js +16 -2
- package/dist/node.d.ts +10 -1
- package/dist/node.js +32 -1
- package/dist/schemas/api-contracts.d.ts +319 -100
- 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-MDWTGOAY.js +0 -101
package/dist/index.js
CHANGED
|
@@ -1,22 +1,16 @@
|
|
|
1
|
-
import
|
|
2
|
-
BOOTSTRAP_CANONICAL,
|
|
3
|
-
BOOTSTRAP_MARKER_BEGIN,
|
|
4
|
-
BOOTSTRAP_MARKER_END,
|
|
5
|
-
BOOTSTRAP_REGEX,
|
|
6
|
-
LEGACY_KB_MARKER_BEGIN,
|
|
7
|
-
LEGACY_KB_MARKER_END,
|
|
8
|
-
LEGACY_KB_REGEX
|
|
9
|
-
} from "./chunk-MDWTGOAY.js";
|
|
1
|
+
import "./chunk-LXNCAKJZ.js";
|
|
10
2
|
import {
|
|
11
3
|
PROTECTED_TOKENS,
|
|
12
4
|
createTranslator,
|
|
13
5
|
defaultMessages,
|
|
14
|
-
detectNodeLocale,
|
|
15
6
|
enMessages,
|
|
16
|
-
normalizeLocale,
|
|
17
7
|
resolveFabricLocale,
|
|
18
8
|
zhCNMessages
|
|
19
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-AQMDXC6J.js";
|
|
10
|
+
import {
|
|
11
|
+
atomicWriteJson,
|
|
12
|
+
withFileLock
|
|
13
|
+
} from "./chunk-C7WZPYZE.js";
|
|
20
14
|
import {
|
|
21
15
|
FabExtractKnowledgeInputSchema,
|
|
22
16
|
FabExtractKnowledgeInputShape,
|
|
@@ -26,14 +20,17 @@ import {
|
|
|
26
20
|
FabReviewOutputSchema,
|
|
27
21
|
FabReviewOutputShape,
|
|
28
22
|
KNOWLEDGE_TYPE_CODES,
|
|
23
|
+
KNOWN_SCOPE_PREFIXES,
|
|
29
24
|
KnowledgeEntryFrontmatterSchema,
|
|
30
25
|
KnowledgeTypeSchema,
|
|
31
26
|
LayerSchema,
|
|
32
27
|
MaturitySchema,
|
|
33
28
|
ONBOARD_SLOT_NAMES,
|
|
34
29
|
ONBOARD_SLOT_TOTAL,
|
|
35
|
-
|
|
30
|
+
PERSONAL_SCOPE,
|
|
31
|
+
PROPOSED_REASON_DESCRIPTIONS_BY_LOCALE,
|
|
36
32
|
ProposedReasonSchema,
|
|
33
|
+
SCOPE_COORDINATE_PATTERN,
|
|
37
34
|
StableIdSchema,
|
|
38
35
|
annotateIntentRequestSchema,
|
|
39
36
|
archiveScanAnnotations,
|
|
@@ -42,12 +39,14 @@ import {
|
|
|
42
39
|
citeContractMetricsSchema,
|
|
43
40
|
citeCoverageReportSchema,
|
|
44
41
|
citeLayerTypeBreakdownSchema,
|
|
42
|
+
entryScopeMetadataSchema,
|
|
45
43
|
fabExtractKnowledgeAnnotations,
|
|
46
44
|
fabReviewAnnotations,
|
|
47
45
|
formatKnowledgeId,
|
|
48
46
|
historyStateQuerySchema,
|
|
49
47
|
humanLockApproveRequestSchema,
|
|
50
48
|
humanLockFileParamsSchema,
|
|
49
|
+
isPersonalScope,
|
|
51
50
|
knowledgeSectionsAnnotations,
|
|
52
51
|
knowledgeSectionsInputSchema,
|
|
53
52
|
knowledgeSectionsOutputSchema,
|
|
@@ -63,9 +62,55 @@ import {
|
|
|
63
62
|
recallAnnotations,
|
|
64
63
|
recallInputSchema,
|
|
65
64
|
recallOutputSchema,
|
|
65
|
+
scopeCoordinateSchema,
|
|
66
|
+
scopeRoot,
|
|
66
67
|
structuredWarningSchema
|
|
67
|
-
} from "./chunk-
|
|
68
|
-
import
|
|
68
|
+
} from "./chunk-5AKCRBKJ.js";
|
|
69
|
+
import {
|
|
70
|
+
BOOTSTRAP_CANONICAL_BY_LOCALE,
|
|
71
|
+
BOOTSTRAP_CANONICAL_EN,
|
|
72
|
+
BOOTSTRAP_CANONICAL_ZH,
|
|
73
|
+
BOOTSTRAP_MARKER_BEGIN,
|
|
74
|
+
BOOTSTRAP_MARKER_END,
|
|
75
|
+
BOOTSTRAP_REGEX,
|
|
76
|
+
matchBootstrapCanonicalLocale,
|
|
77
|
+
resolveBootstrapCanonical
|
|
78
|
+
} from "./chunk-BDJQIOQO.js";
|
|
79
|
+
import {
|
|
80
|
+
GLOBAL_BINDINGS_DIR,
|
|
81
|
+
GLOBAL_STATE_DIR,
|
|
82
|
+
PERSONAL_STORE_SENTINEL,
|
|
83
|
+
STORES_ROOT_DIR,
|
|
84
|
+
STORE_ALIAS_PATTERN,
|
|
85
|
+
STORE_KNOWLEDGE_TYPE_DIRS,
|
|
86
|
+
STORE_LAYOUT,
|
|
87
|
+
STORE_MOUNT_GROUPS,
|
|
88
|
+
STORE_MOUNT_NAME_PATTERN,
|
|
89
|
+
STORE_PROJECT_ID_PATTERN,
|
|
90
|
+
STORE_UUID_PATTERN,
|
|
91
|
+
deriveMountLabel,
|
|
92
|
+
detectNodeLocale,
|
|
93
|
+
globalConfigPath,
|
|
94
|
+
globalConfigSchema,
|
|
95
|
+
loadGlobalConfig,
|
|
96
|
+
mountedStoreSchema,
|
|
97
|
+
normalizeLocale,
|
|
98
|
+
requiredStoreEntrySchema,
|
|
99
|
+
resolveGlobalLocale,
|
|
100
|
+
resolveGlobalRoot,
|
|
101
|
+
saveGlobalConfig,
|
|
102
|
+
storeAliasSchema,
|
|
103
|
+
storeIdentitySchema,
|
|
104
|
+
storeKnowledgeTypeDir,
|
|
105
|
+
storeMountGroup,
|
|
106
|
+
storeMountNameSchema,
|
|
107
|
+
storeMountSubPath,
|
|
108
|
+
storeProjectSchema,
|
|
109
|
+
storeProjectsFileSchema,
|
|
110
|
+
storeRelativePath,
|
|
111
|
+
storeRelativePathForMount,
|
|
112
|
+
storeUuidSchema
|
|
113
|
+
} from "./chunk-2GLIAZ5M.js";
|
|
69
114
|
|
|
70
115
|
// src/schemas/agents-meta.ts
|
|
71
116
|
import { z } from "zod";
|
|
@@ -77,10 +122,8 @@ var KNOWLEDGE_TYPE_SINGULAR_TO_PLURAL = {
|
|
|
77
122
|
pitfall: "pitfalls",
|
|
78
123
|
process: "processes"
|
|
79
124
|
};
|
|
80
|
-
var AGENTS_META_LAYERS = ["L0", "L1", "L2"];
|
|
81
125
|
var AGENTS_META_TOPOLOGY_TYPES = ["mirror", "cross-cutting", "domain", "local", "global"];
|
|
82
126
|
var AGENTS_META_IDENTITY_SOURCES = ["declared", "derived"];
|
|
83
|
-
var agentsLayerSchema = z.enum(AGENTS_META_LAYERS);
|
|
84
127
|
var agentsTopologyTypeSchema = z.enum(AGENTS_META_TOPOLOGY_TYPES);
|
|
85
128
|
var agentsIdentitySourceSchema = z.enum(AGENTS_META_IDENTITY_SOURCES);
|
|
86
129
|
var ruleDescriptionSchema = z.object({
|
|
@@ -112,13 +155,18 @@ var ruleDescriptionSchema = z.object({
|
|
|
112
155
|
// relevance_scope → 'broad' (always-surface, safe default)
|
|
113
156
|
// relevance_paths → [] (no path anchors)
|
|
114
157
|
relevance_scope: z.enum(["narrow", "broad"]).default("broad"),
|
|
115
|
-
relevance_paths: z.array(z.string()).default([])
|
|
158
|
+
relevance_paths: z.array(z.string()).default([]),
|
|
159
|
+
// v2.2 H2-related (W1-T7): explicit graph edges to related KB entries by
|
|
160
|
+
// stable_id. Authored in frontmatter (`related: [KT-DEC-0001, KT-PIT-0002]`)
|
|
161
|
+
// or written by the fabric-connect skill (SK2); read by fab_recall's
|
|
162
|
+
// include_related packaging (MC1). Optional + default [] so the field is a
|
|
163
|
+
// pure additive — every pre-v2.2 entry parses unchanged. The schema is
|
|
164
|
+
// .strict(), so this MUST be declared or `related:` frontmatter would be
|
|
165
|
+
// rejected at parse time.
|
|
166
|
+
related: z.array(z.string()).default([]).optional()
|
|
116
167
|
}).strict();
|
|
117
168
|
var ruleDescriptionIndexItemSchema = z.object({
|
|
118
169
|
stable_id: z.string(),
|
|
119
|
-
level: agentsLayerSchema,
|
|
120
|
-
required: z.boolean(),
|
|
121
|
-
selectable: z.boolean(),
|
|
122
170
|
description: ruleDescriptionSchema
|
|
123
171
|
}).strict();
|
|
124
172
|
var agentsMetaNodeBaseSchema = z.object({
|
|
@@ -128,10 +176,6 @@ var agentsMetaNodeBaseSchema = z.object({
|
|
|
128
176
|
hash: z.string(),
|
|
129
177
|
stable_id: z.string().optional(),
|
|
130
178
|
identity_source: agentsIdentitySourceSchema.optional(),
|
|
131
|
-
activation: z.object({
|
|
132
|
-
tier: z.enum(["always", "path", "description"]),
|
|
133
|
-
description: z.string().optional()
|
|
134
|
-
}).optional(),
|
|
135
179
|
description: ruleDescriptionSchema.optional(),
|
|
136
180
|
sections: z.array(z.string()).optional()
|
|
137
181
|
}).passthrough();
|
|
@@ -170,7 +214,6 @@ function withDerivedAgentsMetaNodeDefaults(node) {
|
|
|
170
214
|
const identitySource = isKnowledgeEntry ? "declared" : deriveAgentsMetaIdentitySource(node);
|
|
171
215
|
return {
|
|
172
216
|
...node,
|
|
173
|
-
level: node.level ?? deriveAgentsMetaLayer(node.file),
|
|
174
217
|
topology_type: node.topology_type ?? deriveAgentsMetaTopologyType(node.file),
|
|
175
218
|
stable_id: stableId,
|
|
176
219
|
identity_source: identitySource
|
|
@@ -214,34 +257,12 @@ function deriveAgentsMetaIdentitySource(node) {
|
|
|
214
257
|
const derivedStableId = deriveAgentsMetaStableId(node.file);
|
|
215
258
|
return node.stable_id !== void 0 && node.stable_id !== derivedStableId ? "declared" : "derived";
|
|
216
259
|
}
|
|
217
|
-
function deriveAgentsMetaLayer(file) {
|
|
218
|
-
const normalized = normalizePath(file);
|
|
219
|
-
if (normalized === "AGENTS.md") {
|
|
220
|
-
return "L0";
|
|
221
|
-
}
|
|
222
|
-
if (hasCrossCuttingSegment(normalized)) {
|
|
223
|
-
return "L1";
|
|
224
|
-
}
|
|
225
|
-
const depthSource = getDepthSource(normalized);
|
|
226
|
-
const directoryDepth = getDirectoryDepth(depthSource);
|
|
227
|
-
if (directoryDepth === 0) {
|
|
228
|
-
return "L0";
|
|
229
|
-
}
|
|
230
|
-
if (directoryDepth <= 2) {
|
|
231
|
-
return "L1";
|
|
232
|
-
}
|
|
233
|
-
return "L2";
|
|
234
|
-
}
|
|
235
260
|
function deriveAgentsMetaTopologyType(file) {
|
|
236
261
|
return hasCrossCuttingSegment(normalizePath(file)) ? "cross-cutting" : "mirror";
|
|
237
262
|
}
|
|
238
263
|
function getDepthSource(file) {
|
|
239
264
|
return file.startsWith(FABRIC_AGENTS_PREFIX) ? file.slice(FABRIC_AGENTS_PREFIX.length) : file;
|
|
240
265
|
}
|
|
241
|
-
function getDirectoryDepth(file) {
|
|
242
|
-
const segments = file.split("/").filter(Boolean);
|
|
243
|
-
return Math.max(segments.length - 1, 0);
|
|
244
|
-
}
|
|
245
266
|
function hasCrossCuttingSegment(file) {
|
|
246
267
|
return file.split("/").includes("_cross");
|
|
247
268
|
}
|
|
@@ -327,104 +348,35 @@ var humanLockFileSchema = z4.object({
|
|
|
327
348
|
});
|
|
328
349
|
|
|
329
350
|
// src/schemas/fabric-config.ts
|
|
330
|
-
import { z as z6 } from "zod";
|
|
331
|
-
|
|
332
|
-
// src/schemas/store.ts
|
|
333
351
|
import { z as z5 } from "zod";
|
|
334
|
-
var
|
|
335
|
-
var
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
store_uuid: storeUuidSchema,
|
|
340
|
-
// ISO-8601. When the store was first initialized.
|
|
341
|
-
created_at: z5.string(),
|
|
342
|
-
// Optional human-facing canonical alias baked into the store (e.g. the
|
|
343
|
-
// team picks "platform-kb"). Local per-machine aliases are resolved by the
|
|
344
|
-
// StoreResolver from config and may differ; this is the suggested default.
|
|
345
|
-
canonical_alias: z5.string().optional(),
|
|
346
|
-
// Optional one-line description surfaced in `store list` / onboarding.
|
|
347
|
-
description: z5.string().optional(),
|
|
348
|
-
// The semantic scopes this store is *allowed* to hold. A shared (team)
|
|
349
|
-
// store MUST NOT list "personal" (R5#3 privacy boundary, enforced at write
|
|
350
|
-
// time in P2). Open coordinate strings — see schemas/scope.ts.
|
|
351
|
-
allowed_scopes: z5.array(z5.string()).optional()
|
|
352
|
-
}).strict();
|
|
353
|
-
var requiredStoreEntrySchema = z5.object({
|
|
354
|
-
id: z5.string().min(1),
|
|
355
|
-
suggested_remote: z5.union([z5.string().min(1), z5.literal(PERSONAL_STORE_SENTINEL)]).optional()
|
|
352
|
+
var auditModeSchema = z5.enum(["strict", "warn", "off"]);
|
|
353
|
+
var clientPathsSchema = z5.object({
|
|
354
|
+
claudeCodeCLI: z5.string().optional(),
|
|
355
|
+
claudeCodeDesktop: z5.string().optional(),
|
|
356
|
+
codexCLI: z5.string().optional()
|
|
356
357
|
}).strict();
|
|
357
|
-
var
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
];
|
|
364
|
-
var
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
var STORES_ROOT_DIR = "stores";
|
|
371
|
-
var GLOBAL_STATE_DIR = "state";
|
|
372
|
-
var GLOBAL_BINDINGS_DIR = "bindings";
|
|
373
|
-
function storeKnowledgeTypeDir(type) {
|
|
374
|
-
return `${STORE_LAYOUT.knowledgeDir}/${type}`;
|
|
375
|
-
}
|
|
376
|
-
function storeRelativePath(storeUuid) {
|
|
377
|
-
return `${STORES_ROOT_DIR}/${storeUuid}`;
|
|
378
|
-
}
|
|
379
|
-
var mountedStoreSchema = z5.object({
|
|
380
|
-
// Intrinsic identity of the mounted store (matches its store.json).
|
|
381
|
-
store_uuid: storeUuidSchema,
|
|
382
|
-
// Local per-machine alias the user references this store by (resolver maps
|
|
383
|
-
// alias → uuid). May differ from the store's canonical_alias.
|
|
384
|
-
alias: z5.string().min(1),
|
|
385
|
-
// Git remote locator for this clone, if any. Absent = local-only store
|
|
386
|
-
// (valid; doctor nudges to add a remote for backup — R5#5, P6).
|
|
387
|
-
remote: z5.string().min(1).optional(),
|
|
388
|
-
// v2.1.0-rc.1 P3: marks the implicit personal store (the one minted by
|
|
389
|
-
// `install --global`). Exactly one mounted store carries personal=true; it
|
|
390
|
-
// is the write target for personal-scope entries (R5#3) and always in the
|
|
391
|
-
// read-set (S11). Optional (no default) so the output type stays a plain
|
|
392
|
-
// optional — consumers coalesce `?? false` when building resolver input.
|
|
393
|
-
personal: z5.boolean().optional(),
|
|
394
|
-
// Whether writes are accepted into this store from this machine. Optional;
|
|
395
|
-
// consumers coalesce `?? true`. Shared stores cloned read-only set false.
|
|
396
|
-
writable: z5.boolean().optional()
|
|
358
|
+
var mcpPayloadLimitsSchema = z5.object({
|
|
359
|
+
warnBytes: z5.number().int().positive().optional(),
|
|
360
|
+
hardBytes: z5.number().int().positive().optional()
|
|
361
|
+
}).optional();
|
|
362
|
+
var selectionTokenTtlMsSchema = z5.number().int().min(3e4).max(36e5);
|
|
363
|
+
var planContextTopKSchema = z5.number().int().min(1).max(200);
|
|
364
|
+
var fabricLanguageSchema = z5.enum(["zh-CN", "en"]);
|
|
365
|
+
var defaultLayerFilterSchema = z5.enum(["team", "personal", "both"]);
|
|
366
|
+
var nudgeModeSchema = z5.enum(["silent", "minimal", "normal", "verbose"]);
|
|
367
|
+
var observeConfigSchema = z5.object({
|
|
368
|
+
session_start: z5.boolean().optional(),
|
|
369
|
+
pre_tool_use: z5.boolean().optional(),
|
|
370
|
+
stop: z5.boolean().optional()
|
|
397
371
|
}).strict();
|
|
398
|
-
var
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
stores: z5.array(mountedStoreSchema).optional().default([])
|
|
405
|
-
}).passthrough();
|
|
406
|
-
|
|
407
|
-
// src/schemas/fabric-config.ts
|
|
408
|
-
var auditModeSchema = z6.enum(["strict", "warn", "off"]);
|
|
409
|
-
var clientPathsSchema = z6.object({
|
|
410
|
-
claudeCodeCLI: z6.string().optional(),
|
|
411
|
-
claudeCodeDesktop: z6.string().optional(),
|
|
412
|
-
cursor: z6.string().optional(),
|
|
413
|
-
codexCLI: z6.string().optional()
|
|
372
|
+
var writeRouteSchema = z5.object({
|
|
373
|
+
scope: z5.string().regex(
|
|
374
|
+
SCOPE_COORDINATE_PATTERN,
|
|
375
|
+
"write route scope must be ':'-joined lowercase [a-z0-9_-] segments"
|
|
376
|
+
),
|
|
377
|
+
store: z5.string().min(1)
|
|
414
378
|
}).strict();
|
|
415
|
-
var
|
|
416
|
-
warnBytes: z6.number().int().positive().optional(),
|
|
417
|
-
hardBytes: z6.number().int().positive().optional()
|
|
418
|
-
}).optional();
|
|
419
|
-
var selectionTokenTtlMsSchema = z6.number().int().min(3e4).max(36e5);
|
|
420
|
-
var fabricLanguageSchema = z6.enum([
|
|
421
|
-
"match-existing",
|
|
422
|
-
"zh-CN",
|
|
423
|
-
"en",
|
|
424
|
-
"zh-CN-hybrid"
|
|
425
|
-
]);
|
|
426
|
-
var defaultLayerFilterSchema = z6.enum(["team", "personal", "both"]);
|
|
427
|
-
var fabricConfigSchema = z6.object({
|
|
379
|
+
var fabricConfigSchema = z5.object({
|
|
428
380
|
clientPaths: clientPathsSchema.optional(),
|
|
429
381
|
// v2.1.0-rc.1 P0 (S13-projectid): the project's stable identity. A UUID
|
|
430
382
|
// bound at `fabric install` time; a remote-derived hash is only a SUGGESTED
|
|
@@ -433,19 +385,37 @@ var fabricConfigSchema = z6.object({
|
|
|
433
385
|
// fabric-config.json files simply lack it and the ProjectRootResolver mints
|
|
434
386
|
// one on next install. `.fabric/fabric-config.json` carrying this field is
|
|
435
387
|
// also the upward marker the ProjectRootResolver searches for (S15/S32).
|
|
436
|
-
project_id:
|
|
388
|
+
project_id: z5.string().optional(),
|
|
389
|
+
// Store-only runtime binding identity. Defaults to project_id when omitted,
|
|
390
|
+
// but worktrees / sandboxes can set this to isolate hook/runtime state while
|
|
391
|
+
// keeping the same committed project identity.
|
|
392
|
+
workspace_binding_id: z5.string().optional(),
|
|
437
393
|
// v2.1.0-rc.1 P0 (S59/B3): the stores this repo expects mounted. Each entry
|
|
438
394
|
// names a store by alias/UUID with an optional suggested_remote (or the
|
|
439
395
|
// `$personal` sentinel). Drives the read-set (required_stores ∪ implicit
|
|
440
396
|
// personal, S11/S54) and `clone`'s missing-store onboarding (S51). Optional
|
|
441
397
|
// + absent → read-set is just the implicit personal store.
|
|
442
|
-
required_stores:
|
|
398
|
+
required_stores: z5.array(requiredStoreEntrySchema).optional(),
|
|
443
399
|
// v2.1.0-rc.1 P3 (S60 / `store switch-write`): alias of the store that
|
|
444
400
|
// non-personal-scope writes land in for this project. Set by
|
|
445
401
|
// `fabric store switch-write <alias>`; consumed as the resolver's
|
|
446
402
|
// activeWriteAlias. Absent → no active write store yet. Personal-scope
|
|
447
403
|
// writes always target the implicit personal store regardless (R5#3).
|
|
448
|
-
active_write_store:
|
|
404
|
+
active_write_store: z5.string().optional(),
|
|
405
|
+
// v2.1 global-refactor (W1/A2 — store project registry): the project this repo
|
|
406
|
+
// currently participates in, as the SINGLE scope segment forming the
|
|
407
|
+
// `project:<id>` coordinate (schemas/scope.ts). Set by `store bind --project
|
|
408
|
+
// <id>` (validated against the bound store's projects.json). Drives:
|
|
409
|
+
// - write: project-scoped writes get `semantic_scope: project:<active_project>`.
|
|
410
|
+
// - recall: keep `project:<active_project>` + non-project coords, drop other
|
|
411
|
+
// `project:*` entries (G-FILTER).
|
|
412
|
+
// Absent → the repo has no project binding; recall does not project-filter.
|
|
413
|
+
active_project: z5.string().optional(),
|
|
414
|
+
// Global Store Topology: scope-aware write routing for multi shared/org stores.
|
|
415
|
+
// Personal scope ignores these routes and always resolves to the implicit
|
|
416
|
+
// personal store. `active_write_store` remains a backward-compatible fallback.
|
|
417
|
+
write_routes: z5.array(writeRouteSchema).optional(),
|
|
418
|
+
default_write_store: z5.string().optional(),
|
|
449
419
|
// rc.17 (R-cut): the dev/test fixture-path config field was removed
|
|
450
420
|
// end-to-end. The `EXTERNAL_FIXTURE_PATH` env var is now the sole source
|
|
451
421
|
// consumed by `resolveDevMode()`. No z.preprocess alias — pre-rc.17
|
|
@@ -453,14 +423,23 @@ var fabricConfigSchema = z6.object({
|
|
|
453
423
|
// the lenient root parser (no .strict() at root). Pre-user clean-slate per
|
|
454
424
|
// memory/feedback_clean_slate.md; mirrors the rc.12 hard-rename precedent
|
|
455
425
|
// documented above.
|
|
456
|
-
scanIgnores:
|
|
426
|
+
scanIgnores: z5.array(z5.string()).optional(),
|
|
457
427
|
audit_mode: auditModeSchema.optional(),
|
|
458
428
|
mcpPayloadLimits: mcpPayloadLimitsSchema,
|
|
459
|
-
//
|
|
460
|
-
//
|
|
461
|
-
//
|
|
462
|
-
|
|
429
|
+
// grill-6fixes (D1): `fabric_language` is no longer a per-project field —
|
|
430
|
+
// language is a single machine-wide tone in `~/.fabric/fabric-global.json`.
|
|
431
|
+
// The root parser is lenient (no .strict()), so any stale `fabric_language`
|
|
432
|
+
// key left in an existing project config is silently dropped.
|
|
463
433
|
default_layer_filter: defaultLayerFilterSchema.optional().default("both"),
|
|
434
|
+
// v2.2 dual-sink (Goal A / D4): human-output preset. See nudgeModeSchema for
|
|
435
|
+
// the level semantics + the flow ⊥ observation invariant (nudge_mode never
|
|
436
|
+
// touches the AI additionalContext sink). Default "normal" preserves the
|
|
437
|
+
// pre-dual-sink human visibility so existing dogfood repos see no regression.
|
|
438
|
+
nudge_mode: nudgeModeSchema.optional().default("normal"),
|
|
439
|
+
// v2.2 dual-sink (Goal A / D4): per-event human-output overrides. A set value
|
|
440
|
+
// wins over the nudge_mode preset for that event; absent events fall back to
|
|
441
|
+
// the preset. AI sink unaffected (same invariant as nudge_mode).
|
|
442
|
+
observe: observeConfigSchema.optional(),
|
|
464
443
|
// Cooldown for the fabric-hint Stop hook (formerly archive-hint, renamed in
|
|
465
444
|
// rc.5 TASK-010). After ANY of the three signals (archive / review / import)
|
|
466
445
|
// fires, that signal stays silent for this many hours regardless of state
|
|
@@ -468,7 +447,7 @@ var fabricConfigSchema = z6.object({
|
|
|
468
447
|
// day if the user keeps ignoring it." Set to 24 to align with the archive
|
|
469
448
|
// trigger threshold. The legacy `archive_hint_` key is retained for backward
|
|
470
449
|
// compat with existing user fabric-config.json files.
|
|
471
|
-
archive_hint_cooldown_hours:
|
|
450
|
+
archive_hint_cooldown_hours: z5.number().int().positive().optional().default(12),
|
|
472
451
|
// Underseed-node threshold for the fabric-hint Stop hook's import signal
|
|
473
452
|
// (rc.5 TASK-010). When the canonical knowledge node count is strictly less
|
|
474
453
|
// than this value AND a successful `init_scan_completed` event happened at
|
|
@@ -477,7 +456,7 @@ var fabricConfigSchema = z6.object({
|
|
|
477
456
|
// the rule-of-thumb that a workspace with fewer than ten knowledge entries
|
|
478
457
|
// is below the floor for plan_context retrieval to be meaningful. Also
|
|
479
458
|
// consumed by `doctor` lint #22 (knowledge_underseeded).
|
|
480
|
-
underseed_node_threshold:
|
|
459
|
+
underseed_node_threshold: z5.number().int().positive().optional().default(10),
|
|
481
460
|
// Edit-count threshold for the fabric-hint Stop hook's Signal A
|
|
482
461
|
// (rc.6 TASK-022 / E5). Signal A fires when EITHER (a) >=24h have elapsed
|
|
483
462
|
// since the last `knowledge_proposed` event, OR (b) >=archive_edit_threshold
|
|
@@ -488,102 +467,102 @@ var fabricConfigSchema = z6.object({
|
|
|
488
467
|
// there is probably something worth archiving"; lowered values nag more
|
|
489
468
|
// aggressively, higher values rely on the 24h fallback. Missing or absent
|
|
490
469
|
// edit-counter file degrades safely to the 24h-only path.
|
|
491
|
-
archive_edit_threshold:
|
|
470
|
+
archive_edit_threshold: z5.number().int().positive().optional().default(20),
|
|
492
471
|
// rc.7 T7: hours-since-last-knowledge_proposed cutoff for Signal A's
|
|
493
472
|
// time branch. Was hardcoded as 24 in fabric-hint.cjs's THRESHOLD_HOURS;
|
|
494
473
|
// externalized so chatty workspaces can lower the bar and quiet ones can
|
|
495
474
|
// raise it. Default 24 preserves rc.6 behavior. See docs/configuration.md.
|
|
496
|
-
archive_hint_hours:
|
|
475
|
+
archive_hint_hours: z5.number().int().positive().optional().default(24),
|
|
497
476
|
// rc.7 T7: pending-count cutoff for Signal B (review skill). Was
|
|
498
477
|
// hardcoded as 10 in fabric-hint.cjs's THRESHOLD_PENDING_COUNT.
|
|
499
478
|
// Default 10 preserves rc.6 behavior. See docs/configuration.md for
|
|
500
479
|
// small/medium/large repo recommendations.
|
|
501
|
-
review_hint_pending_count:
|
|
480
|
+
review_hint_pending_count: z5.number().int().positive().optional().default(10),
|
|
502
481
|
// rc.7 T7: pending-age cutoff (in days) for Signal B (review skill).
|
|
503
482
|
// Was hardcoded as 7 in fabric-hint.cjs's THRESHOLD_PENDING_AGE_DAYS.
|
|
504
483
|
// Default 7 preserves rc.6 behavior. See docs/configuration.md.
|
|
505
|
-
review_hint_pending_age_days:
|
|
484
|
+
review_hint_pending_age_days: z5.number().int().positive().optional().default(7),
|
|
506
485
|
// rc.7 T7 + T10 pre-wiring: days-since-last-doctor cutoff for the future
|
|
507
486
|
// Signal D (maintenance hint). T10 will consume this to decide when the
|
|
508
487
|
// fabric-hint Stop hook surfaces a "run `fabric doctor`" reminder.
|
|
509
488
|
// Default 14 reflects a fortnightly cadence — long enough to avoid nag,
|
|
510
489
|
// short enough to catch index drift before it compounds.
|
|
511
|
-
maintenance_hint_days:
|
|
490
|
+
maintenance_hint_days: z5.number().int().positive().optional().default(14),
|
|
512
491
|
// rc.7 T7 + T10 pre-wiring: cooldown between Signal D reminders, in
|
|
513
492
|
// days. Once Signal D fires, it stays silent for this many days even if
|
|
514
493
|
// the user doesn't run doctor. Default 7 keeps the reminder weekly at
|
|
515
494
|
// worst — pairing 14d trigger + 7d cooldown means at most ~2 reminders
|
|
516
495
|
// per month for a workspace that ignores them.
|
|
517
|
-
maintenance_hint_cooldown_days:
|
|
496
|
+
maintenance_hint_cooldown_days: z5.number().int().positive().optional().default(7),
|
|
518
497
|
// rc.9+ (skill-contract-fix B1): first-run import window in months. The
|
|
519
498
|
// `fabric-import` skill scans this many months of git history on the very
|
|
520
499
|
// first invocation (when no prior `import_run_completed` event exists).
|
|
521
500
|
// Default 60 (~5 years) captures the bulk of a mature repo's signal in
|
|
522
501
|
// one pass; small / fresh repos can lower to 12-24 with no loss.
|
|
523
|
-
import_window_first_run_months:
|
|
502
|
+
import_window_first_run_months: z5.number().int().min(1).optional().default(60),
|
|
524
503
|
// rc.9+ (skill-contract-fix B1): rerun import window in months. After
|
|
525
504
|
// the first successful import, subsequent runs only scan this many
|
|
526
505
|
// recent months — assumed everything older has already been crystallized
|
|
527
506
|
// into pending or canonical knowledge. Default 2 keeps incremental cost
|
|
528
507
|
// low; raise to 6 if the workspace pauses fabric-import for long stretches.
|
|
529
|
-
import_window_rerun_months:
|
|
508
|
+
import_window_rerun_months: z5.number().int().min(1).optional().default(2),
|
|
530
509
|
// rc.9+ (skill-contract-fix B1): hard cap on pending entries produced
|
|
531
510
|
// per fabric-import invocation. Prevents one run from dumping hundreds
|
|
532
511
|
// of proposals when a backfill window is wide open. Default 10 matches
|
|
533
512
|
// the rule-of-thumb "human can triage ~10 pending entries in one
|
|
534
513
|
// review pass." Range 1-50.
|
|
535
|
-
import_max_pending_per_run:
|
|
514
|
+
import_max_pending_per_run: z5.number().int().min(1).max(50).optional().default(10),
|
|
536
515
|
// rc.9+ (skill-contract-fix B1): hard cap on commits scanned per
|
|
537
516
|
// fabric-import invocation. Bounds runtime on monorepos with high
|
|
538
517
|
// commit velocity. Default 500 covers ~2 months of typical churn;
|
|
539
518
|
// range 50-2000. Hitting the cap mid-window is logged but non-fatal.
|
|
540
|
-
import_max_commits_scan:
|
|
519
|
+
import_max_commits_scan: z5.number().int().min(50).max(2e3).optional().default(500),
|
|
541
520
|
// rc.9+ (skill-contract-fix B1): canonical-node count above which
|
|
542
521
|
// fabric-import's pre-flight should warn / suggest review instead of
|
|
543
522
|
// proceeding. A workspace with 50+ canonical entries usually benefits
|
|
544
523
|
// more from `fabric-review` to consolidate than from importing more.
|
|
545
524
|
// Default 50; raise to 100+ for large polyglot repos.
|
|
546
|
-
import_skip_canonical_threshold:
|
|
525
|
+
import_skip_canonical_threshold: z5.number().int().positive().optional().default(50),
|
|
547
526
|
// rc.9+ (skill-contract-fix B1): max candidate entries surfaced per
|
|
548
527
|
// fabric-archive batch (one invocation of the skill). Pagination knob
|
|
549
528
|
// for the archive UI flow. Default 8 keeps each batch reviewable in
|
|
550
529
|
// one sitting; raise for large repos with high archive throughput.
|
|
551
|
-
archive_max_candidates_per_batch:
|
|
530
|
+
archive_max_candidates_per_batch: z5.number().int().positive().optional().default(8),
|
|
552
531
|
// rc.9+ (skill-contract-fix B1): max recently-touched paths included
|
|
553
532
|
// in fabric-archive's "relevant context" lookup. Limits the size of
|
|
554
533
|
// the path-relevance digest the skill emits when ranking candidates.
|
|
555
534
|
// Default 20; large repos with deep directory fan-out can raise to
|
|
556
535
|
// 50+ if archive candidates feel under-contextualized.
|
|
557
|
-
archive_max_recent_paths:
|
|
536
|
+
archive_max_recent_paths: z5.number().int().positive().optional().default(20),
|
|
558
537
|
// rc.9+ (skill-contract-fix B1): max prior fabric-archive sessions
|
|
559
538
|
// summarised in the digest the skill loads on start. Prevents the
|
|
560
539
|
// digest from ballooning past the model context budget on workspaces
|
|
561
540
|
// that have archived repeatedly. Default 10; lower if context pressure
|
|
562
541
|
// bites, raise if you want longer-range archive trend visibility.
|
|
563
|
-
archive_digest_max_sessions:
|
|
542
|
+
archive_digest_max_sessions: z5.number().int().positive().optional().default(10),
|
|
564
543
|
// rc.9+ (skill-contract-fix B1): max review results returned per
|
|
565
544
|
// topic when `fabric-review` clusters pending entries. Pagination
|
|
566
545
|
// knob analogous to archive_max_candidates_per_batch but scoped to
|
|
567
546
|
// each topic cluster. Default 8; raise to 15-20 for large repos
|
|
568
547
|
// where each topic legitimately groups many pending entries.
|
|
569
|
-
review_topic_result_cap:
|
|
548
|
+
review_topic_result_cap: z5.number().int().positive().optional().default(8),
|
|
570
549
|
// rc.9+ (skill-contract-fix B1): age threshold (in days) above which
|
|
571
550
|
// a pending entry is considered "stale" by fabric-review and surfaced
|
|
572
551
|
// for explicit resolve-or-drop decision. Default 14; tighter than the
|
|
573
552
|
// 7d Signal-B trigger because review specifically targets the long
|
|
574
553
|
// tail. Large repos with slower cadence can raise to 30.
|
|
575
|
-
review_stale_pending_days:
|
|
554
|
+
review_stale_pending_days: z5.number().int().positive().optional().default(14),
|
|
576
555
|
// v2.0.0-rc.34 TASK-05: reverse-unarchive opt-in. When true, callers of the
|
|
577
556
|
// `unarchiveKnowledge` primitive (and any future doctor auto-detect lint built
|
|
578
557
|
// on top) will execute the file move + ledger emit. When false (default),
|
|
579
558
|
// the same callers MUST short-circuit before any mutation — the primitive is
|
|
580
559
|
// shipped but inert until explicitly enabled. Opt-in posture mirrors the
|
|
581
560
|
// archive-flow precedent: destructive-ish file moves stay behind a flag.
|
|
582
|
-
reverse_unarchive_enabled:
|
|
561
|
+
reverse_unarchive_enabled: z5.boolean().optional().default(false),
|
|
583
562
|
// v2.0.0-rc.34 TASK-05: forces `unarchiveKnowledge` into dry-run mode even
|
|
584
563
|
// when called with `options.dryRun=false`. Lets operators preview a
|
|
585
564
|
// restoration pass before flipping `reverse_unarchive_enabled` to true.
|
|
586
|
-
reverse_unarchive_dry_run:
|
|
565
|
+
reverse_unarchive_dry_run: z5.boolean().optional().default(false),
|
|
587
566
|
// v2.0.0-rc.34 TASK-06: long-session cite-policy evict window in user-prompt
|
|
588
567
|
// turns. UserPromptSubmit hook (Claude Code only) maintains a per-session
|
|
589
568
|
// counter and re-injects the cite contract reminder via
|
|
@@ -591,7 +570,31 @@ var fabricConfigSchema = z6.object({
|
|
|
591
570
|
// Default 0 = OFF (opt-in). Recommend 10-20 for active sessions; 5 for
|
|
592
571
|
// high-contract-criticality projects. Other strategies (time-based,
|
|
593
572
|
// token-budget) deferred to rc.35 per plan locked-decisions 2026-05-26.
|
|
594
|
-
cite_evict_interval:
|
|
573
|
+
cite_evict_interval: z5.number().int().min(0).optional().default(0),
|
|
574
|
+
// v2.1 ⑤ cite-redesign (P5): recall-based cite-accounting hook config. The
|
|
575
|
+
// rc.34 cite_evict_interval turn-counter above is superseded by the
|
|
576
|
+
// PreToolUse(Edit/Write) recall-aware nudge in cite-policy-evict.cjs; the old
|
|
577
|
+
// key is retained for back-compat (inert now that the hook moved off
|
|
578
|
+
// UserPromptSubmit). `cite_recall_nudge` is the master switch (default true =
|
|
579
|
+
// ON); set false to silence the "改前先 fab_recall" nudge entirely (mirrors
|
|
580
|
+
// the cite_evict_interval=0 opt-out convention). `cite_recall_window_minutes`
|
|
581
|
+
// bounds how far back an in-session fab_recall counts as "informing" the edit
|
|
582
|
+
// (default 30; 0 = unbounded).
|
|
583
|
+
cite_recall_nudge: z5.boolean().optional().default(true),
|
|
584
|
+
cite_recall_window_minutes: z5.number().int().min(0).optional().default(30),
|
|
585
|
+
// F2: glob exemptions for the cite nudge (cite-policy-evict.cjs). Edit paths
|
|
586
|
+
// matching any glob skip the "改前先 fab_recall" nudge — meta/orchestration
|
|
587
|
+
// files (e.g. `.workflow/` scratchpads) are not source the cite policy
|
|
588
|
+
// governs. MERGED with the hook's built-in [".workflow/**"] default; an
|
|
589
|
+
// omitted/empty value keeps just that default. `*` = within a path segment,
|
|
590
|
+
// `**` = across segments.
|
|
591
|
+
cite_nudge_ignore_globs: z5.array(z5.string()).optional(),
|
|
592
|
+
// v2.1 ④ conflict-detection (P4): bm25 content-similarity threshold (0..1)
|
|
593
|
+
// for the knowledge-conflict lint (`fabric doctor --lint-conflicts`). A
|
|
594
|
+
// same-(type,layer) pair whose normalized bm25 similarity reaches this floor
|
|
595
|
+
// is surfaced as a candidate (possible duplicate OR conflict). Conservative
|
|
596
|
+
// default 0.5 — raise to reduce noise, lower to catch looser pairs.
|
|
597
|
+
conflict_lint_similarity_threshold: z5.number().min(0).max(1).optional().default(0.5),
|
|
595
598
|
// v2.0.0-rc.22 Scope A T3: sliding-window retention (in days) for the
|
|
596
599
|
// event ledger rotation primitive (`rotateEventLedgerIfNeeded`). Lines
|
|
597
600
|
// whose `ts` is older than `now - fabric_event_retention_days * 86_400_000`
|
|
@@ -604,7 +607,7 @@ var fabricConfigSchema = z6.object({
|
|
|
604
607
|
// Mirrors cite-policy precedent of locking enum-style numeric tunables
|
|
605
608
|
// to a small literal set (vs free `.positive()`) to prevent fat-finger
|
|
606
609
|
// misconfig.
|
|
607
|
-
fabric_event_retention_days:
|
|
610
|
+
fabric_event_retention_days: z5.union([z5.literal(7), z5.literal(30), z5.literal(90)]).optional(),
|
|
608
611
|
// v2.0.0-rc.23 TASK-014 (F8c): onboard slot opt-out list. Tracks slot
|
|
609
612
|
// names the user explicitly dismissed during fabric-archive's first-run
|
|
610
613
|
// onboard phase (or via `fabric config dismiss-slot <slot>`). Dismissed
|
|
@@ -621,7 +624,7 @@ var fabricConfigSchema = z6.object({
|
|
|
621
624
|
//
|
|
622
625
|
// Default `[]` keeps the field optional on existing configs — fresh
|
|
623
626
|
// installs land with no opt-outs.
|
|
624
|
-
onboard_slots_opted_out:
|
|
627
|
+
onboard_slots_opted_out: z5.array(z5.string()).optional().default([]),
|
|
625
628
|
// v2.0.0-rc.33 W2-1 (P0-9): TopK upper bound for the broad SessionStart hint
|
|
626
629
|
// banner emitted by knowledge-hint-broad.cjs. After plan-context-hint returns
|
|
627
630
|
// its full broad-scoped index, the hook slices the entries to this many
|
|
@@ -633,20 +636,45 @@ var fabricConfigSchema = z6.object({
|
|
|
633
636
|
// Range 1..50; values above 20 effectively disable the cap because the
|
|
634
637
|
// TRUNCATION_THRESHOLD=12 grouped-render kicks in. Mirrors the rc.7 T7 +
|
|
635
638
|
// archive_max_* pattern of externalizing previously-hardcoded thresholds.
|
|
636
|
-
hint_broad_top_k:
|
|
639
|
+
hint_broad_top_k: z5.number().int().min(1).max(50).optional().default(8),
|
|
640
|
+
// KT-DEC-0036: the SessionStart broad-menu is now index-only (title + summary
|
|
641
|
+
// per always-active entry, no eager body), so the former `hint_broad_budget_chars`
|
|
642
|
+
// body char-budget knob was retired — there is no rendered body left to bound.
|
|
643
|
+
// W4-1 (KT-DEC-0028 / KT-MOD-0001): scale backstop for the FULL broad index.
|
|
644
|
+
// After W2-1 retired the hint_broad_top_k hard cap, the broad banner shows
|
|
645
|
+
// every broad entry (completeness); this is the only guard — once a store's
|
|
646
|
+
// rendered broad index exceeds this many lines the overflow tail folds into a
|
|
647
|
+
// single drift marker. The doctor `broad-index-drift` lint (W4-2) warns at 80%
|
|
648
|
+
// of this value per store so the corpus can be pruned (fabric-audit) BEFORE the
|
|
649
|
+
// banner silently truncates. Default 50; range 20..500 (read inline by
|
|
650
|
+
// knowledge-hint-broad.cjs#readBroadIndexBackstop with the same bounds).
|
|
651
|
+
broad_index_backstop: z5.number().int().min(20).max(500).optional().default(50),
|
|
637
652
|
// v2.0.0-rc.37 NEW-16: durable per-signal dismiss for the fabric-hint Stop
|
|
638
653
|
// hook nudges. Any signal type listed here is suppressed at emit time across
|
|
639
654
|
// all sessions (the session-scoped sibling lives in a .fabric/.cache sidecar
|
|
640
655
|
// written on request). Mirrors the cite_evict_interval=0 opt-out convention —
|
|
641
656
|
// a knob for an existing surface, not a new feature. Unknown types ignored.
|
|
642
|
-
hint_dismiss_signals:
|
|
657
|
+
hint_dismiss_signals: z5.array(z5.enum(["archive", "review", "import", "maintenance"])).optional(),
|
|
658
|
+
// v2.1 ADJ-NEWN-4: user-override escape hatches for the two strong behavioral
|
|
659
|
+
// policies (cite-before-edit + self-archive). The strong policies can make an
|
|
660
|
+
// agent feel like a "stubborn parrot" (D2 user-in-control red line); these
|
|
661
|
+
// flags let a user durably turn either off via fabric-config.json (or the
|
|
662
|
+
// `fabric config` panel) without editing bootstrap/AGENTS.md. Default true
|
|
663
|
+
// preserves rc.x behavior (policies ON); set false to opt a project out.
|
|
664
|
+
// The bootstrap behavior layer references these so the AGENTS.md rules degrade
|
|
665
|
+
// from "MUST" to "optional" when disabled — a config knob for an existing
|
|
666
|
+
// surface, mirroring the cite_evict_interval=0 / hint_dismiss_signals opt-out
|
|
667
|
+
// convention, NOT a new feature. Wave3 J32 will quantify the friction these
|
|
668
|
+
// relieve; until then they ship as inert-safe opt-outs.
|
|
669
|
+
cite_policy_enabled: z5.boolean().optional().default(true),
|
|
670
|
+
self_archive_policy_enabled: z5.boolean().optional().default(true),
|
|
643
671
|
// v2.0.0-rc.33 W2-1 (P0-9): TopK upper bound for the narrow PreToolUse hint
|
|
644
672
|
// emitted by knowledge-hint-narrow.cjs. After filtering to entries whose
|
|
645
673
|
// `relevance_scope === "narrow"` (rc.27 TASK-005 audit §2.5 fix), the hook
|
|
646
674
|
// slices to this many before the E3 emit-gate / renderSummary pipeline.
|
|
647
675
|
// Default 5 keeps each per-Edit hint terse — five lines max so the agent's
|
|
648
676
|
// working memory is not displaced by an unwieldy banner. Range 1..20.
|
|
649
|
-
hint_narrow_top_k:
|
|
677
|
+
hint_narrow_top_k: z5.number().int().min(1).max(20).optional().default(5),
|
|
650
678
|
// v2.0.0-rc.33 W2-1 (P0-9): per-file dedup window (in PreToolUse turns) for
|
|
651
679
|
// the narrow hint. Same (file_path, stable_id) tuple stays silent for this
|
|
652
680
|
// many turns even when the E3 cross-session cache would otherwise re-emit.
|
|
@@ -656,7 +684,7 @@ var fabricConfigSchema = z6.object({
|
|
|
656
684
|
// Storage: .fabric/.cache/narrow-dedup-window.json — distinct from session-
|
|
657
685
|
// hints cache so a window-only suppression does not poison cross-session
|
|
658
686
|
// dedupe semantics.
|
|
659
|
-
hint_narrow_dedup_window_turns:
|
|
687
|
+
hint_narrow_dedup_window_turns: z5.number().int().min(1).max(50).optional().default(5),
|
|
660
688
|
// v2.0.0-rc.33 W2-5 (P1-8): cooldown between broad SessionStart hint emits,
|
|
661
689
|
// in hours. Distinct from the archive_hint_cooldown_hours that gates the
|
|
662
690
|
// fabric-hint Stop hook — knowledge-hint-broad re-fires on every
|
|
@@ -665,29 +693,34 @@ var fabricConfigSchema = z6.object({
|
|
|
665
693
|
// menu at most once per hour"; 0 means "no cooldown, current behavior."
|
|
666
694
|
// Range 0..168 (one week). Stored alongside fabric-hint's cooldown cache
|
|
667
695
|
// under a distinct knowledge-hint-broad key.
|
|
668
|
-
hint_broad_cooldown_hours:
|
|
696
|
+
hint_broad_cooldown_hours: z5.number().int().min(0).max(168).optional().default(0),
|
|
669
697
|
// v2.0.0-rc.33 W2-5 (P1-8): cooldown for the narrow PreToolUse hint.
|
|
670
698
|
// Same shape as hint_broad_cooldown_hours but applies to per-Edit hint
|
|
671
699
|
// re-emission across the cooldown window — independent of E3 session-
|
|
672
700
|
// hints dedupe. Default 0 preserves rc.32 behavior; set to e.g. 1 to
|
|
673
701
|
// throttle hint frequency during rapid-fire editing sprints. Range
|
|
674
702
|
// 0..168 (one week).
|
|
675
|
-
hint_narrow_cooldown_hours:
|
|
703
|
+
hint_narrow_cooldown_hours: z5.number().int().min(0).max(168).optional().default(0),
|
|
676
704
|
// v2.0.0-rc.33 W4-B3 (T5 P2): per-maturity inactivity thresholds (days)
|
|
677
|
-
// driving orphan_demote. Hardcoded at
|
|
705
|
+
// driving orphan_demote. Hardcoded at proven=90/verified=30/draft=14 in
|
|
678
706
|
// rc.32; chatty workspaces want them tighter, slow ones want them looser.
|
|
679
707
|
// Each field optional; absent → defaults inside doctor.ts apply. Ranges
|
|
680
708
|
// chosen so a typo can't accidentally disable the lint (min 1).
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
709
|
+
//
|
|
710
|
+
// v2.2 W3-T5 (F-MATURITY-ENDORSED): the canonical maturity enum is
|
|
711
|
+
// draft/verified/proven (KT-DEC-0005). These threshold keys use the canonical
|
|
712
|
+
// vocabulary; the loader maps proven→stable / verified→endorsed onto the
|
|
713
|
+
// doctor's internal orphan_demote ladder.
|
|
714
|
+
orphan_demote_proven_days: z5.number().int().min(1).max(3650).optional(),
|
|
715
|
+
orphan_demote_verified_days: z5.number().int().min(1).max(3650).optional(),
|
|
716
|
+
orphan_demote_draft_days: z5.number().int().min(1).max(3650).optional(),
|
|
684
717
|
// v2.0.0-rc.33 W4-A3 (T4 P2): per-entry summary truncation length used by
|
|
685
718
|
// knowledge-hint-{broad,narrow}.cjs. Hard-coded at 80 chars in rc.32 — too
|
|
686
719
|
// short for entries with parameterized summaries (e.g. "Use bcrypt with
|
|
687
720
|
// cost=12 for password hashing"), too long for terse pitfalls. Range 40..240;
|
|
688
721
|
// default 80 preserves rc.32 behavior. Both hooks read the same key so the
|
|
689
722
|
// banner styling stays consistent across SessionStart + PreToolUse.
|
|
690
|
-
hint_summary_max_len:
|
|
723
|
+
hint_summary_max_len: z5.number().int().min(40).max(240).optional().default(80),
|
|
691
724
|
// v2.0.0-rc.33 W2-6 (P0-7 + P0-8): when true, knowledge-hint hooks emit
|
|
692
725
|
// their banners as `hookSpecificOutput.additionalContext` JSON on stdout
|
|
693
726
|
// (per Claude Code PreToolUse hook contract — see
|
|
@@ -697,7 +730,7 @@ var fabricConfigSchema = z6.object({
|
|
|
697
730
|
// coverage focus (rc.32 baseline 3.1% → primary cause: reminders never
|
|
698
731
|
// entered model context). Set false to revert to legacy stderr-only mode
|
|
699
732
|
// for hosts that don't honor the JSON contract.
|
|
700
|
-
hint_reminder_to_context:
|
|
733
|
+
hint_reminder_to_context: z5.boolean().optional().default(true),
|
|
701
734
|
// v2.0.0-rc.29 TASK-008 (BUG-F3): selection-token TTL override. The
|
|
702
735
|
// `fab_plan_context` MCP tool hands clients a `selection_token` whose default
|
|
703
736
|
// 5-minute lifetime (`SELECTION_TOKEN_TTL_MS` at
|
|
@@ -713,12 +746,56 @@ var fabricConfigSchema = z6.object({
|
|
|
713
746
|
// so the server-side per-field reader can validate without re-running the
|
|
714
747
|
// whole fabricConfigSchema on every plan_context call — that lets a corrupt
|
|
715
748
|
// unrelated field stay isolated from the hot read path.
|
|
716
|
-
selection_token_ttl_ms: selectionTokenTtlMsSchema.optional()
|
|
749
|
+
selection_token_ttl_ms: selectionTokenTtlMsSchema.optional(),
|
|
750
|
+
// v2.2 A-INFRA-3 (W1-T3-TOPK): bound on `fab_plan_context` candidate count,
|
|
751
|
+
// applied after BM25 ranking. Absent → library default (24). See
|
|
752
|
+
// planContextTopKSchema for the range/calibration rationale.
|
|
753
|
+
plan_context_top_k: planContextTopKSchema.optional(),
|
|
754
|
+
// KT-DEC-0038: ratio-to-top relevance floor (α) for recall / plan_context.
|
|
755
|
+
// After ranking, keep only candidates whose fused score >= α × the top
|
|
756
|
+
// candidate's score — self-normalizing against the current query's max, so it
|
|
757
|
+
// is immune to BM25's uncalibrated cross-query scale. top_k is a pure safety
|
|
758
|
+
// cap above this. Range 0..1; absent → library default (0.25). 0 disables the
|
|
759
|
+
// floor (keep all up to top_k).
|
|
760
|
+
recall_relevance_ratio: z5.number().min(0).max(1).optional(),
|
|
761
|
+
// KT-DEC-0037: the `retrieval_budget_profile` enum was deleted. top_k is the
|
|
762
|
+
// sole retrieval knob (plan_context_top_k above); payload limits pass through
|
|
763
|
+
// explicit `mcpPayloadLimits`, else the fixed PAYLOAD_LIMIT_DEFAULT_* guardrail.
|
|
764
|
+
// v2.2 C2-vector (W2-T7): OPTIONAL dense-embedding semantic retrieval, layered
|
|
765
|
+
// as a recall supplement after BM25. Default OFF (`--no-embed` is the baseline);
|
|
766
|
+
// requires the operator to install the optional `fastembed` package — absent →
|
|
767
|
+
// text-only fallback. Never grows the default install footprint.
|
|
768
|
+
embed_enabled: z5.boolean().optional().default(false),
|
|
769
|
+
// Weight applied to the 0..1 cosine similarity before it joins the additive
|
|
770
|
+
// score. Capped at 49 — strictly BELOW BM25_WEIGHT (50) — so a perfect vector
|
|
771
|
+
// match (weight × 1) can never outscore a single strong BM25 term match. This
|
|
772
|
+
// ENFORCES the "vectors supplement, never override lexical relevance"
|
|
773
|
+
// invariant in the schema rather than leaving it to a comment (W2-REVIEW codex
|
|
774
|
+
// MED-4). Range 0..49; default 30.
|
|
775
|
+
embed_weight: z5.number().int().min(0).max(49).optional().default(30),
|
|
776
|
+
// v2.1 ③ vector-chinese-model (P3): which fastembed model to load. The prior
|
|
777
|
+
// code pinned fastembed's English default (bge-small-en-v1.5) — wrong for the
|
|
778
|
+
// Chinese-heavy zh-CN-hybrid KB. Values are the fastembed@2.x EmbeddingModel
|
|
779
|
+
// enum strings. Default `fast-bge-small-zh-v1.5` (BGESmallZH): light, fast,
|
|
780
|
+
// Chinese-capable (bm25 already covers English/code tokens; the vector term
|
|
781
|
+
// supplements Chinese semantics). `fast-multilingual-e5-large` (MLE5Large) is
|
|
782
|
+
// available for full multilingual recall at a ~1GB download + slower CPU cost.
|
|
783
|
+
// (V1 research: fastembed@2.1.0 has NO multilingual-e5-SMALL — the originally
|
|
784
|
+
// planned pin — so bge-small-zh is the light Chinese choice.)
|
|
785
|
+
embed_model: z5.enum([
|
|
786
|
+
"fast-bge-small-zh-v1.5",
|
|
787
|
+
"fast-multilingual-e5-large",
|
|
788
|
+
"fast-bge-small-en-v1.5",
|
|
789
|
+
"fast-bge-small-en",
|
|
790
|
+
"fast-bge-base-en-v1.5",
|
|
791
|
+
"fast-bge-base-en",
|
|
792
|
+
"fast-all-MiniLM-L6-v2"
|
|
793
|
+
]).optional().default("fast-bge-small-zh-v1.5")
|
|
717
794
|
});
|
|
718
795
|
|
|
719
796
|
// src/schemas/fabric-config-introspect.ts
|
|
720
|
-
import { z as
|
|
721
|
-
var positiveIntSchema =
|
|
797
|
+
import { z as z6 } from "zod";
|
|
798
|
+
var positiveIntSchema = z6.coerce.number().int().positive();
|
|
722
799
|
function makePositiveIntField(key, defaultValue) {
|
|
723
800
|
return {
|
|
724
801
|
key,
|
|
@@ -774,6 +851,28 @@ function makeEnumField(key, group, enumValues, defaultValue) {
|
|
|
774
851
|
}
|
|
775
852
|
};
|
|
776
853
|
}
|
|
854
|
+
function makeBooleanField(key, defaultValue) {
|
|
855
|
+
return {
|
|
856
|
+
key,
|
|
857
|
+
group: "D_behavior",
|
|
858
|
+
widget: "select",
|
|
859
|
+
label_i18n_key: `cli.config.fields.${key}.label`,
|
|
860
|
+
description_i18n_key: `cli.config.fields.${key}.description`,
|
|
861
|
+
default: String(defaultValue),
|
|
862
|
+
enum_values: ["true", "false"],
|
|
863
|
+
validate(raw) {
|
|
864
|
+
const trimmed = raw.trim();
|
|
865
|
+
if (trimmed === "true") return { ok: true, value: true };
|
|
866
|
+
if (trimmed === "false") return { ok: true, value: false };
|
|
867
|
+
return { ok: false, error: "Must be one of: true, false." };
|
|
868
|
+
},
|
|
869
|
+
format_for_display(value) {
|
|
870
|
+
if (typeof value === "boolean") return String(value);
|
|
871
|
+
if (value === void 0 || value === null) return String(defaultValue);
|
|
872
|
+
return String(value);
|
|
873
|
+
}
|
|
874
|
+
};
|
|
875
|
+
}
|
|
777
876
|
var SCHEMA_DEFAULTS = fabricConfigSchema.parse({});
|
|
778
877
|
function pickNumberDefault(key) {
|
|
779
878
|
const v = SCHEMA_DEFAULTS[key];
|
|
@@ -802,12 +901,13 @@ function getPanelFieldByKey(key) {
|
|
|
802
901
|
}
|
|
803
902
|
var PANEL_FIELDS = [
|
|
804
903
|
// --- Group A: Locale (2) ---
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
904
|
+
// grill-6fixes (D1): `fabric_language` is no longer a project-config field —
|
|
905
|
+
// it is the single machine-wide tone in `~/.fabric/fabric-global.json`. The
|
|
906
|
+
// panel still surfaces it (the `fabric config` language entry), but config.ts
|
|
907
|
+
// special-cases this key to read/write the GLOBAL config instead of the
|
|
908
|
+
// project file. Default is a literal "en" since there is no project-schema
|
|
909
|
+
// default to derive from.
|
|
910
|
+
makeEnumField("fabric_language", "A_locale", fabricLanguageSchema.options, "en"),
|
|
811
911
|
makeEnumField(
|
|
812
912
|
"default_layer_filter",
|
|
813
913
|
"A_locale",
|
|
@@ -851,39 +951,23 @@ var PANEL_FIELDS = [
|
|
|
851
951
|
"C_audit",
|
|
852
952
|
auditModeSchema.options,
|
|
853
953
|
AUDIT_MODE_PANEL_DEFAULT
|
|
854
|
-
)
|
|
954
|
+
),
|
|
955
|
+
// --- Group D: Behavior / features (2) ---
|
|
956
|
+
// nudge_mode — the master switch for the human-visible nudge experience
|
|
957
|
+
// (the most user-facing runtime knob, previously JSON-only). embed_enabled —
|
|
958
|
+
// vector semantic recall, panel-editable now that config lives in `.fabric`
|
|
959
|
+
// (A1); enabling also needs the host-side `fabric install --enable-embed`.
|
|
960
|
+
makeEnumField("nudge_mode", "D_behavior", nudgeModeSchema.options, "normal"),
|
|
961
|
+
makeBooleanField("embed_enabled", false)
|
|
855
962
|
];
|
|
856
963
|
|
|
857
|
-
// src/schemas/scope.ts
|
|
858
|
-
import { z as z8 } from "zod";
|
|
859
|
-
var PERSONAL_SCOPE = "personal";
|
|
860
|
-
var KNOWN_SCOPE_PREFIXES = ["personal", "team", "project", "org"];
|
|
861
|
-
var SCOPE_COORDINATE_PATTERN = /^[a-z0-9_-]+(:[a-z0-9_-]+)*$/u;
|
|
862
|
-
var scopeCoordinateSchema = z8.string().min(1).regex(
|
|
863
|
-
SCOPE_COORDINATE_PATTERN,
|
|
864
|
-
"scope coordinate must be ':'-joined lowercase [a-z0-9_-] segments"
|
|
865
|
-
);
|
|
866
|
-
function scopeRoot(coordinate) {
|
|
867
|
-
const colon = coordinate.indexOf(":");
|
|
868
|
-
return colon === -1 ? coordinate : coordinate.slice(0, colon);
|
|
869
|
-
}
|
|
870
|
-
function isPersonalScope(coordinate) {
|
|
871
|
-
return scopeRoot(coordinate) === PERSONAL_SCOPE;
|
|
872
|
-
}
|
|
873
|
-
var entryScopeMetadataSchema = z8.object({
|
|
874
|
-
semantic_scope: scopeCoordinateSchema,
|
|
875
|
-
// Store alias or UUID. Validated as a non-empty string here; the resolver
|
|
876
|
-
// (P0.6) maps alias→UUID and verifies the store is in the read-set.
|
|
877
|
-
visibility_store: z8.string().min(1)
|
|
878
|
-
}).strict();
|
|
879
|
-
|
|
880
964
|
// src/schemas/store-stable-id.ts
|
|
881
|
-
import { z as
|
|
965
|
+
import { z as z7 } from "zod";
|
|
882
966
|
var localKnowledgeIdSchema = StableIdSchema;
|
|
883
967
|
var UID_SEGMENT_PATTERN = /^[a-z0-9-]+$/u;
|
|
884
|
-
var uidSchema =
|
|
968
|
+
var uidSchema = z7.string().min(1).regex(UID_SEGMENT_PATTERN, "uid must be lowercase [a-z0-9-] segments");
|
|
885
969
|
var GLOBAL_REF_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(:[a-z0-9-]+)?:K[PT]-(MOD|DEC|GLD|PIT|PRO)-\d{4,}$/u;
|
|
886
|
-
var globalRefSchema =
|
|
970
|
+
var globalRefSchema = z7.string().regex(GLOBAL_REF_PATTERN, "global_ref must be <store_uuid>[:<uid>]:<local_id>");
|
|
887
971
|
function formatGlobalRef(parts) {
|
|
888
972
|
const { store_uuid, uid, local_id } = parts;
|
|
889
973
|
return uid === void 0 ? `${store_uuid}:${local_id}` : `${store_uuid}:${uid}:${local_id}`;
|
|
@@ -908,14 +992,14 @@ function parseGlobalRef(ref) {
|
|
|
908
992
|
local_id
|
|
909
993
|
};
|
|
910
994
|
}
|
|
911
|
-
var storeKnowledgeTypeCountersSchema =
|
|
912
|
-
MOD:
|
|
913
|
-
DEC:
|
|
914
|
-
GLD:
|
|
915
|
-
PIT:
|
|
916
|
-
PRO:
|
|
995
|
+
var storeKnowledgeTypeCountersSchema = z7.object({
|
|
996
|
+
MOD: z7.number().int().nonnegative().default(0),
|
|
997
|
+
DEC: z7.number().int().nonnegative().default(0),
|
|
998
|
+
GLD: z7.number().int().nonnegative().default(0),
|
|
999
|
+
PIT: z7.number().int().nonnegative().default(0),
|
|
1000
|
+
PRO: z7.number().int().nonnegative().default(0)
|
|
917
1001
|
}).default({ MOD: 0, DEC: 0, GLD: 0, PIT: 0, PRO: 0 });
|
|
918
|
-
var storeCountersSchema =
|
|
1002
|
+
var storeCountersSchema = z7.object({
|
|
919
1003
|
KP: storeKnowledgeTypeCountersSchema,
|
|
920
1004
|
KT: storeKnowledgeTypeCountersSchema
|
|
921
1005
|
}).default({
|
|
@@ -924,64 +1008,63 @@ var storeCountersSchema = z9.object({
|
|
|
924
1008
|
});
|
|
925
1009
|
|
|
926
1010
|
// src/schemas/parity-matrix.ts
|
|
927
|
-
import { z as
|
|
928
|
-
var PARITY_CLIENTS = ["claudeCode", "codexCLI"
|
|
929
|
-
var parityClientSchema =
|
|
1011
|
+
import { z as z8 } from "zod";
|
|
1012
|
+
var PARITY_CLIENTS = ["claudeCode", "codexCLI"];
|
|
1013
|
+
var parityClientSchema = z8.enum(PARITY_CLIENTS);
|
|
930
1014
|
var PARITY_SURFACES = ["skill", "hook", "mcp", "render"];
|
|
931
|
-
var paritySurfaceSchema =
|
|
932
|
-
var parityClientExpectationSchema =
|
|
933
|
-
supported:
|
|
934
|
-
mechanism:
|
|
935
|
-
notes:
|
|
1015
|
+
var paritySurfaceSchema = z8.enum(PARITY_SURFACES);
|
|
1016
|
+
var parityClientExpectationSchema = z8.object({
|
|
1017
|
+
supported: z8.boolean(),
|
|
1018
|
+
mechanism: z8.string().optional(),
|
|
1019
|
+
notes: z8.string().optional()
|
|
936
1020
|
}).strict();
|
|
937
|
-
var parityCapabilitySchema =
|
|
938
|
-
id:
|
|
1021
|
+
var parityCapabilitySchema = z8.object({
|
|
1022
|
+
id: z8.string().min(1),
|
|
939
1023
|
surface: paritySurfaceSchema,
|
|
940
|
-
description:
|
|
941
|
-
clients:
|
|
1024
|
+
description: z8.string().min(1),
|
|
1025
|
+
clients: z8.object({
|
|
942
1026
|
claudeCode: parityClientExpectationSchema,
|
|
943
|
-
codexCLI: parityClientExpectationSchema
|
|
944
|
-
cursor: parityClientExpectationSchema
|
|
1027
|
+
codexCLI: parityClientExpectationSchema
|
|
945
1028
|
}).strict()
|
|
946
1029
|
}).strict();
|
|
947
|
-
var parityMatrixSchema =
|
|
1030
|
+
var parityMatrixSchema = z8.object({
|
|
948
1031
|
// Schema/version tag of the matrix document itself.
|
|
949
|
-
version:
|
|
1032
|
+
version: z8.string().min(1),
|
|
950
1033
|
// Free-form note on what release/milestone this matrix targets.
|
|
951
|
-
generated_for:
|
|
952
|
-
capabilities:
|
|
1034
|
+
generated_for: z8.string().min(1),
|
|
1035
|
+
capabilities: z8.array(parityCapabilitySchema).min(1)
|
|
953
1036
|
}).strict();
|
|
954
1037
|
|
|
955
1038
|
// src/resolver/contracts.ts
|
|
956
|
-
import { z as
|
|
1039
|
+
import { z as z9 } from "zod";
|
|
957
1040
|
var PROJECT_ROOT_SIGNALS = ["env", "marker", "cwd", "repo"];
|
|
958
|
-
var projectRootSignalSchema =
|
|
959
|
-
var projectRootSignalsSchema =
|
|
1041
|
+
var projectRootSignalSchema = z9.enum(PROJECT_ROOT_SIGNALS);
|
|
1042
|
+
var projectRootSignalsSchema = z9.object({
|
|
960
1043
|
// FABRIC_PROJECT_ROOT, if set.
|
|
961
|
-
env:
|
|
1044
|
+
env: z9.string().optional(),
|
|
962
1045
|
// Nearest directory AT-OR-ABOVE cwd holding `.fabric/fabric-config.json`,
|
|
963
1046
|
// if any (the upward marker search result; may equal cwd).
|
|
964
|
-
markerDir:
|
|
1047
|
+
markerDir: z9.string().optional(),
|
|
965
1048
|
// Always present — the process cwd.
|
|
966
|
-
cwd:
|
|
1049
|
+
cwd: z9.string().min(1),
|
|
967
1050
|
// git repo root, if inside a repo.
|
|
968
|
-
repoRoot:
|
|
1051
|
+
repoRoot: z9.string().optional(),
|
|
969
1052
|
// The `project_id` read from the winning root's fabric-config.json during
|
|
970
1053
|
// (fs) signal collection. The pure resolver echoes it — it cannot invent a
|
|
971
1054
|
// UUID. Worktrees of one repo share the committed config, hence the same
|
|
972
1055
|
// project_id (S45 merge). Absent when no .fabric config exists at the root
|
|
973
1056
|
// yet (fresh repo-fallback) → resolution still yields the root with a null
|
|
974
1057
|
// projectId so the caller can mint+persist one at install time.
|
|
975
|
-
discoveredProjectId:
|
|
1058
|
+
discoveredProjectId: z9.string().optional()
|
|
976
1059
|
}).strict();
|
|
977
|
-
var projectRootResolutionSchema =
|
|
1060
|
+
var projectRootResolutionSchema = z9.object({
|
|
978
1061
|
// Absolute project root directory.
|
|
979
|
-
projectRoot:
|
|
1062
|
+
projectRoot: z9.string().min(1),
|
|
980
1063
|
// Stable project identity. One repo = one .fabric = one project_id (S32);
|
|
981
1064
|
// git worktrees of the same repo resolve to the SAME project_id (S45).
|
|
982
1065
|
// Null when the resolved root has no fabric-config.json yet (fresh
|
|
983
1066
|
// repo-fallback) — the caller mints + persists a UUID at install time.
|
|
984
|
-
projectId:
|
|
1067
|
+
projectId: z9.string().min(1).nullable(),
|
|
985
1068
|
// Which signal won.
|
|
986
1069
|
signalUsed: projectRootSignalSchema
|
|
987
1070
|
}).strict();
|
|
@@ -990,91 +1073,96 @@ var STORE_RESOLVER_WARNING_CODES = [
|
|
|
990
1073
|
// required_stores entry has no matching mounted store (S51)
|
|
991
1074
|
"local_only_no_remote",
|
|
992
1075
|
// mounted but local-only (R5#5 nudge, non-fatal)
|
|
993
|
-
"alias_unresolved"
|
|
1076
|
+
"alias_unresolved",
|
|
994
1077
|
// referenced alias maps to no mounted store
|
|
1078
|
+
"missing_write_route"
|
|
1079
|
+
// multi/shared write requires an explicit route
|
|
995
1080
|
];
|
|
996
|
-
var storeResolverWarningCodeSchema =
|
|
997
|
-
var storeResolverWarningSchema =
|
|
1081
|
+
var storeResolverWarningCodeSchema = z9.enum(STORE_RESOLVER_WARNING_CODES);
|
|
1082
|
+
var storeResolverWarningSchema = z9.object({
|
|
998
1083
|
code: storeResolverWarningCodeSchema,
|
|
999
1084
|
// The alias/UUID/id the warning concerns.
|
|
1000
|
-
ref:
|
|
1001
|
-
message:
|
|
1085
|
+
ref: z9.string().min(1),
|
|
1086
|
+
message: z9.string().min(1)
|
|
1002
1087
|
}).strict();
|
|
1003
|
-
var readSetEntrySchema =
|
|
1004
|
-
store_uuid:
|
|
1005
|
-
alias:
|
|
1006
|
-
remote:
|
|
1088
|
+
var readSetEntrySchema = z9.object({
|
|
1089
|
+
store_uuid: z9.string().min(1),
|
|
1090
|
+
alias: z9.string().min(1),
|
|
1091
|
+
remote: z9.string().min(1).optional(),
|
|
1007
1092
|
// Whether this store accepts writes from the current context. Personal
|
|
1008
1093
|
// store is writable; shared stores writable iff mounted with write intent.
|
|
1009
|
-
writable:
|
|
1094
|
+
writable: z9.boolean()
|
|
1010
1095
|
}).strict();
|
|
1011
|
-
var storeReadSetSchema =
|
|
1012
|
-
stores:
|
|
1013
|
-
warnings:
|
|
1096
|
+
var storeReadSetSchema = z9.object({
|
|
1097
|
+
stores: z9.array(readSetEntrySchema),
|
|
1098
|
+
warnings: z9.array(storeResolverWarningSchema)
|
|
1014
1099
|
}).strict();
|
|
1015
|
-
var writeTargetSchema =
|
|
1016
|
-
store_uuid:
|
|
1017
|
-
alias:
|
|
1100
|
+
var writeTargetSchema = z9.object({
|
|
1101
|
+
store_uuid: z9.string().min(1),
|
|
1102
|
+
alias: z9.string().min(1)
|
|
1018
1103
|
}).strict();
|
|
1019
|
-
var storeResolveInputSchema =
|
|
1104
|
+
var storeResolveInputSchema = z9.object({
|
|
1020
1105
|
// Machine identity (S33) — namespaces personal ids; identifies personal store.
|
|
1021
|
-
uid:
|
|
1106
|
+
uid: z9.string().min(1),
|
|
1022
1107
|
// Stores mounted on this machine (from global config).
|
|
1023
|
-
mountedStores:
|
|
1024
|
-
|
|
1025
|
-
store_uuid:
|
|
1026
|
-
alias:
|
|
1027
|
-
|
|
1028
|
-
|
|
1108
|
+
mountedStores: z9.array(
|
|
1109
|
+
z9.object({
|
|
1110
|
+
store_uuid: z9.string().min(1),
|
|
1111
|
+
alias: z9.string().min(1),
|
|
1112
|
+
mount_name: z9.string().min(1).optional(),
|
|
1113
|
+
remote: z9.string().min(1).optional(),
|
|
1114
|
+
writable: z9.boolean().default(true),
|
|
1029
1115
|
// Marks the implicit personal store.
|
|
1030
|
-
personal:
|
|
1116
|
+
personal: z9.boolean().default(false)
|
|
1031
1117
|
}).strict()
|
|
1032
1118
|
),
|
|
1033
1119
|
// The project's declared required_stores (ids/aliases + optional remote).
|
|
1034
|
-
requiredStores:
|
|
1035
|
-
|
|
1036
|
-
id:
|
|
1037
|
-
suggested_remote:
|
|
1120
|
+
requiredStores: z9.array(
|
|
1121
|
+
z9.object({
|
|
1122
|
+
id: z9.string().min(1),
|
|
1123
|
+
suggested_remote: z9.string().min(1).optional()
|
|
1038
1124
|
}).strict()
|
|
1039
1125
|
),
|
|
1040
1126
|
// Alias selected as the active write store for non-personal scopes, if any.
|
|
1041
|
-
activeWriteAlias:
|
|
1127
|
+
activeWriteAlias: z9.string().min(1).optional(),
|
|
1128
|
+
// Scope-aware write routes. Exact scope wins first, then longest prefix route.
|
|
1129
|
+
writeRoutes: z9.array(
|
|
1130
|
+
z9.object({
|
|
1131
|
+
scope: z9.string().min(1),
|
|
1132
|
+
store: z9.string().min(1)
|
|
1133
|
+
}).strict()
|
|
1134
|
+
).optional().default([]),
|
|
1135
|
+
defaultWriteAlias: z9.string().min(1).optional()
|
|
1042
1136
|
}).strict();
|
|
1043
|
-
var projectRootGoldenCaseSchema =
|
|
1044
|
-
name:
|
|
1045
|
-
note:
|
|
1137
|
+
var projectRootGoldenCaseSchema = z9.object({
|
|
1138
|
+
name: z9.string().min(1),
|
|
1139
|
+
note: z9.string().optional(),
|
|
1046
1140
|
signals: projectRootSignalsSchema,
|
|
1047
1141
|
// null expected = resolver should return no root for these signals.
|
|
1048
1142
|
expected: projectRootResolutionSchema.nullable()
|
|
1049
1143
|
}).strict();
|
|
1050
|
-
var projectRootGoldenFileSchema =
|
|
1051
|
-
contract:
|
|
1052
|
-
cases:
|
|
1144
|
+
var projectRootGoldenFileSchema = z9.object({
|
|
1145
|
+
contract: z9.literal("project-root.golden"),
|
|
1146
|
+
cases: z9.array(projectRootGoldenCaseSchema).min(1)
|
|
1053
1147
|
}).strict();
|
|
1054
|
-
var readSetGoldenCaseSchema =
|
|
1055
|
-
name:
|
|
1056
|
-
note:
|
|
1148
|
+
var readSetGoldenCaseSchema = z9.object({
|
|
1149
|
+
name: z9.string().min(1),
|
|
1150
|
+
note: z9.string().optional(),
|
|
1057
1151
|
input: storeResolveInputSchema,
|
|
1058
1152
|
// Scope under test for the write-target expectation.
|
|
1059
|
-
writeScope:
|
|
1060
|
-
expected:
|
|
1153
|
+
writeScope: z9.string().min(1),
|
|
1154
|
+
expected: z9.object({
|
|
1061
1155
|
readSet: storeReadSetSchema,
|
|
1062
1156
|
writeTarget: writeTargetSchema.nullable(),
|
|
1063
|
-
writeWarnings:
|
|
1157
|
+
writeWarnings: z9.array(storeResolverWarningSchema)
|
|
1064
1158
|
}).strict()
|
|
1065
1159
|
}).strict();
|
|
1066
|
-
var readSetGoldenFileSchema =
|
|
1067
|
-
contract:
|
|
1068
|
-
cases:
|
|
1160
|
+
var readSetGoldenFileSchema = z9.object({
|
|
1161
|
+
contract: z9.literal("read-set.golden"),
|
|
1162
|
+
cases: z9.array(readSetGoldenCaseSchema).min(1)
|
|
1069
1163
|
}).strict();
|
|
1070
1164
|
|
|
1071
1165
|
// src/resolver/project-root-resolver.ts
|
|
1072
|
-
var ResolverNotImplementedError = class extends Error {
|
|
1073
|
-
constructor(what) {
|
|
1074
|
-
super(`${what} is not implemented yet (TDD target)`);
|
|
1075
|
-
this.name = "ResolverNotImplementedError";
|
|
1076
|
-
}
|
|
1077
|
-
};
|
|
1078
1166
|
function createProjectRootResolver() {
|
|
1079
1167
|
return {
|
|
1080
1168
|
resolve(signals) {
|
|
@@ -1112,12 +1200,65 @@ function personalEntry(input) {
|
|
|
1112
1200
|
}
|
|
1113
1201
|
return entry;
|
|
1114
1202
|
}
|
|
1203
|
+
function readSetEntryFromMounted(store) {
|
|
1204
|
+
const entry = {
|
|
1205
|
+
store_uuid: store.store_uuid,
|
|
1206
|
+
alias: store.alias,
|
|
1207
|
+
writable: store.writable
|
|
1208
|
+
};
|
|
1209
|
+
if (store.remote !== void 0) {
|
|
1210
|
+
entry.remote = store.remote;
|
|
1211
|
+
return { entry };
|
|
1212
|
+
}
|
|
1213
|
+
return {
|
|
1214
|
+
entry,
|
|
1215
|
+
warning: {
|
|
1216
|
+
code: "local_only_no_remote",
|
|
1217
|
+
ref: store.alias,
|
|
1218
|
+
message: `store '${store.alias}' is local-only; add a git remote to back it up (\`fabric store ... \` / doctor nudge)`
|
|
1219
|
+
}
|
|
1220
|
+
};
|
|
1221
|
+
}
|
|
1222
|
+
function isMountedPersonal(input, storeUuid) {
|
|
1223
|
+
return input.mountedStores.some((store) => store.store_uuid === storeUuid && store.personal);
|
|
1224
|
+
}
|
|
1225
|
+
function routeMatches(routeScope, scope) {
|
|
1226
|
+
return scope === routeScope || scope.startsWith(`${routeScope}:`);
|
|
1227
|
+
}
|
|
1228
|
+
function resolveRouteAlias(input, scope) {
|
|
1229
|
+
const routes = input.writeRoutes ?? [];
|
|
1230
|
+
const exact = routes.find((route) => route.scope === scope);
|
|
1231
|
+
if (exact !== void 0) {
|
|
1232
|
+
return exact.store;
|
|
1233
|
+
}
|
|
1234
|
+
const prefix = routes.filter((route) => routeMatches(route.scope, scope)).sort((a, b) => b.scope.length - a.scope.length)[0];
|
|
1235
|
+
return prefix?.store ?? input.defaultWriteAlias ?? input.activeWriteAlias;
|
|
1236
|
+
}
|
|
1237
|
+
function hasMultipleSharedStores(input, readSet) {
|
|
1238
|
+
return readSet.stores.filter((store) => !isMountedPersonal(input, store.store_uuid)).length > 1;
|
|
1239
|
+
}
|
|
1240
|
+
function hasExplicitRouteOrDefault(input, scope) {
|
|
1241
|
+
const routes = input.writeRoutes ?? [];
|
|
1242
|
+
return routes.some((route) => routeMatches(route.scope, scope)) || input.defaultWriteAlias !== void 0;
|
|
1243
|
+
}
|
|
1115
1244
|
function createStoreResolver() {
|
|
1116
1245
|
return {
|
|
1117
1246
|
resolveReadSet(input) {
|
|
1118
1247
|
const stores = [];
|
|
1119
1248
|
const warnings = [];
|
|
1249
|
+
const seenStoreUuids = /* @__PURE__ */ new Set();
|
|
1120
1250
|
for (const req of input.requiredStores) {
|
|
1251
|
+
if (req.suggested_remote === "$personal") {
|
|
1252
|
+
const personal2 = findPersonal(input);
|
|
1253
|
+
if (personal2 === void 0) {
|
|
1254
|
+
warnings.push({
|
|
1255
|
+
code: "missing_store",
|
|
1256
|
+
ref: req.id,
|
|
1257
|
+
message: `required store '${req.id}' is not mounted; run \`fabric store add\` (suggested remote: $personal)`
|
|
1258
|
+
});
|
|
1259
|
+
}
|
|
1260
|
+
continue;
|
|
1261
|
+
}
|
|
1121
1262
|
const matched = input.mountedStores.find(
|
|
1122
1263
|
(m) => !m.personal && (m.alias === req.id || m.store_uuid === req.id)
|
|
1123
1264
|
);
|
|
@@ -1130,25 +1271,20 @@ function createStoreResolver() {
|
|
|
1130
1271
|
});
|
|
1131
1272
|
continue;
|
|
1132
1273
|
}
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
entry.remote = matched.remote;
|
|
1140
|
-
} else {
|
|
1141
|
-
warnings.push({
|
|
1142
|
-
code: "local_only_no_remote",
|
|
1143
|
-
ref: matched.alias,
|
|
1144
|
-
message: `store '${matched.alias}' is local-only; add a git remote to back it up (\`fabric store ... \` / doctor nudge)`
|
|
1145
|
-
});
|
|
1274
|
+
if (seenStoreUuids.has(matched.store_uuid)) {
|
|
1275
|
+
continue;
|
|
1276
|
+
}
|
|
1277
|
+
const { entry, warning } = readSetEntryFromMounted(matched);
|
|
1278
|
+
if (warning !== void 0) {
|
|
1279
|
+
warnings.push(warning);
|
|
1146
1280
|
}
|
|
1147
1281
|
stores.push(entry);
|
|
1282
|
+
seenStoreUuids.add(matched.store_uuid);
|
|
1148
1283
|
}
|
|
1149
1284
|
const personal = personalEntry(input);
|
|
1150
|
-
if (personal !== void 0) {
|
|
1285
|
+
if (personal !== void 0 && !seenStoreUuids.has(personal.store_uuid)) {
|
|
1151
1286
|
stores.push(personal);
|
|
1287
|
+
seenStoreUuids.add(personal.store_uuid);
|
|
1152
1288
|
}
|
|
1153
1289
|
return { stores, warnings };
|
|
1154
1290
|
},
|
|
@@ -1169,15 +1305,31 @@ function createStoreResolver() {
|
|
|
1169
1305
|
}
|
|
1170
1306
|
return { target: { store_uuid: p.store_uuid, alias: p.alias }, warnings: [] };
|
|
1171
1307
|
}
|
|
1172
|
-
const
|
|
1308
|
+
const readSet = this.resolveReadSet(input);
|
|
1309
|
+
if (hasMultipleSharedStores(input, readSet) && !hasExplicitRouteOrDefault(input, scope)) {
|
|
1310
|
+
return {
|
|
1311
|
+
target: null,
|
|
1312
|
+
warnings: [
|
|
1313
|
+
{
|
|
1314
|
+
code: "missing_write_route",
|
|
1315
|
+
ref: scope,
|
|
1316
|
+
message: `scope '${scope}' has no explicit write route; set \`fabric store route-write ${scope} <alias>\``
|
|
1317
|
+
}
|
|
1318
|
+
]
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
const routeAlias = resolveRouteAlias(input, scope);
|
|
1322
|
+
const active = routeAlias === void 0 ? void 0 : readSet.stores.find(
|
|
1323
|
+
(store) => store.writable && !isMountedPersonal(input, store.store_uuid) && (store.alias === routeAlias || store.store_uuid === routeAlias)
|
|
1324
|
+
);
|
|
1173
1325
|
if (active === void 0) {
|
|
1174
1326
|
return {
|
|
1175
1327
|
target: null,
|
|
1176
1328
|
warnings: [
|
|
1177
1329
|
{
|
|
1178
1330
|
code: "alias_unresolved",
|
|
1179
|
-
ref:
|
|
1180
|
-
message: `no writable store for scope '${scope}'; set
|
|
1331
|
+
ref: routeAlias ?? scope,
|
|
1332
|
+
message: `no writable store for scope '${scope}'; set a write route or default write store`
|
|
1181
1333
|
}
|
|
1182
1334
|
]
|
|
1183
1335
|
};
|
|
@@ -1191,7 +1343,8 @@ function createStoreResolver() {
|
|
|
1191
1343
|
}
|
|
1192
1344
|
|
|
1193
1345
|
// src/resolver/store-disk-reader.ts
|
|
1194
|
-
import { existsSync, readdirSync, readFileSync
|
|
1346
|
+
import { existsSync, lstatSync, readdirSync, readFileSync } from "fs";
|
|
1347
|
+
import { readFile } from "fs/promises";
|
|
1195
1348
|
import { join } from "path";
|
|
1196
1349
|
function readStoreIdentity(absDir) {
|
|
1197
1350
|
const identityFile = join(absDir, STORE_LAYOUT.identityFile);
|
|
@@ -1207,6 +1360,17 @@ function readStoreIdentity(absDir) {
|
|
|
1207
1360
|
const parsed = storeIdentitySchema.safeParse(raw);
|
|
1208
1361
|
return parsed.success ? parsed.data : null;
|
|
1209
1362
|
}
|
|
1363
|
+
async function readStoreIdentityAsync(absDir) {
|
|
1364
|
+
const identityFile = join(absDir, STORE_LAYOUT.identityFile);
|
|
1365
|
+
let raw;
|
|
1366
|
+
try {
|
|
1367
|
+
raw = JSON.parse(await readFile(identityFile, "utf8"));
|
|
1368
|
+
} catch {
|
|
1369
|
+
return null;
|
|
1370
|
+
}
|
|
1371
|
+
const parsed = storeIdentitySchema.safeParse(raw);
|
|
1372
|
+
return parsed.success ? parsed.data : null;
|
|
1373
|
+
}
|
|
1210
1374
|
function recognizeStoreDir(absDir) {
|
|
1211
1375
|
return readStoreIdentity(absDir) !== null;
|
|
1212
1376
|
}
|
|
@@ -1226,9 +1390,23 @@ function hasScriptExtension(name) {
|
|
|
1226
1390
|
const dot = name.lastIndexOf(".");
|
|
1227
1391
|
return dot !== -1 && SCRIPT_EXTENSIONS.has(name.slice(dot).toLowerCase());
|
|
1228
1392
|
}
|
|
1229
|
-
|
|
1393
|
+
var STORE_SCAN_MAX_DEPTH = 32;
|
|
1394
|
+
var STORE_SCAN_MAX_ENTRIES = 1e5;
|
|
1395
|
+
function findStoreExecutableViolations(absDir, options = {}) {
|
|
1396
|
+
const maxDepth = options.maxDepth ?? STORE_SCAN_MAX_DEPTH;
|
|
1397
|
+
const maxEntries = options.maxEntries ?? STORE_SCAN_MAX_ENTRIES;
|
|
1230
1398
|
const violations = [];
|
|
1231
|
-
|
|
1399
|
+
let entriesScanned = 0;
|
|
1400
|
+
let bounded = false;
|
|
1401
|
+
const walk = (dir, rel, depth) => {
|
|
1402
|
+
if (bounded) {
|
|
1403
|
+
return;
|
|
1404
|
+
}
|
|
1405
|
+
if (depth > maxDepth) {
|
|
1406
|
+
violations.push(`<scan-bounded: depth > ${maxDepth} at ${rel === "" ? "." : rel}>`);
|
|
1407
|
+
bounded = true;
|
|
1408
|
+
return;
|
|
1409
|
+
}
|
|
1232
1410
|
let entries;
|
|
1233
1411
|
try {
|
|
1234
1412
|
entries = readdirSync(dir);
|
|
@@ -1236,19 +1414,32 @@ function findStoreExecutableViolations(absDir) {
|
|
|
1236
1414
|
return;
|
|
1237
1415
|
}
|
|
1238
1416
|
for (const entry of entries) {
|
|
1417
|
+
if (bounded) {
|
|
1418
|
+
return;
|
|
1419
|
+
}
|
|
1239
1420
|
if (rel === "" && entry === ".git") {
|
|
1240
1421
|
continue;
|
|
1241
1422
|
}
|
|
1423
|
+
entriesScanned += 1;
|
|
1424
|
+
if (entriesScanned > maxEntries) {
|
|
1425
|
+
violations.push(`<scan-bounded: entries > ${maxEntries}>`);
|
|
1426
|
+
bounded = true;
|
|
1427
|
+
return;
|
|
1428
|
+
}
|
|
1242
1429
|
const abs = join(dir, entry);
|
|
1243
1430
|
const relPath = rel === "" ? entry : `${rel}/${entry}`;
|
|
1244
1431
|
let stat;
|
|
1245
1432
|
try {
|
|
1246
|
-
stat =
|
|
1433
|
+
stat = lstatSync(abs);
|
|
1247
1434
|
} catch {
|
|
1248
1435
|
continue;
|
|
1249
1436
|
}
|
|
1437
|
+
if (stat.isSymbolicLink()) {
|
|
1438
|
+
violations.push(relPath);
|
|
1439
|
+
continue;
|
|
1440
|
+
}
|
|
1250
1441
|
if (stat.isDirectory()) {
|
|
1251
|
-
walk(abs, relPath);
|
|
1442
|
+
walk(abs, relPath, depth + 1);
|
|
1252
1443
|
continue;
|
|
1253
1444
|
}
|
|
1254
1445
|
if ((stat.mode & 73) !== 0 || hasScriptExtension(entry)) {
|
|
@@ -1256,7 +1447,7 @@ function findStoreExecutableViolations(absDir) {
|
|
|
1256
1447
|
}
|
|
1257
1448
|
}
|
|
1258
1449
|
};
|
|
1259
|
-
walk(absDir, "");
|
|
1450
|
+
walk(absDir, "", 0);
|
|
1260
1451
|
return violations;
|
|
1261
1452
|
}
|
|
1262
1453
|
|
|
@@ -1360,9 +1551,10 @@ function resolveCandidates(candidates, options = {}) {
|
|
|
1360
1551
|
}
|
|
1361
1552
|
|
|
1362
1553
|
// src/store/core.ts
|
|
1363
|
-
import {
|
|
1364
|
-
import {
|
|
1554
|
+
import { execFile } from "child_process";
|
|
1555
|
+
import { access, mkdir, readdir, readFile as readFile2, writeFile } from "fs/promises";
|
|
1365
1556
|
import { join as join2 } from "path";
|
|
1557
|
+
import { promisify } from "util";
|
|
1366
1558
|
var STORE_PENDING_DIR = "pending";
|
|
1367
1559
|
var STORE_GITIGNORE = [
|
|
1368
1560
|
"# v2.1 store \u2014 volatile / derived data is never committed",
|
|
@@ -1371,74 +1563,288 @@ var STORE_GITIGNORE = [
|
|
|
1371
1563
|
".cache/",
|
|
1372
1564
|
""
|
|
1373
1565
|
].join("\n");
|
|
1374
|
-
|
|
1375
|
-
|
|
1566
|
+
var execFileAsync = promisify(execFile);
|
|
1567
|
+
async function git(cwd, args) {
|
|
1568
|
+
await execFileAsync("git", args, { cwd });
|
|
1376
1569
|
}
|
|
1377
|
-
function initStore(absDir, identity, options = {}) {
|
|
1570
|
+
async function initStore(absDir, identity, options = {}) {
|
|
1378
1571
|
const parsed = storeIdentitySchema.parse(identity);
|
|
1379
1572
|
const identityFile = join2(absDir, STORE_LAYOUT.identityFile);
|
|
1380
|
-
|
|
1573
|
+
try {
|
|
1574
|
+
await access(identityFile);
|
|
1381
1575
|
throw new Error(`store already initialized at ${absDir} (store.json exists)`);
|
|
1576
|
+
} catch (err) {
|
|
1577
|
+
if (err instanceof Error && err.message.includes("already initialized")) {
|
|
1578
|
+
throw err;
|
|
1579
|
+
}
|
|
1382
1580
|
}
|
|
1383
1581
|
for (const type of STORE_KNOWLEDGE_TYPE_DIRS) {
|
|
1384
|
-
|
|
1582
|
+
const typeDir = join2(absDir, STORE_LAYOUT.knowledgeDir, type);
|
|
1583
|
+
await mkdir(typeDir, { recursive: true });
|
|
1584
|
+
await writeFile(join2(typeDir, ".gitkeep"), "", "utf8");
|
|
1385
1585
|
}
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1586
|
+
await mkdir(join2(absDir, STORE_LAYOUT.knowledgeDir, STORE_PENDING_DIR), { recursive: true });
|
|
1587
|
+
await mkdir(join2(absDir, STORE_LAYOUT.bindingsDir), { recursive: true });
|
|
1588
|
+
await mkdir(join2(absDir, STORE_LAYOUT.stateDir), { recursive: true });
|
|
1589
|
+
await writeFile(identityFile, `${JSON.stringify(parsed, null, 2)}
|
|
1390
1590
|
`, "utf8");
|
|
1391
|
-
|
|
1591
|
+
await writeFile(join2(absDir, ".gitignore"), STORE_GITIGNORE, "utf8");
|
|
1392
1592
|
if (options.git !== false) {
|
|
1393
|
-
git(absDir, ["init", "-b", "main"]);
|
|
1593
|
+
await git(absDir, ["init", "-b", "main"]);
|
|
1394
1594
|
}
|
|
1395
|
-
const readBack =
|
|
1595
|
+
const readBack = await readStoreIdentityAsync(absDir);
|
|
1396
1596
|
if (readBack === null) {
|
|
1397
1597
|
throw new Error(`store init wrote an unrecognizable store.json at ${absDir}`);
|
|
1398
1598
|
}
|
|
1399
1599
|
return readBack;
|
|
1400
1600
|
}
|
|
1401
|
-
function listMarkdown(dir) {
|
|
1402
|
-
|
|
1601
|
+
async function listMarkdown(dir) {
|
|
1602
|
+
let entries;
|
|
1603
|
+
try {
|
|
1604
|
+
entries = await readdir(dir);
|
|
1605
|
+
} catch {
|
|
1403
1606
|
return [];
|
|
1404
1607
|
}
|
|
1405
|
-
return
|
|
1608
|
+
return entries.filter((name) => name.endsWith(".md")).sort().map((name) => join2(dir, name));
|
|
1406
1609
|
}
|
|
1407
|
-
function listStoreKnowledge(store) {
|
|
1610
|
+
async function listStoreKnowledge(store) {
|
|
1408
1611
|
const refs = [];
|
|
1409
1612
|
for (const type of STORE_KNOWLEDGE_TYPE_DIRS) {
|
|
1410
|
-
for (const file of listMarkdown(join2(store.dir, STORE_LAYOUT.knowledgeDir, type))) {
|
|
1613
|
+
for (const file of await listMarkdown(join2(store.dir, STORE_LAYOUT.knowledgeDir, type))) {
|
|
1411
1614
|
refs.push({ store_uuid: store.store_uuid, alias: store.alias, type, file });
|
|
1412
1615
|
}
|
|
1413
1616
|
}
|
|
1414
1617
|
return refs;
|
|
1415
1618
|
}
|
|
1416
|
-
function readKnowledgeAcrossStores(stores) {
|
|
1417
|
-
|
|
1619
|
+
async function readKnowledgeAcrossStores(stores) {
|
|
1620
|
+
const lists = await Promise.all(stores.map((store) => listStoreKnowledge(store)));
|
|
1621
|
+
return lists.flat();
|
|
1622
|
+
}
|
|
1623
|
+
function storeProjectsPath(storeDir) {
|
|
1624
|
+
return join2(storeDir, STORE_LAYOUT.projectsFile);
|
|
1418
1625
|
}
|
|
1419
|
-
function
|
|
1420
|
-
|
|
1421
|
-
|
|
1626
|
+
async function readStoreProjects(storeDir) {
|
|
1627
|
+
const path = storeProjectsPath(storeDir);
|
|
1628
|
+
let raw;
|
|
1629
|
+
try {
|
|
1630
|
+
raw = JSON.parse(await readFile2(path, "utf8"));
|
|
1631
|
+
} catch {
|
|
1632
|
+
return [];
|
|
1633
|
+
}
|
|
1634
|
+
const parsed = storeProjectsFileSchema.safeParse(raw);
|
|
1635
|
+
return parsed.success ? parsed.data.projects : [];
|
|
1636
|
+
}
|
|
1637
|
+
async function storeHasProject(storeDir, id) {
|
|
1638
|
+
return (await readStoreProjects(storeDir)).some((p) => p.id === id);
|
|
1639
|
+
}
|
|
1640
|
+
async function addStoreProject(storeDir, project) {
|
|
1641
|
+
const parsed = storeProjectSchema.parse(project);
|
|
1642
|
+
const existing = await readStoreProjects(storeDir);
|
|
1643
|
+
if (existing.some((p) => p.id === parsed.id)) {
|
|
1644
|
+
throw new Error(`project '${parsed.id}' already exists in store at ${storeDir}`);
|
|
1645
|
+
}
|
|
1646
|
+
const next = [...existing, parsed];
|
|
1647
|
+
const validated = storeProjectsFileSchema.parse({ projects: next });
|
|
1648
|
+
await writeFile(storeProjectsPath(storeDir), `${JSON.stringify(validated, null, 2)}
|
|
1649
|
+
`, "utf8");
|
|
1650
|
+
return validated.projects;
|
|
1651
|
+
}
|
|
1652
|
+
async function aggregatePendingAcrossStores(stores) {
|
|
1653
|
+
const lists = await Promise.all(stores.map(
|
|
1654
|
+
async (store) => (await listMarkdown(join2(store.dir, STORE_LAYOUT.knowledgeDir, STORE_PENDING_DIR))).map((file) => ({
|
|
1422
1655
|
store_uuid: store.store_uuid,
|
|
1423
1656
|
alias: store.alias,
|
|
1424
1657
|
type: STORE_PENDING_DIR,
|
|
1425
1658
|
file
|
|
1426
1659
|
}))
|
|
1427
|
-
);
|
|
1660
|
+
));
|
|
1661
|
+
return lists.flat();
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
// src/store/store-counters.ts
|
|
1665
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync as readdirSync2, writeFileSync } from "fs";
|
|
1666
|
+
import { join as join3 } from "path";
|
|
1667
|
+
function storeCountersPath(storeDir) {
|
|
1668
|
+
return join3(storeDir, STORE_LAYOUT.countersFile);
|
|
1669
|
+
}
|
|
1670
|
+
function readStoreCounters(storeDir) {
|
|
1671
|
+
let raw;
|
|
1672
|
+
try {
|
|
1673
|
+
raw = readFileSync2(storeCountersPath(storeDir), "utf8");
|
|
1674
|
+
} catch {
|
|
1675
|
+
return defaultAgentsMetaCounters();
|
|
1676
|
+
}
|
|
1677
|
+
let parsed;
|
|
1678
|
+
try {
|
|
1679
|
+
parsed = JSON.parse(raw);
|
|
1680
|
+
} catch {
|
|
1681
|
+
return defaultAgentsMetaCounters();
|
|
1682
|
+
}
|
|
1683
|
+
const result = AgentsMetaCountersSchema.safeParse(parsed);
|
|
1684
|
+
return result.success ? result.data : defaultAgentsMetaCounters();
|
|
1685
|
+
}
|
|
1686
|
+
function preserveCorruptCounters(path, raw) {
|
|
1687
|
+
const corruptedPath = `${path}.corrupted.${Date.now()}`;
|
|
1688
|
+
writeFileSync(corruptedPath, raw, "utf8");
|
|
1689
|
+
return corruptedPath;
|
|
1690
|
+
}
|
|
1691
|
+
function readStoreCountersForAllocation(storeDir) {
|
|
1692
|
+
const path = storeCountersPath(storeDir);
|
|
1693
|
+
if (!existsSync2(path)) {
|
|
1694
|
+
return defaultAgentsMetaCounters();
|
|
1695
|
+
}
|
|
1696
|
+
const raw = readFileSync2(path, "utf8");
|
|
1697
|
+
let parsed;
|
|
1698
|
+
try {
|
|
1699
|
+
parsed = JSON.parse(raw);
|
|
1700
|
+
} catch (error) {
|
|
1701
|
+
const corruptedPath = preserveCorruptCounters(path, raw);
|
|
1702
|
+
throw new Error(
|
|
1703
|
+
`store counters.json is corrupt; forensic copy saved to ${corruptedPath}. Run doctor --fix or reconcileStoreCounters before allocating a new stable_id. Parse error: ${error instanceof Error ? error.message : String(error)}`
|
|
1704
|
+
);
|
|
1705
|
+
}
|
|
1706
|
+
const result = AgentsMetaCountersSchema.safeParse(parsed);
|
|
1707
|
+
if (!result.success) {
|
|
1708
|
+
const corruptedPath = preserveCorruptCounters(path, raw);
|
|
1709
|
+
throw new Error(
|
|
1710
|
+
`store counters.json is schema-invalid; forensic copy saved to ${corruptedPath}. Run doctor --fix or reconcileStoreCounters before allocating a new stable_id.`
|
|
1711
|
+
);
|
|
1712
|
+
}
|
|
1713
|
+
return result.data;
|
|
1714
|
+
}
|
|
1715
|
+
async function allocateStoreKnowledgeId(layer, type, storeDir) {
|
|
1716
|
+
const countersPath = storeCountersPath(storeDir);
|
|
1717
|
+
return withFileLock(`${countersPath}.lock`, async () => {
|
|
1718
|
+
const counters = readStoreCountersForAllocation(storeDir);
|
|
1719
|
+
const { id, nextCounters } = allocateKnowledgeId(layer, type, counters);
|
|
1720
|
+
await atomicWriteJson(countersPath, nextCounters, { indent: 2 });
|
|
1721
|
+
return id;
|
|
1722
|
+
});
|
|
1723
|
+
}
|
|
1724
|
+
function readEntryId(file) {
|
|
1725
|
+
let content;
|
|
1726
|
+
try {
|
|
1727
|
+
content = readFileSync2(file, "utf8");
|
|
1728
|
+
} catch {
|
|
1729
|
+
return null;
|
|
1730
|
+
}
|
|
1731
|
+
const match = content.match(/^id:\s*(\S+)\s*$/mu);
|
|
1732
|
+
if (match) {
|
|
1733
|
+
return match[1] ?? null;
|
|
1734
|
+
}
|
|
1735
|
+
const stem = file.slice(file.lastIndexOf("/") + 1).replace(/\.md$/u, "");
|
|
1736
|
+
const idPart = stem.split("--")[0];
|
|
1737
|
+
return idPart.length > 0 ? idPart : null;
|
|
1738
|
+
}
|
|
1739
|
+
function reconcileStoreCounters(storeDir) {
|
|
1740
|
+
const current = readStoreCounters(storeDir);
|
|
1741
|
+
const next = {
|
|
1742
|
+
KP: { ...current.KP },
|
|
1743
|
+
KT: { ...current.KT }
|
|
1744
|
+
};
|
|
1745
|
+
for (const type of STORE_KNOWLEDGE_TYPE_DIRS) {
|
|
1746
|
+
const dir = join3(storeDir, STORE_LAYOUT.knowledgeDir, type);
|
|
1747
|
+
if (!existsSync2(dir)) {
|
|
1748
|
+
continue;
|
|
1749
|
+
}
|
|
1750
|
+
for (const name of readdirSync2(dir)) {
|
|
1751
|
+
if (!name.endsWith(".md")) {
|
|
1752
|
+
continue;
|
|
1753
|
+
}
|
|
1754
|
+
const parsed = parseKnowledgeId(readEntryId(join3(dir, name)) ?? "");
|
|
1755
|
+
if (parsed === null) {
|
|
1756
|
+
continue;
|
|
1757
|
+
}
|
|
1758
|
+
const layerKey = parsed.layer === "personal" ? "KP" : "KT";
|
|
1759
|
+
const typeCode = KNOWLEDGE_TYPE_CODES[parsed.type];
|
|
1760
|
+
next[layerKey][typeCode] = Math.max(next[layerKey][typeCode], parsed.counter);
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
writeFileSync(storeCountersPath(storeDir), `${JSON.stringify(next, null, 2)}
|
|
1764
|
+
`, "utf8");
|
|
1765
|
+
return next;
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
// src/store/project-config-io.ts
|
|
1769
|
+
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
1770
|
+
import { join as join4 } from "path";
|
|
1771
|
+
function projectConfigPath(projectRoot) {
|
|
1772
|
+
return join4(projectRoot, ".fabric", "fabric-config.json");
|
|
1773
|
+
}
|
|
1774
|
+
function loadProjectConfig(projectRoot) {
|
|
1775
|
+
const path = projectConfigPath(projectRoot);
|
|
1776
|
+
if (!existsSync3(path)) {
|
|
1777
|
+
return null;
|
|
1778
|
+
}
|
|
1779
|
+
return fabricConfigSchema.parse(JSON.parse(readFileSync3(path, "utf8")));
|
|
1780
|
+
}
|
|
1781
|
+
function saveProjectConfig(config, projectRoot) {
|
|
1782
|
+
const validated = fabricConfigSchema.parse(config);
|
|
1783
|
+
mkdirSync(join4(projectRoot, ".fabric"), { recursive: true });
|
|
1784
|
+
writeFileSync2(projectConfigPath(projectRoot), `${JSON.stringify(validated, null, 2)}
|
|
1785
|
+
`, "utf8");
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
// src/store/resolve-input.ts
|
|
1789
|
+
function buildStoreResolveInput(projectRoot, globalRoot = resolveGlobalRoot()) {
|
|
1790
|
+
const global = loadGlobalConfig(globalRoot);
|
|
1791
|
+
if (global === null) {
|
|
1792
|
+
return null;
|
|
1793
|
+
}
|
|
1794
|
+
const project = loadProjectConfig(projectRoot);
|
|
1795
|
+
return {
|
|
1796
|
+
uid: global.uid,
|
|
1797
|
+
mountedStores: global.stores.map((s) => ({
|
|
1798
|
+
store_uuid: s.store_uuid,
|
|
1799
|
+
alias: s.alias,
|
|
1800
|
+
...s.mount_name === void 0 ? {} : { mount_name: s.mount_name },
|
|
1801
|
+
...s.remote === void 0 ? {} : { remote: s.remote },
|
|
1802
|
+
writable: s.writable ?? true,
|
|
1803
|
+
personal: s.personal ?? false
|
|
1804
|
+
})),
|
|
1805
|
+
requiredStores: (project?.required_stores ?? []).map(
|
|
1806
|
+
(r) => ({
|
|
1807
|
+
id: r.id,
|
|
1808
|
+
...r.suggested_remote === void 0 ? {} : { suggested_remote: r.suggested_remote }
|
|
1809
|
+
})
|
|
1810
|
+
),
|
|
1811
|
+
...project?.active_write_store === void 0 ? {} : { activeWriteAlias: project.active_write_store },
|
|
1812
|
+
writeRoutes: project?.write_routes ?? [],
|
|
1813
|
+
...project?.default_write_store === void 0 ? {} : { defaultWriteAlias: project.default_write_store }
|
|
1814
|
+
};
|
|
1428
1815
|
}
|
|
1429
1816
|
|
|
1430
1817
|
// src/store/secret-scan.ts
|
|
1431
|
-
var
|
|
1432
|
-
{ rule: "aws-access-key-id", re: /\bAKIA[0-9A-Z]{16}\b
|
|
1433
|
-
{ rule: "private-key-block", re: /-----BEGIN (?:RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY
|
|
1434
|
-
{ rule: "openai-api-key", re: /\bsk-[A-Za-z0-9]{20,}\b
|
|
1435
|
-
{ rule: "github-token", re: /\bgh[pousr]_[A-Za-z0-9]{20,}\b
|
|
1436
|
-
{ rule: "slack-token", re: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b
|
|
1818
|
+
var CREDENTIAL_RULES = [
|
|
1819
|
+
{ rule: "aws-access-key-id", re: /\bAKIA[0-9A-Z]{16}\b/, category: "credential" },
|
|
1820
|
+
{ rule: "private-key-block", re: /-----BEGIN (?:RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----/, category: "credential" },
|
|
1821
|
+
{ rule: "openai-api-key", re: /\bsk-[A-Za-z0-9]{20,}\b/, category: "credential" },
|
|
1822
|
+
{ rule: "github-token", re: /\bgh[pousr]_[A-Za-z0-9]{20,}\b/, category: "credential" },
|
|
1823
|
+
{ rule: "slack-token", re: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/, category: "credential" },
|
|
1437
1824
|
{
|
|
1438
1825
|
rule: "credential-assignment",
|
|
1439
|
-
re: /(?:password|passwd|secret|api[_-]?key|access[_-]?token|token)\s*[:=]\s*['"][^'"\s]{8,}[
|
|
1826
|
+
re: /(?:password|passwd|secret|api[_-]?key|access[_-]?token|token)\s*[:=]\s*(?:"[^'"\s]{8,}"|'[^'"\s]{8,}'|[A-Za-z0-9_./+=:@-]{8,})/i,
|
|
1827
|
+
category: "credential"
|
|
1828
|
+
}
|
|
1829
|
+
];
|
|
1830
|
+
var PII_RULES = [
|
|
1831
|
+
{
|
|
1832
|
+
rule: "email-address",
|
|
1833
|
+
re: /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/i,
|
|
1834
|
+
category: "pii"
|
|
1835
|
+
},
|
|
1836
|
+
{
|
|
1837
|
+
rule: "ipv4-address",
|
|
1838
|
+
re: /\b(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\b/,
|
|
1839
|
+
category: "pii"
|
|
1840
|
+
},
|
|
1841
|
+
{
|
|
1842
|
+
rule: "phone-number",
|
|
1843
|
+
re: /(?<!\d)(?:\+?1[-.\s]?)?(?:\(?\d{3}\)?[-.\s]?)\d{3}[-.\s]?\d{4}(?!\d)/,
|
|
1844
|
+
category: "pii"
|
|
1440
1845
|
}
|
|
1441
1846
|
];
|
|
1847
|
+
var SECRET_RULES = [...CREDENTIAL_RULES, ...PII_RULES];
|
|
1442
1848
|
function scanForSecrets(content) {
|
|
1443
1849
|
const findings = [];
|
|
1444
1850
|
const lines = content.split(/\r?\n/u);
|
|
@@ -1452,17 +1858,76 @@ function scanForSecrets(content) {
|
|
|
1452
1858
|
return findings;
|
|
1453
1859
|
}
|
|
1454
1860
|
function hasSecrets(content) {
|
|
1455
|
-
|
|
1861
|
+
const lines = content.split(/\r?\n/u);
|
|
1862
|
+
for (const line of lines) {
|
|
1863
|
+
for (const { re } of CREDENTIAL_RULES) {
|
|
1864
|
+
if (re.test(line)) {
|
|
1865
|
+
return true;
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
return false;
|
|
1456
1870
|
}
|
|
1457
1871
|
var REDACTION_PLACEHOLDER_PREFIX = "[REDACTED:";
|
|
1458
1872
|
function redactSecrets(content) {
|
|
1873
|
+
return redactByRules(content, SECRET_RULES);
|
|
1874
|
+
}
|
|
1875
|
+
function redactPii(content) {
|
|
1876
|
+
return redactByRules(content, PII_RULES);
|
|
1877
|
+
}
|
|
1878
|
+
function redactByRules(content, rules) {
|
|
1459
1879
|
let out = content;
|
|
1460
|
-
for (const { rule, re } of
|
|
1880
|
+
for (const { rule, re } of rules) {
|
|
1461
1881
|
const flags = re.flags.includes("i") ? "gi" : "g";
|
|
1462
1882
|
out = out.replace(new RegExp(re.source, flags), `${REDACTION_PLACEHOLDER_PREFIX}${rule}]`);
|
|
1463
1883
|
}
|
|
1464
1884
|
return out;
|
|
1465
1885
|
}
|
|
1886
|
+
function scrubRemoteUrl(remote) {
|
|
1887
|
+
const httpStripped = remote.replace(/^(https?:\/\/)[^/@]+@/i, "$1");
|
|
1888
|
+
if (httpStripped !== remote) {
|
|
1889
|
+
return httpStripped;
|
|
1890
|
+
}
|
|
1891
|
+
return remote.replace(
|
|
1892
|
+
/^([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)[^/@]*:[^/@]*@/,
|
|
1893
|
+
"$1"
|
|
1894
|
+
);
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
// src/scanner/scan-recommendations.ts
|
|
1898
|
+
function buildScanRecommendations(input, t) {
|
|
1899
|
+
const recs = [];
|
|
1900
|
+
if (input.hasExistingFabric === false) {
|
|
1901
|
+
recs.push(t("scan.rec.install"));
|
|
1902
|
+
}
|
|
1903
|
+
if (input.readmeOk === false) {
|
|
1904
|
+
recs.push(t("scan.rec.readme"));
|
|
1905
|
+
}
|
|
1906
|
+
if (input.hasContributing === false) {
|
|
1907
|
+
recs.push(t("scan.rec.contributing"));
|
|
1908
|
+
}
|
|
1909
|
+
switch (input.frameworkKind) {
|
|
1910
|
+
case "cocos-creator":
|
|
1911
|
+
recs.push(t("scan.rec.cocos.lifecycle"));
|
|
1912
|
+
recs.push(t("scan.rec.cocos.human-protect"));
|
|
1913
|
+
if (input.hasMeta === true) {
|
|
1914
|
+
recs.push(t("scan.rec.cocos.meta-lock"));
|
|
1915
|
+
}
|
|
1916
|
+
break;
|
|
1917
|
+
case "next":
|
|
1918
|
+
recs.push(t("scan.rec.next"));
|
|
1919
|
+
break;
|
|
1920
|
+
case "vite":
|
|
1921
|
+
recs.push(t("scan.rec.vite"));
|
|
1922
|
+
break;
|
|
1923
|
+
case "unknown":
|
|
1924
|
+
recs.push(t("scan.rec.unknown"));
|
|
1925
|
+
break;
|
|
1926
|
+
default:
|
|
1927
|
+
recs.push(t("scan.rec.generic", { kind: input.frameworkKind }));
|
|
1928
|
+
}
|
|
1929
|
+
return recs;
|
|
1930
|
+
}
|
|
1466
1931
|
|
|
1467
1932
|
// src/store/cross-store-lint.ts
|
|
1468
1933
|
function lintCrossStoreReferences(input) {
|
|
@@ -1535,10 +2000,10 @@ function buildDebugBundle(input) {
|
|
|
1535
2000
|
}
|
|
1536
2001
|
|
|
1537
2002
|
// src/schemas/provenance.ts
|
|
1538
|
-
import { z as
|
|
1539
|
-
var knowledgeProvenanceSchema =
|
|
2003
|
+
import { z as z10 } from "zod";
|
|
2004
|
+
var knowledgeProvenanceSchema = z10.object({
|
|
1540
2005
|
store_uuid: storeUuidSchema,
|
|
1541
|
-
alias:
|
|
2006
|
+
alias: z10.string().min(1),
|
|
1542
2007
|
local_id: localKnowledgeIdSchema,
|
|
1543
2008
|
global_ref: globalRefSchema,
|
|
1544
2009
|
// Optional scope coordinate of the entry (resolution axis); present when the
|
|
@@ -1547,7 +2012,7 @@ var knowledgeProvenanceSchema = z12.object({
|
|
|
1547
2012
|
}).strict();
|
|
1548
2013
|
|
|
1549
2014
|
// src/schemas/mcp-store-contracts.ts
|
|
1550
|
-
import { z as
|
|
2015
|
+
import { z as z11 } from "zod";
|
|
1551
2016
|
var MCP_STORE_AWARE_TOOLS = [
|
|
1552
2017
|
"fab_recall",
|
|
1553
2018
|
"fab_plan_context",
|
|
@@ -1556,14 +2021,14 @@ var MCP_STORE_AWARE_TOOLS = [
|
|
|
1556
2021
|
"fab_extract_knowledge",
|
|
1557
2022
|
"fab_review"
|
|
1558
2023
|
];
|
|
1559
|
-
var storeAwareEntrySchema =
|
|
1560
|
-
stable_id:
|
|
2024
|
+
var storeAwareEntrySchema = z11.object({
|
|
2025
|
+
stable_id: z11.string(),
|
|
1561
2026
|
global_ref: globalRefSchema,
|
|
1562
2027
|
provenance: knowledgeProvenanceSchema
|
|
1563
2028
|
}).strict();
|
|
1564
|
-
var writtenToStoreSchema =
|
|
2029
|
+
var writtenToStoreSchema = z11.object({
|
|
1565
2030
|
store_uuid: storeUuidSchema,
|
|
1566
|
-
alias:
|
|
2031
|
+
alias: z11.string().min(1)
|
|
1567
2032
|
}).strict();
|
|
1568
2033
|
var MCP_STORE_AWARE_CONTRACTS = {
|
|
1569
2034
|
fab_recall: { tool: "fab_recall", surfacesEntries: true, echoesWrittenStore: false },
|
|
@@ -1576,7 +2041,7 @@ var MCP_STORE_AWARE_CONTRACTS = {
|
|
|
1576
2041
|
fab_archive_scan: {
|
|
1577
2042
|
tool: "fab_archive_scan",
|
|
1578
2043
|
surfacesEntries: false,
|
|
1579
|
-
echoesWrittenStore:
|
|
2044
|
+
echoesWrittenStore: false
|
|
1580
2045
|
},
|
|
1581
2046
|
fab_extract_knowledge: {
|
|
1582
2047
|
tool: "fab_extract_knowledge",
|
|
@@ -1587,50 +2052,184 @@ var MCP_STORE_AWARE_CONTRACTS = {
|
|
|
1587
2052
|
};
|
|
1588
2053
|
|
|
1589
2054
|
// src/schemas/bindings-snapshot.ts
|
|
1590
|
-
import { z as
|
|
1591
|
-
var resolvedBindingsSnapshotSchema =
|
|
2055
|
+
import { z as z12 } from "zod";
|
|
2056
|
+
var resolvedBindingsSnapshotSchema = z12.object({
|
|
1592
2057
|
// Schema version of the snapshot document.
|
|
1593
|
-
version:
|
|
2058
|
+
version: z12.literal(1),
|
|
1594
2059
|
// The project this snapshot is bound to (S13).
|
|
1595
|
-
project_id:
|
|
2060
|
+
project_id: z12.string().min(1),
|
|
2061
|
+
// The local runtime binding key. Defaults to project_id for standard repos;
|
|
2062
|
+
// worktrees may isolate state by setting fabric-config.workspace_binding_id.
|
|
2063
|
+
workspace_binding_id: z12.string().min(1),
|
|
1596
2064
|
// ISO-8601 generation timestamp (provenance / staleness signal for doctor).
|
|
1597
|
-
generated_at:
|
|
2065
|
+
generated_at: z12.string().min(1),
|
|
1598
2066
|
// Pre-resolved read-set (required_stores ∪ implicit personal + warnings).
|
|
1599
2067
|
read_set: storeReadSetSchema,
|
|
1600
2068
|
// Pre-resolved active write target for non-personal scopes (null if none).
|
|
1601
|
-
write_target: writeTargetSchema.nullable()
|
|
2069
|
+
write_target: writeTargetSchema.nullable(),
|
|
2070
|
+
// Pre-computed store-backed knowledge counts, snapshotted at write time.
|
|
2071
|
+
// PROVENANCE ONLY: these are store-global counts cached in a per-workspace
|
|
2072
|
+
// file, so they go stale whenever store content changes out-of-band (a `git
|
|
2073
|
+
// pull` in the store repo, a sync run from a *different* bound workspace,
|
|
2074
|
+
// etc.) — the snapshot is only regenerated by install/sync/store-ops in the
|
|
2075
|
+
// workspace that runs them (KT-PIT-0017). Hooks MUST NOT trust these numbers
|
|
2076
|
+
// for nudges; they recount live from `knowledge_store_dirs`. Retained for
|
|
2077
|
+
// doctor provenance + backward-compatible fallback when dirs are absent.
|
|
2078
|
+
knowledge_stats: z12.object({
|
|
2079
|
+
pending_count: z12.number().int().nonnegative(),
|
|
2080
|
+
canonical_count: z12.number().int().nonnegative(),
|
|
2081
|
+
oldest_pending_mtime_ms: z12.number().nonnegative().nullable()
|
|
2082
|
+
}).strict().optional(),
|
|
2083
|
+
// Resolved absolute store ROOT dirs the knowledge_stats were derived from.
|
|
2084
|
+
// STABLE across content sync — they only change when mounts/bindings change,
|
|
2085
|
+
// which DOES regenerate the snapshot. Hooks walk `<dir>/knowledge/<type>` +
|
|
2086
|
+
// `<dir>/knowledge/pending` LIVE off these roots so nudge counts are always
|
|
2087
|
+
// fresh regardless of how store content changed (the underseed / review-
|
|
2088
|
+
// backlog false-positive root cure; pairs with knowledge_stats above).
|
|
2089
|
+
knowledge_store_dirs: z12.array(z12.string().min(1)).optional()
|
|
1602
2090
|
}).strict();
|
|
1603
2091
|
|
|
1604
2092
|
// src/store/bindings.ts
|
|
1605
|
-
import {
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
2093
|
+
import {
|
|
2094
|
+
existsSync as existsSync4,
|
|
2095
|
+
mkdirSync as mkdirSync2,
|
|
2096
|
+
readdirSync as readdirSync3,
|
|
2097
|
+
readFileSync as readFileSync4,
|
|
2098
|
+
renameSync,
|
|
2099
|
+
statSync,
|
|
2100
|
+
unlinkSync,
|
|
2101
|
+
writeFileSync as writeFileSync3
|
|
2102
|
+
} from "fs";
|
|
2103
|
+
import { join as join5, resolve, sep } from "path";
|
|
2104
|
+
var SAFE_BINDING_ID = /^[A-Za-z0-9._-]+$/;
|
|
2105
|
+
function assertSafeBindingId(bindingId) {
|
|
2106
|
+
if (!SAFE_BINDING_ID.test(bindingId) || bindingId.includes("..")) {
|
|
2107
|
+
throw new Error(
|
|
2108
|
+
`bindingsSnapshotPath: refusing unsafe workspace_binding_id ${JSON.stringify(bindingId)} (must match ${SAFE_BINDING_ID} and contain no "..")`
|
|
2109
|
+
);
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
function bindingsSnapshotPath(globalRoot, bindingId) {
|
|
2113
|
+
assertSafeBindingId(bindingId);
|
|
2114
|
+
const bindingsDir = resolve(join5(globalRoot, GLOBAL_STATE_DIR, GLOBAL_BINDINGS_DIR));
|
|
2115
|
+
const path = resolve(join5(bindingsDir, `${bindingId}_resolved.json`));
|
|
2116
|
+
if (path !== bindingsDir && !path.startsWith(bindingsDir + sep)) {
|
|
2117
|
+
throw new Error(`bindingsSnapshotPath: resolved path escapes bindings dir for ${JSON.stringify(bindingId)}`);
|
|
2118
|
+
}
|
|
2119
|
+
return path;
|
|
2120
|
+
}
|
|
2121
|
+
function resolveWorkspaceBindingId(config) {
|
|
2122
|
+
return config.workspace_binding_id ?? config.project_id;
|
|
2123
|
+
}
|
|
2124
|
+
function countMarkdownFiles(dir) {
|
|
2125
|
+
let count = 0;
|
|
2126
|
+
let oldestMtimeMs = null;
|
|
2127
|
+
if (!existsSync4(dir)) {
|
|
2128
|
+
return { count, oldestMtimeMs };
|
|
2129
|
+
}
|
|
2130
|
+
let entries;
|
|
2131
|
+
try {
|
|
2132
|
+
entries = readdirSync3(dir, { withFileTypes: true });
|
|
2133
|
+
} catch {
|
|
2134
|
+
return { count, oldestMtimeMs };
|
|
2135
|
+
}
|
|
2136
|
+
for (const entry of entries) {
|
|
2137
|
+
const fullPath = join5(dir, entry.name);
|
|
2138
|
+
if (entry.isDirectory()) {
|
|
2139
|
+
const nested = countMarkdownFiles(fullPath);
|
|
2140
|
+
count += nested.count;
|
|
2141
|
+
if (nested.oldestMtimeMs !== null && (oldestMtimeMs === null || nested.oldestMtimeMs < oldestMtimeMs)) {
|
|
2142
|
+
oldestMtimeMs = nested.oldestMtimeMs;
|
|
2143
|
+
}
|
|
2144
|
+
continue;
|
|
2145
|
+
}
|
|
2146
|
+
if (!entry.isFile() || !entry.name.endsWith(".md")) {
|
|
2147
|
+
continue;
|
|
2148
|
+
}
|
|
2149
|
+
let mtimeMs;
|
|
2150
|
+
try {
|
|
2151
|
+
mtimeMs = statSync(fullPath).mtimeMs;
|
|
2152
|
+
} catch {
|
|
2153
|
+
continue;
|
|
2154
|
+
}
|
|
2155
|
+
count += 1;
|
|
2156
|
+
if (oldestMtimeMs === null || mtimeMs < oldestMtimeMs) {
|
|
2157
|
+
oldestMtimeMs = mtimeMs;
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
return { count, oldestMtimeMs };
|
|
2161
|
+
}
|
|
2162
|
+
function collectKnowledgeStats(globalRoot, resolveInput, readSet) {
|
|
2163
|
+
let pendingCount = 0;
|
|
2164
|
+
let oldestPendingMtimeMs = null;
|
|
2165
|
+
let canonicalCount = 0;
|
|
2166
|
+
const storeDirs = [];
|
|
2167
|
+
for (const store of readSet.stores) {
|
|
2168
|
+
const mounted = resolveInput.mountedStores.find((entry) => entry.store_uuid === store.store_uuid) ?? {
|
|
2169
|
+
store_uuid: store.store_uuid
|
|
2170
|
+
};
|
|
2171
|
+
const storeDir = join5(globalRoot, storeRelativePathForMount(mounted));
|
|
2172
|
+
storeDirs.push(storeDir);
|
|
2173
|
+
for (const type of STORE_KNOWLEDGE_TYPE_DIRS) {
|
|
2174
|
+
const canonical = countMarkdownFiles(join5(storeDir, STORE_LAYOUT.knowledgeDir, type));
|
|
2175
|
+
canonicalCount += canonical.count;
|
|
2176
|
+
}
|
|
2177
|
+
const pending = countMarkdownFiles(join5(storeDir, STORE_LAYOUT.knowledgeDir, "pending"));
|
|
2178
|
+
pendingCount += pending.count;
|
|
2179
|
+
if (pending.oldestMtimeMs !== null && (oldestPendingMtimeMs === null || pending.oldestMtimeMs < oldestPendingMtimeMs)) {
|
|
2180
|
+
oldestPendingMtimeMs = pending.oldestMtimeMs;
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
return {
|
|
2184
|
+
stats: {
|
|
2185
|
+
pending_count: pendingCount,
|
|
2186
|
+
canonical_count: canonicalCount,
|
|
2187
|
+
oldest_pending_mtime_ms: oldestPendingMtimeMs
|
|
2188
|
+
},
|
|
2189
|
+
storeDirs
|
|
2190
|
+
};
|
|
2191
|
+
}
|
|
2192
|
+
function atomicWriteJsonSync(path, value) {
|
|
2193
|
+
const tmpPath = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
2194
|
+
try {
|
|
2195
|
+
writeFileSync3(tmpPath, `${JSON.stringify(value, null, 2)}
|
|
2196
|
+
`, "utf8");
|
|
2197
|
+
renameSync(tmpPath, path);
|
|
2198
|
+
} catch (error) {
|
|
2199
|
+
try {
|
|
2200
|
+
unlinkSync(tmpPath);
|
|
2201
|
+
} catch {
|
|
2202
|
+
}
|
|
2203
|
+
throw error;
|
|
2204
|
+
}
|
|
1609
2205
|
}
|
|
1610
2206
|
function writeBindingsSnapshot(options) {
|
|
1611
2207
|
const resolver = createStoreResolver();
|
|
1612
2208
|
const read_set = resolver.resolveReadSet(options.resolveInput);
|
|
1613
2209
|
const { target } = resolver.resolveWriteTarget(options.resolveInput, options.writeScope);
|
|
2210
|
+
const { stats, storeDirs } = collectKnowledgeStats(options.globalRoot, options.resolveInput, read_set);
|
|
1614
2211
|
const snapshot = resolvedBindingsSnapshotSchema.parse({
|
|
1615
2212
|
version: 1,
|
|
1616
2213
|
project_id: options.projectId,
|
|
2214
|
+
workspace_binding_id: options.workspaceBindingId ?? options.projectId,
|
|
1617
2215
|
generated_at: options.now,
|
|
1618
2216
|
read_set,
|
|
1619
|
-
write_target: target
|
|
2217
|
+
write_target: target,
|
|
2218
|
+
knowledge_stats: stats,
|
|
2219
|
+
knowledge_store_dirs: storeDirs
|
|
1620
2220
|
});
|
|
1621
|
-
const path = bindingsSnapshotPath(options.globalRoot,
|
|
1622
|
-
mkdirSync2(
|
|
1623
|
-
|
|
1624
|
-
`, "utf8");
|
|
2221
|
+
const path = bindingsSnapshotPath(options.globalRoot, snapshot.workspace_binding_id);
|
|
2222
|
+
mkdirSync2(join5(path, ".."), { recursive: true });
|
|
2223
|
+
atomicWriteJsonSync(path, snapshot);
|
|
1625
2224
|
return snapshot;
|
|
1626
2225
|
}
|
|
1627
2226
|
function readBindingsSnapshot(globalRoot, projectId) {
|
|
1628
2227
|
const path = bindingsSnapshotPath(globalRoot, projectId);
|
|
1629
|
-
if (!
|
|
2228
|
+
if (!existsSync4(path)) {
|
|
1630
2229
|
return null;
|
|
1631
2230
|
}
|
|
1632
2231
|
try {
|
|
1633
|
-
const parsed = resolvedBindingsSnapshotSchema.safeParse(JSON.parse(
|
|
2232
|
+
const parsed = resolvedBindingsSnapshotSchema.safeParse(JSON.parse(readFileSync4(path, "utf8")));
|
|
1634
2233
|
return parsed.success ? parsed.data : null;
|
|
1635
2234
|
} catch {
|
|
1636
2235
|
return null;
|
|
@@ -1639,7 +2238,9 @@ function readBindingsSnapshot(globalRoot, projectId) {
|
|
|
1639
2238
|
|
|
1640
2239
|
// src/store/store-lifecycle.ts
|
|
1641
2240
|
function findMountedStore(config, aliasOrUuid) {
|
|
1642
|
-
return config.stores.find(
|
|
2241
|
+
return config.stores.find(
|
|
2242
|
+
(s) => s.alias === aliasOrUuid || s.store_uuid === aliasOrUuid || s.mount_name === aliasOrUuid
|
|
2243
|
+
);
|
|
1643
2244
|
}
|
|
1644
2245
|
function addMountedStore(config, store) {
|
|
1645
2246
|
const aliasClash = config.stores.find(
|
|
@@ -1650,10 +2251,32 @@ function addMountedStore(config, store) {
|
|
|
1650
2251
|
`alias '${store.alias}' already mounts store ${aliasClash.store_uuid}; choose another alias`
|
|
1651
2252
|
);
|
|
1652
2253
|
}
|
|
2254
|
+
const mountNameClash = store.mount_name === void 0 ? void 0 : config.stores.find(
|
|
2255
|
+
(s) => s.mount_name === store.mount_name && s.store_uuid !== store.store_uuid
|
|
2256
|
+
);
|
|
2257
|
+
if (mountNameClash !== void 0) {
|
|
2258
|
+
throw new Error(
|
|
2259
|
+
`mount_name '${store.mount_name}' already maps to store ${mountNameClash.store_uuid}; choose another mount_name`
|
|
2260
|
+
);
|
|
2261
|
+
}
|
|
2262
|
+
const sanitized = store.remote === void 0 ? store : { ...store, remote: scrubRemoteUrl(store.remote) };
|
|
2263
|
+
store = sanitized;
|
|
1653
2264
|
const existing = config.stores.find((s) => s.store_uuid === store.store_uuid);
|
|
1654
2265
|
const stores = existing === void 0 ? [...config.stores, store] : config.stores.map((s) => s.store_uuid === store.store_uuid ? store : s);
|
|
1655
2266
|
return { ...config, stores };
|
|
1656
2267
|
}
|
|
2268
|
+
function disambiguateAlias(existingAliases, desired) {
|
|
2269
|
+
const taken = new Set(existingAliases);
|
|
2270
|
+
if (!taken.has(desired)) {
|
|
2271
|
+
return desired;
|
|
2272
|
+
}
|
|
2273
|
+
for (let n = 2; ; n += 1) {
|
|
2274
|
+
const candidate = `${desired}-${n}`;
|
|
2275
|
+
if (!taken.has(candidate)) {
|
|
2276
|
+
return candidate;
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
1657
2280
|
function detachMountedStore(config, alias) {
|
|
1658
2281
|
const detached = config.stores.find((s) => s.alias === alias) ?? null;
|
|
1659
2282
|
if (detached === null) {
|
|
@@ -1665,7 +2288,8 @@ function detachMountedStore(config, alias) {
|
|
|
1665
2288
|
};
|
|
1666
2289
|
}
|
|
1667
2290
|
function bindRequiredStore(required, entry) {
|
|
1668
|
-
|
|
2291
|
+
const safeEntry = entry.suggested_remote === void 0 ? entry : { ...entry, suggested_remote: scrubRemoteUrl(entry.suggested_remote) };
|
|
2292
|
+
return required.some((r) => r.id === safeEntry.id) ? required.map((r) => r.id === safeEntry.id ? safeEntry : r) : [...required, safeEntry];
|
|
1669
2293
|
}
|
|
1670
2294
|
function explainStore(config, alias) {
|
|
1671
2295
|
const store = findMountedStore(config, alias);
|
|
@@ -1681,155 +2305,155 @@ function explainStore(config, alias) {
|
|
|
1681
2305
|
}
|
|
1682
2306
|
|
|
1683
2307
|
// src/schemas/forensic-report.ts
|
|
1684
|
-
import { z as
|
|
1685
|
-
var forensicCodeSampleSchema =
|
|
1686
|
-
path:
|
|
1687
|
-
lines:
|
|
1688
|
-
snippet:
|
|
1689
|
-
pattern_hint:
|
|
1690
|
-
});
|
|
1691
|
-
var forensicEvidenceAnchorSchema =
|
|
1692
|
-
file:
|
|
1693
|
-
line:
|
|
1694
|
-
snippet:
|
|
1695
|
-
});
|
|
1696
|
-
var forensicAssertionCoverageSchema =
|
|
1697
|
-
ratio:
|
|
1698
|
-
total:
|
|
1699
|
-
matched:
|
|
1700
|
-
co_occurring_patterns:
|
|
1701
|
-
});
|
|
1702
|
-
var forensicAssertionSchema =
|
|
1703
|
-
type:
|
|
1704
|
-
statement:
|
|
1705
|
-
confidence:
|
|
1706
|
-
evidence:
|
|
2308
|
+
import { z as z13 } from "zod";
|
|
2309
|
+
var forensicCodeSampleSchema = z13.object({
|
|
2310
|
+
path: z13.string(),
|
|
2311
|
+
lines: z13.string(),
|
|
2312
|
+
snippet: z13.string(),
|
|
2313
|
+
pattern_hint: z13.string()
|
|
2314
|
+
});
|
|
2315
|
+
var forensicEvidenceAnchorSchema = z13.object({
|
|
2316
|
+
file: z13.string(),
|
|
2317
|
+
line: z13.string(),
|
|
2318
|
+
snippet: z13.string()
|
|
2319
|
+
});
|
|
2320
|
+
var forensicAssertionCoverageSchema = z13.object({
|
|
2321
|
+
ratio: z13.number().min(0).max(1),
|
|
2322
|
+
total: z13.number().int().nonnegative(),
|
|
2323
|
+
matched: z13.number().int().nonnegative(),
|
|
2324
|
+
co_occurring_patterns: z13.array(z13.string())
|
|
2325
|
+
});
|
|
2326
|
+
var forensicAssertionSchema = z13.object({
|
|
2327
|
+
type: z13.enum(["framework", "pattern", "invariant", "domain"]),
|
|
2328
|
+
statement: z13.string(),
|
|
2329
|
+
confidence: z13.enum(["HIGH", "MEDIUM", "LOW"]),
|
|
2330
|
+
evidence: z13.array(forensicEvidenceAnchorSchema),
|
|
1707
2331
|
coverage: forensicAssertionCoverageSchema,
|
|
1708
|
-
proposed_rule:
|
|
1709
|
-
alternatives:
|
|
1710
|
-
});
|
|
1711
|
-
var forensicTopologySchema =
|
|
1712
|
-
total_files:
|
|
1713
|
-
by_ext:
|
|
1714
|
-
key_dirs:
|
|
1715
|
-
max_depth:
|
|
1716
|
-
});
|
|
1717
|
-
var forensicEntryPointSchema =
|
|
1718
|
-
path:
|
|
1719
|
-
reason:
|
|
1720
|
-
size_bytes:
|
|
1721
|
-
});
|
|
1722
|
-
var forensicFrameworkSchema =
|
|
1723
|
-
kind:
|
|
1724
|
-
version:
|
|
1725
|
-
subkind:
|
|
1726
|
-
evidence:
|
|
1727
|
-
});
|
|
1728
|
-
var forensicReadmeSchema =
|
|
1729
|
-
quality:
|
|
1730
|
-
line_count:
|
|
1731
|
-
has_contributing:
|
|
1732
|
-
});
|
|
1733
|
-
var candidateFileEntrySchema =
|
|
1734
|
-
path:
|
|
1735
|
-
family:
|
|
1736
|
-
rationale:
|
|
1737
|
-
});
|
|
1738
|
-
var forensicSamplingBudgetSchema =
|
|
1739
|
-
max_files:
|
|
1740
|
-
max_lines_per_file:
|
|
1741
|
-
});
|
|
1742
|
-
var forensicReportSchema =
|
|
1743
|
-
version:
|
|
1744
|
-
generated_at:
|
|
1745
|
-
generated_by:
|
|
1746
|
-
target:
|
|
1747
|
-
project_name:
|
|
2332
|
+
proposed_rule: z13.string().optional(),
|
|
2333
|
+
alternatives: z13.array(z13.string()).optional()
|
|
2334
|
+
});
|
|
2335
|
+
var forensicTopologySchema = z13.object({
|
|
2336
|
+
total_files: z13.number().int().nonnegative(),
|
|
2337
|
+
by_ext: z13.record(z13.number().int().nonnegative()),
|
|
2338
|
+
key_dirs: z13.array(z13.string()),
|
|
2339
|
+
max_depth: z13.number().int().nonnegative()
|
|
2340
|
+
});
|
|
2341
|
+
var forensicEntryPointSchema = z13.object({
|
|
2342
|
+
path: z13.string(),
|
|
2343
|
+
reason: z13.string(),
|
|
2344
|
+
size_bytes: z13.number().int().nonnegative().optional()
|
|
2345
|
+
});
|
|
2346
|
+
var forensicFrameworkSchema = z13.object({
|
|
2347
|
+
kind: z13.string(),
|
|
2348
|
+
version: z13.string(),
|
|
2349
|
+
subkind: z13.string(),
|
|
2350
|
+
evidence: z13.array(z13.string())
|
|
2351
|
+
});
|
|
2352
|
+
var forensicReadmeSchema = z13.object({
|
|
2353
|
+
quality: z13.enum(["missing", "stub", "ok"]),
|
|
2354
|
+
line_count: z13.number().int().nonnegative(),
|
|
2355
|
+
has_contributing: z13.boolean()
|
|
2356
|
+
});
|
|
2357
|
+
var candidateFileEntrySchema = z13.object({
|
|
2358
|
+
path: z13.string(),
|
|
2359
|
+
family: z13.enum(["entry", "component", "config", "test", "domain"]),
|
|
2360
|
+
rationale: z13.string()
|
|
2361
|
+
});
|
|
2362
|
+
var forensicSamplingBudgetSchema = z13.object({
|
|
2363
|
+
max_files: z13.literal(15),
|
|
2364
|
+
max_lines_per_file: z13.literal(100)
|
|
2365
|
+
});
|
|
2366
|
+
var forensicReportSchema = z13.object({
|
|
2367
|
+
version: z13.string(),
|
|
2368
|
+
generated_at: z13.string(),
|
|
2369
|
+
generated_by: z13.string(),
|
|
2370
|
+
target: z13.string(),
|
|
2371
|
+
project_name: z13.string(),
|
|
1748
2372
|
framework: forensicFrameworkSchema,
|
|
1749
2373
|
topology: forensicTopologySchema,
|
|
1750
|
-
entry_points:
|
|
1751
|
-
code_samples:
|
|
1752
|
-
assertions:
|
|
1753
|
-
candidate_files:
|
|
2374
|
+
entry_points: z13.array(forensicEntryPointSchema),
|
|
2375
|
+
code_samples: z13.array(forensicCodeSampleSchema),
|
|
2376
|
+
assertions: z13.array(forensicAssertionSchema),
|
|
2377
|
+
candidate_files: z13.array(candidateFileEntrySchema),
|
|
1754
2378
|
sampling_budget: forensicSamplingBudgetSchema,
|
|
1755
2379
|
readme: forensicReadmeSchema,
|
|
1756
|
-
recommendations_for_skill:
|
|
2380
|
+
recommendations_for_skill: z13.array(z13.string()).optional()
|
|
1757
2381
|
});
|
|
1758
2382
|
|
|
1759
2383
|
// src/schemas/init-context.ts
|
|
1760
|
-
import { z as
|
|
1761
|
-
var initContextFrameworkSchema =
|
|
1762
|
-
kind:
|
|
1763
|
-
version:
|
|
1764
|
-
subkind:
|
|
1765
|
-
});
|
|
1766
|
-
var initContextInvariantConfidenceSnapshotSchema =
|
|
1767
|
-
confidence:
|
|
1768
|
-
evidence_refs:
|
|
1769
|
-
});
|
|
1770
|
-
var initContextSourceEvidenceSchema =
|
|
1771
|
-
file:
|
|
1772
|
-
lines:
|
|
1773
|
-
});
|
|
1774
|
-
var initContextInvariantSchema =
|
|
1775
|
-
type:
|
|
1776
|
-
rule:
|
|
1777
|
-
rationale:
|
|
2384
|
+
import { z as z14 } from "zod";
|
|
2385
|
+
var initContextFrameworkSchema = z14.object({
|
|
2386
|
+
kind: z14.string(),
|
|
2387
|
+
version: z14.string(),
|
|
2388
|
+
subkind: z14.string()
|
|
2389
|
+
});
|
|
2390
|
+
var initContextInvariantConfidenceSnapshotSchema = z14.object({
|
|
2391
|
+
confidence: z14.enum(["HIGH", "MEDIUM", "LOW"]),
|
|
2392
|
+
evidence_refs: z14.array(z14.string())
|
|
2393
|
+
});
|
|
2394
|
+
var initContextSourceEvidenceSchema = z14.object({
|
|
2395
|
+
file: z14.string(),
|
|
2396
|
+
lines: z14.string()
|
|
2397
|
+
});
|
|
2398
|
+
var initContextInvariantSchema = z14.object({
|
|
2399
|
+
type: z14.enum(["ban", "require", "protect"]),
|
|
2400
|
+
rule: z14.string(),
|
|
2401
|
+
rationale: z14.string().optional(),
|
|
1778
2402
|
confidence_snapshot: initContextInvariantConfidenceSnapshotSchema.optional(),
|
|
1779
|
-
source_evidence:
|
|
1780
|
-
});
|
|
1781
|
-
var initContextDomainGroupSchema =
|
|
1782
|
-
name:
|
|
1783
|
-
paths:
|
|
1784
|
-
summary:
|
|
1785
|
-
topology_type:
|
|
1786
|
-
target_path:
|
|
1787
|
-
});
|
|
1788
|
-
var initContextInterviewTrailEntrySchema =
|
|
1789
|
-
phase:
|
|
1790
|
-
question:
|
|
1791
|
-
answer:
|
|
1792
|
-
presentation:
|
|
1793
|
-
user_corrections:
|
|
1794
|
-
});
|
|
1795
|
-
var initContextSchema =
|
|
2403
|
+
source_evidence: z14.array(initContextSourceEvidenceSchema).optional()
|
|
2404
|
+
});
|
|
2405
|
+
var initContextDomainGroupSchema = z14.object({
|
|
2406
|
+
name: z14.string(),
|
|
2407
|
+
paths: z14.array(z14.string()),
|
|
2408
|
+
summary: z14.string().optional(),
|
|
2409
|
+
topology_type: z14.enum(["mirror", "cross-cutting"]).optional(),
|
|
2410
|
+
target_path: z14.string().optional()
|
|
2411
|
+
});
|
|
2412
|
+
var initContextInterviewTrailEntrySchema = z14.object({
|
|
2413
|
+
phase: z14.string(),
|
|
2414
|
+
question: z14.string(),
|
|
2415
|
+
answer: z14.string(),
|
|
2416
|
+
presentation: z14.string().optional(),
|
|
2417
|
+
user_corrections: z14.array(z14.string()).optional()
|
|
2418
|
+
});
|
|
2419
|
+
var initContextSchema = z14.object({
|
|
1796
2420
|
framework: initContextFrameworkSchema,
|
|
1797
|
-
architecture_patterns:
|
|
1798
|
-
invariants:
|
|
1799
|
-
domain_groups:
|
|
1800
|
-
interview_trail:
|
|
1801
|
-
forensic_ref:
|
|
2421
|
+
architecture_patterns: z14.array(z14.string()),
|
|
2422
|
+
invariants: z14.array(initContextInvariantSchema),
|
|
2423
|
+
domain_groups: z14.array(initContextDomainGroupSchema),
|
|
2424
|
+
interview_trail: z14.array(initContextInterviewTrailEntrySchema),
|
|
2425
|
+
forensic_ref: z14.string()
|
|
1802
2426
|
});
|
|
1803
2427
|
|
|
1804
2428
|
// src/schemas/events.ts
|
|
1805
|
-
import { z as
|
|
1806
|
-
var metaUpdatedEventSchema =
|
|
1807
|
-
type:
|
|
2429
|
+
import { z as z15 } from "zod";
|
|
2430
|
+
var metaUpdatedEventSchema = z15.object({
|
|
2431
|
+
type: z15.literal("meta:updated"),
|
|
1808
2432
|
payload: agentsMetaSchema
|
|
1809
2433
|
});
|
|
1810
|
-
var lockDriftEventSchema =
|
|
1811
|
-
type:
|
|
1812
|
-
payload:
|
|
1813
|
-
locked:
|
|
1814
|
-
drifted:
|
|
2434
|
+
var lockDriftEventSchema = z15.object({
|
|
2435
|
+
type: z15.literal("lock:drift"),
|
|
2436
|
+
payload: z15.object({
|
|
2437
|
+
locked: z15.array(humanLockEntrySchema),
|
|
2438
|
+
drifted: z15.array(humanLockEntrySchema)
|
|
1815
2439
|
})
|
|
1816
2440
|
});
|
|
1817
|
-
var lockApprovedEventSchema =
|
|
1818
|
-
type:
|
|
1819
|
-
payload:
|
|
1820
|
-
locked:
|
|
1821
|
-
approved:
|
|
2441
|
+
var lockApprovedEventSchema = z15.object({
|
|
2442
|
+
type: z15.literal("lock:approved"),
|
|
2443
|
+
payload: z15.object({
|
|
2444
|
+
locked: z15.array(humanLockEntrySchema),
|
|
2445
|
+
approved: z15.array(humanLockEntrySchema)
|
|
1822
2446
|
})
|
|
1823
2447
|
});
|
|
1824
|
-
var ledgerAppendedEventSchema =
|
|
1825
|
-
type:
|
|
2448
|
+
var ledgerAppendedEventSchema = z15.object({
|
|
2449
|
+
type: z15.literal("ledger:appended"),
|
|
1826
2450
|
payload: ledgerEntrySchema
|
|
1827
2451
|
});
|
|
1828
|
-
var driftDetectedEventSchema =
|
|
1829
|
-
type:
|
|
2452
|
+
var driftDetectedEventSchema = z15.object({
|
|
2453
|
+
type: z15.literal("drift:detected"),
|
|
1830
2454
|
payload: forensicReportSchema
|
|
1831
2455
|
});
|
|
1832
|
-
var fabricEventSchema =
|
|
2456
|
+
var fabricEventSchema = z15.discriminatedUnion("type", [
|
|
1833
2457
|
metaUpdatedEventSchema,
|
|
1834
2458
|
lockDriftEventSchema,
|
|
1835
2459
|
lockApprovedEventSchema,
|
|
@@ -1838,7 +2462,7 @@ var fabricEventSchema = z17.discriminatedUnion("type", [
|
|
|
1838
2462
|
]);
|
|
1839
2463
|
|
|
1840
2464
|
// src/schemas/event-ledger.ts
|
|
1841
|
-
import { z as
|
|
2465
|
+
import { z as z16 } from "zod";
|
|
1842
2466
|
|
|
1843
2467
|
// src/cite-line-parser.ts
|
|
1844
2468
|
var ID_RE = /^K[TP]-[A-Z]+-\d+$/;
|
|
@@ -1852,17 +2476,12 @@ function splitStorePrefix(token) {
|
|
|
1852
2476
|
return colon === -1 ? { store: null, id: token } : { store: token.slice(0, colon), id: token.slice(colon + 1) };
|
|
1853
2477
|
}
|
|
1854
2478
|
var CHAINED_FROM_ID_RE = /chained-from\s+(K[TP]-[A-Z]+-\d+)/i;
|
|
1855
|
-
var LEGACY_CITE_TAG_REMAP = {
|
|
1856
|
-
planned: "applied",
|
|
1857
|
-
recalled: "applied",
|
|
1858
|
-
"chained-from": "applied"
|
|
1859
|
-
};
|
|
1860
2479
|
function normalizeCiteTag(rawTag) {
|
|
1861
2480
|
const head = rawTag.trim().split(/[\s:]+/)[0].toLowerCase();
|
|
1862
2481
|
if (head === "applied" || head === "dismissed" || head === "none") {
|
|
1863
2482
|
return head;
|
|
1864
2483
|
}
|
|
1865
|
-
return
|
|
2484
|
+
return "none";
|
|
1866
2485
|
}
|
|
1867
2486
|
function parseTag(rawTag) {
|
|
1868
2487
|
if (!rawTag) return "none";
|
|
@@ -1950,146 +2569,131 @@ function parseCiteLine(raw) {
|
|
|
1950
2569
|
}
|
|
1951
2570
|
|
|
1952
2571
|
// src/schemas/event-ledger.ts
|
|
1953
|
-
var citeTagSchema =
|
|
2572
|
+
var citeTagSchema = z16.preprocess(
|
|
1954
2573
|
(value) => typeof value === "string" ? normalizeCiteTag(value) : value,
|
|
1955
|
-
|
|
2574
|
+
z16.enum(["applied", "dismissed", "none"])
|
|
1956
2575
|
);
|
|
1957
2576
|
var eventLedgerEnvelopeSchema = {
|
|
1958
|
-
kind:
|
|
1959
|
-
id:
|
|
1960
|
-
ts:
|
|
1961
|
-
schema_version:
|
|
1962
|
-
correlation_id:
|
|
1963
|
-
session_id:
|
|
2577
|
+
kind: z16.literal("fabric-event"),
|
|
2578
|
+
id: z16.string(),
|
|
2579
|
+
ts: z16.number().int().nonnegative(),
|
|
2580
|
+
schema_version: z16.literal(1),
|
|
2581
|
+
correlation_id: z16.string().optional(),
|
|
2582
|
+
session_id: z16.string().optional()
|
|
1964
2583
|
};
|
|
1965
|
-
var stringRecordSchema =
|
|
1966
|
-
var knowledgeContextPlannedEventSchema =
|
|
2584
|
+
var stringRecordSchema = z16.record(z16.string());
|
|
2585
|
+
var knowledgeContextPlannedEventSchema = z16.object({
|
|
1967
2586
|
...eventLedgerEnvelopeSchema,
|
|
1968
|
-
event_type:
|
|
1969
|
-
target_paths:
|
|
1970
|
-
required_stable_ids:
|
|
1971
|
-
ai_selectable_stable_ids:
|
|
1972
|
-
final_stable_ids:
|
|
1973
|
-
selection_token:
|
|
1974
|
-
client_hash:
|
|
1975
|
-
intent:
|
|
1976
|
-
known_tech:
|
|
1977
|
-
diagnostics:
|
|
1978
|
-
});
|
|
1979
|
-
var knowledgeSelectionEventSchema =
|
|
2587
|
+
event_type: z16.literal("knowledge_context_planned"),
|
|
2588
|
+
target_paths: z16.array(z16.string()),
|
|
2589
|
+
required_stable_ids: z16.array(z16.string()),
|
|
2590
|
+
ai_selectable_stable_ids: z16.array(z16.string()),
|
|
2591
|
+
final_stable_ids: z16.array(z16.string()),
|
|
2592
|
+
selection_token: z16.string().optional(),
|
|
2593
|
+
client_hash: z16.string().optional(),
|
|
2594
|
+
intent: z16.string().optional(),
|
|
2595
|
+
known_tech: z16.array(z16.string()).optional(),
|
|
2596
|
+
diagnostics: z16.array(z16.unknown()).optional()
|
|
2597
|
+
});
|
|
2598
|
+
var knowledgeSelectionEventSchema = z16.object({
|
|
1980
2599
|
...eventLedgerEnvelopeSchema,
|
|
1981
|
-
event_type:
|
|
1982
|
-
selection_token:
|
|
1983
|
-
target_paths:
|
|
1984
|
-
required_stable_ids:
|
|
1985
|
-
ai_selectable_stable_ids:
|
|
1986
|
-
ai_selected_stable_ids:
|
|
1987
|
-
final_stable_ids:
|
|
2600
|
+
event_type: z16.literal("knowledge_selection"),
|
|
2601
|
+
selection_token: z16.string(),
|
|
2602
|
+
target_paths: z16.array(z16.string()),
|
|
2603
|
+
required_stable_ids: z16.array(z16.string()),
|
|
2604
|
+
ai_selectable_stable_ids: z16.array(z16.string()),
|
|
2605
|
+
ai_selected_stable_ids: z16.array(z16.string()),
|
|
2606
|
+
final_stable_ids: z16.array(z16.string()),
|
|
1988
2607
|
ai_selection_reasons: stringRecordSchema,
|
|
1989
|
-
rejected_stable_ids:
|
|
1990
|
-
ignored_stable_ids:
|
|
2608
|
+
rejected_stable_ids: z16.array(z16.string()),
|
|
2609
|
+
ignored_stable_ids: z16.array(z16.string())
|
|
1991
2610
|
});
|
|
1992
|
-
var knowledgeSectionsFetchedEventSchema =
|
|
2611
|
+
var knowledgeSectionsFetchedEventSchema = z16.object({
|
|
1993
2612
|
...eventLedgerEnvelopeSchema,
|
|
1994
|
-
event_type:
|
|
1995
|
-
selection_token:
|
|
1996
|
-
target_paths:
|
|
1997
|
-
requested_sections:
|
|
1998
|
-
final_stable_ids:
|
|
1999
|
-
ai_selected_stable_ids:
|
|
2000
|
-
diagnostics:
|
|
2001
|
-
});
|
|
2002
|
-
var editIntentCheckedEventSchema =
|
|
2613
|
+
event_type: z16.literal("knowledge_sections_fetched"),
|
|
2614
|
+
selection_token: z16.string(),
|
|
2615
|
+
target_paths: z16.array(z16.string()).optional(),
|
|
2616
|
+
requested_sections: z16.array(z16.string()),
|
|
2617
|
+
final_stable_ids: z16.array(z16.string()),
|
|
2618
|
+
ai_selected_stable_ids: z16.array(z16.string()),
|
|
2619
|
+
diagnostics: z16.array(z16.unknown()).optional()
|
|
2620
|
+
});
|
|
2621
|
+
var editIntentCheckedEventSchema = z16.object({
|
|
2003
2622
|
...eventLedgerEnvelopeSchema,
|
|
2004
|
-
event_type:
|
|
2005
|
-
path:
|
|
2006
|
-
compliant:
|
|
2007
|
-
intent:
|
|
2008
|
-
ledger_entry_id:
|
|
2623
|
+
event_type: z16.literal("edit_intent_checked"),
|
|
2624
|
+
path: z16.string(),
|
|
2625
|
+
compliant: z16.boolean(),
|
|
2626
|
+
intent: z16.string(),
|
|
2627
|
+
ledger_entry_id: z16.string(),
|
|
2009
2628
|
// rc.35 TASK-07 (P0-2): add "hook" — emitted by the PreToolUse narrow hook
|
|
2010
2629
|
// for every Edit/Write/MultiEdit fire so cite-coverage doctor metrics see
|
|
2011
2630
|
// actual edit signals (previously editsTouched was permanently 0 because
|
|
2012
2631
|
// no production caller of appendLedgerEntry existed).
|
|
2013
|
-
ledger_source:
|
|
2014
|
-
commit_sha:
|
|
2015
|
-
parent_sha:
|
|
2016
|
-
parent_ledger_entry_id:
|
|
2017
|
-
diff_stat:
|
|
2018
|
-
annotation:
|
|
2019
|
-
matched_rule_context_ts:
|
|
2020
|
-
window_ms:
|
|
2021
|
-
});
|
|
2022
|
-
var knowledgeDriftDetectedEventSchema =
|
|
2632
|
+
ledger_source: z16.enum(["ai", "human", "hook"]).optional(),
|
|
2633
|
+
commit_sha: z16.string().optional(),
|
|
2634
|
+
parent_sha: z16.string().optional(),
|
|
2635
|
+
parent_ledger_entry_id: z16.string().optional(),
|
|
2636
|
+
diff_stat: z16.string().optional(),
|
|
2637
|
+
annotation: z16.string().optional(),
|
|
2638
|
+
matched_rule_context_ts: z16.number().int().nonnegative().nullable(),
|
|
2639
|
+
window_ms: z16.number().int().nonnegative()
|
|
2640
|
+
});
|
|
2641
|
+
var knowledgeDriftDetectedEventSchema = z16.object({
|
|
2023
2642
|
...eventLedgerEnvelopeSchema,
|
|
2024
|
-
event_type:
|
|
2025
|
-
revision:
|
|
2026
|
-
drifted_stable_ids:
|
|
2027
|
-
missing_files:
|
|
2028
|
-
stale_files:
|
|
2029
|
-
details:
|
|
2030
|
-
|
|
2031
|
-
file:
|
|
2032
|
-
stable_id:
|
|
2033
|
-
expected_hash:
|
|
2034
|
-
actual_hash:
|
|
2643
|
+
event_type: z16.literal("knowledge_drift_detected"),
|
|
2644
|
+
revision: z16.string().optional(),
|
|
2645
|
+
drifted_stable_ids: z16.array(z16.string()),
|
|
2646
|
+
missing_files: z16.array(z16.string()),
|
|
2647
|
+
stale_files: z16.array(z16.string()),
|
|
2648
|
+
details: z16.array(
|
|
2649
|
+
z16.object({
|
|
2650
|
+
file: z16.string(),
|
|
2651
|
+
stable_id: z16.string(),
|
|
2652
|
+
expected_hash: z16.string(),
|
|
2653
|
+
actual_hash: z16.string().nullable()
|
|
2035
2654
|
})
|
|
2036
2655
|
).optional()
|
|
2037
2656
|
});
|
|
2038
|
-
var mcpEventLedgerEventSchema =
|
|
2657
|
+
var mcpEventLedgerEventSchema = z16.object({
|
|
2039
2658
|
...eventLedgerEnvelopeSchema,
|
|
2040
|
-
event_type:
|
|
2041
|
-
mcp_event_id:
|
|
2042
|
-
stream_id:
|
|
2043
|
-
message:
|
|
2659
|
+
event_type: z16.literal("mcp_event"),
|
|
2660
|
+
mcp_event_id: z16.string(),
|
|
2661
|
+
stream_id: z16.string(),
|
|
2662
|
+
message: z16.unknown()
|
|
2044
2663
|
});
|
|
2045
|
-
var reapplyCompletedEventSchema =
|
|
2664
|
+
var reapplyCompletedEventSchema = z16.object({
|
|
2046
2665
|
...eventLedgerEnvelopeSchema,
|
|
2047
|
-
event_type:
|
|
2048
|
-
preserved_ledger:
|
|
2049
|
-
preserved_meta:
|
|
2050
|
-
rules_count:
|
|
2666
|
+
event_type: z16.literal("reapply_completed"),
|
|
2667
|
+
preserved_ledger: z16.boolean(),
|
|
2668
|
+
preserved_meta: z16.boolean(),
|
|
2669
|
+
rules_count: z16.number().int().nonnegative()
|
|
2051
2670
|
});
|
|
2052
|
-
var installDiffAppliedEventSchema =
|
|
2671
|
+
var installDiffAppliedEventSchema = z16.object({
|
|
2053
2672
|
...eventLedgerEnvelopeSchema,
|
|
2054
|
-
event_type:
|
|
2055
|
-
applied:
|
|
2056
|
-
canonical:
|
|
2057
|
-
drifted:
|
|
2673
|
+
event_type: z16.literal("install_diff_applied"),
|
|
2674
|
+
applied: z16.array(z16.string()),
|
|
2675
|
+
canonical: z16.array(z16.string()),
|
|
2676
|
+
drifted: z16.array(z16.string())
|
|
2058
2677
|
});
|
|
2059
|
-
var eventLedgerTruncatedEventSchema =
|
|
2678
|
+
var eventLedgerTruncatedEventSchema = z16.object({
|
|
2060
2679
|
...eventLedgerEnvelopeSchema,
|
|
2061
|
-
event_type:
|
|
2062
|
-
byte_offset:
|
|
2063
|
-
byte_length:
|
|
2064
|
-
corrupted_path:
|
|
2680
|
+
event_type: z16.literal("event_ledger_truncated"),
|
|
2681
|
+
byte_offset: z16.number().int().nonnegative(),
|
|
2682
|
+
byte_length: z16.number().int().nonnegative(),
|
|
2683
|
+
corrupted_path: z16.string()
|
|
2065
2684
|
});
|
|
2066
|
-
var
|
|
2685
|
+
var metaReconciledOnStartupEventSchema = z16.object({
|
|
2067
2686
|
...eventLedgerEnvelopeSchema,
|
|
2068
|
-
event_type:
|
|
2069
|
-
|
|
2070
|
-
|
|
2687
|
+
event_type: z16.literal("meta_reconciled_on_startup"),
|
|
2688
|
+
reconciled_files: z16.array(z16.string()),
|
|
2689
|
+
duration_ms: z16.number().int().nonnegative(),
|
|
2690
|
+
source: z16.literal("reconcileKnowledge")
|
|
2071
2691
|
});
|
|
2072
|
-
var
|
|
2073
|
-
...eventLedgerEnvelopeSchema,
|
|
2074
|
-
event_type: z18.literal("bootstrap_marker_migrated"),
|
|
2075
|
-
path: z18.string(),
|
|
2076
|
-
migrated_count: z18.number().int().nonnegative(),
|
|
2077
|
-
legacy_marker: z18.literal("fabric:knowledge-base"),
|
|
2078
|
-
new_marker: z18.literal("fabric:bootstrap"),
|
|
2079
|
-
timestamp: z18.string()
|
|
2080
|
-
});
|
|
2081
|
-
var metaReconciledOnStartupEventSchema = z18.object({
|
|
2692
|
+
var metaReconciledEventSchema = z16.object({
|
|
2082
2693
|
...eventLedgerEnvelopeSchema,
|
|
2083
|
-
event_type:
|
|
2084
|
-
reconciled_files:
|
|
2085
|
-
duration_ms:
|
|
2086
|
-
source: z18.literal("reconcileKnowledge")
|
|
2087
|
-
});
|
|
2088
|
-
var metaReconciledEventSchema = z18.object({
|
|
2089
|
-
...eventLedgerEnvelopeSchema,
|
|
2090
|
-
event_type: z18.literal("meta_reconciled"),
|
|
2091
|
-
reconciled_files: z18.array(z18.string()),
|
|
2092
|
-
duration_ms: z18.number().int().nonnegative(),
|
|
2694
|
+
event_type: z16.literal("meta_reconciled"),
|
|
2695
|
+
reconciled_files: z16.array(z16.string()),
|
|
2696
|
+
duration_ms: z16.number().int().nonnegative(),
|
|
2093
2697
|
// v2.0.0-rc.23 TASK-005 (a-B): added `auto-heal-description` trigger so the
|
|
2094
2698
|
// read-path plan_context handler can drive a full reconcile when it detects
|
|
2095
2699
|
// any node carrying `description === undefined` (legacy meta drift that the
|
|
@@ -2103,7 +2707,7 @@ var metaReconciledEventSchema = z18.object({
|
|
|
2103
2707
|
// v2.0.0-rc.29 TASK-005 (BUG-G1): `auto-heal-after-drift` added so
|
|
2104
2708
|
// `ensureKnowledgeFresh` hot-path can chain a paired reconcile (closing the
|
|
2105
2709
|
// drift→heal gap) when the caller opts in via `autoHealOnDrift: true`.
|
|
2106
|
-
trigger:
|
|
2710
|
+
trigger: z16.enum([
|
|
2107
2711
|
"doctor",
|
|
2108
2712
|
"manual",
|
|
2109
2713
|
"auto-heal-description",
|
|
@@ -2111,195 +2715,207 @@ var metaReconciledEventSchema = z18.object({
|
|
|
2111
2715
|
"post-approve",
|
|
2112
2716
|
"post-modify"
|
|
2113
2717
|
]),
|
|
2114
|
-
source:
|
|
2718
|
+
source: z16.literal("reconcileKnowledge"),
|
|
2115
2719
|
// v2.0.0-rc.22 TASK-014 (Scope E): set when reconcileKnowledge forced a
|
|
2116
2720
|
// writeKnowledgeMeta on revision drift alone (no per-file content drift).
|
|
2117
2721
|
// Distinguishes top-level schema/revision repair from the standard per-file
|
|
2118
2722
|
// drift path. Optional so existing emitters stay unchanged.
|
|
2119
|
-
force_write_reason:
|
|
2723
|
+
force_write_reason: z16.enum(["revision_drift"]).optional()
|
|
2120
2724
|
});
|
|
2121
|
-
var claudeSkillPathMigratedEventSchema =
|
|
2725
|
+
var claudeSkillPathMigratedEventSchema = z16.object({
|
|
2122
2726
|
...eventLedgerEnvelopeSchema,
|
|
2123
|
-
event_type:
|
|
2124
|
-
from:
|
|
2125
|
-
to:
|
|
2727
|
+
event_type: z16.literal("claude_skill_path_migrated"),
|
|
2728
|
+
from: z16.string(),
|
|
2729
|
+
to: z16.string()
|
|
2126
2730
|
});
|
|
2127
|
-
var claudeHookPathMigratedEventSchema =
|
|
2731
|
+
var claudeHookPathMigratedEventSchema = z16.object({
|
|
2128
2732
|
...eventLedgerEnvelopeSchema,
|
|
2129
|
-
event_type:
|
|
2130
|
-
from:
|
|
2131
|
-
to:
|
|
2733
|
+
event_type: z16.literal("claude_hook_path_migrated"),
|
|
2734
|
+
from: z16.string(),
|
|
2735
|
+
to: z16.string()
|
|
2132
2736
|
});
|
|
2133
|
-
var codexSkillPathMigratedEventSchema =
|
|
2737
|
+
var codexSkillPathMigratedEventSchema = z16.object({
|
|
2134
2738
|
...eventLedgerEnvelopeSchema,
|
|
2135
|
-
event_type:
|
|
2136
|
-
from:
|
|
2137
|
-
to:
|
|
2739
|
+
event_type: z16.literal("codex_skill_path_migrated"),
|
|
2740
|
+
from: z16.string(),
|
|
2741
|
+
to: z16.string()
|
|
2138
2742
|
});
|
|
2139
|
-
var initScanCompletedEventSchema =
|
|
2743
|
+
var initScanCompletedEventSchema = z16.object({
|
|
2140
2744
|
...eventLedgerEnvelopeSchema,
|
|
2141
|
-
event_type:
|
|
2142
|
-
written_stable_ids:
|
|
2143
|
-
duration_ms:
|
|
2144
|
-
source:
|
|
2745
|
+
event_type: z16.literal("init_scan_completed"),
|
|
2746
|
+
written_stable_ids: z16.array(z16.string()),
|
|
2747
|
+
duration_ms: z16.number().int().nonnegative(),
|
|
2748
|
+
source: z16.enum(["init", "scan", "doctor_fix", "doctor-rescan"]).optional()
|
|
2145
2749
|
});
|
|
2146
|
-
var knowledgeProposedEventSchema =
|
|
2750
|
+
var knowledgeProposedEventSchema = z16.object({
|
|
2147
2751
|
...eventLedgerEnvelopeSchema,
|
|
2148
|
-
event_type:
|
|
2149
|
-
stable_id:
|
|
2150
|
-
timestamp:
|
|
2151
|
-
reason:
|
|
2752
|
+
event_type: z16.literal("knowledge_proposed"),
|
|
2753
|
+
stable_id: z16.string().optional(),
|
|
2754
|
+
timestamp: z16.string().datetime(),
|
|
2755
|
+
reason: z16.string().optional()
|
|
2152
2756
|
});
|
|
2153
|
-
var knowledgePromoteStartedEventSchema =
|
|
2757
|
+
var knowledgePromoteStartedEventSchema = z16.object({
|
|
2154
2758
|
...eventLedgerEnvelopeSchema,
|
|
2155
|
-
event_type:
|
|
2156
|
-
stable_id:
|
|
2157
|
-
timestamp:
|
|
2158
|
-
reason:
|
|
2759
|
+
event_type: z16.literal("knowledge_promote_started"),
|
|
2760
|
+
stable_id: z16.string().optional(),
|
|
2761
|
+
timestamp: z16.string().datetime(),
|
|
2762
|
+
reason: z16.string().optional()
|
|
2159
2763
|
});
|
|
2160
|
-
var knowledgePromotedEventSchema =
|
|
2764
|
+
var knowledgePromotedEventSchema = z16.object({
|
|
2161
2765
|
...eventLedgerEnvelopeSchema,
|
|
2162
|
-
event_type:
|
|
2163
|
-
stable_id:
|
|
2164
|
-
timestamp:
|
|
2165
|
-
reason:
|
|
2766
|
+
event_type: z16.literal("knowledge_promoted"),
|
|
2767
|
+
stable_id: z16.string().optional(),
|
|
2768
|
+
timestamp: z16.string().datetime(),
|
|
2769
|
+
reason: z16.string().optional()
|
|
2166
2770
|
});
|
|
2167
|
-
var knowledgePromoteFailedEventSchema =
|
|
2771
|
+
var knowledgePromoteFailedEventSchema = z16.object({
|
|
2168
2772
|
...eventLedgerEnvelopeSchema,
|
|
2169
|
-
event_type:
|
|
2170
|
-
stable_id:
|
|
2171
|
-
timestamp:
|
|
2172
|
-
reason:
|
|
2773
|
+
event_type: z16.literal("knowledge_promote_failed"),
|
|
2774
|
+
stable_id: z16.string().optional(),
|
|
2775
|
+
timestamp: z16.string().datetime(),
|
|
2776
|
+
reason: z16.string()
|
|
2173
2777
|
});
|
|
2174
|
-
var
|
|
2778
|
+
var knowledgeModifiedEventSchema = z16.object({
|
|
2779
|
+
...eventLedgerEnvelopeSchema,
|
|
2780
|
+
event_type: z16.literal("knowledge_modified"),
|
|
2781
|
+
stable_id: z16.string().optional(),
|
|
2782
|
+
timestamp: z16.string().datetime(),
|
|
2783
|
+
path: z16.string(),
|
|
2784
|
+
changed_fields: z16.array(z16.string()),
|
|
2785
|
+
before: z16.record(z16.unknown()),
|
|
2786
|
+
after: z16.record(z16.unknown()),
|
|
2787
|
+
reason: z16.string().optional()
|
|
2788
|
+
});
|
|
2789
|
+
var knowledgeLayerChangedEventSchema = z16.object({
|
|
2175
2790
|
...eventLedgerEnvelopeSchema,
|
|
2176
|
-
event_type:
|
|
2177
|
-
stable_id:
|
|
2178
|
-
timestamp:
|
|
2179
|
-
reason:
|
|
2180
|
-
from_layer:
|
|
2181
|
-
to_layer:
|
|
2791
|
+
event_type: z16.literal("knowledge_layer_changed"),
|
|
2792
|
+
stable_id: z16.string().optional(),
|
|
2793
|
+
timestamp: z16.string().datetime(),
|
|
2794
|
+
reason: z16.string().optional(),
|
|
2795
|
+
from_layer: z16.enum(["team", "personal"]),
|
|
2796
|
+
to_layer: z16.enum(["team", "personal"]),
|
|
2182
2797
|
// v2.0.0-rc.37 NEW-24: record the pre-flip stable_id so downstream consumers
|
|
2183
2798
|
// (fab_plan_context redirect surface, fab_get_knowledge_sections.redirect_to)
|
|
2184
2799
|
// can map a stale caller-held id back to the post-flip canonical id without
|
|
2185
2800
|
// requiring the caller to re-issue plan-context. Optional for forward-
|
|
2186
2801
|
// compatibility with rc ≤36 events that never carried this field.
|
|
2187
|
-
previous_stable_id:
|
|
2802
|
+
previous_stable_id: z16.string().optional()
|
|
2188
2803
|
});
|
|
2189
|
-
var knowledgeIdRedirectEventSchema =
|
|
2804
|
+
var knowledgeIdRedirectEventSchema = z16.object({
|
|
2190
2805
|
...eventLedgerEnvelopeSchema,
|
|
2191
|
-
event_type:
|
|
2192
|
-
timestamp:
|
|
2193
|
-
previous_stable_id:
|
|
2194
|
-
new_stable_id:
|
|
2195
|
-
reason:
|
|
2806
|
+
event_type: z16.literal("knowledge_id_redirect"),
|
|
2807
|
+
timestamp: z16.string().datetime(),
|
|
2808
|
+
previous_stable_id: z16.string(),
|
|
2809
|
+
new_stable_id: z16.string(),
|
|
2810
|
+
reason: z16.string().optional()
|
|
2196
2811
|
});
|
|
2197
|
-
var knowledgeSlugRenamedEventSchema =
|
|
2812
|
+
var knowledgeSlugRenamedEventSchema = z16.object({
|
|
2198
2813
|
...eventLedgerEnvelopeSchema,
|
|
2199
|
-
event_type:
|
|
2200
|
-
stable_id:
|
|
2201
|
-
timestamp:
|
|
2202
|
-
reason:
|
|
2203
|
-
from_slug:
|
|
2204
|
-
to_slug:
|
|
2205
|
-
});
|
|
2206
|
-
var knowledgeDemotedEventSchema =
|
|
2814
|
+
event_type: z16.literal("knowledge_slug_renamed"),
|
|
2815
|
+
stable_id: z16.string().optional(),
|
|
2816
|
+
timestamp: z16.string().datetime(),
|
|
2817
|
+
reason: z16.string().optional(),
|
|
2818
|
+
from_slug: z16.string(),
|
|
2819
|
+
to_slug: z16.string()
|
|
2820
|
+
});
|
|
2821
|
+
var knowledgeDemotedEventSchema = z16.object({
|
|
2207
2822
|
...eventLedgerEnvelopeSchema,
|
|
2208
|
-
event_type:
|
|
2209
|
-
stable_id:
|
|
2210
|
-
timestamp:
|
|
2211
|
-
reason:
|
|
2823
|
+
event_type: z16.literal("knowledge_demoted"),
|
|
2824
|
+
stable_id: z16.string().optional(),
|
|
2825
|
+
timestamp: z16.string().datetime(),
|
|
2826
|
+
reason: z16.string().optional()
|
|
2212
2827
|
});
|
|
2213
|
-
var knowledgeArchivedEventSchema =
|
|
2828
|
+
var knowledgeArchivedEventSchema = z16.object({
|
|
2214
2829
|
...eventLedgerEnvelopeSchema,
|
|
2215
|
-
event_type:
|
|
2216
|
-
stable_id:
|
|
2217
|
-
timestamp:
|
|
2218
|
-
reason:
|
|
2830
|
+
event_type: z16.literal("knowledge_archived"),
|
|
2831
|
+
stable_id: z16.string().optional(),
|
|
2832
|
+
timestamp: z16.string().datetime(),
|
|
2833
|
+
reason: z16.string().optional()
|
|
2219
2834
|
});
|
|
2220
|
-
var knowledgeArchiveAttemptedEventSchema =
|
|
2835
|
+
var knowledgeArchiveAttemptedEventSchema = z16.object({
|
|
2221
2836
|
...eventLedgerEnvelopeSchema,
|
|
2222
|
-
event_type:
|
|
2223
|
-
stable_id:
|
|
2224
|
-
timestamp:
|
|
2225
|
-
reason:
|
|
2837
|
+
event_type: z16.literal("knowledge_archive_attempted"),
|
|
2838
|
+
stable_id: z16.string().optional(),
|
|
2839
|
+
timestamp: z16.string().datetime(),
|
|
2840
|
+
reason: z16.string().optional()
|
|
2226
2841
|
});
|
|
2227
|
-
var knowledgeUnarchivedEventSchema =
|
|
2842
|
+
var knowledgeUnarchivedEventSchema = z16.object({
|
|
2228
2843
|
...eventLedgerEnvelopeSchema,
|
|
2229
|
-
event_type:
|
|
2230
|
-
stable_id:
|
|
2231
|
-
timestamp:
|
|
2232
|
-
reason:
|
|
2844
|
+
event_type: z16.literal("knowledge_unarchived"),
|
|
2845
|
+
stable_id: z16.string().optional(),
|
|
2846
|
+
timestamp: z16.string().datetime(),
|
|
2847
|
+
reason: z16.string().optional(),
|
|
2233
2848
|
// Pre-move archive path (e.g. ".fabric/.archive/decisions/KT-D-0007--single-cjs-hook.md").
|
|
2234
|
-
archive_path:
|
|
2235
|
-
// Post-move canonical path (e.g. "
|
|
2236
|
-
restored_to:
|
|
2849
|
+
archive_path: z16.string().optional(),
|
|
2850
|
+
// Post-move canonical path (e.g. "knowledge/decisions/KT-DEC-0007--single-cjs-hook.md" inside the resolved store).
|
|
2851
|
+
restored_to: z16.string().optional()
|
|
2237
2852
|
});
|
|
2238
|
-
var knowledgeDeferredEventSchema =
|
|
2853
|
+
var knowledgeDeferredEventSchema = z16.object({
|
|
2239
2854
|
...eventLedgerEnvelopeSchema,
|
|
2240
|
-
event_type:
|
|
2241
|
-
stable_id:
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2855
|
+
event_type: z16.literal("knowledge_deferred"),
|
|
2856
|
+
stable_id: z16.string().optional(),
|
|
2857
|
+
pending_path: z16.string().optional(),
|
|
2858
|
+
timestamp: z16.string().datetime(),
|
|
2859
|
+
reason: z16.string().optional(),
|
|
2860
|
+
until: z16.string().datetime().optional()
|
|
2861
|
+
});
|
|
2862
|
+
var knowledgeRejectedEventSchema = z16.object({
|
|
2247
2863
|
...eventLedgerEnvelopeSchema,
|
|
2248
|
-
event_type:
|
|
2249
|
-
stable_id:
|
|
2250
|
-
timestamp:
|
|
2251
|
-
reason:
|
|
2864
|
+
event_type: z16.literal("knowledge_rejected"),
|
|
2865
|
+
stable_id: z16.string().optional(),
|
|
2866
|
+
timestamp: z16.string().datetime(),
|
|
2867
|
+
reason: z16.string()
|
|
2252
2868
|
});
|
|
2253
|
-
var knowledgeConsumedEventSchema =
|
|
2869
|
+
var knowledgeConsumedEventSchema = z16.object({
|
|
2254
2870
|
...eventLedgerEnvelopeSchema,
|
|
2255
|
-
event_type:
|
|
2256
|
-
stable_id:
|
|
2257
|
-
consumed_at:
|
|
2258
|
-
client_hash:
|
|
2871
|
+
event_type: z16.literal("knowledge_consumed"),
|
|
2872
|
+
stable_id: z16.string(),
|
|
2873
|
+
consumed_at: z16.string().datetime(),
|
|
2874
|
+
client_hash: z16.string()
|
|
2259
2875
|
});
|
|
2260
|
-
var knowledgeScopeDegradedEventSchema =
|
|
2876
|
+
var knowledgeScopeDegradedEventSchema = z16.object({
|
|
2261
2877
|
...eventLedgerEnvelopeSchema,
|
|
2262
|
-
event_type:
|
|
2263
|
-
stable_id:
|
|
2264
|
-
timestamp:
|
|
2265
|
-
from_scope:
|
|
2266
|
-
to_scope:
|
|
2267
|
-
reason:
|
|
2268
|
-
});
|
|
2269
|
-
var doctorRunEventSchema =
|
|
2878
|
+
event_type: z16.literal("knowledge_scope_degraded"),
|
|
2879
|
+
stable_id: z16.string(),
|
|
2880
|
+
timestamp: z16.string().datetime(),
|
|
2881
|
+
from_scope: z16.enum(["narrow", "broad"]),
|
|
2882
|
+
to_scope: z16.enum(["narrow", "broad"]),
|
|
2883
|
+
reason: z16.string()
|
|
2884
|
+
});
|
|
2885
|
+
var doctorRunEventSchema = z16.object({
|
|
2270
2886
|
...eventLedgerEnvelopeSchema,
|
|
2271
|
-
event_type:
|
|
2272
|
-
mode:
|
|
2273
|
-
issues:
|
|
2274
|
-
mutations:
|
|
2275
|
-
timestamp:
|
|
2887
|
+
event_type: z16.literal("doctor_run"),
|
|
2888
|
+
mode: z16.enum(["lint", "fix-knowledge"]),
|
|
2889
|
+
issues: z16.number().int().nonnegative(),
|
|
2890
|
+
mutations: z16.number().int().nonnegative().optional(),
|
|
2891
|
+
timestamp: z16.string().datetime()
|
|
2276
2892
|
});
|
|
2277
|
-
var knowledgePathDangledEventSchema =
|
|
2893
|
+
var knowledgePathDangledEventSchema = z16.object({
|
|
2278
2894
|
...eventLedgerEnvelopeSchema,
|
|
2279
|
-
event_type:
|
|
2280
|
-
stable_id:
|
|
2281
|
-
removed_glob:
|
|
2895
|
+
event_type: z16.literal("knowledge_path_dangled"),
|
|
2896
|
+
stable_id: z16.string(),
|
|
2897
|
+
removed_glob: z16.string()
|
|
2282
2898
|
});
|
|
2283
|
-
var relevanceMigrationRunEventSchema =
|
|
2899
|
+
var relevanceMigrationRunEventSchema = z16.object({
|
|
2284
2900
|
...eventLedgerEnvelopeSchema,
|
|
2285
|
-
event_type:
|
|
2286
|
-
timestamp:
|
|
2287
|
-
scanned_count:
|
|
2288
|
-
touched_count:
|
|
2901
|
+
event_type: z16.literal("relevance_migration_run"),
|
|
2902
|
+
timestamp: z16.string().datetime(),
|
|
2903
|
+
scanned_count: z16.number().int().nonnegative(),
|
|
2904
|
+
touched_count: z16.number().int().nonnegative()
|
|
2289
2905
|
});
|
|
2290
|
-
var pendingAutoArchivedEventSchema =
|
|
2906
|
+
var pendingAutoArchivedEventSchema = z16.object({
|
|
2291
2907
|
...eventLedgerEnvelopeSchema,
|
|
2292
|
-
event_type:
|
|
2293
|
-
pending_path:
|
|
2294
|
-
archived_to:
|
|
2295
|
-
reason:
|
|
2908
|
+
event_type: z16.literal("pending_auto_archived"),
|
|
2909
|
+
pending_path: z16.string(),
|
|
2910
|
+
archived_to: z16.string(),
|
|
2911
|
+
reason: z16.string()
|
|
2296
2912
|
});
|
|
2297
|
-
var assistantTurnObservedEventSchema =
|
|
2913
|
+
var assistantTurnObservedEventSchema = z16.object({
|
|
2298
2914
|
...eventLedgerEnvelopeSchema,
|
|
2299
|
-
event_type:
|
|
2300
|
-
kb_line_raw:
|
|
2301
|
-
cite_ids:
|
|
2302
|
-
cite_tags:
|
|
2915
|
+
event_type: z16.literal("assistant_turn_observed"),
|
|
2916
|
+
kb_line_raw: z16.string().nullable(),
|
|
2917
|
+
cite_ids: z16.array(z16.string()).default([]),
|
|
2918
|
+
cite_tags: z16.array(citeTagSchema).default([]),
|
|
2303
2919
|
// v2.0.0-rc.24 TASK-01: per-cite contract commitments. Index-aligned with
|
|
2304
2920
|
// cite_ids/cite_tags (commitments[i] belongs to cite_ids[i]). Each slot
|
|
2305
2921
|
// carries `operators[]` (kind + glob target) or `skip_reason` when the cite
|
|
@@ -2307,72 +2923,201 @@ var assistantTurnObservedEventSchema = z18.object({
|
|
|
2307
2923
|
// empty array via `.default([])` and are excluded from contract-policy
|
|
2308
2924
|
// audits by the marker-gate (see cite_contract_policy_activated below).
|
|
2309
2925
|
// Mirrors the rc.20 cite_tags parallel-array evolution exactly.
|
|
2310
|
-
cite_commitments:
|
|
2311
|
-
|
|
2312
|
-
operators:
|
|
2313
|
-
|
|
2314
|
-
kind:
|
|
2315
|
-
target:
|
|
2926
|
+
cite_commitments: z16.array(
|
|
2927
|
+
z16.object({
|
|
2928
|
+
operators: z16.array(
|
|
2929
|
+
z16.object({
|
|
2930
|
+
kind: z16.enum(["edit", "not_edit", "require", "forbid"]),
|
|
2931
|
+
target: z16.string()
|
|
2316
2932
|
})
|
|
2317
2933
|
),
|
|
2318
|
-
skip_reason:
|
|
2934
|
+
skip_reason: z16.string().nullable()
|
|
2319
2935
|
})
|
|
2320
2936
|
).default([]),
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2937
|
+
// lifecycle-refactor W3-T4 (§2 store 轴 / store-qualified 观测): per-cite store
|
|
2938
|
+
// qualifier, index-aligned with cite_ids. Mirrors the cite-line-parser's
|
|
2939
|
+
// `cite_stores` output (`<alias-or-uuid>:<id>` → the qualifier; a bare id →
|
|
2940
|
+
// null). Persists the store provenance the parser already extracts so
|
|
2941
|
+
// doctor --cite-coverage can break compliance down per store WITHOUT joining
|
|
2942
|
+
// against the store registry. Additive `.optional()` (NOT `.default([])`) so
|
|
2943
|
+
// existing inline event constructors stay valid without supplying it — pre-W3-T4
|
|
2944
|
+
// events parse with the field absent and bucket under the unqualified default.
|
|
2945
|
+
cite_stores: z16.array(z16.string().nullable()).optional(),
|
|
2946
|
+
client: z16.enum(["cc", "codex"]).optional(),
|
|
2947
|
+
turn_id: z16.string(),
|
|
2948
|
+
envelope_index: z16.number().int().nonnegative().optional(),
|
|
2949
|
+
timestamp: z16.string().datetime()
|
|
2950
|
+
});
|
|
2951
|
+
var citePolicyActivatedEventSchema = z16.object({
|
|
2952
|
+
...eventLedgerEnvelopeSchema,
|
|
2953
|
+
event_type: z16.literal("cite_policy_activated"),
|
|
2954
|
+
policy_version: z16.string(),
|
|
2955
|
+
timestamp: z16.string().datetime()
|
|
2956
|
+
});
|
|
2957
|
+
var citeContractPolicyActivatedEventSchema = z16.object({
|
|
2958
|
+
...eventLedgerEnvelopeSchema,
|
|
2959
|
+
event_type: z16.literal("cite_contract_policy_activated")
|
|
2325
2960
|
});
|
|
2326
|
-
var
|
|
2961
|
+
var eventsRotatedEventSchema = z16.object({
|
|
2327
2962
|
...eventLedgerEnvelopeSchema,
|
|
2328
|
-
event_type:
|
|
2329
|
-
|
|
2330
|
-
|
|
2963
|
+
event_type: z16.literal("events_rotated"),
|
|
2964
|
+
cutoff_ts: z16.string().datetime(),
|
|
2965
|
+
archived_count: z16.number().int().nonnegative(),
|
|
2966
|
+
kept_count: z16.number().int().nonnegative(),
|
|
2967
|
+
archive_path: z16.string()
|
|
2331
2968
|
});
|
|
2332
|
-
var
|
|
2969
|
+
var knowledgeMetaAutoHealedEventSchema = z16.object({
|
|
2333
2970
|
...eventLedgerEnvelopeSchema,
|
|
2334
|
-
event_type:
|
|
2971
|
+
event_type: z16.literal("knowledge_meta_auto_healed"),
|
|
2972
|
+
previous_revision_hash: z16.string(),
|
|
2973
|
+
revision_hash: z16.string(),
|
|
2974
|
+
trigger: z16.literal("read"),
|
|
2975
|
+
caller: z16.enum(["planContext", "getKnowledgeSections", "getKnowledge", "extractKnowledge"]).optional()
|
|
2335
2976
|
});
|
|
2336
|
-
var
|
|
2977
|
+
var serveLockClearedEventSchema = z16.object({
|
|
2337
2978
|
...eventLedgerEnvelopeSchema,
|
|
2338
|
-
event_type:
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
archive_path: z18.string()
|
|
2979
|
+
event_type: z16.literal("serve_lock_cleared"),
|
|
2980
|
+
pid: z16.number().int().nonnegative(),
|
|
2981
|
+
age_ms: z16.number().int().nonnegative(),
|
|
2982
|
+
timestamp: z16.string().datetime()
|
|
2343
2983
|
});
|
|
2344
|
-
var
|
|
2984
|
+
var knowledgeEnrichedEventSchema = z16.object({
|
|
2345
2985
|
...eventLedgerEnvelopeSchema,
|
|
2346
|
-
event_type:
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2986
|
+
event_type: z16.literal("knowledge_enriched"),
|
|
2987
|
+
path: z16.string(),
|
|
2988
|
+
added_fields: z16.array(z16.enum(["intent_clues", "tech_stack", "impact", "must_read_if"])),
|
|
2989
|
+
mode: z16.enum(["auto", "preview", "readonly", "interactive"]),
|
|
2990
|
+
timestamp: z16.string().datetime()
|
|
2351
2991
|
});
|
|
2352
|
-
var
|
|
2992
|
+
var sessionArchiveAttemptedEventSchema = z16.object({
|
|
2353
2993
|
...eventLedgerEnvelopeSchema,
|
|
2354
|
-
event_type:
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2994
|
+
event_type: z16.literal("session_archive_attempted"),
|
|
2995
|
+
outcome: z16.enum(["proposed", "viability_failed", "user_dismissed", "skipped_no_signal"]),
|
|
2996
|
+
covered_through_ts: z16.number().int().nonnegative(),
|
|
2997
|
+
candidates_proposed: z16.number().int().nonnegative().default(0),
|
|
2998
|
+
knowledge_proposed_ids: z16.array(z16.string()).default([])
|
|
2358
2999
|
});
|
|
2359
|
-
var
|
|
3000
|
+
var hookSurfaceEmittedEventSchema = z16.object({
|
|
3001
|
+
...eventLedgerEnvelopeSchema,
|
|
3002
|
+
event_type: z16.literal("hook_surface_emitted"),
|
|
3003
|
+
hook_name: z16.string(),
|
|
3004
|
+
client: z16.enum(["cc", "codex"]),
|
|
3005
|
+
target_channel: z16.string(),
|
|
3006
|
+
rendered_ids: z16.array(z16.string()),
|
|
3007
|
+
delivery_status: z16.enum(["delivered", "suppressed", "error"]),
|
|
3008
|
+
suppression_reason: z16.string().optional()
|
|
3009
|
+
});
|
|
3010
|
+
var hookSignalEmittedEventSchema = z16.object({
|
|
2360
3011
|
...eventLedgerEnvelopeSchema,
|
|
2361
|
-
event_type:
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
3012
|
+
event_type: z16.literal("hook_signal_emitted"),
|
|
3013
|
+
signal_type: z16.enum(["archive", "review", "maintenance", "other"]),
|
|
3014
|
+
threshold: z16.number(),
|
|
3015
|
+
actual_value: z16.number(),
|
|
3016
|
+
fired: z16.boolean()
|
|
2366
3017
|
});
|
|
2367
|
-
var
|
|
3018
|
+
var mcpStdioTraceEventSchema = z16.object({
|
|
3019
|
+
...eventLedgerEnvelopeSchema,
|
|
3020
|
+
event_type: z16.literal("mcp_stdio_trace"),
|
|
3021
|
+
tool_name: z16.string(),
|
|
3022
|
+
request_id: z16.string(),
|
|
3023
|
+
duration_ms: z16.number().nonnegative(),
|
|
3024
|
+
status: z16.enum(["ok", "error"]),
|
|
3025
|
+
payload_bytes_in: z16.number().int().nonnegative(),
|
|
3026
|
+
payload_bytes_out: z16.number().int().nonnegative(),
|
|
3027
|
+
error_code: z16.string().optional()
|
|
3028
|
+
});
|
|
3029
|
+
var payloadGuardObservedEventSchema = z16.object({
|
|
2368
3030
|
...eventLedgerEnvelopeSchema,
|
|
2369
|
-
event_type:
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
3031
|
+
event_type: z16.literal("payload_guard_observed"),
|
|
3032
|
+
tool_name: z16.string(),
|
|
3033
|
+
path_count: z16.number().int().nonnegative(),
|
|
3034
|
+
tokens_estimated: z16.number().int().nonnegative(),
|
|
3035
|
+
truncated: z16.boolean(),
|
|
3036
|
+
cap: z16.number().int().positive()
|
|
3037
|
+
});
|
|
3038
|
+
var skillInvocationStartedEventSchema = z16.object({
|
|
3039
|
+
...eventLedgerEnvelopeSchema,
|
|
3040
|
+
event_type: z16.literal("skill_invocation_started"),
|
|
3041
|
+
skill_name: z16.string(),
|
|
3042
|
+
trigger_source: z16.enum(["user", "auto_invoke", "ai_self_trigger", "chained"]),
|
|
3043
|
+
entry_point: z16.string()
|
|
2374
3044
|
});
|
|
2375
|
-
var
|
|
3045
|
+
var skillInvocationCompletedEventSchema = z16.object({
|
|
3046
|
+
...eventLedgerEnvelopeSchema,
|
|
3047
|
+
event_type: z16.literal("skill_invocation_completed"),
|
|
3048
|
+
skill_name: z16.string(),
|
|
3049
|
+
trigger_source: z16.enum(["user", "auto_invoke", "ai_self_trigger", "chained"]),
|
|
3050
|
+
entry_point: z16.string(),
|
|
3051
|
+
outcome: z16.enum(["completed", "aborted", "error", "no_op"]),
|
|
3052
|
+
elapsed_ms: z16.number().nonnegative().optional()
|
|
3053
|
+
});
|
|
3054
|
+
var skillPhaseTransitionEventSchema = z16.object({
|
|
3055
|
+
...eventLedgerEnvelopeSchema,
|
|
3056
|
+
event_type: z16.literal("skill_phase_transition"),
|
|
3057
|
+
skill_name: z16.string(),
|
|
3058
|
+
phase: z16.string(),
|
|
3059
|
+
status: z16.enum(["entered", "completed", "skipped", "failed"]),
|
|
3060
|
+
checkpoint: z16.string().optional(),
|
|
3061
|
+
elapsed_ms: z16.number().nonnegative().optional()
|
|
3062
|
+
});
|
|
3063
|
+
var skillTriggerCandidateEventSchema = z16.object({
|
|
3064
|
+
...eventLedgerEnvelopeSchema,
|
|
3065
|
+
event_type: z16.literal("skill_trigger_candidate"),
|
|
3066
|
+
skill_name: z16.string(),
|
|
3067
|
+
trigger_source: z16.enum(["user", "auto_invoke", "ai_self_trigger", "chained"]),
|
|
3068
|
+
signal: z16.string(),
|
|
3069
|
+
invoked: z16.boolean()
|
|
3070
|
+
});
|
|
3071
|
+
var llmJudgeRunEventSchema = z16.object({
|
|
3072
|
+
...eventLedgerEnvelopeSchema,
|
|
3073
|
+
event_type: z16.literal("llm_judge_run"),
|
|
3074
|
+
prompt: z16.string(),
|
|
3075
|
+
version: z16.string(),
|
|
3076
|
+
model: z16.string(),
|
|
3077
|
+
input_trace_id: z16.string(),
|
|
3078
|
+
score: z16.number(),
|
|
3079
|
+
rationale: z16.string()
|
|
3080
|
+
});
|
|
3081
|
+
var clientCapabilitySnapshotEventSchema = z16.object({
|
|
3082
|
+
...eventLedgerEnvelopeSchema,
|
|
3083
|
+
event_type: z16.literal("client_capability_snapshot"),
|
|
3084
|
+
client: z16.enum(["cc", "codex"]),
|
|
3085
|
+
capabilities: z16.array(z16.string()),
|
|
3086
|
+
version: z16.string()
|
|
3087
|
+
});
|
|
3088
|
+
var sessionEndedEventSchema = z16.object({
|
|
3089
|
+
...eventLedgerEnvelopeSchema,
|
|
3090
|
+
event_type: z16.literal("session_ended")
|
|
3091
|
+
});
|
|
3092
|
+
var fileMutatedEventSchema = z16.object({
|
|
3093
|
+
...eventLedgerEnvelopeSchema,
|
|
3094
|
+
event_type: z16.literal("file_mutated"),
|
|
3095
|
+
path: z16.string(),
|
|
3096
|
+
tool_call_id: z16.string(),
|
|
3097
|
+
tool_name: z16.string().optional(),
|
|
3098
|
+
source_event_id: z16.string().optional(),
|
|
3099
|
+
store_id: z16.string().optional()
|
|
3100
|
+
});
|
|
3101
|
+
var knowledgeBodyReadEventSchema = z16.object({
|
|
3102
|
+
...eventLedgerEnvelopeSchema,
|
|
3103
|
+
event_type: z16.literal("knowledge_body_read"),
|
|
3104
|
+
stable_id: z16.string(),
|
|
3105
|
+
store: z16.string().optional(),
|
|
3106
|
+
path: z16.string(),
|
|
3107
|
+
tool_call_id: z16.string().optional(),
|
|
3108
|
+
tool_name: z16.string().optional()
|
|
3109
|
+
});
|
|
3110
|
+
var precompactObservedEventSchema = z16.object({
|
|
3111
|
+
...eventLedgerEnvelopeSchema,
|
|
3112
|
+
event_type: z16.literal("precompact_observed")
|
|
3113
|
+
});
|
|
3114
|
+
var graphEdgeCandidateRequestedEventSchema = z16.object({
|
|
3115
|
+
...eventLedgerEnvelopeSchema,
|
|
3116
|
+
event_type: z16.literal("graph_edge_candidate_requested"),
|
|
3117
|
+
stable_id: z16.string(),
|
|
3118
|
+
store: z16.string().optional()
|
|
3119
|
+
});
|
|
3120
|
+
var eventLedgerEventSchema = z16.discriminatedUnion("event_type", [
|
|
2376
3121
|
knowledgeContextPlannedEventSchema,
|
|
2377
3122
|
knowledgeSelectionEventSchema,
|
|
2378
3123
|
knowledgeSectionsFetchedEventSchema,
|
|
@@ -2382,10 +3127,6 @@ var eventLedgerEventSchema = z18.discriminatedUnion("event_type", [
|
|
|
2382
3127
|
reapplyCompletedEventSchema,
|
|
2383
3128
|
installDiffAppliedEventSchema,
|
|
2384
3129
|
eventLedgerTruncatedEventSchema,
|
|
2385
|
-
mcpConfigMigratedEventSchema,
|
|
2386
|
-
// v2.0.0-rc.19 TASK-004: bootstrap_marker_migrated — one-time fabric:knowledge-base
|
|
2387
|
-
// → fabric:bootstrap marker rewrite emitted per file by `fabric doctor --fix`.
|
|
2388
|
-
bootstrapMarkerMigratedEventSchema,
|
|
2389
3130
|
metaReconciledOnStartupEventSchema,
|
|
2390
3131
|
metaReconciledEventSchema,
|
|
2391
3132
|
claudeSkillPathMigratedEventSchema,
|
|
@@ -2397,6 +3138,7 @@ var eventLedgerEventSchema = z18.discriminatedUnion("event_type", [
|
|
|
2397
3138
|
knowledgePromoteStartedEventSchema,
|
|
2398
3139
|
knowledgePromotedEventSchema,
|
|
2399
3140
|
knowledgePromoteFailedEventSchema,
|
|
3141
|
+
knowledgeModifiedEventSchema,
|
|
2400
3142
|
knowledgeLayerChangedEventSchema,
|
|
2401
3143
|
// v2.0.0-rc.37 NEW-24: dedicated old→new stable_id mapping event
|
|
2402
3144
|
knowledgeIdRedirectEventSchema,
|
|
@@ -2453,14 +3195,63 @@ var eventLedgerEventSchema = z18.discriminatedUnion("event_type", [
|
|
|
2453
3195
|
// fabric-archive skill at the end of every invocation. Drives Phase 0.0
|
|
2454
3196
|
// cross-session digest, outcome-based rescan filter (skips user_dismissed),
|
|
2455
3197
|
// covered_through_ts watermark, and `fabric doctor --archive-history`.
|
|
2456
|
-
sessionArchiveAttemptedEventSchema
|
|
3198
|
+
sessionArchiveAttemptedEventSchema,
|
|
3199
|
+
// v2.1 GATE-INSTR (NEW-N-3): 9 interaction-axis instrumentation events.
|
|
3200
|
+
hookSurfaceEmittedEventSchema,
|
|
3201
|
+
hookSignalEmittedEventSchema,
|
|
3202
|
+
mcpStdioTraceEventSchema,
|
|
3203
|
+
payloadGuardObservedEventSchema,
|
|
3204
|
+
skillInvocationStartedEventSchema,
|
|
3205
|
+
skillInvocationCompletedEventSchema,
|
|
3206
|
+
skillPhaseTransitionEventSchema,
|
|
3207
|
+
skillTriggerCandidateEventSchema,
|
|
3208
|
+
llmJudgeRunEventSchema,
|
|
3209
|
+
clientCapabilitySnapshotEventSchema,
|
|
3210
|
+
// lifecycle-refactor Wave 2 — dormant-hook activation markers.
|
|
3211
|
+
sessionEndedEventSchema,
|
|
3212
|
+
fileMutatedEventSchema,
|
|
3213
|
+
// KT-DEC-0030: knowledge_body_read — PostToolUse native-Read consumption marker
|
|
3214
|
+
// (replaces knowledge_consumed as the funnel's "body opened" signal).
|
|
3215
|
+
knowledgeBodyReadEventSchema,
|
|
3216
|
+
precompactObservedEventSchema,
|
|
3217
|
+
graphEdgeCandidateRequestedEventSchema
|
|
2457
3218
|
]);
|
|
3219
|
+
|
|
3220
|
+
// src/text-tokenize.ts
|
|
3221
|
+
var CJK_CLASS = "\\u3400-\\u4dbf\\u4e00-\\u9fff\\uf900-\\ufaff\\u3040-\\u30ff\\uac00-\\ud7af";
|
|
3222
|
+
var RUN_RE = new RegExp(`[a-z0-9]+|[${CJK_CLASS}]+`, "gu");
|
|
3223
|
+
var CJK_FIRST_RE = new RegExp(`[${CJK_CLASS}]`, "u");
|
|
3224
|
+
function tokenize(text) {
|
|
3225
|
+
if (text.length === 0) {
|
|
3226
|
+
return [];
|
|
3227
|
+
}
|
|
3228
|
+
const tokens = [];
|
|
3229
|
+
const lowered = text.toLowerCase();
|
|
3230
|
+
RUN_RE.lastIndex = 0;
|
|
3231
|
+
let match;
|
|
3232
|
+
while ((match = RUN_RE.exec(lowered)) !== null) {
|
|
3233
|
+
const run = match[0];
|
|
3234
|
+
if (CJK_FIRST_RE.test(run[0])) {
|
|
3235
|
+
if (run.length === 1) {
|
|
3236
|
+
tokens.push(run);
|
|
3237
|
+
} else {
|
|
3238
|
+
for (let i = 0; i < run.length - 1; i += 1) {
|
|
3239
|
+
tokens.push(run.slice(i, i + 2));
|
|
3240
|
+
}
|
|
3241
|
+
}
|
|
3242
|
+
} else {
|
|
3243
|
+
tokens.push(run);
|
|
3244
|
+
}
|
|
3245
|
+
}
|
|
3246
|
+
return tokens;
|
|
3247
|
+
}
|
|
2458
3248
|
export {
|
|
2459
3249
|
AGENTS_META_IDENTITY_SOURCES,
|
|
2460
|
-
AGENTS_META_LAYERS,
|
|
2461
3250
|
AGENTS_META_TOPOLOGY_TYPES,
|
|
2462
3251
|
AgentsMetaCountersSchema,
|
|
2463
|
-
|
|
3252
|
+
BOOTSTRAP_CANONICAL_BY_LOCALE,
|
|
3253
|
+
BOOTSTRAP_CANONICAL_EN,
|
|
3254
|
+
BOOTSTRAP_CANONICAL_ZH,
|
|
2464
3255
|
BOOTSTRAP_MARKER_BEGIN,
|
|
2465
3256
|
BOOTSTRAP_MARKER_END,
|
|
2466
3257
|
BOOTSTRAP_REGEX,
|
|
@@ -2479,9 +3270,6 @@ export {
|
|
|
2479
3270
|
KNOWN_SCOPE_PREFIXES,
|
|
2480
3271
|
KnowledgeEntryFrontmatterSchema,
|
|
2481
3272
|
KnowledgeTypeSchema,
|
|
2482
|
-
LEGACY_KB_MARKER_BEGIN,
|
|
2483
|
-
LEGACY_KB_MARKER_END,
|
|
2484
|
-
LEGACY_KB_REGEX,
|
|
2485
3273
|
LayerSchema,
|
|
2486
3274
|
MCP_STORE_AWARE_CONTRACTS,
|
|
2487
3275
|
MCP_STORE_AWARE_TOOLS,
|
|
@@ -2493,30 +3281,34 @@ export {
|
|
|
2493
3281
|
PERSONAL_SCOPE,
|
|
2494
3282
|
PERSONAL_STORE_SENTINEL,
|
|
2495
3283
|
PROJECT_ROOT_SIGNALS,
|
|
2496
|
-
|
|
3284
|
+
PROPOSED_REASON_DESCRIPTIONS_BY_LOCALE,
|
|
2497
3285
|
PROTECTED_TOKENS,
|
|
2498
3286
|
ProposedReasonSchema,
|
|
2499
3287
|
REDACTION_PLACEHOLDER_PREFIX,
|
|
2500
|
-
ResolverNotImplementedError,
|
|
2501
3288
|
SCOPE_COORDINATE_PATTERN,
|
|
2502
3289
|
STORES_ROOT_DIR,
|
|
3290
|
+
STORE_ALIAS_PATTERN,
|
|
2503
3291
|
STORE_GITIGNORE,
|
|
2504
3292
|
STORE_KNOWLEDGE_TYPE_DIRS,
|
|
2505
3293
|
STORE_LAYOUT,
|
|
3294
|
+
STORE_MOUNT_GROUPS,
|
|
3295
|
+
STORE_MOUNT_NAME_PATTERN,
|
|
2506
3296
|
STORE_PENDING_DIR,
|
|
3297
|
+
STORE_PROJECT_ID_PATTERN,
|
|
2507
3298
|
STORE_RESOLVER_WARNING_CODES,
|
|
2508
3299
|
STORE_UUID_PATTERN,
|
|
2509
3300
|
StableIdSchema,
|
|
2510
3301
|
UID_SEGMENT_PATTERN,
|
|
2511
3302
|
addMountedStore,
|
|
3303
|
+
addStoreProject,
|
|
2512
3304
|
agentsIdentitySourceSchema,
|
|
2513
|
-
agentsLayerSchema,
|
|
2514
3305
|
agentsMetaNodeSchema,
|
|
2515
3306
|
agentsMetaSchema,
|
|
2516
3307
|
agentsTopologyTypeSchema,
|
|
2517
3308
|
aggregatePendingAcrossStores,
|
|
2518
3309
|
aiLedgerEntrySchema,
|
|
2519
3310
|
allocateKnowledgeId,
|
|
3311
|
+
allocateStoreKnowledgeId,
|
|
2520
3312
|
annotateIntentRequestSchema,
|
|
2521
3313
|
archiveScanAnnotations,
|
|
2522
3314
|
archiveScanInputSchema,
|
|
@@ -2525,9 +3317,10 @@ export {
|
|
|
2525
3317
|
auditModeSchema,
|
|
2526
3318
|
bindRequiredStore,
|
|
2527
3319
|
bindingsSnapshotPath,
|
|
2528
|
-
bootstrapMarkerMigratedEventSchema,
|
|
2529
3320
|
buildDebugBundle,
|
|
2530
3321
|
buildFailureTrace,
|
|
3322
|
+
buildScanRecommendations,
|
|
3323
|
+
buildStoreResolveInput,
|
|
2531
3324
|
candidateFileEntrySchema,
|
|
2532
3325
|
citeContractMetricsSchema,
|
|
2533
3326
|
citeContractPolicyActivatedEventSchema,
|
|
@@ -2536,6 +3329,7 @@ export {
|
|
|
2536
3329
|
citePolicyActivatedEventSchema,
|
|
2537
3330
|
claudeHookPathMigratedEventSchema,
|
|
2538
3331
|
claudeSkillPathMigratedEventSchema,
|
|
3332
|
+
clientCapabilitySnapshotEventSchema,
|
|
2539
3333
|
clientPathsSchema,
|
|
2540
3334
|
codexSkillPathMigratedEventSchema,
|
|
2541
3335
|
createProjectRootResolver,
|
|
@@ -2545,11 +3339,12 @@ export {
|
|
|
2545
3339
|
defaultLayerFilterSchema,
|
|
2546
3340
|
defaultMessages,
|
|
2547
3341
|
deriveAgentsMetaIdentitySource,
|
|
2548
|
-
deriveAgentsMetaLayer,
|
|
2549
3342
|
deriveAgentsMetaStableId,
|
|
2550
3343
|
deriveAgentsMetaTopologyType,
|
|
3344
|
+
deriveMountLabel,
|
|
2551
3345
|
detachMountedStore,
|
|
2552
3346
|
detectNodeLocale,
|
|
3347
|
+
disambiguateAlias,
|
|
2553
3348
|
doctorRunEventSchema,
|
|
2554
3349
|
driftDetectedEventSchema,
|
|
2555
3350
|
editIntentCheckedEventSchema,
|
|
@@ -2564,6 +3359,7 @@ export {
|
|
|
2564
3359
|
fabricConfigSchema,
|
|
2565
3360
|
fabricEventSchema,
|
|
2566
3361
|
fabricLanguageSchema,
|
|
3362
|
+
fileMutatedEventSchema,
|
|
2567
3363
|
findMountedStore,
|
|
2568
3364
|
findStoreExecutableViolations,
|
|
2569
3365
|
forensicAssertionCoverageSchema,
|
|
@@ -2580,10 +3376,14 @@ export {
|
|
|
2580
3376
|
formatKnowledgeId,
|
|
2581
3377
|
getPanelFieldByKey,
|
|
2582
3378
|
getPanelFields,
|
|
3379
|
+
globalConfigPath,
|
|
2583
3380
|
globalConfigSchema,
|
|
2584
3381
|
globalRefSchema,
|
|
3382
|
+
graphEdgeCandidateRequestedEventSchema,
|
|
2585
3383
|
hasSecrets,
|
|
2586
3384
|
historyStateQuerySchema,
|
|
3385
|
+
hookSignalEmittedEventSchema,
|
|
3386
|
+
hookSurfaceEmittedEventSchema,
|
|
2587
3387
|
humanLedgerEntrySchema,
|
|
2588
3388
|
humanLockApproveRequestSchema,
|
|
2589
3389
|
humanLockEntrySchema,
|
|
@@ -2604,6 +3404,7 @@ export {
|
|
|
2604
3404
|
isPersonalScope,
|
|
2605
3405
|
knowledgeArchiveAttemptedEventSchema,
|
|
2606
3406
|
knowledgeArchivedEventSchema,
|
|
3407
|
+
knowledgeBodyReadEventSchema,
|
|
2607
3408
|
knowledgeConsumedEventSchema,
|
|
2608
3409
|
knowledgeContextPlannedEventSchema,
|
|
2609
3410
|
knowledgeDeferredEventSchema,
|
|
@@ -2613,6 +3414,7 @@ export {
|
|
|
2613
3414
|
knowledgeIdRedirectEventSchema,
|
|
2614
3415
|
knowledgeLayerChangedEventSchema,
|
|
2615
3416
|
knowledgeMetaAutoHealedEventSchema,
|
|
3417
|
+
knowledgeModifiedEventSchema,
|
|
2616
3418
|
knowledgePathDangledEventSchema,
|
|
2617
3419
|
knowledgePromoteFailedEventSchema,
|
|
2618
3420
|
knowledgePromoteStartedEventSchema,
|
|
@@ -2637,18 +3439,24 @@ export {
|
|
|
2637
3439
|
ledgerSourceSchema,
|
|
2638
3440
|
lintCrossStoreReferences,
|
|
2639
3441
|
listStoreKnowledge,
|
|
3442
|
+
llmJudgeRunEventSchema,
|
|
3443
|
+
loadGlobalConfig,
|
|
3444
|
+
loadProjectConfig,
|
|
2640
3445
|
localKnowledgeIdSchema,
|
|
2641
3446
|
lockApprovedEventSchema,
|
|
2642
3447
|
lockDriftEventSchema,
|
|
2643
|
-
|
|
3448
|
+
matchBootstrapCanonicalLocale,
|
|
2644
3449
|
mcpEventLedgerEventSchema,
|
|
2645
3450
|
mcpPayloadLimitsSchema,
|
|
3451
|
+
mcpStdioTraceEventSchema,
|
|
2646
3452
|
metaReconciledEventSchema,
|
|
2647
3453
|
metaReconciledOnStartupEventSchema,
|
|
2648
3454
|
metaUpdatedEventSchema,
|
|
2649
3455
|
mountedStoreSchema,
|
|
2650
3456
|
normalizeCiteTag,
|
|
2651
3457
|
normalizeLocale,
|
|
3458
|
+
nudgeModeSchema,
|
|
3459
|
+
observeConfigSchema,
|
|
2652
3460
|
onboardSlotSchema,
|
|
2653
3461
|
parityCapabilitySchema,
|
|
2654
3462
|
parityClientExpectationSchema,
|
|
@@ -2658,12 +3466,16 @@ export {
|
|
|
2658
3466
|
parseCiteLine,
|
|
2659
3467
|
parseGlobalRef,
|
|
2660
3468
|
parseKnowledgeId,
|
|
3469
|
+
payloadGuardObservedEventSchema,
|
|
2661
3470
|
pendingAutoArchivedEventSchema,
|
|
2662
3471
|
planContextAnnotations,
|
|
2663
3472
|
planContextHintNarrowEntrySchema,
|
|
2664
3473
|
planContextHintOutputSchema,
|
|
2665
3474
|
planContextInputSchema,
|
|
2666
3475
|
planContextOutputSchema,
|
|
3476
|
+
planContextTopKSchema,
|
|
3477
|
+
precompactObservedEventSchema,
|
|
3478
|
+
projectConfigPath,
|
|
2667
3479
|
projectRootGoldenCaseSchema,
|
|
2668
3480
|
projectRootGoldenFileSchema,
|
|
2669
3481
|
projectRootResolutionSchema,
|
|
@@ -2674,41 +3486,69 @@ export {
|
|
|
2674
3486
|
readSetEntrySchema,
|
|
2675
3487
|
readSetGoldenCaseSchema,
|
|
2676
3488
|
readSetGoldenFileSchema,
|
|
3489
|
+
readStoreCounters,
|
|
2677
3490
|
readStoreIdentity,
|
|
3491
|
+
readStoreIdentityAsync,
|
|
3492
|
+
readStoreProjects,
|
|
2678
3493
|
reapplyCompletedEventSchema,
|
|
2679
3494
|
recallAnnotations,
|
|
2680
3495
|
recallInputSchema,
|
|
2681
3496
|
recallOutputSchema,
|
|
2682
3497
|
recognizeStoreDir,
|
|
3498
|
+
reconcileStoreCounters,
|
|
3499
|
+
redactPii,
|
|
2683
3500
|
redactSecrets,
|
|
2684
3501
|
relevanceMigrationRunEventSchema,
|
|
2685
3502
|
requiredStoreEntrySchema,
|
|
3503
|
+
resolveBootstrapCanonical,
|
|
2686
3504
|
resolveCandidates,
|
|
2687
3505
|
resolveFabricLocale,
|
|
3506
|
+
resolveGlobalLocale,
|
|
3507
|
+
resolveGlobalRoot,
|
|
2688
3508
|
resolveStoreQualifiedId,
|
|
3509
|
+
resolveWorkspaceBindingId,
|
|
2689
3510
|
resolvedBindingsSnapshotSchema,
|
|
2690
3511
|
ruleDescriptionIndexItemSchema,
|
|
2691
3512
|
ruleDescriptionSchema,
|
|
3513
|
+
saveGlobalConfig,
|
|
3514
|
+
saveProjectConfig,
|
|
2692
3515
|
scanForSecrets,
|
|
2693
3516
|
scopeCoordinateSchema,
|
|
2694
3517
|
scopeRoot,
|
|
3518
|
+
scrubRemoteUrl,
|
|
2695
3519
|
selectionTokenTtlMsSchema,
|
|
2696
3520
|
serveLockClearedEventSchema,
|
|
2697
3521
|
sessionArchiveAttemptedEventSchema,
|
|
3522
|
+
sessionEndedEventSchema,
|
|
3523
|
+
skillInvocationCompletedEventSchema,
|
|
3524
|
+
skillInvocationStartedEventSchema,
|
|
3525
|
+
skillPhaseTransitionEventSchema,
|
|
3526
|
+
skillTriggerCandidateEventSchema,
|
|
3527
|
+
storeAliasSchema,
|
|
2698
3528
|
storeAwareEntrySchema,
|
|
3529
|
+
storeCountersPath,
|
|
2699
3530
|
storeCountersSchema,
|
|
3531
|
+
storeHasProject,
|
|
2700
3532
|
storeIdentitySchema,
|
|
2701
3533
|
storeKnowledgeTypeDir,
|
|
3534
|
+
storeMountGroup,
|
|
3535
|
+
storeMountNameSchema,
|
|
3536
|
+
storeMountSubPath,
|
|
3537
|
+
storeProjectSchema,
|
|
3538
|
+
storeProjectsFileSchema,
|
|
2702
3539
|
storeReadSetSchema,
|
|
2703
3540
|
storeRelativePath,
|
|
3541
|
+
storeRelativePathForMount,
|
|
2704
3542
|
storeResolveInputSchema,
|
|
2705
3543
|
storeResolverWarningCodeSchema,
|
|
2706
3544
|
storeResolverWarningSchema,
|
|
2707
3545
|
storeUuidSchema,
|
|
2708
3546
|
structuredWarningSchema,
|
|
3547
|
+
tokenize,
|
|
2709
3548
|
uidSchema,
|
|
2710
3549
|
withDerivedAgentsMetaNodeDefaults,
|
|
2711
3550
|
writeBindingsSnapshot,
|
|
3551
|
+
writeRouteSchema,
|
|
2712
3552
|
writeTargetSchema,
|
|
2713
3553
|
writtenToStoreSchema,
|
|
2714
3554
|
zhCNMessages
|