@fenglimg/fabric-server 1.5.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,21 +2,26 @@ import {
2
2
  AGENTS_MD_RESOURCE_URI,
3
3
  AgentsMetaFileMissingError,
4
4
  AgentsMetaInvalidError,
5
+ LEDGER_PATH,
6
+ LEGACY_LEDGER_PATH,
5
7
  appendLedgerEntry,
6
8
  approveHumanLock,
7
9
  contextCache,
10
+ ensureParentDirectory,
11
+ getLedgerPath,
12
+ getLegacyLedgerPath,
8
13
  getRules,
9
14
  readAgentsMeta,
10
15
  readHumanLock,
11
16
  readHumanLockEntry,
12
17
  readLedger,
18
+ resolveLedgerPaths,
13
19
  runDoctorReport
14
- } from "./chunk-E3RZ276F.js";
20
+ } from "./chunk-TZCE2K4D.js";
15
21
 
16
22
  // src/http.ts
17
23
  import { randomUUID } from "crypto";
18
24
  import { appendFile, readFile as readFile2 } from "fs/promises";
19
- import { join as join3 } from "path";
20
25
  import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
21
26
  import {
22
27
  StreamableHTTPServerTransport
@@ -126,8 +131,7 @@ import chokidar from "chokidar";
126
131
  var AGENTS_META_PATH = ".fabric/agents.meta.json";
127
132
  var HUMAN_LOCK_PATH = ".fabric/human-lock.json";
128
133
  var FORENSIC_PATH = ".fabric/forensic.json";
129
- var LEDGER_PATH = ".intent-ledger.jsonl";
130
- var WATCHED_PATHS = [AGENTS_META_PATH, HUMAN_LOCK_PATH, FORENSIC_PATH, LEDGER_PATH];
134
+ var WATCHED_PATHS = [AGENTS_META_PATH, HUMAN_LOCK_PATH, FORENSIC_PATH, LEDGER_PATH, LEGACY_LEDGER_PATH];
131
135
  var CONNECTION_LIMIT = 10;
132
136
  var HEARTBEAT_INTERVAL_MS = 3e4;
133
137
  var WATCH_DEBOUNCE_MS = 75;
@@ -166,6 +170,7 @@ function createEventsHandler(options) {
166
170
  const state = {
167
171
  clients: /* @__PURE__ */ new Set(),
168
172
  pendingTimers: /* @__PURE__ */ new Map(),
173
+ activeLedgerPath: getLedgerPath(projectRoot),
169
174
  ledgerOffset: 0,
170
175
  ledgerRemainder: "",
171
176
  humanLockSnapshot: createEmptyHumanLockSnapshot(),
@@ -243,7 +248,9 @@ async function ensureWatcher(state, projectRoot) {
243
248
  if (state.watcher !== void 0) {
244
249
  return;
245
250
  }
246
- state.ledgerOffset = await readFileSize(join(projectRoot, LEDGER_PATH));
251
+ const ledgerState = await resolveLedgerWatchState(projectRoot);
252
+ state.activeLedgerPath = ledgerState.path;
253
+ state.ledgerOffset = ledgerState.size;
247
254
  state.ledgerRemainder = "";
248
255
  state.humanLockSnapshot = await readHumanLockSnapshot(projectRoot);
249
256
  const watcher = chokidar.watch([...WATCHED_PATHS], {
@@ -306,7 +313,7 @@ async function readEventsForFile(state, projectRoot, relativePath) {
306
313
  const event = await readDriftDetectedEvent(projectRoot);
307
314
  return event === null ? [] : [event];
308
315
  }
309
- if (relativePath === LEDGER_PATH) {
316
+ if (relativePath === LEDGER_PATH || relativePath === LEGACY_LEDGER_PATH) {
310
317
  return await readLedgerAppendedEvents(state, projectRoot);
311
318
  }
312
319
  return [];
@@ -370,8 +377,14 @@ async function readHumanLockEvents(state, projectRoot) {
370
377
  return events;
371
378
  }
372
379
  async function readLedgerAppendedEvents(state, projectRoot) {
373
- const ledgerPath = join(projectRoot, LEDGER_PATH);
374
- const nextSize = await readFileSize(ledgerPath);
380
+ const ledgerState = await resolveLedgerWatchState(projectRoot);
381
+ const ledgerPath = ledgerState.path;
382
+ const nextSize = ledgerState.size;
383
+ if (ledgerPath !== state.activeLedgerPath) {
384
+ state.activeLedgerPath = ledgerPath;
385
+ state.ledgerOffset = 0;
386
+ state.ledgerRemainder = "";
387
+ }
375
388
  if (nextSize < state.ledgerOffset) {
376
389
  state.ledgerOffset = 0;
377
390
  state.ledgerRemainder = "";
@@ -394,6 +407,12 @@ async function readLedgerAppendedEvents(state, projectRoot) {
394
407
  await handle.close();
395
408
  }
396
409
  }
410
+ async function resolveLedgerWatchState(projectRoot) {
411
+ const paths = await resolveLedgerPaths(projectRoot);
412
+ const path = paths.usingLegacy ? paths.legacyPath : paths.primaryPath;
413
+ const size = await readFileSize(path);
414
+ return { path, size };
415
+ }
397
416
  function parseLedgerAppendedEvent(line) {
398
417
  try {
399
418
  const parsed = JSON.parse(line);
@@ -1084,12 +1103,13 @@ function hashToken(token) {
1084
1103
 
1085
1104
  // src/http.ts
1086
1105
  var DEFAULT_HOST = "127.0.0.1";
1087
- var LEDGER_FILE = ".intent-ledger.jsonl";
1088
1106
  var NOTIFY_DEBOUNCE_MS = 200;
1089
1107
  var JsonlEventStore = class {
1090
- constructor(ledgerPath) {
1108
+ constructor(projectRoot, ledgerPath) {
1109
+ this.projectRoot = projectRoot;
1091
1110
  this.ledgerPath = ledgerPath;
1092
1111
  }
1112
+ projectRoot;
1093
1113
  ledgerPath;
1094
1114
  async storeEvent(streamId, message) {
1095
1115
  const eventId = randomUUID();
@@ -1099,6 +1119,7 @@ var JsonlEventStore = class {
1099
1119
  streamId,
1100
1120
  message
1101
1121
  };
1122
+ await ensureParentDirectory(this.ledgerPath);
1102
1123
  await appendFile(this.ledgerPath, `${JSON.stringify(entry)}
1103
1124
  `, "utf8");
1104
1125
  return eventId;
@@ -1131,9 +1152,17 @@ var JsonlEventStore = class {
1131
1152
  raw = await readFile2(this.ledgerPath, "utf8");
1132
1153
  } catch (error) {
1133
1154
  if (isNodeError2(error) && error.code === "ENOENT") {
1134
- return [];
1155
+ try {
1156
+ raw = await readFile2(getLegacyLedgerPath(this.projectRoot), "utf8");
1157
+ } catch (legacyError) {
1158
+ if (isNodeError2(legacyError) && legacyError.code === "ENOENT") {
1159
+ return [];
1160
+ }
1161
+ throw legacyError;
1162
+ }
1163
+ } else {
1164
+ throw error;
1135
1165
  }
1136
- throw error;
1137
1166
  }
1138
1167
  return raw.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0).map((line) => parseStoredMcpEvent(line)).filter((event) => event !== null);
1139
1168
  }
@@ -1141,8 +1170,8 @@ var JsonlEventStore = class {
1141
1170
  function createFabricHttpApp(options) {
1142
1171
  const { projectRoot, host = DEFAULT_HOST, authToken, dashboardDistPath, dev } = options;
1143
1172
  const app = createMcpExpressApp({ host });
1144
- const ledgerPath = join3(projectRoot, LEDGER_FILE);
1145
- const eventStore = new JsonlEventStore(ledgerPath);
1173
+ const ledgerPath = getLedgerPath(projectRoot);
1174
+ const eventStore = new JsonlEventStore(projectRoot, ledgerPath);
1146
1175
  const sessions = /* @__PURE__ */ new Map();
1147
1176
  process.env.FABRIC_PROJECT_ROOT = projectRoot;
1148
1177
  const cacheWatcher = chokidar2.watch(
package/dist/index.d.ts CHANGED
@@ -2,6 +2,11 @@ import { Server } from 'node:http';
2
2
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
3
  import { AuditMode, LedgerEntry, HumanLockEntry } from '@fenglimg/fabric-shared';
4
4
 
5
+ declare const LEDGER_PATH = ".fabric/.intent-ledger.jsonl";
6
+ declare const LEGACY_LEDGER_PATH = ".intent-ledger.jsonl";
7
+ declare function getLedgerPath(projectRoot: string): string;
8
+ declare function getLegacyLedgerPath(projectRoot: string): string;
9
+
5
10
  type DoctorStatus = "ok" | "warn" | "error";
6
11
  type DoctorCheck = {
7
12
  name: string;
@@ -25,6 +30,9 @@ type DoctorSummary = {
25
30
  lastLedgerEntryTs: number | null;
26
31
  lastLedgerEntryAgeMs: number | null;
27
32
  metaRevision: string | null;
33
+ ledgerPath: string;
34
+ legacyLedgerPath: string;
35
+ legacyLedgerDetected: boolean;
28
36
  audit: {
29
37
  enabled: boolean;
30
38
  mode: AuditMode;
@@ -39,11 +47,17 @@ type DoctorReport = {
39
47
  summary: DoctorSummary;
40
48
  audit: DoctorAuditReport | null;
41
49
  };
50
+ type DoctorFixReport = {
51
+ changed: boolean;
52
+ migratedLedger: boolean;
53
+ message: string;
54
+ report: DoctorReport;
55
+ };
42
56
  type DoctorAuditViolation = {
43
57
  editTs: number;
44
58
  entryId: string;
45
59
  intent: string;
46
- lastGetRulesTs: number | null;
60
+ lastRuleAccessTs: number | null;
47
61
  path: string;
48
62
  };
49
63
  type DoctorAuditReport = {
@@ -55,6 +69,7 @@ type DoctorAuditReport = {
55
69
  violations: DoctorAuditViolation[];
56
70
  };
57
71
  declare function runDoctorReport(target: string): Promise<DoctorReport>;
72
+ declare function runDoctorFix(target: string): Promise<DoctorFixReport>;
58
73
  declare function runDoctorAuditReport(target: string, options?: {
59
74
  force?: boolean;
60
75
  mode?: AuditMode;
@@ -102,4 +117,4 @@ declare function startHttpServer(options: {
102
117
  dev?: boolean;
103
118
  }): Promise<Server>;
104
119
 
105
- export { AGENTS_MD_RESOURCE_URI, type ApproveHumanLockInput, type ApproveHumanLockResult, type DoctorAuditReport, type DoctorReport, type HumanLockStatus, approveHumanLock, createFabricServer, readHumanLock, readHumanLockEntry, runDoctorAuditReport, runDoctorReport, startHttpServer, startStdioServer };
120
+ export { AGENTS_MD_RESOURCE_URI, type ApproveHumanLockInput, type ApproveHumanLockResult, type DoctorAuditReport, type DoctorFixReport, type DoctorReport, type HumanLockStatus, LEDGER_PATH, LEGACY_LEDGER_PATH, approveHumanLock, createFabricServer, getLedgerPath, getLegacyLedgerPath, readHumanLock, readHumanLockEntry, runDoctorAuditReport, runDoctorFix, runDoctorReport, startHttpServer, startStdioServer };