@fenglimg/fabric-shared 1.6.0 → 1.8.0-rc.1

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/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import "./chunk-LXNCAKJZ.js";
1
2
  import {
2
3
  PROTECTED_TOKENS,
3
4
  createTranslator,
@@ -6,8 +7,25 @@ import {
6
7
  enMessages,
7
8
  normalizeLocale,
8
9
  zhCNMessages
9
- } from "./chunk-KNZIX6IL.js";
10
- import "./chunk-LXNCAKJZ.js";
10
+ } from "./chunk-7A3RSITZ.js";
11
+ import {
12
+ annotateIntentRequestSchema,
13
+ getRulesAnnotations,
14
+ getRulesInputSchema,
15
+ getRulesOutputSchema,
16
+ historyStateQuerySchema,
17
+ humanLockApproveRequestSchema,
18
+ humanLockFileParamsSchema,
19
+ ledgerQuerySchema,
20
+ ledgerSourceSchema,
21
+ planContextAnnotations,
22
+ planContextInputSchema,
23
+ planContextOutputSchema,
24
+ ruleSectionsAnnotations,
25
+ ruleSectionsInputSchema,
26
+ ruleSectionsOutputSchema,
27
+ structuredWarningSchema
28
+ } from "./chunk-KV27CZH3.js";
11
29
 
12
30
  // src/schemas/agents-meta.ts
13
31
  import { z } from "zod";
@@ -49,7 +67,8 @@ var agentsMetaNodeBaseSchema = z.object({
49
67
  tier: z.enum(["always", "path", "description"]),
50
68
  description: z.string().optional()
51
69
  }).optional(),
52
- description: ruleDescriptionSchema.optional()
70
+ description: ruleDescriptionSchema.optional(),
71
+ sections: z.array(z.string()).optional()
53
72
  });
54
73
  var agentsMetaNodeSchema = z.preprocess((value) => {
55
74
  if (!isRecord(value) || typeof value.file !== "string") {
@@ -125,59 +144,35 @@ function isRecord(value) {
125
144
  return typeof value === "object" && value !== null;
126
145
  }
127
146
 
128
- // src/schemas/api-contracts.ts
147
+ // src/schemas/rule-test-index.ts
129
148
  import { z as z2 } from "zod";
130
- var ledgerSourceSchema = z2.enum(["ai", "human"]);
131
- var timestampFilterSchema = z2.preprocess((value) => {
132
- if (value === void 0 || value === null || value === "") {
133
- return void 0;
134
- }
135
- if (typeof value === "number") {
136
- return value;
137
- }
138
- if (typeof value === "string") {
139
- const trimmed = value.trim();
140
- if (trimmed.length === 0) {
141
- return void 0;
142
- }
143
- if (/^\d+$/.test(trimmed)) {
144
- return Number.parseInt(trimmed, 10);
145
- }
146
- const parsed = Date.parse(trimmed);
147
- return Number.isNaN(parsed) ? value : parsed;
148
- }
149
- return value;
150
- }, z2.number().int().nonnegative());
151
- var ledgerQuerySchema = z2.object({
152
- source: ledgerSourceSchema.optional(),
153
- since: timestampFilterSchema.optional()
154
- });
155
- var historyStateQuerySchema = z2.object({
156
- ledger_id: z2.string().trim().min(1).optional(),
157
- ts: timestampFilterSchema.optional()
158
- }).superRefine((value, ctx) => {
159
- const provided = [value.ledger_id, value.ts].filter((entry) => entry !== void 0);
160
- if (provided.length !== 1) {
161
- ctx.addIssue({
162
- code: z2.ZodIssueCode.custom,
163
- message: "Provide exactly one of ledger_id or ts.",
164
- path: ["ledger_id"]
165
- });
166
- }
167
- });
168
- var humanLockApproveRequestSchema = z2.object({
169
- file: z2.string().min(1),
170
- start_line: z2.number().int().positive(),
171
- end_line: z2.number().int().positive(),
172
- new_hash: z2.string().min(1)
173
- });
174
- var humanLockFileParamsSchema = z2.object({
175
- file: z2.string().min(1)
176
- });
177
- var annotateIntentRequestSchema = z2.object({
178
- ledger_entry_id: z2.string().min(1),
179
- annotation: z2.string().trim().min(1)
180
- });
149
+ var RULE_TEST_INDEX_SCHEMA_VERSION = 1;
150
+ var hashSchema = z2.string().min(1);
151
+ var ruleTestLinkSchema = z2.object({
152
+ rule_stable_id: z2.string().min(1),
153
+ rule_file: z2.string().min(1),
154
+ rule_hash: hashSchema,
155
+ previous_rule_hash: hashSchema.optional(),
156
+ test_file: z2.string().min(1),
157
+ test_hash: hashSchema,
158
+ previous_test_hash: hashSchema.optional(),
159
+ annotation_line: z2.number().int().positive()
160
+ }).strict();
161
+ var ruleTestOrphanAnnotationSchema = z2.object({
162
+ rule_stable_id: z2.string().min(1),
163
+ test_file: z2.string().min(1),
164
+ test_hash: hashSchema,
165
+ previous_test_hash: hashSchema.optional(),
166
+ annotation_line: z2.number().int().positive()
167
+ }).strict();
168
+ var ruleTestIndexSchema = z2.object({
169
+ schema_version: z2.literal(RULE_TEST_INDEX_SCHEMA_VERSION),
170
+ generated_at: z2.string().datetime({ offset: true }),
171
+ revision: z2.string().min(1).optional(),
172
+ previous_revision: z2.string().min(1).optional(),
173
+ links: z2.array(ruleTestLinkSchema),
174
+ orphan_annotations: z2.array(ruleTestOrphanAnnotationSchema)
175
+ }).strict();
181
176
 
182
177
  // src/schemas/ledger-entry.ts
183
178
  import { z as z3 } from "zod";
@@ -230,17 +225,19 @@ var clientPathsSchema = z5.object({
230
225
  claudeCodeCLI: z5.string().optional(),
231
226
  claudeCodeDesktop: z5.string().optional(),
232
227
  cursor: z5.string().optional(),
233
- windsurf: z5.string().optional(),
234
- rooCode: z5.string().optional(),
235
- geminiCLI: z5.string().optional(),
236
228
  codexCLI: z5.string().optional()
237
- });
229
+ }).passthrough();
230
+ var mcpPayloadLimitsSchema = z5.object({
231
+ warnBytes: z5.number().int().positive().optional(),
232
+ hardBytes: z5.number().int().positive().optional()
233
+ }).optional();
238
234
  var fabricConfigSchema = z5.object({
239
235
  clientPaths: clientPathsSchema.optional(),
240
236
  externalFixturePath: z5.string().optional(),
241
237
  scanIgnores: z5.array(z5.string()).optional(),
242
238
  auditMode: auditModeSchema.optional(),
243
- audit_mode: auditModeSchema.optional()
239
+ audit_mode: auditModeSchema.optional(),
240
+ mcpPayloadLimits: mcpPayloadLimitsSchema
244
241
  });
245
242
 
246
243
  // src/schemas/forensic-report.ts
@@ -399,11 +396,179 @@ var fabricEventSchema = z8.discriminatedUnion("type", [
399
396
  ledgerAppendedEventSchema,
400
397
  driftDetectedEventSchema
401
398
  ]);
399
+
400
+ // src/schemas/event-ledger.ts
401
+ import { z as z9 } from "zod";
402
+ var eventLedgerEnvelopeSchema = {
403
+ kind: z9.literal("fabric-event"),
404
+ id: z9.string(),
405
+ ts: z9.number().int().nonnegative(),
406
+ schema_version: z9.literal(1),
407
+ correlation_id: z9.string().optional(),
408
+ session_id: z9.string().optional()
409
+ };
410
+ var stringRecordSchema = z9.record(z9.string());
411
+ var ruleContextPlannedEventSchema = z9.object({
412
+ ...eventLedgerEnvelopeSchema,
413
+ event_type: z9.literal("rule_context_planned"),
414
+ target_paths: z9.array(z9.string()),
415
+ required_stable_ids: z9.array(z9.string()),
416
+ ai_selectable_stable_ids: z9.array(z9.string()),
417
+ final_stable_ids: z9.array(z9.string()),
418
+ selection_token: z9.string().optional(),
419
+ client_hash: z9.string().optional(),
420
+ intent: z9.string().optional(),
421
+ known_tech: z9.array(z9.string()).optional(),
422
+ diagnostics: z9.array(z9.unknown()).optional()
423
+ });
424
+ var ruleSelectionEventSchema = z9.object({
425
+ ...eventLedgerEnvelopeSchema,
426
+ event_type: z9.literal("rule_selection"),
427
+ selection_token: z9.string(),
428
+ target_paths: z9.array(z9.string()),
429
+ required_stable_ids: z9.array(z9.string()),
430
+ ai_selectable_stable_ids: z9.array(z9.string()),
431
+ ai_selected_stable_ids: z9.array(z9.string()),
432
+ final_stable_ids: z9.array(z9.string()),
433
+ ai_selection_reasons: stringRecordSchema,
434
+ rejected_stable_ids: z9.array(z9.string()),
435
+ ignored_stable_ids: z9.array(z9.string())
436
+ });
437
+ var ruleSectionsFetchedEventSchema = z9.object({
438
+ ...eventLedgerEnvelopeSchema,
439
+ event_type: z9.literal("rule_sections_fetched"),
440
+ selection_token: z9.string(),
441
+ target_paths: z9.array(z9.string()).optional(),
442
+ requested_sections: z9.array(z9.string()),
443
+ final_stable_ids: z9.array(z9.string()),
444
+ ai_selected_stable_ids: z9.array(z9.string()),
445
+ diagnostics: z9.array(z9.unknown()).optional()
446
+ });
447
+ var editIntentCheckedEventSchema = z9.object({
448
+ ...eventLedgerEnvelopeSchema,
449
+ event_type: z9.literal("edit_intent_checked"),
450
+ path: z9.string(),
451
+ compliant: z9.boolean(),
452
+ intent: z9.string(),
453
+ ledger_entry_id: z9.string(),
454
+ ledger_source: z9.enum(["ai", "human"]).optional(),
455
+ commit_sha: z9.string().optional(),
456
+ parent_sha: z9.string().optional(),
457
+ parent_ledger_entry_id: z9.string().optional(),
458
+ diff_stat: z9.string().optional(),
459
+ annotation: z9.string().optional(),
460
+ matched_rule_context_ts: z9.number().int().nonnegative().nullable(),
461
+ window_ms: z9.number().int().nonnegative()
462
+ });
463
+ var ruleDriftDetectedEventSchema = z9.object({
464
+ ...eventLedgerEnvelopeSchema,
465
+ event_type: z9.literal("rule_drift_detected"),
466
+ revision: z9.string().optional(),
467
+ drifted_stable_ids: z9.array(z9.string()),
468
+ missing_files: z9.array(z9.string()),
469
+ stale_files: z9.array(z9.string()),
470
+ details: z9.array(
471
+ z9.object({
472
+ file: z9.string(),
473
+ stable_id: z9.string(),
474
+ expected_hash: z9.string(),
475
+ actual_hash: z9.string().nullable()
476
+ })
477
+ ).optional()
478
+ });
479
+ var ruleBaselineAcceptedEventSchema = z9.object({
480
+ ...eventLedgerEnvelopeSchema,
481
+ event_type: z9.literal("rule_baseline_accepted"),
482
+ revision: z9.string(),
483
+ previous_revision: z9.string().optional(),
484
+ accepted_stable_ids: z9.array(z9.string()),
485
+ source: z9.enum(["doctor_fix", "sync_meta"]).optional()
486
+ });
487
+ var baselineSyncedEventSchema = z9.object({
488
+ ...eventLedgerEnvelopeSchema,
489
+ event_type: z9.literal("baseline_synced"),
490
+ revision: z9.string(),
491
+ previous_revision: z9.string().optional(),
492
+ synced_files: z9.array(z9.string()),
493
+ accepted_stable_ids: z9.array(z9.string()),
494
+ source: z9.enum(["doctor_fix", "sync_meta"])
495
+ });
496
+ var mcpEventLedgerEventSchema = z9.object({
497
+ ...eventLedgerEnvelopeSchema,
498
+ event_type: z9.literal("mcp_event"),
499
+ mcp_event_id: z9.string(),
500
+ stream_id: z9.string(),
501
+ message: z9.unknown()
502
+ });
503
+ var reapplyCompletedEventSchema = z9.object({
504
+ ...eventLedgerEnvelopeSchema,
505
+ event_type: z9.literal("reapply_completed"),
506
+ preserved_ledger: z9.boolean(),
507
+ preserved_meta: z9.boolean(),
508
+ rules_count: z9.number().int().nonnegative()
509
+ });
510
+ var eventLedgerTruncatedEventSchema = z9.object({
511
+ ...eventLedgerEnvelopeSchema,
512
+ event_type: z9.literal("event_ledger_truncated"),
513
+ byte_offset: z9.number().int().nonnegative(),
514
+ byte_length: z9.number().int().nonnegative(),
515
+ corrupted_path: z9.string()
516
+ });
517
+ var mcpConfigMigratedEventSchema = z9.object({
518
+ ...eventLedgerEnvelopeSchema,
519
+ event_type: z9.literal("mcp_config_migrated"),
520
+ source: z9.literal("doctor_fix"),
521
+ removed_from: z9.string()
522
+ });
523
+ var metaReconciledOnStartupEventSchema = z9.object({
524
+ ...eventLedgerEnvelopeSchema,
525
+ event_type: z9.literal("meta_reconciled_on_startup"),
526
+ reconciled_files: z9.array(z9.string()),
527
+ duration_ms: z9.number().int().nonnegative(),
528
+ source: z9.literal("reconcileRules")
529
+ });
530
+ var metaReconciledEventSchema = z9.object({
531
+ ...eventLedgerEnvelopeSchema,
532
+ event_type: z9.literal("meta_reconciled"),
533
+ reconciled_files: z9.array(z9.string()),
534
+ duration_ms: z9.number().int().nonnegative(),
535
+ trigger: z9.enum(["doctor", "manual"]),
536
+ source: z9.literal("reconcileRules")
537
+ });
538
+ var claudeSkillPathMigratedEventSchema = z9.object({
539
+ ...eventLedgerEnvelopeSchema,
540
+ event_type: z9.literal("claude_skill_path_migrated"),
541
+ from: z9.string(),
542
+ to: z9.string()
543
+ });
544
+ var legacyClientPathPresentEventSchema = z9.object({
545
+ ...eventLedgerEnvelopeSchema,
546
+ event_type: z9.literal("legacy_client_path_present"),
547
+ removed: z9.array(z9.string())
548
+ });
549
+ var eventLedgerEventSchema = z9.discriminatedUnion("event_type", [
550
+ ruleContextPlannedEventSchema,
551
+ ruleSelectionEventSchema,
552
+ ruleSectionsFetchedEventSchema,
553
+ editIntentCheckedEventSchema,
554
+ ruleDriftDetectedEventSchema,
555
+ ruleBaselineAcceptedEventSchema,
556
+ baselineSyncedEventSchema,
557
+ mcpEventLedgerEventSchema,
558
+ reapplyCompletedEventSchema,
559
+ eventLedgerTruncatedEventSchema,
560
+ mcpConfigMigratedEventSchema,
561
+ metaReconciledOnStartupEventSchema,
562
+ metaReconciledEventSchema,
563
+ claudeSkillPathMigratedEventSchema,
564
+ legacyClientPathPresentEventSchema
565
+ ]);
402
566
  export {
403
567
  AGENTS_META_IDENTITY_SOURCES,
404
568
  AGENTS_META_LAYERS,
405
569
  AGENTS_META_TOPOLOGY_TYPES,
406
570
  PROTECTED_TOKENS,
571
+ RULE_TEST_INDEX_SCHEMA_VERSION,
407
572
  agentsIdentitySourceSchema,
408
573
  agentsLayerSchema,
409
574
  agentsMetaNodeSchema,
@@ -412,7 +577,9 @@ export {
412
577
  aiLedgerEntrySchema,
413
578
  annotateIntentRequestSchema,
414
579
  auditModeSchema,
580
+ baselineSyncedEventSchema,
415
581
  candidateFileEntrySchema,
582
+ claudeSkillPathMigratedEventSchema,
416
583
  clientPathsSchema,
417
584
  createTranslator,
418
585
  defaultMessages,
@@ -422,7 +589,10 @@ export {
422
589
  deriveAgentsMetaTopologyType,
423
590
  detectNodeLocale,
424
591
  driftDetectedEventSchema,
592
+ editIntentCheckedEventSchema,
425
593
  enMessages,
594
+ eventLedgerEventSchema,
595
+ eventLedgerTruncatedEventSchema,
426
596
  fabricConfigSchema,
427
597
  fabricEventSchema,
428
598
  forensicAssertionCoverageSchema,
@@ -435,6 +605,9 @@ export {
435
605
  forensicReportSchema,
436
606
  forensicSamplingBudgetSchema,
437
607
  forensicTopologySchema,
608
+ getRulesAnnotations,
609
+ getRulesInputSchema,
610
+ getRulesOutputSchema,
438
611
  historyStateQuerySchema,
439
612
  humanLedgerEntrySchema,
440
613
  humanLockApproveRequestSchema,
@@ -452,12 +625,34 @@ export {
452
625
  ledgerEntrySchema,
453
626
  ledgerQuerySchema,
454
627
  ledgerSourceSchema,
628
+ legacyClientPathPresentEventSchema,
455
629
  lockApprovedEventSchema,
456
630
  lockDriftEventSchema,
631
+ mcpConfigMigratedEventSchema,
632
+ mcpEventLedgerEventSchema,
633
+ mcpPayloadLimitsSchema,
634
+ metaReconciledEventSchema,
635
+ metaReconciledOnStartupEventSchema,
457
636
  metaUpdatedEventSchema,
458
637
  normalizeLocale,
638
+ planContextAnnotations,
639
+ planContextInputSchema,
640
+ planContextOutputSchema,
641
+ reapplyCompletedEventSchema,
642
+ ruleBaselineAcceptedEventSchema,
643
+ ruleContextPlannedEventSchema,
459
644
  ruleDescriptionIndexItemSchema,
460
645
  ruleDescriptionSchema,
646
+ ruleDriftDetectedEventSchema,
647
+ ruleSectionsAnnotations,
648
+ ruleSectionsFetchedEventSchema,
649
+ ruleSectionsInputSchema,
650
+ ruleSectionsOutputSchema,
651
+ ruleSelectionEventSchema,
652
+ ruleTestIndexSchema,
653
+ ruleTestLinkSchema,
654
+ ruleTestOrphanAnnotationSchema,
655
+ structuredWarningSchema,
461
656
  withDerivedAgentsMetaNodeDefaults,
462
657
  zhCNMessages
463
658
  };
@@ -0,0 +1,14 @@
1
+ interface AtomicWriteOptions {
2
+ fsync?: boolean;
3
+ }
4
+ interface AtomicWriteJsonOptions extends AtomicWriteOptions {
5
+ indent?: number;
6
+ }
7
+ declare function atomicWriteText(path: string, content: string, opts?: AtomicWriteOptions): Promise<void>;
8
+ declare function atomicWriteJson(path: string, value: unknown, opts?: AtomicWriteJsonOptions): Promise<void>;
9
+ interface LedgerWriteQueue {
10
+ append(path: string, line: string): Promise<void>;
11
+ }
12
+ declare function createLedgerWriteQueue(): LedgerWriteQueue;
13
+
14
+ export { type AtomicWriteJsonOptions, type AtomicWriteOptions, type LedgerWriteQueue, atomicWriteJson, atomicWriteText, createLedgerWriteQueue };
@@ -0,0 +1,60 @@
1
+ // src/node/atomic-write.ts
2
+ import { appendFile, open, rename, unlink, writeFile } from "fs/promises";
3
+ function makeTmpSuffix() {
4
+ const rand = Math.floor(Math.random() * 65535).toString(16).padStart(4, "0");
5
+ return `.${process.pid}.${Date.now()}.${rand}.tmp`;
6
+ }
7
+ async function atomicWriteText(path, content, opts) {
8
+ const tmpPath = path + makeTmpSuffix();
9
+ try {
10
+ if (opts?.fsync) {
11
+ const fd = await open(tmpPath, "w");
12
+ try {
13
+ await fd.writeFile(content, "utf8");
14
+ await fd.datasync();
15
+ } finally {
16
+ await fd.close();
17
+ }
18
+ } else {
19
+ await writeFile(tmpPath, content, "utf8");
20
+ }
21
+ await rename(tmpPath, path);
22
+ } catch (err) {
23
+ try {
24
+ await unlink(tmpPath);
25
+ } catch {
26
+ }
27
+ throw err;
28
+ }
29
+ }
30
+ async function atomicWriteJson(path, value, opts) {
31
+ const indent = opts?.indent ?? 2;
32
+ const content = JSON.stringify(value, null, indent) + "\n";
33
+ await atomicWriteText(path, content, { fsync: opts?.fsync });
34
+ }
35
+ function createLedgerWriteQueue() {
36
+ const chains = /* @__PURE__ */ new Map();
37
+ async function doAppend(path, line) {
38
+ const normalized = line.endsWith("\n") ? line : line + "\n";
39
+ await appendFile(path, normalized, "utf8");
40
+ }
41
+ return {
42
+ append(path, line) {
43
+ const prev = chains.get(path) ?? Promise.resolve();
44
+ const next = prev.catch(() => void 0).then(() => doAppend(path, line));
45
+ chains.set(path, next);
46
+ const guarded = next.catch(() => void 0);
47
+ guarded.finally(() => {
48
+ if (chains.get(path) === next) {
49
+ chains.delete(path);
50
+ }
51
+ });
52
+ return next;
53
+ }
54
+ };
55
+ }
56
+ export {
57
+ atomicWriteJson,
58
+ atomicWriteText,
59
+ createLedgerWriteQueue
60
+ };
@@ -0,0 +1,12 @@
1
+ declare const FABRIC_BOOTSTRAP_PATH = ".fabric/bootstrap/README.md";
2
+ /**
3
+ * Build the content for .fabric/bootstrap/README.md.
4
+ *
5
+ * Produces the same structured bootstrap guide that `fab init` writes, using
6
+ * the detected framework kind and the project name from package.json. This
7
+ * lives in shared so both the CLI and the server doctor --fix path can use the
8
+ * identical builder.
9
+ */
10
+ declare function buildBootstrapContent(projectRoot: string): string;
11
+
12
+ export { FABRIC_BOOTSTRAP_PATH, buildBootstrapContent };
@@ -0,0 +1,52 @@
1
+ import {
2
+ detectFramework
3
+ } from "../chunk-GI6L6VTT.js";
4
+
5
+ // src/node/bootstrap-guide.ts
6
+ import { existsSync, readFileSync } from "fs";
7
+ import { join, parse } from "path";
8
+ var FABRIC_BOOTSTRAP_PATH = ".fabric/bootstrap/README.md";
9
+ function buildBootstrapContent(projectRoot) {
10
+ const framework = detectFramework(projectRoot);
11
+ const projectName = readProjectName(projectRoot) ?? parse(projectRoot).base;
12
+ const frameworkKind = framework.kind;
13
+ const content = `# ${projectName} \u2014 Fabric Bootstrap Protocol
14
+
15
+ ## CORE RULES (DO NOT TRANSLATE)
16
+
17
+ MUST: Treat this file as the Fabric Protocol bootstrap for this repository.
18
+ MUST: Treat \`.fabric/rules/\` as the source of truth for all Fabric rule bodies.
19
+ MUST: Before ANY code reading, architecture planning, or logic modification, call \`fab_plan_context(paths=[<target file>])\`, then call \`fab_get_rule_sections\`.
20
+ MUST: When creating or changing an L1/L2 rule node, keep \`.fabric/agents.meta.json\` synchronized through Fabric tooling.
21
+ MUST: Preserve protected tokens exactly: \`AGENTS.md\`, \`.fabric/rules/\`, \`.fabric/agents.meta.json\`, \`fab_plan_context\`, \`fab_get_rule_sections\`, \`rule sources\`, \`rule source mirroring\`, \`MUST\`, \`NEVER\`.
22
+ NEVER: Add import-style directive lines to this bootstrap file.
23
+ NEVER: Put framework, domain, repository rule bodies, or submodule rules in this file.
24
+ NEVER: Create colocated \`AGENTS.md\` rule files under source directories.
25
+
26
+ ## Usage
27
+
28
+ - This file bootstraps the Fabric Protocol; it does not carry project-specific rules.
29
+ - Detailed bootstrap notes are in \`.fabric/bootstrap/README.md\`.
30
+ - Detected framework kind: \`${frameworkKind}\`.
31
+ - This repository uses \`rule source mirroring\`: source directories contain ZERO rule files, while \`.fabric/rules/\` mirrors source paths for AI constraints.
32
+ - Root-level rules belong in \`.fabric/rules/root.md\`; cross-domain rules in \`.fabric/rules/_cross/\`.
33
+ - If \`.fabric/rules/root.md\` is missing, complete the Fabric initialization flow before normal coding.
34
+ `;
35
+ return content;
36
+ }
37
+ function readProjectName(projectRoot) {
38
+ const packageJsonPath = join(projectRoot, "package.json");
39
+ if (!existsSync(packageJsonPath)) {
40
+ return void 0;
41
+ }
42
+ try {
43
+ const raw = JSON.parse(readFileSync(packageJsonPath, "utf8"));
44
+ return typeof raw.name === "string" && raw.name.length > 0 ? raw.name : void 0;
45
+ } catch {
46
+ return void 0;
47
+ }
48
+ }
49
+ export {
50
+ FABRIC_BOOTSTRAP_PATH,
51
+ buildBootstrapContent
52
+ };
@@ -0,0 +1,16 @@
1
+ interface PayloadGuardOptions {
2
+ warnBytes?: number;
3
+ hardBytes?: number;
4
+ }
5
+ interface PayloadGuardResult {
6
+ bytes: number;
7
+ warning?: {
8
+ code: 'mcp_payload_warn';
9
+ message: string;
10
+ bytes: number;
11
+ threshold: number;
12
+ };
13
+ }
14
+ declare function enforcePayloadLimit(serializedPayload: string, opts?: PayloadGuardOptions): PayloadGuardResult;
15
+
16
+ export { type PayloadGuardOptions, type PayloadGuardResult, enforcePayloadLimit };
@@ -0,0 +1,40 @@
1
+ import {
2
+ MCPError
3
+ } from "../chunk-3SZRB42B.js";
4
+
5
+ // src/node/mcp-payload-guard.ts
6
+ var McpPayloadTooLargeError = class extends MCPError {
7
+ code = "MCP_PAYLOAD_TOO_LARGE";
8
+ httpStatus = 413;
9
+ };
10
+ var DEFAULT_WARN = 16384;
11
+ var DEFAULT_HARD = 65536;
12
+ function enforcePayloadLimit(serializedPayload, opts) {
13
+ const warnAt = opts?.warnBytes ?? DEFAULT_WARN;
14
+ const hardAt = opts?.hardBytes ?? DEFAULT_HARD;
15
+ const bytes = Buffer.byteLength(serializedPayload, "utf8");
16
+ if (bytes > hardAt) {
17
+ throw new McpPayloadTooLargeError(
18
+ `MCP payload ${bytes} bytes exceeds hard limit ${hardAt}`,
19
+ {
20
+ actionHint: `Reduce response size or increase fabric.config.json mcpPayloadLimits.hardBytes`,
21
+ details: { bytes, threshold: hardAt }
22
+ }
23
+ );
24
+ }
25
+ if (bytes > warnAt) {
26
+ return {
27
+ bytes,
28
+ warning: {
29
+ code: "mcp_payload_warn",
30
+ message: `Payload ${bytes}B exceeds warning threshold ${warnAt}B`,
31
+ bytes,
32
+ threshold: warnAt
33
+ }
34
+ };
35
+ }
36
+ return { bytes };
37
+ }
38
+ export {
39
+ enforcePayloadLimit
40
+ };