@fenglimg/fabric-server 2.0.0-rc.36 → 2.0.0-rc.37
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/LICENSE +21 -0
- package/README.md +34 -0
- package/dist/index.d.ts +141 -27
- package/dist/index.js +10111 -1693
- package/package.json +30 -8
- package/dist/chunk-5XXH2VZZ.js +0 -7379
- package/dist/http-ZRVOXE6C.js +0 -1286
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 wangzhichao (fenglimg)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# @fenglimg/fabric-server
|
|
2
|
+
|
|
3
|
+
Fabric MCP knowledge server. Runs over stdio transport and serves Claude Code, Cursor, and Codex CLI from a single `.fabric/` directory.
|
|
4
|
+
|
|
5
|
+
## Tools exposed
|
|
6
|
+
|
|
7
|
+
- `fab_plan_context` — neutral rule description index + selection token
|
|
8
|
+
- `fab_get_knowledge_sections` — fetch full markdown bodies by stable_id
|
|
9
|
+
- `fab_recall` — combined one-call recall (plan + sections), the rc.37+ default
|
|
10
|
+
- `fab_extract_knowledge` — persist a pending knowledge entry
|
|
11
|
+
- `fab_review` — list / approve / reject / modify / defer pending entries
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
Usually installed indirectly via [`@fenglimg/fabric-cli`](https://www.npmjs.com/package/@fenglimg/fabric-cli):
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm i -g @fenglimg/fabric-cli
|
|
19
|
+
fabric install
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Direct consumption (programmatic):
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm i @fenglimg/fabric-server
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Repo
|
|
29
|
+
|
|
30
|
+
Source + issues + roadmap: <https://github.com/fenglimg/fabric-v2>
|
|
31
|
+
|
|
32
|
+
## License
|
|
33
|
+
|
|
34
|
+
MIT — see [LICENSE](./LICENSE).
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import { Server } from 'node:http';
|
|
2
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
2
|
import { AgentsMeta, KnowledgeTestIndex, AgentsLayer, AgentsTopologyType, KnowledgeType, Layer, StableId, AgentsMetaCounters, EventLedgerEventInput, EventLedgerEvent, RuleDescriptionIndexItem } from '@fenglimg/fabric-shared';
|
|
4
3
|
import { FabExtractKnowledgeInput, FabExtractKnowledgeOutput, FabReviewInput, FabReviewOutput } from '@fenglimg/fabric-shared/schemas/api-contracts';
|
|
5
|
-
import { IOFabricError } from '@fenglimg/fabric-shared/errors';
|
|
6
4
|
|
|
7
5
|
interface InFlightTracker {
|
|
8
6
|
enter(requestId: string): void;
|
|
@@ -18,9 +16,11 @@ declare function createInFlightTracker(): InFlightTracker;
|
|
|
18
16
|
declare const LEDGER_PATH = ".fabric/.intent-ledger.jsonl";
|
|
19
17
|
declare const LEGACY_LEDGER_PATH = ".intent-ledger.jsonl";
|
|
20
18
|
declare const EVENT_LEDGER_PATH = ".fabric/events.jsonl";
|
|
19
|
+
declare const METRICS_LEDGER_PATH = ".fabric/metrics.jsonl";
|
|
21
20
|
declare function getLedgerPath(projectRoot: string): string;
|
|
22
21
|
declare function getLegacyLedgerPath(projectRoot: string): string;
|
|
23
22
|
declare function getEventLedgerPath(projectRoot: string): string;
|
|
23
|
+
declare function getMetricsLedgerPath(projectRoot: string): string;
|
|
24
24
|
|
|
25
25
|
type DoctorStatus = "ok" | "warn" | "error";
|
|
26
26
|
type DoctorIssueKind = "fixable_error" | "manual_error" | "warning" | "info";
|
|
@@ -164,6 +164,23 @@ type ArchiveHistoryReport = {
|
|
|
164
164
|
declare function runDoctorArchiveHistory(projectRoot: string, options: {
|
|
165
165
|
since: number;
|
|
166
166
|
}): Promise<ArchiveHistoryReport>;
|
|
167
|
+
type HistoryDayRow = {
|
|
168
|
+
date: string;
|
|
169
|
+
doctor_runs_lint: number;
|
|
170
|
+
doctor_runs_fix: number;
|
|
171
|
+
doctor_total_issues: number;
|
|
172
|
+
doctor_total_mutations: number;
|
|
173
|
+
archive_attempts: number;
|
|
174
|
+
archive_proposed: number;
|
|
175
|
+
};
|
|
176
|
+
type HistoryAllReport = {
|
|
177
|
+
rows: HistoryDayRow[];
|
|
178
|
+
since_ms: number;
|
|
179
|
+
generated_at: string;
|
|
180
|
+
};
|
|
181
|
+
declare function runDoctorHistoryAll(projectRoot: string, options: {
|
|
182
|
+
since: number;
|
|
183
|
+
}): Promise<HistoryAllReport>;
|
|
167
184
|
type EnrichDescriptionsMode = "auto" | "preview" | "readonly" | "interactive";
|
|
168
185
|
type EnrichDescriptionsCandidate = {
|
|
169
186
|
path: string;
|
|
@@ -352,6 +369,7 @@ type PlanContextResult = {
|
|
|
352
369
|
};
|
|
353
370
|
auto_healed?: boolean;
|
|
354
371
|
previous_revision_hash?: string;
|
|
372
|
+
redirects?: Record<string, string>;
|
|
355
373
|
};
|
|
356
374
|
type SelectionTokenState = {
|
|
357
375
|
token: string;
|
|
@@ -365,6 +383,126 @@ type SelectionTokenState = {
|
|
|
365
383
|
declare function planContext(projectRoot: string, input: PlanContextInput): Promise<PlanContextResult>;
|
|
366
384
|
declare function readSelectionToken(token: string, now?: number): SelectionTokenState | undefined;
|
|
367
385
|
|
|
386
|
+
type RecallInput = PlanContextInput & {
|
|
387
|
+
/**
|
|
388
|
+
* Optional explicit set of stable_ids to fetch bodies for. When omitted,
|
|
389
|
+
* fab_recall picks up every stable_id surfaced in the shared description
|
|
390
|
+
* index (the common case after rc.37 selectable-filter removal). When
|
|
391
|
+
* provided, filters the fetched body set to this intersection.
|
|
392
|
+
*/
|
|
393
|
+
ids?: string[];
|
|
394
|
+
};
|
|
395
|
+
type RecallResult = PlanContextResult & {
|
|
396
|
+
rules: Array<{
|
|
397
|
+
stable_id: string;
|
|
398
|
+
level: "L0" | "L1" | "L2";
|
|
399
|
+
path: string;
|
|
400
|
+
body: string;
|
|
401
|
+
}>;
|
|
402
|
+
selected_stable_ids: string[];
|
|
403
|
+
diagnostics: Array<{
|
|
404
|
+
code: "missing_knowledge_metadata";
|
|
405
|
+
severity: "warn";
|
|
406
|
+
stable_id: string;
|
|
407
|
+
message: string;
|
|
408
|
+
}>;
|
|
409
|
+
};
|
|
410
|
+
declare function recall(projectRoot: string, input: RecallInput): Promise<RecallResult>;
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* O(1) in-memory increment for a named counter. Safe to call from any MCP
|
|
414
|
+
* tool handler; no I/O happens until the next `flushMetrics()` call.
|
|
415
|
+
*
|
|
416
|
+
* `delta` defaults to 1; callers can pass a positive integer (e.g. fetched
|
|
417
|
+
* N stable_ids in a single sections call) to fold N bumps into one.
|
|
418
|
+
*/
|
|
419
|
+
declare function bumpCounter(projectRoot: string, name: string, delta?: number): void;
|
|
420
|
+
/**
|
|
421
|
+
* Snapshot the current counter accumulator and reset it. Returned map is a
|
|
422
|
+
* frozen copy; the live accumulator starts fresh from zero. Exposed so
|
|
423
|
+
* flushMetrics + tests + a future fab_metrics manual-flush CLI hook can all
|
|
424
|
+
* use the same primitive without racing.
|
|
425
|
+
*/
|
|
426
|
+
declare function drainCounters(projectRoot: string): Record<string, number>;
|
|
427
|
+
/**
|
|
428
|
+
* Drain the current accumulator and append one JSONL row to
|
|
429
|
+
* `.fabric/metrics.jsonl`. Returns the appended row (or `null` when the
|
|
430
|
+
* accumulator was empty — no spurious zero rows). fs failures degrade
|
|
431
|
+
* silently; the next flush will carry the union of the failed-write
|
|
432
|
+
* interval + the current one.
|
|
433
|
+
*/
|
|
434
|
+
declare function flushMetrics(projectRoot: string, options?: {
|
|
435
|
+
windowMs?: number;
|
|
436
|
+
now?: Date;
|
|
437
|
+
}): Promise<MetricsRow | null>;
|
|
438
|
+
/**
|
|
439
|
+
* Start the background flush timer for a project root. Idempotent — calling
|
|
440
|
+
* twice on the same root replaces the prior interval. Returns a stop handle
|
|
441
|
+
* the caller can invoke at shutdown to flush + clear the timer.
|
|
442
|
+
*
|
|
443
|
+
* The flush is fire-and-forget (no await on the setInterval callback) so
|
|
444
|
+
* the timer cadence stays accurate even when fs is slow.
|
|
445
|
+
*/
|
|
446
|
+
declare function startMetricsFlush(projectRoot: string, options?: {
|
|
447
|
+
intervalMs?: number;
|
|
448
|
+
}): () => Promise<void>;
|
|
449
|
+
/**
|
|
450
|
+
* Cancel the background flush timer for a project root if one is running.
|
|
451
|
+
* Does NOT drain the accumulator — callers that want a final flush should
|
|
452
|
+
* await flushMetrics(projectRoot) afterward.
|
|
453
|
+
*/
|
|
454
|
+
declare function stopMetricsFlush(projectRoot: string): void;
|
|
455
|
+
/**
|
|
456
|
+
* Read accumulated metrics rows from `.fabric/metrics.jsonl`. Missing file
|
|
457
|
+
* returns []. Malformed rows are dropped silently (the sidecar is best-
|
|
458
|
+
* effort observability; a corrupt row never blocks a reader).
|
|
459
|
+
*
|
|
460
|
+
* Exposed for the NEW-34 `fab metrics` CLI dashboard + future doctor lints
|
|
461
|
+
* (e.g. cite-goodhart pattern replay) that need counter trends without
|
|
462
|
+
* walking events.jsonl.
|
|
463
|
+
*/
|
|
464
|
+
declare function readMetrics(projectRoot: string): Promise<MetricsRow[]>;
|
|
465
|
+
type MetricsRow = {
|
|
466
|
+
timestamp: string;
|
|
467
|
+
window: string;
|
|
468
|
+
counters: Record<string, number>;
|
|
469
|
+
};
|
|
470
|
+
/**
|
|
471
|
+
* Canonical metric counter names used by the high-frequency emitters that
|
|
472
|
+
* left events.jsonl as part of the rc.37 Wave B clean-slate. Centralized
|
|
473
|
+
* here so the B5 hard-gate (`metric_event_in_jsonl`) can grep for these
|
|
474
|
+
* exact strings and fail when one accidentally re-appears in the audit
|
|
475
|
+
* ledger emit path.
|
|
476
|
+
*/
|
|
477
|
+
declare const METRIC_COUNTER_NAMES: {
|
|
478
|
+
readonly knowledge_consumed: "knowledge_consumed";
|
|
479
|
+
readonly edit_intent_checked: "edit_intent_checked";
|
|
480
|
+
readonly knowledge_context_planned: "knowledge_context_planned";
|
|
481
|
+
readonly knowledge_sections_fetched: "knowledge_sections_fetched";
|
|
482
|
+
};
|
|
483
|
+
type MetricCounterName = (typeof METRIC_COUNTER_NAMES)[keyof typeof METRIC_COUNTER_NAMES];
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Start the background rotation timer for a project root. Idempotent —
|
|
487
|
+
* calling twice on the same root replaces the prior interval. Returns a
|
|
488
|
+
* stop handle the caller can invoke at shutdown.
|
|
489
|
+
*
|
|
490
|
+
* The tick fires fire-and-forget (no await on the setInterval callback) so
|
|
491
|
+
* the cadence stays accurate even when fs is slow. The first tick fires
|
|
492
|
+
* AFTER one full interval — startup-time rotation should run separately
|
|
493
|
+
* if desired (most callers don't, because rotation work blocks the
|
|
494
|
+
* connect path).
|
|
495
|
+
*/
|
|
496
|
+
declare function startRotationTick(projectRoot: string, options?: {
|
|
497
|
+
intervalMs?: number;
|
|
498
|
+
}): () => void;
|
|
499
|
+
/**
|
|
500
|
+
* Cancel the background rotation timer for a project root if one is
|
|
501
|
+
* running. Does NOT trigger a final rotation — callers that want a final
|
|
502
|
+
* rotation should call rotateEventLedgerIfNeeded(projectRoot) directly.
|
|
503
|
+
*/
|
|
504
|
+
declare function stopRotationTick(projectRoot: string): void;
|
|
505
|
+
|
|
368
506
|
/**
|
|
369
507
|
* Shared constants used across the server package.
|
|
370
508
|
*/
|
|
@@ -466,23 +604,6 @@ interface ReconcileKnowledgeOptions {
|
|
|
466
604
|
*/
|
|
467
605
|
declare function reconcileKnowledge(projectRoot: string, opts?: ReconcileKnowledgeOptions): Promise<KnowledgeSyncReport>;
|
|
468
606
|
|
|
469
|
-
declare class ServeLockHeldError extends IOFabricError {
|
|
470
|
-
readonly code = "SERVE_LOCK_HELD";
|
|
471
|
-
readonly httpStatus = 423;
|
|
472
|
-
}
|
|
473
|
-
interface LockState {
|
|
474
|
-
pid: number;
|
|
475
|
-
acquiredAt: number;
|
|
476
|
-
host?: string;
|
|
477
|
-
}
|
|
478
|
-
interface AcquireOptions {
|
|
479
|
-
force?: boolean;
|
|
480
|
-
}
|
|
481
|
-
declare function acquireLock(projectRoot: string, opts?: AcquireOptions): void;
|
|
482
|
-
declare function releaseLock(projectRoot: string): void;
|
|
483
|
-
declare function readLockState(projectRoot: string): LockState | null;
|
|
484
|
-
declare function checkLockOrThrow(projectRoot: string, opts?: AcquireOptions): void;
|
|
485
|
-
|
|
486
607
|
/**
|
|
487
608
|
* Returns an info-level startup message when CLAUDE.md or AGENTS.md exist at
|
|
488
609
|
* the project root, or null when neither is present.
|
|
@@ -517,12 +638,5 @@ interface ShutdownHandlerDeps {
|
|
|
517
638
|
* `invoked` flag, so per-signal dedup is isolated.
|
|
518
639
|
*/
|
|
519
640
|
declare function createShutdownHandler(deps: ShutdownHandlerDeps): () => void;
|
|
520
|
-
declare function startHttpServer(options: {
|
|
521
|
-
port: number;
|
|
522
|
-
projectRoot: string;
|
|
523
|
-
host?: string;
|
|
524
|
-
authToken?: string;
|
|
525
|
-
allowLoopbackNoAuth?: boolean;
|
|
526
|
-
}): Promise<Server>;
|
|
527
641
|
|
|
528
|
-
export { AGENTS_MD_RESOURCE_URI, type
|
|
642
|
+
export { AGENTS_MD_RESOURCE_URI, type ArchiveHistoryEntry, type ArchiveHistoryReport, type CiteCoverageReport, type DoctorApplyLintMutation, type DoctorApplyLintMutationKind, type DoctorApplyLintReport, type DoctorFixReport, type DoctorIssue, type DoctorReport, EVENT_LEDGER_PATH, type EnrichDescriptionsCandidate, type EnrichDescriptionsMode, type EnrichDescriptionsReport, type HistoryAllReport, type HistoryDayRow, type InFlightTracker, KnowledgeIdAllocator, type KnowledgeMetaBuildResult, type KnowledgeMetaBuildSource, type KnowledgeSyncLedgerEvent, type KnowledgeSyncOptions, type KnowledgeSyncReport, LEDGER_PATH, LEGACY_LEDGER_PATH, type LedgerEvent, METRICS_LEDGER_PATH, METRIC_COUNTER_NAMES, type MetricCounterName, type MetricsRow, type PlanContextInput, type PlanContextResult, type RecallInput, type RecallResult, type ReconcileKnowledgeOptions, type RequirementProfile, type SelectionTokenState, type ShutdownHandlerDeps, type StructuredWarning, type WriteKnowledgeMetaOptions, appendEventLedgerEvent, buildKnowledgeMeta, bumpCounter, computeKnowledgeBasedAgentsMeta, computeKnowledgeTestIndex, createFabricServer, createInFlightTracker, createShutdownHandler, deriveKnowledgeMetaLayer, deriveKnowledgeMetaTopologyType, drainCounters, enrichDescriptions, ensureKnowledgeFresh, extractKnowledge, flushAndSyncEventLedger, flushMetrics, formatPreexistingRootMessage, getEventLedgerPath, getLedgerPath, getLegacyLedgerPath, getMetricsLedgerPath, isSameKnowledgeTestIndex, loadKbIdTypeMap, planContext, readMetrics, readSelectionToken, recall, reconcileKnowledge, reviewKnowledge, runDoctorApplyLint, runDoctorArchiveHistory, runDoctorCiteCoverage, runDoctorFix, runDoctorHistoryAll, runDoctorReport, stableStringify, startMetricsFlush, startRotationTick, startStdioServer, stopMetricsFlush, stopRotationTick, writeKnowledgeMeta };
|