@a-company/sentinel 0.2.0 → 3.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.
package/dist/index.js CHANGED
@@ -1,6 +1,19 @@
1
1
  import {
2
- SentinelStorage
3
- } from "./chunk-KPMG4XED.js";
2
+ SentinelClient,
3
+ SentinelTransport,
4
+ createSentinelClient,
5
+ createSentinelTransport,
6
+ enableSentinel
7
+ } from "./chunk-VQ3SIN7S.js";
8
+ import {
9
+ DEFAULT_AUTH_CONFIG,
10
+ DEFAULT_RATE_LIMIT_CONFIG,
11
+ DEFAULT_SERVER_CONFIG,
12
+ SentinelStorage,
13
+ loadConfig,
14
+ loadServerConfig,
15
+ writeConfig
16
+ } from "./chunk-NTX74ZPM.js";
4
17
 
5
18
  // src/matcher.ts
6
19
  var DEFAULT_CONFIG = {
@@ -498,143 +511,9 @@ var Sentinel = class {
498
511
  }
499
512
  };
500
513
 
501
- // src/config.ts
514
+ // src/detector.ts
502
515
  import * as fs2 from "fs";
503
516
  import * as path2 from "path";
504
- var CONFIG_FILES = [".sentinel.yaml", ".sentinel.yml"];
505
- function loadConfig(projectDir) {
506
- for (const filename of CONFIG_FILES) {
507
- const filePath = path2.join(projectDir, filename);
508
- if (fs2.existsSync(filePath)) {
509
- const content = fs2.readFileSync(filePath, "utf-8");
510
- return parseSimpleYaml(content);
511
- }
512
- }
513
- return null;
514
- }
515
- function writeConfig(projectDir, config) {
516
- const filePath = path2.join(projectDir, ".sentinel.yaml");
517
- const content = serializeSimpleYaml(config);
518
- fs2.writeFileSync(filePath, content, "utf-8");
519
- }
520
- function parseSimpleYaml(content) {
521
- const config = { version: "1.0", project: "" };
522
- const lines = content.split("\n");
523
- let currentSection = null;
524
- let currentSubSection = null;
525
- for (const line of lines) {
526
- const trimmed = line.trimEnd();
527
- if (!trimmed || trimmed.startsWith("#")) continue;
528
- const topMatch = trimmed.match(/^(\w+):\s*(.+)$/);
529
- if (topMatch) {
530
- const [, key, value] = topMatch;
531
- if (key === "version") config.version = value.replace(/['"]/g, "");
532
- else if (key === "project") config.project = value.replace(/['"]/g, "");
533
- else if (key === "environment") config.environment = value.replace(/['"]/g, "");
534
- currentSection = null;
535
- currentSubSection = null;
536
- continue;
537
- }
538
- const sectionMatch = trimmed.match(/^(\w+):$/);
539
- if (sectionMatch) {
540
- currentSection = sectionMatch[1];
541
- currentSubSection = null;
542
- if (currentSection === "symbols" && !config.symbols) {
543
- config.symbols = {};
544
- }
545
- if (currentSection === "routes" && !config.routes) {
546
- config.routes = {};
547
- }
548
- if (currentSection === "scrub" && !config.scrub) {
549
- config.scrub = {};
550
- }
551
- continue;
552
- }
553
- const subMatch = trimmed.match(/^\s{2}(\w+):$/);
554
- if (subMatch && currentSection) {
555
- currentSubSection = subMatch[1];
556
- if (currentSection === "symbols" && config.symbols) {
557
- config.symbols[currentSubSection] = [];
558
- }
559
- if (currentSection === "scrub" && config.scrub) {
560
- config.scrub[currentSubSection] = [];
561
- }
562
- continue;
563
- }
564
- const listMatch = trimmed.match(/^\s+-\s+(.+)$/);
565
- if (listMatch && currentSection && currentSubSection) {
566
- const value = listMatch[1].replace(/['"]/g, "");
567
- if (currentSection === "symbols" && config.symbols) {
568
- const arr = config.symbols[currentSubSection];
569
- if (Array.isArray(arr)) arr.push(value);
570
- }
571
- if (currentSection === "scrub" && config.scrub) {
572
- const arr = config.scrub[currentSubSection];
573
- if (Array.isArray(arr)) arr.push(value);
574
- }
575
- continue;
576
- }
577
- const routeMatch = trimmed.match(/^\s+(['"]?\/[^'"]+['"]?):\s+['"]?([^'"]+)['"]?$/);
578
- if (routeMatch && currentSection === "routes" && config.routes) {
579
- const route = routeMatch[1].replace(/['"]/g, "");
580
- config.routes[route] = routeMatch[2];
581
- continue;
582
- }
583
- }
584
- return config;
585
- }
586
- function serializeSimpleYaml(config) {
587
- const lines = [];
588
- lines.push(`# Sentinel Configuration`);
589
- lines.push(`# Auto-generated \u2014 edit freely`);
590
- lines.push("");
591
- lines.push(`version: "${config.version}"`);
592
- lines.push(`project: "${config.project}"`);
593
- if (config.environment) {
594
- lines.push(`environment: "${config.environment}"`);
595
- }
596
- if (config.symbols) {
597
- lines.push("");
598
- lines.push("symbols:");
599
- for (const [key, values] of Object.entries(config.symbols)) {
600
- if (values && values.length > 0) {
601
- lines.push(` ${key}:`);
602
- for (const v of values) {
603
- lines.push(` - ${v}`);
604
- }
605
- }
606
- }
607
- }
608
- if (config.routes && Object.keys(config.routes).length > 0) {
609
- lines.push("");
610
- lines.push("routes:");
611
- for (const [route, symbol] of Object.entries(config.routes)) {
612
- lines.push(` "${route}": ${symbol}`);
613
- }
614
- }
615
- if (config.scrub) {
616
- lines.push("");
617
- lines.push("scrub:");
618
- if (config.scrub.headers?.length) {
619
- lines.push(" headers:");
620
- for (const h of config.scrub.headers) {
621
- lines.push(` - ${h}`);
622
- }
623
- }
624
- if (config.scrub.fields?.length) {
625
- lines.push(" fields:");
626
- for (const f of config.scrub.fields) {
627
- lines.push(` - ${f}`);
628
- }
629
- }
630
- }
631
- lines.push("");
632
- return lines.join("\n");
633
- }
634
-
635
- // src/detector.ts
636
- import * as fs3 from "fs";
637
- import * as path3 from "path";
638
517
  var DIR_PATTERNS = [
639
518
  { dirs: ["services", "src/services"], prefix: "#", type: "components" },
640
519
  { dirs: ["routes", "src/routes", "api", "src/api"], prefix: "#", type: "components" },
@@ -669,13 +548,13 @@ function detectSymbols(projectDir) {
669
548
  }
670
549
  for (const pattern of DIR_PATTERNS) {
671
550
  for (const dir of pattern.dirs) {
672
- const fullPath = path3.join(projectDir, dir);
673
- if (!fs3.existsSync(fullPath)) continue;
551
+ const fullPath = path2.join(projectDir, dir);
552
+ if (!fs2.existsSync(fullPath)) continue;
674
553
  const files = safeReaddir(fullPath);
675
554
  for (const file of files) {
676
- const ext = path3.extname(file);
555
+ const ext = path2.extname(file);
677
556
  if (!CODE_EXTENSIONS.has(ext)) continue;
678
- const name = path3.basename(file, ext);
557
+ const name = path2.basename(file, ext);
679
558
  if (name === "index" || name.endsWith(".test") || name.endsWith(".spec")) continue;
680
559
  const symbol = `${pattern.prefix}${toKebabCase(name)}`;
681
560
  if (!result[pattern.type].includes(symbol)) {
@@ -691,7 +570,7 @@ function generateConfig(projectDir) {
691
570
  const detected = detectSymbols(projectDir);
692
571
  return {
693
572
  version: "1.0",
694
- project: path3.basename(projectDir),
573
+ project: path2.basename(projectDir),
695
574
  symbols: {
696
575
  components: detected.components.length > 0 ? detected.components : void 0,
697
576
  gates: detected.gates.length > 0 ? detected.gates : void 0,
@@ -702,8 +581,8 @@ function generateConfig(projectDir) {
702
581
  };
703
582
  }
704
583
  function readPurposeFiles(projectDir) {
705
- const paradigmDir = path3.join(projectDir, ".paradigm");
706
- if (!fs3.existsSync(paradigmDir)) return null;
584
+ const paradigmDir = path2.join(projectDir, ".paradigm");
585
+ if (!fs2.existsSync(paradigmDir)) return null;
707
586
  const result = {
708
587
  components: [],
709
588
  gates: [],
@@ -714,7 +593,7 @@ function readPurposeFiles(projectDir) {
714
593
  const purposeFiles = findFiles(projectDir, ".purpose");
715
594
  for (const file of purposeFiles) {
716
595
  try {
717
- const content = fs3.readFileSync(file, "utf-8");
596
+ const content = fs2.readFileSync(file, "utf-8");
718
597
  extractPurposeSymbols(content, result);
719
598
  } catch {
720
599
  }
@@ -767,13 +646,13 @@ function extractPurposeSymbols(content, result) {
767
646
  function scanRoutes(projectDir, result) {
768
647
  const routeDirs = ["routes", "src/routes", "api", "src/api"];
769
648
  for (const dir of routeDirs) {
770
- const fullPath = path3.join(projectDir, dir);
771
- if (!fs3.existsSync(fullPath)) continue;
649
+ const fullPath = path2.join(projectDir, dir);
650
+ if (!fs2.existsSync(fullPath)) continue;
772
651
  const files = safeReaddir(fullPath);
773
652
  for (const file of files) {
774
- const ext = path3.extname(file);
653
+ const ext = path2.extname(file);
775
654
  if (!CODE_EXTENSIONS.has(ext)) continue;
776
- const name = path3.basename(file, ext);
655
+ const name = path2.basename(file, ext);
777
656
  if (name === "index") continue;
778
657
  const routePrefix = `/api/${toKebabCase(name)}`;
779
658
  const component = `#${toKebabCase(name)}`;
@@ -786,10 +665,10 @@ function toKebabCase(str) {
786
665
  }
787
666
  function safeReaddir(dir) {
788
667
  try {
789
- return fs3.readdirSync(dir).filter((f) => {
790
- const fullPath = path3.join(dir, f);
668
+ return fs2.readdirSync(dir).filter((f) => {
669
+ const fullPath = path2.join(dir, f);
791
670
  try {
792
- return fs3.statSync(fullPath).isFile();
671
+ return fs2.statSync(fullPath).isFile();
793
672
  } catch {
794
673
  return false;
795
674
  }
@@ -803,12 +682,12 @@ function findFiles(dir, filename, maxDepth = 4, depth = 0) {
803
682
  const results = [];
804
683
  const skipDirs = /* @__PURE__ */ new Set(["node_modules", "dist", ".git", "coverage", ".next", ".nuxt"]);
805
684
  try {
806
- const entries = fs3.readdirSync(dir, { withFileTypes: true });
685
+ const entries = fs2.readdirSync(dir, { withFileTypes: true });
807
686
  for (const entry of entries) {
808
687
  if (entry.isFile() && entry.name === filename) {
809
- results.push(path3.join(dir, entry.name));
688
+ results.push(path2.join(dir, entry.name));
810
689
  } else if (entry.isDirectory() && !skipDirs.has(entry.name)) {
811
- results.push(...findFiles(path3.join(dir, entry.name), filename, maxDepth, depth + 1));
690
+ results.push(...findFiles(path2.join(dir, entry.name), filename, maxDepth, depth + 1));
812
691
  }
813
692
  }
814
693
  } catch {
@@ -817,11 +696,18 @@ function findFiles(dir, filename, maxDepth = 4, depth = 0) {
817
696
  }
818
697
 
819
698
  // src/grouper.ts
820
- var SIMILARITY_THRESHOLD = 0.6;
699
+ var DEFAULT_SIMILARITY_THRESHOLD = 0.6;
700
+ var DECAY_HALF_LIFE_DAYS = 14;
821
701
  var IncidentGrouper = class {
822
- constructor(storage) {
702
+ constructor(storage, config) {
823
703
  this.storage = storage;
704
+ this.similarityThreshold = config?.similarityThreshold ?? DEFAULT_SIMILARITY_THRESHOLD;
705
+ this.decayHalfLifeDays = config?.decayHalfLifeDays ?? DECAY_HALF_LIFE_DAYS;
706
+ this.useStackFingerprint = config?.useStackFingerprint ?? true;
824
707
  }
708
+ similarityThreshold;
709
+ decayHalfLifeDays;
710
+ useStackFingerprint;
825
711
  /**
826
712
  * Try to find or create a group for an incident
827
713
  * Returns the group ID if grouped, null if no suitable group
@@ -867,7 +753,7 @@ var IncidentGrouper = class {
867
753
  continue;
868
754
  }
869
755
  const score = this.calculateSimilarity(incident, candidate);
870
- if (score >= SIMILARITY_THRESHOLD) {
756
+ if (score >= this.similarityThreshold) {
871
757
  similar.push({ incident: candidate, score });
872
758
  }
873
759
  }
@@ -888,7 +774,7 @@ var IncidentGrouper = class {
888
774
  continue;
889
775
  }
890
776
  const similar = ungrouped.filter(
891
- (other) => other.id !== incident.id && !processed.has(other.id) && this.calculateSimilarity(incident, other) >= SIMILARITY_THRESHOLD
777
+ (other) => other.id !== incident.id && !processed.has(other.id) && this.calculateSimilarity(incident, other) >= this.similarityThreshold
892
778
  );
893
779
  if (similar.length + 1 >= minSize) {
894
780
  const members = [incident, ...similar];
@@ -915,11 +801,17 @@ var IncidentGrouper = class {
915
801
  }
916
802
  /**
917
803
  * Calculate similarity between two incidents (0-1)
804
+ * Applies time-decay so older incidents contribute less, and optionally
805
+ * uses stack trace fingerprinting for more accurate grouping.
918
806
  */
919
807
  calculateSimilarity(a, b) {
920
808
  let score = 0;
921
809
  let maxScore = 0;
922
- const symbolWeight = 0.6;
810
+ const hasStacks = this.useStackFingerprint && a.error.stack && b.error.stack;
811
+ const symbolWeight = hasStacks ? 0.45 : 0.6;
812
+ const errorWeight = hasStacks ? 0.25 : 0.3;
813
+ const envWeight = 0.1;
814
+ const stackWeight = hasStacks ? 0.2 : 0;
923
815
  const symbolTypes = [
924
816
  "feature",
925
817
  "component",
@@ -939,19 +831,55 @@ var IncidentGrouper = class {
939
831
  }
940
832
  }
941
833
  }
942
- const errorWeight = 0.3;
943
834
  const errorSimilarity = this.stringSimilarity(
944
835
  a.error.message,
945
836
  b.error.message
946
837
  );
947
838
  score += errorWeight * errorSimilarity;
948
839
  maxScore += errorWeight;
949
- const envWeight = 0.1;
950
840
  if (a.environment === b.environment) {
951
841
  score += envWeight;
952
842
  }
953
843
  maxScore += envWeight;
954
- return maxScore > 0 ? score / maxScore : 0;
844
+ if (hasStacks) {
845
+ const aFingerprint = this.fingerprintStack(a.error.stack);
846
+ const bFingerprint = this.fingerprintStack(b.error.stack);
847
+ const stackSimilarity = this.compareFingerprints(aFingerprint, bFingerprint);
848
+ score += stackWeight * stackSimilarity;
849
+ maxScore += stackWeight;
850
+ }
851
+ const rawScore = maxScore > 0 ? score / maxScore : 0;
852
+ const timeDelta = Math.abs(
853
+ new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
854
+ );
855
+ const daysDelta = timeDelta / (1e3 * 60 * 60 * 24);
856
+ const decayFactor = Math.pow(0.5, daysDelta / this.decayHalfLifeDays);
857
+ return rawScore * decayFactor;
858
+ }
859
+ /**
860
+ * Extract a fingerprint from a stack trace by normalizing frames.
861
+ * Strips line numbers, column numbers, and absolute paths to capture
862
+ * the structural signature of the call stack.
863
+ */
864
+ fingerprintStack(stack) {
865
+ return stack.split("\n").filter((line) => line.trim().startsWith("at ")).slice(0, 10).map((frame) => {
866
+ return frame.trim().replace(/:\d+:\d+\)?$/, "").replace(/\(.*[/\\]/, "(").replace(/^\s*at\s+/, "");
867
+ });
868
+ }
869
+ /**
870
+ * Compare two stack fingerprints (0-1 similarity)
871
+ */
872
+ compareFingerprints(a, b) {
873
+ if (a.length === 0 && b.length === 0) return 1;
874
+ if (a.length === 0 || b.length === 0) return 0;
875
+ let matches = 0;
876
+ const maxLen = Math.max(a.length, b.length);
877
+ for (let i = 0; i < Math.min(a.length, b.length); i++) {
878
+ if (a[i] === b[i]) {
879
+ matches++;
880
+ }
881
+ }
882
+ return matches / maxLen;
955
883
  }
956
884
  /**
957
885
  * Calculate string similarity using Levenshtein distance
@@ -1491,8 +1419,8 @@ var StatsCalculator = class {
1491
1419
  };
1492
1420
 
1493
1421
  // src/enricher.ts
1494
- import * as fs4 from "fs";
1495
- import * as path4 from "path";
1422
+ import * as fs3 from "fs";
1423
+ import * as path3 from "path";
1496
1424
  var ContextEnricher = class {
1497
1425
  constructor(projectRoot = process.cwd()) {
1498
1426
  this.projectRoot = projectRoot;
@@ -1564,12 +1492,12 @@ var ContextEnricher = class {
1564
1492
  * Find symbol in premise index
1565
1493
  */
1566
1494
  findInSymbolIndex(symbol) {
1567
- const indexPath = path4.join(this.projectRoot, ".paradigm", "index.json");
1568
- if (!fs4.existsSync(indexPath)) {
1495
+ const indexPath = path3.join(this.projectRoot, ".paradigm", "index.json");
1496
+ if (!fs3.existsSync(indexPath)) {
1569
1497
  return null;
1570
1498
  }
1571
1499
  try {
1572
- const indexContent = fs4.readFileSync(indexPath, "utf-8");
1500
+ const indexContent = fs3.readFileSync(indexPath, "utf-8");
1573
1501
  const index = JSON.parse(indexContent);
1574
1502
  if (index.symbols && Array.isArray(index.symbols)) {
1575
1503
  return index.symbols.find(
@@ -1587,8 +1515,8 @@ var ContextEnricher = class {
1587
1515
  findInPurposeFiles(symbol) {
1588
1516
  const searchPaths = this.getSearchPathsForSymbol(symbol);
1589
1517
  for (const searchPath of searchPaths) {
1590
- const fullPath = path4.join(this.projectRoot, searchPath);
1591
- if (!fs4.existsSync(fullPath)) {
1518
+ const fullPath = path3.join(this.projectRoot, searchPath);
1519
+ if (!fs3.existsSync(fullPath)) {
1592
1520
  continue;
1593
1521
  }
1594
1522
  const cached = this.purposeCache.get(fullPath);
@@ -1599,7 +1527,7 @@ var ContextEnricher = class {
1599
1527
  continue;
1600
1528
  }
1601
1529
  try {
1602
- const content = fs4.readFileSync(fullPath, "utf-8");
1530
+ const content = fs3.readFileSync(fullPath, "utf-8");
1603
1531
  const purpose = this.parsePurposeFile(content);
1604
1532
  this.purposeCache.set(fullPath, purpose);
1605
1533
  if (purpose.symbol === symbol) {
@@ -1629,11 +1557,11 @@ var ContextEnricher = class {
1629
1557
  const prefix = symbol[0];
1630
1558
  const dirs = prefixDirs[prefix] || [];
1631
1559
  for (const dir of dirs) {
1632
- paths.push(path4.join(dir, cleanSymbol, ".purpose"));
1633
- paths.push(path4.join(dir, `${cleanSymbol}.purpose`));
1560
+ paths.push(path3.join(dir, cleanSymbol, ".purpose"));
1561
+ paths.push(path3.join(dir, `${cleanSymbol}.purpose`));
1634
1562
  }
1635
- paths.push(path4.join(".paradigm", "purposes", `${cleanSymbol}.yaml`));
1636
- paths.push(path4.join(".paradigm", "purposes", `${cleanSymbol}.json`));
1563
+ paths.push(path3.join(".paradigm", "purposes", `${cleanSymbol}.yaml`));
1564
+ paths.push(path3.join(".paradigm", "purposes", `${cleanSymbol}.json`));
1637
1565
  return paths;
1638
1566
  }
1639
1567
  /**
@@ -1698,7 +1626,7 @@ var PatternSuggester = class {
1698
1626
  },
1699
1627
  resolution: {
1700
1628
  description: incident.resolution?.notes || "Resolution approach TBD",
1701
- strategy: "fix-code",
1629
+ strategy: this.inferStrategy([incident]),
1702
1630
  priority: "medium"
1703
1631
  },
1704
1632
  source: "suggested",
@@ -1713,6 +1641,7 @@ var PatternSuggester = class {
1713
1641
  suggestFromGroup(group) {
1714
1642
  const baseId = `group-${group.id.toLowerCase().replace(/[^a-z0-9]/g, "-")}`;
1715
1643
  const symbols = this.buildSymbolCriteria(group.commonSymbols);
1644
+ const groupIncidents = group.incidents.slice(0, 20).map((id) => this.storage.getIncident(id)).filter((i) => i != null);
1716
1645
  const pattern = {
1717
1646
  id: baseId,
1718
1647
  name: group.name || `Pattern from group ${group.id}`,
@@ -1723,7 +1652,7 @@ var PatternSuggester = class {
1723
1652
  },
1724
1653
  resolution: {
1725
1654
  description: "Resolution approach TBD based on grouped incidents",
1726
- strategy: "fix-code",
1655
+ strategy: groupIncidents.length > 0 ? this.inferStrategy(groupIncidents) : "fix-code",
1727
1656
  priority: this.getPriorityFromCount(group.count)
1728
1657
  },
1729
1658
  source: "suggested",
@@ -2022,21 +1951,38 @@ var PatternSuggester = class {
2022
1951
  return false;
2023
1952
  }
2024
1953
  /**
2025
- * Infer resolution strategy from incidents
1954
+ * Infer resolution strategy from incident error patterns and context.
1955
+ * Uses keyword heuristics across all incident messages to pick the
1956
+ * most likely resolution approach.
2026
1957
  */
2027
1958
  inferStrategy(incidents) {
2028
1959
  const messages = incidents.map((i) => i.error.message.toLowerCase());
2029
- if (messages.some((m) => m.includes("timeout") || m.includes("network"))) {
1960
+ const hasKeyword = (keywords) => messages.some((m) => keywords.some((k) => m.includes(k)));
1961
+ if (hasKeyword(["revert", "rollback", "regression", "broke after deploy", "since deploy"])) {
1962
+ return "rollback";
1963
+ }
1964
+ if (hasKeyword(["config", "environment variable", "env var", "missing key", "secret", "credential"])) {
1965
+ return "config-change";
1966
+ }
1967
+ if (hasKeyword(["out of memory", "oom", "heap", "memory limit", "capacity", "too many connections", "pool exhausted"])) {
1968
+ return "scale-up";
1969
+ }
1970
+ if (hasKeyword(["timeout", "network", "econnrefused", "econnreset", "dns", "socket hang up"])) {
2030
1971
  return "retry";
2031
1972
  }
2032
- if (messages.some(
2033
- (m) => m.includes("validation") || m.includes("invalid") || m.includes("required")
2034
- )) {
1973
+ if (hasKeyword(["unavailable", "service down", "circuit breaker", "fallback", "503", "502"])) {
1974
+ return "fallback";
1975
+ }
1976
+ if (hasKeyword(["validation", "invalid", "required", "constraint", "duplicate", "not found", "404"])) {
2035
1977
  return "fix-data";
2036
1978
  }
2037
- if (messages.some((m) => m.includes("permission") || m.includes("403"))) {
1979
+ if (hasKeyword(["permission", "forbidden", "403", "401", "unauthorized", "access denied"])) {
2038
1980
  return "escalate";
2039
1981
  }
1982
+ const uniqueTypes = new Set(incidents.map((i) => i.error.type).filter(Boolean));
1983
+ if (uniqueTypes.size > 2) {
1984
+ return "investigate";
1985
+ }
2040
1986
  return "fix-code";
2041
1987
  }
2042
1988
  /**
@@ -2051,7 +1997,7 @@ var PatternSuggester = class {
2051
1997
  };
2052
1998
 
2053
1999
  // src/importer.ts
2054
- import * as fs5 from "fs";
2000
+ import * as fs4 from "fs";
2055
2001
  var PatternImporter = class {
2056
2002
  /**
2057
2003
  * Validate a pattern export file
@@ -2146,10 +2092,10 @@ var PatternImporter = class {
2146
2092
  * Load patterns from a JSON file
2147
2093
  */
2148
2094
  loadFromFile(filePath) {
2149
- if (!fs5.existsSync(filePath)) {
2095
+ if (!fs4.existsSync(filePath)) {
2150
2096
  throw new Error(`File not found: ${filePath}`);
2151
2097
  }
2152
- const content = fs5.readFileSync(filePath, "utf-8");
2098
+ const content = fs4.readFileSync(filePath, "utf-8");
2153
2099
  const data = JSON.parse(content);
2154
2100
  const validation = this.validate(data);
2155
2101
  if (!validation.valid) {
@@ -2249,22 +2195,178 @@ var PatternImporter = class {
2249
2195
  };
2250
2196
  }
2251
2197
  };
2198
+
2199
+ // src/schema/builtin-paradigm.ts
2200
+ var PARADIGM_SCHEMA = {
2201
+ id: "paradigm-logger",
2202
+ version: "1.0.0",
2203
+ name: "Paradigm Logger",
2204
+ description: "Structured logs from @a-company/paradigm-logger with symbolic context",
2205
+ scope: {
2206
+ field: "correlationId",
2207
+ type: "string",
2208
+ label: "Correlation",
2209
+ ordering: "independent",
2210
+ sessionField: "sessionId"
2211
+ },
2212
+ eventTypes: [
2213
+ {
2214
+ type: "log:debug",
2215
+ category: "logs",
2216
+ label: "Debug Log",
2217
+ severity: "debug",
2218
+ frequency: "high",
2219
+ fields: [
2220
+ { name: "symbol", type: "string", indexed: true, display: true },
2221
+ { name: "symbolType", type: "string", indexed: true, display: true },
2222
+ { name: "message", type: "string", display: true },
2223
+ { name: "service", type: "string", indexed: true, display: true },
2224
+ { name: "durationMs", type: "number", display: true }
2225
+ ]
2226
+ },
2227
+ {
2228
+ type: "log:info",
2229
+ category: "logs",
2230
+ label: "Info Log",
2231
+ severity: "info",
2232
+ frequency: "high",
2233
+ fields: [
2234
+ { name: "symbol", type: "string", indexed: true, display: true },
2235
+ { name: "symbolType", type: "string", indexed: true, display: true },
2236
+ { name: "message", type: "string", display: true },
2237
+ { name: "service", type: "string", indexed: true, display: true },
2238
+ { name: "durationMs", type: "number", display: true }
2239
+ ]
2240
+ },
2241
+ {
2242
+ type: "log:warn",
2243
+ category: "logs",
2244
+ label: "Warning Log",
2245
+ severity: "warn",
2246
+ frequency: "medium",
2247
+ fields: [
2248
+ { name: "symbol", type: "string", indexed: true, display: true },
2249
+ { name: "symbolType", type: "string", indexed: true, display: true },
2250
+ { name: "message", type: "string", display: true },
2251
+ { name: "service", type: "string", indexed: true, display: true }
2252
+ ]
2253
+ },
2254
+ {
2255
+ type: "log:error",
2256
+ category: "logs",
2257
+ label: "Error Log",
2258
+ severity: "error",
2259
+ frequency: "low",
2260
+ fields: [
2261
+ { name: "symbol", type: "string", indexed: true, display: true },
2262
+ { name: "symbolType", type: "string", indexed: true, display: true },
2263
+ { name: "message", type: "string", display: true },
2264
+ { name: "service", type: "string", indexed: true, display: true }
2265
+ ]
2266
+ },
2267
+ {
2268
+ type: "metric:counter",
2269
+ category: "metrics",
2270
+ label: "Counter Metric",
2271
+ severity: "info",
2272
+ frequency: "high",
2273
+ fields: [
2274
+ { name: "name", type: "string", indexed: true, display: true },
2275
+ { name: "value", type: "number", display: true },
2276
+ { name: "tags", type: "object" }
2277
+ ]
2278
+ },
2279
+ {
2280
+ type: "metric:gauge",
2281
+ category: "metrics",
2282
+ label: "Gauge Metric",
2283
+ severity: "info",
2284
+ frequency: "medium",
2285
+ fields: [
2286
+ { name: "name", type: "string", indexed: true, display: true },
2287
+ { name: "value", type: "number", display: true },
2288
+ { name: "tags", type: "object" }
2289
+ ]
2290
+ },
2291
+ {
2292
+ type: "metric:histogram",
2293
+ category: "metrics",
2294
+ label: "Histogram Metric",
2295
+ severity: "info",
2296
+ frequency: "medium",
2297
+ fields: [
2298
+ { name: "name", type: "string", indexed: true, display: true },
2299
+ { name: "value", type: "number", display: true },
2300
+ { name: "tags", type: "object" }
2301
+ ]
2302
+ },
2303
+ {
2304
+ type: "trace:span",
2305
+ category: "traces",
2306
+ label: "Trace Span",
2307
+ severity: "info",
2308
+ frequency: "medium",
2309
+ fields: [
2310
+ { name: "traceId", type: "string", indexed: true, display: true },
2311
+ { name: "spanId", type: "string", indexed: true },
2312
+ { name: "operation", type: "string", display: true },
2313
+ { name: "durationMs", type: "number", display: true },
2314
+ { name: "status", type: "string", display: true }
2315
+ ]
2316
+ },
2317
+ {
2318
+ type: "incident:recorded",
2319
+ category: "incidents",
2320
+ label: "Incident Recorded",
2321
+ severity: "error",
2322
+ frequency: "low",
2323
+ fields: [
2324
+ { name: "incidentId", type: "string", indexed: true, display: true },
2325
+ { name: "errorMessage", type: "string", display: true },
2326
+ { name: "symbols", type: "object" },
2327
+ { name: "environment", type: "string", display: true }
2328
+ ]
2329
+ }
2330
+ ],
2331
+ visualization: {
2332
+ defaultView: "table",
2333
+ categoryColors: {
2334
+ logs: "#3b82f6",
2335
+ metrics: "#22c55e",
2336
+ traces: "#a855f7",
2337
+ incidents: "#ef4444"
2338
+ },
2339
+ summaryFields: ["symbol", "message", "service"],
2340
+ defaultExcluded: ["log:debug"]
2341
+ },
2342
+ tags: ["builtin", "paradigm"]
2343
+ };
2252
2344
  export {
2253
2345
  ContextEnricher,
2346
+ DEFAULT_AUTH_CONFIG,
2347
+ DEFAULT_RATE_LIMIT_CONFIG,
2348
+ DEFAULT_SERVER_CONFIG,
2254
2349
  FlowTracker,
2255
2350
  IncidentGrouper,
2351
+ PARADIGM_SCHEMA,
2256
2352
  PatternImporter,
2257
2353
  PatternMatcher,
2258
2354
  PatternSuggester,
2259
2355
  Sentinel,
2356
+ SentinelClient,
2260
2357
  SentinelStorage,
2358
+ SentinelTransport,
2261
2359
  StatsCalculator,
2262
2360
  TimelineBuilder,
2361
+ createSentinelClient,
2362
+ createSentinelTransport,
2263
2363
  detectSymbols,
2364
+ enableSentinel,
2264
2365
  generateConfig,
2265
2366
  loadAllSeedPatterns,
2266
2367
  loadConfig,
2267
2368
  loadParadigmPatterns,
2369
+ loadServerConfig,
2268
2370
  loadUniversalPatterns,
2269
2371
  writeConfig
2270
2372
  };