@fenglimg/fabric-server 2.0.0-rc.1 → 2.0.0-rc.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-NRWDWAVO.js → chunk-AR2HV5JT.js} +1762 -273
- package/dist/{http-CHCOF6DJ.js → http-AR26GYEV.js} +12 -151
- package/dist/index.d.ts +131 -30
- package/dist/index.js +1273 -263
- package/package.json +4 -5
- package/dist/static/assets/index-DNSKn-El.js +0 -10
- package/dist/static/assets/index-FoBU5Kta.css +0 -1
- package/dist/static/index.html +0 -16
|
@@ -5,16 +5,16 @@ import {
|
|
|
5
5
|
appendEventLedgerEvent,
|
|
6
6
|
contextCache,
|
|
7
7
|
getEventLedgerPath,
|
|
8
|
+
getKnowledge,
|
|
8
9
|
getLedgerPath,
|
|
9
10
|
getLegacyLedgerPath,
|
|
10
|
-
|
|
11
|
-
invalidateRuleSyncCooldown,
|
|
11
|
+
invalidateKnowledgeSyncCooldown,
|
|
12
12
|
isNodeError,
|
|
13
13
|
readAgentsMeta,
|
|
14
14
|
readEventLedger,
|
|
15
15
|
runDoctorReport,
|
|
16
16
|
sha256
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-AR2HV5JT.js";
|
|
18
18
|
|
|
19
19
|
// src/http.ts
|
|
20
20
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
@@ -86,7 +86,6 @@ import { join } from "path";
|
|
|
86
86
|
import {
|
|
87
87
|
agentsMetaSchema,
|
|
88
88
|
fabricEventSchema,
|
|
89
|
-
forensicReportSchema,
|
|
90
89
|
ledgerEntrySchema as ledgerEntrySchema2
|
|
91
90
|
} from "@fenglimg/fabric-shared";
|
|
92
91
|
import { eventLedgerEventSchema } from "@fenglimg/fabric-shared";
|
|
@@ -131,34 +130,6 @@ async function readLegacyLedger(projectRoot) {
|
|
|
131
130
|
}
|
|
132
131
|
return raw.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0).map((line, index) => parseLedgerLine(line, index)).filter((entry) => entry !== null);
|
|
133
132
|
}
|
|
134
|
-
async function appendLedgerEntry(projectRoot, entry) {
|
|
135
|
-
const nextEntry = createStoredLedgerEntry(entry);
|
|
136
|
-
for (const affectedPath of nextEntry.affected_paths) {
|
|
137
|
-
await appendEventLedgerEvent(projectRoot, {
|
|
138
|
-
event_type: "edit_intent_checked",
|
|
139
|
-
ts: nextEntry.ts,
|
|
140
|
-
path: affectedPath,
|
|
141
|
-
compliant: true,
|
|
142
|
-
intent: nextEntry.intent,
|
|
143
|
-
ledger_entry_id: nextEntry.id,
|
|
144
|
-
ledger_source: nextEntry.source,
|
|
145
|
-
commit_sha: nextEntry.source === "ai" ? nextEntry.commit_sha : void 0,
|
|
146
|
-
parent_sha: nextEntry.source === "human" ? nextEntry.parent_sha : void 0,
|
|
147
|
-
parent_ledger_entry_id: nextEntry.source === "human" ? nextEntry.parent_ledger_entry_id : void 0,
|
|
148
|
-
diff_stat: nextEntry.source === "human" ? nextEntry.diff_stat : void 0,
|
|
149
|
-
annotation: nextEntry.source === "human" ? nextEntry.annotation : void 0,
|
|
150
|
-
matched_rule_context_ts: null,
|
|
151
|
-
window_ms: 0
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
return nextEntry;
|
|
155
|
-
}
|
|
156
|
-
function createStoredLedgerEntry(entry) {
|
|
157
|
-
return ledgerEntrySchema.parse({
|
|
158
|
-
...entry,
|
|
159
|
-
id: entry.id ?? `ledger:${randomUUID()}`
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
133
|
function parseLedgerLine(line, index) {
|
|
163
134
|
try {
|
|
164
135
|
const parsed = JSON.parse(line);
|
|
@@ -253,10 +224,8 @@ async function pathExists(path) {
|
|
|
253
224
|
|
|
254
225
|
// src/api/events.ts
|
|
255
226
|
var AGENTS_META_PATH = ".fabric/agents.meta.json";
|
|
256
|
-
var FORENSIC_PATH = ".fabric/forensic.json";
|
|
257
227
|
var WATCHED_PATHS = [
|
|
258
228
|
AGENTS_META_PATH,
|
|
259
|
-
FORENSIC_PATH,
|
|
260
229
|
EVENT_LEDGER_PATH,
|
|
261
230
|
LEDGER_PATH,
|
|
262
231
|
LEGACY_LEDGER_PATH
|
|
@@ -437,10 +406,6 @@ async function readEventsForFile(state, projectRoot, relativePath) {
|
|
|
437
406
|
const event = await readMetaUpdatedEvent(projectRoot);
|
|
438
407
|
return event === null ? [] : [event];
|
|
439
408
|
}
|
|
440
|
-
if (relativePath === FORENSIC_PATH) {
|
|
441
|
-
const event = await readDriftDetectedEvent(projectRoot);
|
|
442
|
-
return event === null ? [] : [event];
|
|
443
|
-
}
|
|
444
409
|
if (relativePath === EVENT_LEDGER_PATH) {
|
|
445
410
|
return await readEventLedgerAppendedEvents(state, projectRoot);
|
|
446
411
|
}
|
|
@@ -461,18 +426,6 @@ async function readMetaUpdatedEvent(projectRoot) {
|
|
|
461
426
|
payload: parsed
|
|
462
427
|
};
|
|
463
428
|
}
|
|
464
|
-
async function readDriftDetectedEvent(projectRoot) {
|
|
465
|
-
const filePath = join(projectRoot, FORENSIC_PATH);
|
|
466
|
-
const raw = await readUtf8File(filePath);
|
|
467
|
-
if (raw === null) {
|
|
468
|
-
return null;
|
|
469
|
-
}
|
|
470
|
-
const parsed = forensicReportSchema.parse(JSON.parse(raw));
|
|
471
|
-
return {
|
|
472
|
-
type: "drift:detected",
|
|
473
|
-
payload: parsed
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
429
|
async function readLedgerAppendedEvents(state, projectRoot) {
|
|
477
430
|
const ledgerState = await resolveLedgerWatchState(projectRoot);
|
|
478
431
|
const ledgerPath = ledgerState.path;
|
|
@@ -829,60 +782,6 @@ function registerHistoryApi(app, projectRoot) {
|
|
|
829
782
|
});
|
|
830
783
|
}
|
|
831
784
|
|
|
832
|
-
// src/api/intent.ts
|
|
833
|
-
import { annotateIntentRequestSchema } from "@fenglimg/fabric-shared";
|
|
834
|
-
|
|
835
|
-
// src/services/annotate-intent.ts
|
|
836
|
-
async function annotateIntent(projectRoot, input) {
|
|
837
|
-
const entries = await readLedger(projectRoot);
|
|
838
|
-
const parentEntry = entries.find((entry2) => entry2.id === input.ledger_entry_id);
|
|
839
|
-
if (parentEntry === void 0) {
|
|
840
|
-
throw new LedgerEntryNotFoundError(`Cannot find ledger entry: ${input.ledger_entry_id}`);
|
|
841
|
-
}
|
|
842
|
-
const lastEntry = entries[entries.length - 1];
|
|
843
|
-
if (lastEntry?.source === "human" && lastEntry.parent_ledger_entry_id === input.ledger_entry_id && lastEntry.annotation === input.annotation) {
|
|
844
|
-
return {
|
|
845
|
-
created: false,
|
|
846
|
-
entry: lastEntry
|
|
847
|
-
};
|
|
848
|
-
}
|
|
849
|
-
const entry = await appendLedgerEntry(projectRoot, createAnnotationEntry(parentEntry, input));
|
|
850
|
-
return {
|
|
851
|
-
created: true,
|
|
852
|
-
entry
|
|
853
|
-
};
|
|
854
|
-
}
|
|
855
|
-
function createAnnotationEntry(parentEntry, input) {
|
|
856
|
-
return {
|
|
857
|
-
ts: Date.now(),
|
|
858
|
-
source: "human",
|
|
859
|
-
parent_sha: input.ledger_entry_id,
|
|
860
|
-
parent_ledger_entry_id: input.ledger_entry_id,
|
|
861
|
-
intent: input.annotation,
|
|
862
|
-
annotation: input.annotation,
|
|
863
|
-
affected_paths: parentEntry.affected_paths,
|
|
864
|
-
diff_stat: "annotation"
|
|
865
|
-
};
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
// src/api/intent.ts
|
|
869
|
-
function registerIntentApi(app, projectRoot) {
|
|
870
|
-
app.post("/api/intent/annotate", async (req, res) => {
|
|
871
|
-
const validation = annotateIntentRequestSchema.safeParse(req.body);
|
|
872
|
-
if (!validation.success) {
|
|
873
|
-
sendValidationError(res, "Invalid intent annotation payload", validation.error.flatten());
|
|
874
|
-
return;
|
|
875
|
-
}
|
|
876
|
-
try {
|
|
877
|
-
await readAgentsMeta(projectRoot);
|
|
878
|
-
const result = await annotateIntent(projectRoot, validation.data);
|
|
879
|
-
res.status(result.created ? 201 : 200).json(result);
|
|
880
|
-
} catch (error) {
|
|
881
|
-
sendUnknownError(res, error);
|
|
882
|
-
}
|
|
883
|
-
});
|
|
884
|
-
}
|
|
885
|
-
|
|
886
785
|
// src/api/ledger.ts
|
|
887
786
|
import { ledgerQuerySchema } from "@fenglimg/fabric-shared";
|
|
888
787
|
function registerLedgerApi(app, projectRoot) {
|
|
@@ -904,8 +803,8 @@ function registerLedgerApi(app, projectRoot) {
|
|
|
904
803
|
});
|
|
905
804
|
}
|
|
906
805
|
|
|
907
|
-
// src/api/
|
|
908
|
-
function
|
|
806
|
+
// src/api/knowledge.ts
|
|
807
|
+
function registerKnowledgeApi(app, projectRoot) {
|
|
909
808
|
app.get("/api/rules", async (_req, res) => {
|
|
910
809
|
try {
|
|
911
810
|
res.json(await readAgentsMeta(projectRoot));
|
|
@@ -915,8 +814,8 @@ function registerRulesApi(app, projectRoot) {
|
|
|
915
814
|
});
|
|
916
815
|
}
|
|
917
816
|
|
|
918
|
-
// src/api/
|
|
919
|
-
function
|
|
817
|
+
// src/api/knowledge-context.ts
|
|
818
|
+
function registerKnowledgeContextApi(app, projectRoot) {
|
|
920
819
|
app.get("/api/rules/context", async (req, res) => {
|
|
921
820
|
const path = typeof req.query.path === "string" ? req.query.path.trim() : "";
|
|
922
821
|
if (path.length === 0) {
|
|
@@ -928,7 +827,7 @@ function registerRulesContextApi(app, projectRoot) {
|
|
|
928
827
|
return;
|
|
929
828
|
}
|
|
930
829
|
try {
|
|
931
|
-
const result = await
|
|
830
|
+
const result = await getKnowledge(projectRoot, { path });
|
|
932
831
|
res.json(result.rules);
|
|
933
832
|
} catch (error) {
|
|
934
833
|
sendUnknownError(res, error);
|
|
@@ -1059,42 +958,6 @@ function buildRecommendations(input) {
|
|
|
1059
958
|
return recommendations;
|
|
1060
959
|
}
|
|
1061
960
|
|
|
1062
|
-
// src/api/static.ts
|
|
1063
|
-
import { existsSync as existsSync2 } from "fs";
|
|
1064
|
-
import { dirname, resolve as resolve2 } from "path";
|
|
1065
|
-
import { fileURLToPath } from "url";
|
|
1066
|
-
import express from "express";
|
|
1067
|
-
var DEFAULT_STATIC_DIR = resolve2(dirname(fileURLToPath(import.meta.url)), "static");
|
|
1068
|
-
function registerDashboardStatic(app, options = {}) {
|
|
1069
|
-
if (options.dev ?? process.env.NODE_ENV === "development") {
|
|
1070
|
-
return;
|
|
1071
|
-
}
|
|
1072
|
-
const staticDir = resolve2(options.dashboardDistPath ?? DEFAULT_STATIC_DIR);
|
|
1073
|
-
const indexPath = resolve2(staticDir, "index.html");
|
|
1074
|
-
if (!existsSync2(indexPath)) {
|
|
1075
|
-
warnMissingDashboard(staticDir);
|
|
1076
|
-
app.get("/", (_req, res) => {
|
|
1077
|
-
res.status(404).json({
|
|
1078
|
-
error: {
|
|
1079
|
-
code: "DASHBOARD_DIST_MISSING",
|
|
1080
|
-
message: `Fabric dashboard dist was not found at ${staticDir}. Run pnpm --filter @fenglimg/fabric-dashboard build.`
|
|
1081
|
-
}
|
|
1082
|
-
});
|
|
1083
|
-
});
|
|
1084
|
-
return;
|
|
1085
|
-
}
|
|
1086
|
-
app.use("/", express.static(staticDir, { index: "index.html", fallthrough: true }));
|
|
1087
|
-
app.get(/^\/(?!api(?:\/|$)|mcp(?:\/|$)|events(?:\/|$)).*/, (_req, res) => {
|
|
1088
|
-
res.sendFile(indexPath);
|
|
1089
|
-
});
|
|
1090
|
-
}
|
|
1091
|
-
function warnMissingDashboard(staticDir) {
|
|
1092
|
-
process.stderr.write(
|
|
1093
|
-
`[fabric-server] dashboard dist missing at ${staticDir}; '/' will return 404 until dashboard assets are built.
|
|
1094
|
-
`
|
|
1095
|
-
);
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
961
|
// src/middleware/bearer-auth.ts
|
|
1099
962
|
import { createHash, timingSafeEqual } from "crypto";
|
|
1100
963
|
function createBearerAuthMiddleware(token) {
|
|
@@ -1222,11 +1085,11 @@ function handleCacheWatcherEvent(relativePath, projectRoot, sessions, timers) {
|
|
|
1222
1085
|
}
|
|
1223
1086
|
if (normalized.startsWith(".fabric/knowledge/") && normalized.endsWith(".md")) {
|
|
1224
1087
|
contextCache.invalidate("file_watch", projectRoot);
|
|
1225
|
-
|
|
1088
|
+
invalidateKnowledgeSyncCooldown(projectRoot);
|
|
1226
1089
|
}
|
|
1227
1090
|
}
|
|
1228
1091
|
function createFabricHttpApp(options) {
|
|
1229
|
-
const { projectRoot, host = DEFAULT_HOST, authToken
|
|
1092
|
+
const { projectRoot, host = DEFAULT_HOST, authToken } = options;
|
|
1230
1093
|
const app = createMcpExpressApp({ host });
|
|
1231
1094
|
const eventStore = new JsonlEventStore(projectRoot);
|
|
1232
1095
|
const sessions = /* @__PURE__ */ new Map();
|
|
@@ -1280,13 +1143,12 @@ function createFabricHttpApp(options) {
|
|
|
1280
1143
|
app.use("/events", bearerAuth);
|
|
1281
1144
|
app.use("/mcp", bearerAuth);
|
|
1282
1145
|
}
|
|
1283
|
-
|
|
1284
|
-
|
|
1146
|
+
registerKnowledgeApi(app, projectRoot);
|
|
1147
|
+
registerKnowledgeContextApi(app, projectRoot);
|
|
1285
1148
|
registerLedgerApi(app, projectRoot);
|
|
1286
1149
|
registerHistoryApi(app, projectRoot);
|
|
1287
1150
|
registerScanApi(app, projectRoot);
|
|
1288
1151
|
registerDoctorApi(app, projectRoot);
|
|
1289
|
-
registerIntentApi(app, projectRoot);
|
|
1290
1152
|
app.get("/events", createEventsHandler({ projectRoot }));
|
|
1291
1153
|
app.all("/mcp", async (req, res) => {
|
|
1292
1154
|
const sessionId = readHeader(req.headers["mcp-session-id"]);
|
|
@@ -1306,7 +1168,6 @@ function createFabricHttpApp(options) {
|
|
|
1306
1168
|
const session = await createSession(eventStore, sessions);
|
|
1307
1169
|
await session.transport.handleRequest(req, res, req.body);
|
|
1308
1170
|
});
|
|
1309
|
-
registerDashboardStatic(app, { dashboardDistPath, dev });
|
|
1310
1171
|
return app;
|
|
1311
1172
|
}
|
|
1312
1173
|
function notifyAllSessions(sessions, kind, uri) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Server } from 'node:http';
|
|
2
2
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
-
import { AgentsMeta,
|
|
3
|
+
import { AgentsMeta, KnowledgeTestIndex, AgentsLayer, AgentsTopologyType, Layer, KnowledgeType, StableId, AgentsMetaCounters, EventLedgerEventInput, EventLedgerEvent, RuleDescriptionIndexItem } from '@fenglimg/fabric-shared';
|
|
4
|
+
import { FabExtractKnowledgeInput, FabExtractKnowledgeOutput, FabReviewInput, FabReviewOutput } from '@fenglimg/fabric-shared/schemas/api-contracts';
|
|
4
5
|
import { IOFabricError } from '@fenglimg/fabric-shared/errors';
|
|
5
6
|
|
|
6
7
|
interface InFlightTracker {
|
|
@@ -76,25 +77,43 @@ type DoctorFixReport = {
|
|
|
76
77
|
message: string;
|
|
77
78
|
report: DoctorReport;
|
|
78
79
|
};
|
|
80
|
+
type DoctorApplyLintMutationKind = "knowledge_orphan_demote_required" | "knowledge_stale_archive_required" | "knowledge_index_drift" | "knowledge_pending_auto_archive" | "knowledge_session_hints_stale_cleanup";
|
|
81
|
+
type DoctorApplyLintMutation = {
|
|
82
|
+
kind: DoctorApplyLintMutationKind;
|
|
83
|
+
path: string;
|
|
84
|
+
detail: string;
|
|
85
|
+
applied: boolean;
|
|
86
|
+
error?: string;
|
|
87
|
+
};
|
|
88
|
+
type DoctorApplyLintReport = {
|
|
89
|
+
changed: boolean;
|
|
90
|
+
mutations: DoctorApplyLintMutation[];
|
|
91
|
+
manual_errors: DoctorIssue[];
|
|
92
|
+
aborted: boolean;
|
|
93
|
+
abort_reason?: string;
|
|
94
|
+
message: string;
|
|
95
|
+
report: DoctorReport;
|
|
96
|
+
};
|
|
79
97
|
declare function runDoctorReport(target: string): Promise<DoctorReport>;
|
|
80
98
|
declare function runDoctorFix(target: string): Promise<DoctorFixReport>;
|
|
99
|
+
declare function runDoctorApplyLint(target: string): Promise<DoctorApplyLintReport>;
|
|
81
100
|
|
|
82
|
-
type
|
|
83
|
-
type
|
|
101
|
+
type KnowledgeMetaBuildSource = "doctor_fix" | "sync_meta";
|
|
102
|
+
type KnowledgeMetaBuildResult = {
|
|
84
103
|
meta: AgentsMeta;
|
|
85
|
-
|
|
104
|
+
knowledgeTestIndex: KnowledgeTestIndex;
|
|
86
105
|
changed: boolean;
|
|
87
106
|
};
|
|
88
|
-
type
|
|
89
|
-
source:
|
|
107
|
+
type WriteKnowledgeMetaOptions = {
|
|
108
|
+
source: KnowledgeMetaBuildSource;
|
|
90
109
|
};
|
|
91
|
-
declare function
|
|
92
|
-
declare function
|
|
93
|
-
declare function
|
|
94
|
-
declare function
|
|
95
|
-
declare function
|
|
96
|
-
declare function
|
|
97
|
-
declare function
|
|
110
|
+
declare function buildKnowledgeMeta(projectRootInput: string): Promise<KnowledgeMetaBuildResult>;
|
|
111
|
+
declare function writeKnowledgeMeta(projectRootInput: string, options: WriteKnowledgeMetaOptions): Promise<KnowledgeMetaBuildResult>;
|
|
112
|
+
declare function computeKnowledgeBasedAgentsMeta(projectRootInput: string, existingMeta?: AgentsMeta): Promise<AgentsMeta>;
|
|
113
|
+
declare function computeKnowledgeTestIndex(projectRootInput: string, computedMeta: AgentsMeta, previousIndex?: KnowledgeTestIndex): Promise<KnowledgeTestIndex>;
|
|
114
|
+
declare function deriveKnowledgeMetaLayer(relativePath: string): AgentsLayer;
|
|
115
|
+
declare function deriveKnowledgeMetaTopologyType(relativePath: string): AgentsTopologyType;
|
|
116
|
+
declare function isSameKnowledgeTestIndex(left: KnowledgeTestIndex, right: KnowledgeTestIndex): boolean;
|
|
98
117
|
declare function stableStringify(value: unknown): string;
|
|
99
118
|
|
|
100
119
|
/**
|
|
@@ -133,6 +152,39 @@ declare class KnowledgeIdAllocator {
|
|
|
133
152
|
private writeMetaAtomic;
|
|
134
153
|
}
|
|
135
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Append-evidence-on-collision service for fab_extract_knowledge.
|
|
157
|
+
*
|
|
158
|
+
* Idempotency_key = sha256({source_session, type, slug}). When the same
|
|
159
|
+
* triple hits an existing pending file (verified by frontmatter
|
|
160
|
+
* `x-fabric-idempotency-key`), the body is preserved and a fresh
|
|
161
|
+
* `## Evidence (call N)` section is appended — LLM-regenerated summaries
|
|
162
|
+
* stay observable without overwriting prior context.
|
|
163
|
+
*
|
|
164
|
+
* NO `id` frontmatter is written — Q2 late-bind delegates id allocation
|
|
165
|
+
* to rc.3 fab_review approve. See planning-context.md "NO id frontmatter".
|
|
166
|
+
*/
|
|
167
|
+
declare function extractKnowledge(projectRoot: string, input: FabExtractKnowledgeInput): Promise<FabExtractKnowledgeOutput>;
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* v2.0 rc.3 fab_review service.
|
|
171
|
+
*
|
|
172
|
+
* Pure async dispatcher over a discriminated union of 6 actions (list, approve,
|
|
173
|
+
* reject, modify, search, defer). All branches are implemented as of TASK-002.
|
|
174
|
+
*
|
|
175
|
+
* Approve performs late-bind id allocation (KP-/KT- + type-code + monotonic
|
|
176
|
+
* counter via KnowledgeIdAllocator), emits 2-phase events (knowledge_promote_started
|
|
177
|
+
* → knowledge_promoted | knowledge_promote_failed), and uses git mv to preserve
|
|
178
|
+
* file history when the target lives in the team layer (same repo). Personal
|
|
179
|
+
* layer files use plain fs.rename because they live under ~/.fabric/ outside
|
|
180
|
+
* the project's git tree.
|
|
181
|
+
*
|
|
182
|
+
* Modify implements the only legal stable_id mutation: layer-flip across
|
|
183
|
+
* KP/KT counter spaces. Allocates a new id under the target layer, renames
|
|
184
|
+
* the file across layer roots, emits knowledge_layer_changed.
|
|
185
|
+
*/
|
|
186
|
+
declare function reviewKnowledge(projectRoot: string, input: FabReviewInput): Promise<FabReviewOutput>;
|
|
187
|
+
|
|
136
188
|
type StoredEventLedgerEvent = EventLedgerEvent;
|
|
137
189
|
declare function appendEventLedgerEvent(projectRoot: string, event: EventLedgerEventInput): Promise<StoredEventLedgerEvent>;
|
|
138
190
|
/**
|
|
@@ -145,6 +197,57 @@ declare function appendEventLedgerEvent(projectRoot: string, event: EventLedgerE
|
|
|
145
197
|
*/
|
|
146
198
|
declare function flushAndSyncEventLedger(projectRoot: string): void;
|
|
147
199
|
|
|
200
|
+
type PlanContextInput = {
|
|
201
|
+
paths: string[];
|
|
202
|
+
intent?: string;
|
|
203
|
+
known_tech?: string[];
|
|
204
|
+
detected_entities?: Record<string, string[]>;
|
|
205
|
+
client_hash?: string;
|
|
206
|
+
correlation_id?: string;
|
|
207
|
+
session_id?: string;
|
|
208
|
+
target_paths?: string[];
|
|
209
|
+
};
|
|
210
|
+
type RequirementProfile = {
|
|
211
|
+
target_path: string;
|
|
212
|
+
path_segments: string[];
|
|
213
|
+
extension: string;
|
|
214
|
+
known_tech: string[];
|
|
215
|
+
user_intent: string;
|
|
216
|
+
detected_entities: string[];
|
|
217
|
+
};
|
|
218
|
+
type PlanContextEntry = {
|
|
219
|
+
path: string;
|
|
220
|
+
requirement_profile: RequirementProfile;
|
|
221
|
+
description_index: RuleDescriptionIndexItem[];
|
|
222
|
+
};
|
|
223
|
+
type PlanContextResult = {
|
|
224
|
+
revision_hash: string;
|
|
225
|
+
stale: boolean;
|
|
226
|
+
selection_token: string;
|
|
227
|
+
entries: PlanContextEntry[];
|
|
228
|
+
shared: {
|
|
229
|
+
description_index: RuleDescriptionIndexItem[];
|
|
230
|
+
preflight_diagnostics: Array<{
|
|
231
|
+
code: "missing_description";
|
|
232
|
+
severity: "warn";
|
|
233
|
+
message: string;
|
|
234
|
+
stable_ids?: string[];
|
|
235
|
+
path?: string;
|
|
236
|
+
}>;
|
|
237
|
+
};
|
|
238
|
+
};
|
|
239
|
+
type SelectionTokenState = {
|
|
240
|
+
token: string;
|
|
241
|
+
revision_hash: string;
|
|
242
|
+
target_paths: string[];
|
|
243
|
+
required_stable_ids: string[];
|
|
244
|
+
ai_selectable_stable_ids: string[];
|
|
245
|
+
created_at: number;
|
|
246
|
+
expires_at: number;
|
|
247
|
+
};
|
|
248
|
+
declare function planContext(projectRoot: string, input: PlanContextInput): Promise<PlanContextResult>;
|
|
249
|
+
declare function readSelectionToken(token: string, now?: number): SelectionTokenState | undefined;
|
|
250
|
+
|
|
148
251
|
/**
|
|
149
252
|
* Shared constants used across the server package.
|
|
150
253
|
*/
|
|
@@ -152,21 +255,21 @@ declare function flushAndSyncEventLedger(projectRoot: string): void;
|
|
|
152
255
|
declare const AGENTS_MD_RESOURCE_URI = "fabric://bootstrap-readme";
|
|
153
256
|
|
|
154
257
|
/**
|
|
155
|
-
*
|
|
258
|
+
* knowledge-sync.ts — Rule-sync orchestrator framework (R28, TASK-011)
|
|
156
259
|
*
|
|
157
|
-
* Public surface:
|
|
260
|
+
* Public surface: ensureKnowledgeFresh, reconcileKnowledge + exported types.
|
|
158
261
|
* Internal helpers are co-located in this file.
|
|
159
262
|
* Does NOT wire any consumers (MCP tools, doctor, watchers).
|
|
160
263
|
*
|
|
161
264
|
* Distinction between the two public entry points:
|
|
162
265
|
*
|
|
163
|
-
* - `
|
|
266
|
+
* - `ensureKnowledgeFresh`: detects drift, emits ledger events, invalidates cache.
|
|
164
267
|
* Does NOT rewrite agents.meta.json. Optimised for hot-path consumers (MCP tools).
|
|
165
268
|
*
|
|
166
|
-
* - `
|
|
269
|
+
* - `reconcileKnowledge`: full scan + rewrites agents.meta.json (via knowledge-meta-builder)
|
|
167
270
|
* + emits ledger events. Used by startup (TASK-022) and doctor repair (TASK-023).
|
|
168
271
|
*/
|
|
169
|
-
interface
|
|
272
|
+
interface KnowledgeSyncOptions {
|
|
170
273
|
mode?: "incremental" | "full";
|
|
171
274
|
/** When true, invalid frontmatter throws RuleValidationError (default: false — collect as warning). */
|
|
172
275
|
throwOnInvalidFrontmatter?: boolean;
|
|
@@ -178,23 +281,23 @@ interface StructuredWarning {
|
|
|
178
281
|
action_hint: string;
|
|
179
282
|
}
|
|
180
283
|
/**
|
|
181
|
-
* Granular ledger event shape for
|
|
182
|
-
* These are returned in
|
|
284
|
+
* Granular ledger event shape for knowledge-sync operations.
|
|
285
|
+
* These are returned in KnowledgeSyncReport and also appended to the event ledger
|
|
183
286
|
* using the nearest available ledger event type (knowledge_drift_detected).
|
|
184
287
|
* The shape below is what callers receive in `.events`.
|
|
185
288
|
*/
|
|
186
|
-
interface
|
|
289
|
+
interface KnowledgeSyncLedgerEvent {
|
|
187
290
|
type: "rule_content_changed" | "rule_added" | "rule_removed";
|
|
188
291
|
stable_id: string;
|
|
189
292
|
path: string;
|
|
190
293
|
prev_hash: string | null;
|
|
191
294
|
new_hash: string | null;
|
|
192
295
|
changed_fields: string[];
|
|
193
|
-
source: "
|
|
296
|
+
source: "ensureKnowledgeFresh" | "reconcileKnowledge";
|
|
194
297
|
}
|
|
195
298
|
/** Alias so the public API says LedgerEvent (as documented). */
|
|
196
|
-
type LedgerEvent =
|
|
197
|
-
interface
|
|
299
|
+
type LedgerEvent = KnowledgeSyncLedgerEvent;
|
|
300
|
+
interface KnowledgeSyncReport {
|
|
198
301
|
status: "fresh" | "reconciled" | "errors";
|
|
199
302
|
events: LedgerEvent[];
|
|
200
303
|
warnings: StructuredWarning[];
|
|
@@ -205,8 +308,8 @@ interface RuleSyncReport {
|
|
|
205
308
|
* invalidates the cache. Does NOT rewrite agents.meta.json. Optimised for
|
|
206
309
|
* hot-path consumers (MCP tools).
|
|
207
310
|
*/
|
|
208
|
-
declare function
|
|
209
|
-
interface
|
|
311
|
+
declare function ensureKnowledgeFresh(projectRoot: string, opts?: KnowledgeSyncOptions): Promise<KnowledgeSyncReport>;
|
|
312
|
+
interface ReconcileKnowledgeOptions {
|
|
210
313
|
/** Identifies who triggered the reconcile; controls which summary ledger event is written. */
|
|
211
314
|
trigger?: "startup" | "doctor" | "manual";
|
|
212
315
|
}
|
|
@@ -219,7 +322,7 @@ interface ReconcileRulesOptions {
|
|
|
219
322
|
* ledger event is appended after per-file drift events. Other trigger values
|
|
220
323
|
* append a `meta_reconciled` event. Omitting the trigger skips the summary.
|
|
221
324
|
*/
|
|
222
|
-
declare function
|
|
325
|
+
declare function reconcileKnowledge(projectRoot: string, opts?: ReconcileKnowledgeOptions): Promise<KnowledgeSyncReport>;
|
|
223
326
|
|
|
224
327
|
declare class ServeLockHeldError extends IOFabricError {
|
|
225
328
|
readonly code = "SERVE_LOCK_HELD";
|
|
@@ -277,8 +380,6 @@ declare function startHttpServer(options: {
|
|
|
277
380
|
projectRoot: string;
|
|
278
381
|
host?: string;
|
|
279
382
|
authToken?: string;
|
|
280
|
-
dashboardDistPath?: string;
|
|
281
|
-
dev?: boolean;
|
|
282
383
|
}): Promise<Server>;
|
|
283
384
|
|
|
284
|
-
export { AGENTS_MD_RESOURCE_URI, type AcquireOptions, type DoctorFixReport, type DoctorIssue, type DoctorReport, EVENT_LEDGER_PATH, type InFlightTracker, KnowledgeIdAllocator, LEDGER_PATH, LEGACY_LEDGER_PATH, type LedgerEvent, type LockState, type
|
|
385
|
+
export { AGENTS_MD_RESOURCE_URI, type AcquireOptions, type DoctorApplyLintMutation, type DoctorApplyLintMutationKind, type DoctorApplyLintReport, type DoctorFixReport, type DoctorIssue, type DoctorReport, EVENT_LEDGER_PATH, type InFlightTracker, KnowledgeIdAllocator, type KnowledgeMetaBuildResult, type KnowledgeMetaBuildSource, type KnowledgeSyncLedgerEvent, type KnowledgeSyncOptions, type KnowledgeSyncReport, LEDGER_PATH, LEGACY_LEDGER_PATH, type LedgerEvent, type LockState, type PlanContextInput, type PlanContextResult, type ReconcileKnowledgeOptions, type RequirementProfile, type SelectionTokenState, ServeLockHeldError, type ShutdownHandlerDeps, type StructuredWarning, type WriteKnowledgeMetaOptions, acquireLock, appendEventLedgerEvent, buildKnowledgeMeta, checkLockOrThrow, computeKnowledgeBasedAgentsMeta, computeKnowledgeTestIndex, createFabricServer, createInFlightTracker, createShutdownHandler, deriveKnowledgeMetaLayer, deriveKnowledgeMetaTopologyType, ensureKnowledgeFresh, extractKnowledge, flushAndSyncEventLedger, formatPreexistingRootMessage, getEventLedgerPath, getLedgerPath, getLegacyLedgerPath, isSameKnowledgeTestIndex, planContext, readLockState, readSelectionToken, reconcileKnowledge, releaseLock, reviewKnowledge, runDoctorApplyLint, runDoctorFix, runDoctorReport, stableStringify, startHttpServer, startStdioServer, writeKnowledgeMeta };
|