@a-company/paradigm 3.1.6 → 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.
Files changed (80) hide show
  1. package/dist/{accept-orchestration-CWZNCGZX.js → accept-orchestration-DIGPJVUR.js} +6 -5
  2. package/dist/{aggregate-W7Q6VIM2.js → aggregate-V4KPR3RW.js} +2 -2
  3. package/dist/{beacon-B47XSTL7.js → beacon-XRXL5KZB.js} +2 -2
  4. package/dist/{chunk-YCLN7WXV.js → chunk-2QNZ6PVD.js} +219 -35
  5. package/dist/{chunk-UM54F7G5.js → chunk-4N6AYEEA.js} +1 -1
  6. package/dist/{chunk-MVXJVRFI.js → chunk-5TUAVVIG.js} +65 -1
  7. package/dist/{chunk-5C4SGQKH.js → chunk-6P4IFIK2.js} +4 -2
  8. package/dist/{chunk-WS5KM7OL.js → chunk-6RNYVBSG.js} +1 -1
  9. package/dist/{chunk-VZ7CXFRZ.js → chunk-ADOBV4PH.js} +1387 -17
  10. package/dist/{chunk-N6PJAPDE.js → chunk-AK5M6KJB.js} +18 -0
  11. package/dist/{chunk-4LGLU2LO.js → chunk-GY5KO3YZ.js} +679 -183
  12. package/dist/{chunk-MC7XC7XQ.js → chunk-GZDFVP2N.js} +20 -13
  13. package/dist/chunk-HPC3JAUP.js +42 -0
  14. package/dist/chunk-IRVA7NKV.js +657 -0
  15. package/dist/{chunk-ZPN7MXRA.js → chunk-KFHK6EBI.js} +184 -1
  16. package/dist/{chunk-UUZ2DMG5.js → chunk-KWDTBXP2.js} +1 -1
  17. package/dist/{chunk-HXY6AY52.js → chunk-M2XMTJHQ.js} +667 -70
  18. package/dist/{chunk-PW2EXJQT.js → chunk-MRENOFTR.js} +24 -1
  19. package/dist/{chunk-QS36NGWV.js → chunk-QHJGB5TV.js} +1 -1
  20. package/dist/chunk-UI3XXVJ6.js +449 -0
  21. package/dist/{chunk-AD2LSCHB.js → chunk-Y4XZWCHK.js} +40 -74
  22. package/dist/{constellation-K3CIQCHI.js → constellation-GNK5DIMH.js} +2 -2
  23. package/dist/{cost-AEK6R7HK.js → cost-AGO5N7DD.js} +1 -1
  24. package/dist/{cursorrules-KI5QWHIX.js → cursorrules-LQFA7M62.js} +2 -2
  25. package/dist/{delete-W67IVTLJ.js → delete-3YXAJ5AA.js} +12 -1
  26. package/dist/{diff-AJJ5H6HV.js → diff-J6C5IHPV.js} +6 -5
  27. package/dist/{dist-2F7NO4H4-KSL6SJIO.js → dist-AG5JNIZU-XSEZ2LLK.js} +28 -3
  28. package/dist/dist-JOHRYQUA.js +7294 -0
  29. package/dist/{dist-GPQ4LAY3.js → dist-OLFOTUHS.js} +26 -6
  30. package/dist/{dist-NHJQVVUW.js → dist-Q6SAZI7X.js} +2 -2
  31. package/dist/{doctor-JBIV5PMN.js → doctor-TQYRF7KK.js} +2 -2
  32. package/dist/{edit-Y7XPYSMK.js → edit-EOMPXOG5.js} +1 -1
  33. package/dist/flow-7JUH6D4H.js +185 -0
  34. package/dist/global-AXILUM5X.js +136 -0
  35. package/dist/{habits-FA65W77Y.js → habits-ZJBAL4HD.js} +234 -5
  36. package/dist/{hooks-RLJFGKPF.js → hooks-DLZEYHI3.js} +1 -1
  37. package/dist/index.js +125 -100
  38. package/dist/{lint-HXKTWRNO.js → lint-N4LMMEXH.js} +141 -1
  39. package/dist/{list-R3QWW4SC.js → list-JKBJ7ESH.js} +1 -1
  40. package/dist/mcp.js +7982 -5065
  41. package/dist/{orchestrate-4ZH5GUQH.js → orchestrate-FAV64G2R.js} +6 -5
  42. package/dist/{probe-OYCP4JYG.js → probe-X3J2JX62.js} +18 -3
  43. package/dist/{promote-E6NBZ3BK.js → promote-HZH5E5CO.js} +1 -1
  44. package/dist/{providers-4PGPZEWP.js → providers-NQ67LO2Z.js} +1 -1
  45. package/dist/{record-OHQNWOUP.js → record-EECZ3E4I.js} +1 -1
  46. package/dist/{remember-6VZ74B7E.js → remember-3KJZGDUG.js} +1 -1
  47. package/dist/{review-RUHX25A5.js → review-BF26ILZB.js} +1 -1
  48. package/dist/{ripple-SBQOSTZD.js → ripple-JIUAMBLA.js} +2 -2
  49. package/dist/sentinel-KDIGZWKT.js +63 -0
  50. package/dist/{server-MV4HNFVF.js → server-NN7WDAZJ.js} +4413 -9
  51. package/dist/{setup-DF4F3ICN.js → setup-363IB6MO.js} +1 -1
  52. package/dist/{setup-JHBPZAG7.js → setup-UKJ3VGHI.js} +4 -4
  53. package/dist/{shift-YELZUPYG.js → shift-KDVYB6CR.js} +16 -13
  54. package/dist/{show-WTOJXUTN.js → show-SAMTXEHG.js} +1 -1
  55. package/dist/{snapshot-GTVPRYZG.js → snapshot-KCMONZAO.js} +2 -2
  56. package/dist/{spawn-BJRQA2NR.js → spawn-EO7B2UM3.js} +2 -2
  57. package/dist/{summary-5SBFO7QK.js → summary-E2PU4UN2.js} +3 -3
  58. package/dist/{switch-6EANJ7O6.js → switch-CC2KACXO.js} +1 -1
  59. package/dist/{sync-5KSTPJ4B.js → sync-5VJPZQNX.js} +2 -2
  60. package/dist/sync-llms-7QDA3ZWC.js +166 -0
  61. package/dist/{team-NWP2KJAB.js → team-6CCNANKE.js} +7 -6
  62. package/dist/{test-MA5TWJQV.js → test-DK2RWLTK.js} +91 -8
  63. package/dist/{thread-JCJVRUQR.js → thread-RNSLADXN.js} +18 -2
  64. package/dist/{timeline-P7BARFLI.js → timeline-TJDVVVA3.js} +1 -1
  65. package/dist/{triage-TBIWJA6R.js → triage-B5W6GZLT.js} +2 -2
  66. package/dist/university-content/courses/para-101.json +2 -1
  67. package/dist/university-content/courses/para-201.json +102 -3
  68. package/dist/university-content/courses/para-301.json +14 -11
  69. package/dist/university-content/courses/para-401.json +57 -3
  70. package/dist/university-content/courses/para-501.json +204 -6
  71. package/dist/university-content/plsat/v3.0.json +808 -3
  72. package/dist/university-content/reference.json +270 -0
  73. package/dist/{upgrade-TIYFQYPO.js → upgrade-RBSE4M6I.js} +1 -1
  74. package/dist/{validate-QEEY6KFS.js → validate-2LTHHORX.js} +1 -1
  75. package/dist/{watch-4LT4O6K7.js → watch-NBPOMOEX.js} +76 -0
  76. package/dist/{watch-2XEYUH43.js → watch-PAEH6MOG.js} +1 -1
  77. package/package.json +1 -1
  78. package/dist/chunk-GWM2WRXL.js +0 -1095
  79. package/dist/sentinel-WB7GIK4V.js +0 -43
  80. /package/dist/{chunk-TAP5N3HH.js → chunk-CCG6KYBT.js} +0 -0
@@ -499,15 +499,15 @@ var require_sql_wasm = __commonJS({
499
499
  "undefined" != typeof __filename ? ya = __filename : ba && (ya = self.location.href);
500
500
  var za = "", Aa, Ba;
501
501
  if (ca) {
502
- var fs2 = __require("fs");
502
+ var fs3 = __require("fs");
503
503
  za = __dirname + "/";
504
504
  Ba = (a) => {
505
505
  a = Ca(a) ? new URL(a) : a;
506
- return fs2.readFileSync(a);
506
+ return fs3.readFileSync(a);
507
507
  };
508
508
  Aa = async (a) => {
509
509
  a = Ca(a) ? new URL(a) : a;
510
- return fs2.readFileSync(a, void 0);
510
+ return fs3.readFileSync(a, void 0);
511
511
  };
512
512
  1 < process.argv.length && (wa = process.argv[1].replace(/\\/g, "/"));
513
513
  process.argv.slice(2);
@@ -789,7 +789,7 @@ var require_sql_wasm = __commonJS({
789
789
  if (ca) {
790
790
  var b = Buffer.alloc(256), c = 0, d = process.stdin.fd;
791
791
  try {
792
- c = fs2.readSync(d, b, 0, 256);
792
+ c = fs3.readSync(d, b, 0, 256);
793
793
  } catch (e) {
794
794
  if (e.toString().includes("EOF")) c = 0;
795
795
  else throw e;
@@ -2121,16 +2121,19 @@ var require_sql_wasm = __commonJS({
2121
2121
  }
2122
2122
  });
2123
2123
 
2124
- // ../sentinel/dist/chunk-KPMG4XED.js
2125
- var import_sql = __toESM(require_sql_wasm(), 1);
2124
+ // ../sentinel/node_modules/uuid/dist/esm-node/native.js
2125
+ import crypto2 from "crypto";
2126
+ var native_default = {
2127
+ randomUUID: crypto2.randomUUID
2128
+ };
2126
2129
 
2127
2130
  // ../sentinel/node_modules/uuid/dist/esm-node/rng.js
2128
- import crypto2 from "crypto";
2131
+ import crypto3 from "crypto";
2129
2132
  var rnds8Pool = new Uint8Array(256);
2130
2133
  var poolPtr = rnds8Pool.length;
2131
2134
  function rng() {
2132
2135
  if (poolPtr > rnds8Pool.length - 16) {
2133
- crypto2.randomFillSync(rnds8Pool);
2136
+ crypto3.randomFillSync(rnds8Pool);
2134
2137
  poolPtr = 0;
2135
2138
  }
2136
2139
  return rnds8Pool.slice(poolPtr, poolPtr += 16);
@@ -2145,12 +2148,6 @@ function unsafeStringify(arr, offset = 0) {
2145
2148
  return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];
2146
2149
  }
2147
2150
 
2148
- // ../sentinel/node_modules/uuid/dist/esm-node/native.js
2149
- import crypto3 from "crypto";
2150
- var native_default = {
2151
- randomUUID: crypto3.randomUUID
2152
- };
2153
-
2154
2151
  // ../sentinel/node_modules/uuid/dist/esm-node/v4.js
2155
2152
  function v4(options, buf, offset) {
2156
2153
  if (native_default.randomUUID && !buf && !options) {
@@ -2171,10 +2168,13 @@ function v4(options, buf, offset) {
2171
2168
  }
2172
2169
  var v4_default = v4;
2173
2170
 
2174
- // ../sentinel/dist/chunk-KPMG4XED.js
2171
+ // ../sentinel/dist/chunk-NTX74ZPM.js
2172
+ var import_sql = __toESM(require_sql_wasm(), 1);
2175
2173
  import * as path from "path";
2176
2174
  import * as fs from "fs";
2177
- var SCHEMA_VERSION = 2;
2175
+ import * as fs2 from "fs";
2176
+ import * as path2 from "path";
2177
+ var SCHEMA_VERSION = 5;
2178
2178
  var DEFAULT_CONFIDENCE = {
2179
2179
  score: 50,
2180
2180
  timesMatched: 0,
@@ -2294,6 +2294,72 @@ var SentinelStorage = class {
2294
2294
  notes TEXT
2295
2295
  );
2296
2296
 
2297
+ -- Structured logs table
2298
+ CREATE TABLE IF NOT EXISTS logs (
2299
+ id TEXT PRIMARY KEY,
2300
+ timestamp TEXT NOT NULL,
2301
+ level TEXT NOT NULL CHECK (level IN ('debug','info','warn','error')),
2302
+ symbol TEXT NOT NULL,
2303
+ symbol_type TEXT NOT NULL DEFAULT 'raw',
2304
+ message TEXT NOT NULL,
2305
+ data_json TEXT,
2306
+ service TEXT NOT NULL,
2307
+ session_id TEXT,
2308
+ correlation_id TEXT,
2309
+ duration_ms REAL,
2310
+ environment TEXT
2311
+ );
2312
+
2313
+ -- Service registry
2314
+ CREATE TABLE IF NOT EXISTS services (
2315
+ name TEXT PRIMARY KEY,
2316
+ version TEXT,
2317
+ pid INTEGER,
2318
+ started_at TEXT NOT NULL,
2319
+ last_seen_at TEXT NOT NULL,
2320
+ environment TEXT,
2321
+ metadata_json TEXT
2322
+ );
2323
+
2324
+ -- Live app state snapshots (latest-wins per service+session)
2325
+ CREATE TABLE IF NOT EXISTS app_state (
2326
+ service TEXT NOT NULL,
2327
+ session_id TEXT NOT NULL,
2328
+ timestamp TEXT NOT NULL,
2329
+ state_json TEXT NOT NULL,
2330
+ active_flows_json TEXT,
2331
+ active_gates_json TEXT,
2332
+ PRIMARY KEY (service, session_id)
2333
+ );
2334
+
2335
+ -- Metrics table
2336
+ CREATE TABLE IF NOT EXISTS metrics (
2337
+ id TEXT PRIMARY KEY,
2338
+ timestamp TEXT NOT NULL,
2339
+ name TEXT NOT NULL,
2340
+ type TEXT NOT NULL CHECK (type IN ('counter','gauge','histogram')),
2341
+ value REAL NOT NULL,
2342
+ tags_json TEXT DEFAULT '{}',
2343
+ service TEXT NOT NULL,
2344
+ environment TEXT
2345
+ );
2346
+
2347
+ -- Traces table
2348
+ CREATE TABLE IF NOT EXISTS traces (
2349
+ trace_id TEXT NOT NULL,
2350
+ span_id TEXT PRIMARY KEY,
2351
+ parent_span_id TEXT,
2352
+ service TEXT NOT NULL,
2353
+ symbol TEXT NOT NULL,
2354
+ operation TEXT NOT NULL,
2355
+ start_time TEXT NOT NULL,
2356
+ end_time TEXT,
2357
+ duration_ms REAL,
2358
+ status TEXT NOT NULL DEFAULT 'ok',
2359
+ tags_json TEXT DEFAULT '{}',
2360
+ log_ids_json TEXT DEFAULT '[]'
2361
+ );
2362
+
2297
2363
  -- Indexes
2298
2364
  CREATE INDEX IF NOT EXISTS idx_incidents_timestamp ON incidents(timestamp);
2299
2365
  CREATE INDEX IF NOT EXISTS idx_incidents_status ON incidents(status);
@@ -2303,6 +2369,18 @@ var SentinelStorage = class {
2303
2369
  CREATE INDEX IF NOT EXISTS idx_practice_events_habit_id ON practice_events(habit_id);
2304
2370
  CREATE INDEX IF NOT EXISTS idx_practice_events_engineer ON practice_events(engineer);
2305
2371
  CREATE INDEX IF NOT EXISTS idx_practice_events_session_id ON practice_events(session_id);
2372
+ CREATE INDEX IF NOT EXISTS idx_logs_timestamp ON logs(timestamp);
2373
+ CREATE INDEX IF NOT EXISTS idx_logs_level ON logs(level);
2374
+ CREATE INDEX IF NOT EXISTS idx_logs_symbol ON logs(symbol);
2375
+ CREATE INDEX IF NOT EXISTS idx_logs_service ON logs(service);
2376
+ CREATE INDEX IF NOT EXISTS idx_logs_session_id ON logs(session_id);
2377
+ CREATE INDEX IF NOT EXISTS idx_logs_correlation_id ON logs(correlation_id);
2378
+ CREATE INDEX IF NOT EXISTS idx_metrics_timestamp ON metrics(timestamp);
2379
+ CREATE INDEX IF NOT EXISTS idx_metrics_name ON metrics(name);
2380
+ CREATE INDEX IF NOT EXISTS idx_metrics_service ON metrics(service);
2381
+ CREATE INDEX IF NOT EXISTS idx_traces_trace_id ON traces(trace_id);
2382
+ CREATE INDEX IF NOT EXISTS idx_traces_service ON traces(service);
2383
+ CREATE INDEX IF NOT EXISTS idx_traces_start_time ON traces(start_time);
2306
2384
  `);
2307
2385
  this.db.run(
2308
2386
  "INSERT OR REPLACE INTO metadata (key, value) VALUES ('schema_version', ?)",
@@ -2432,6 +2510,149 @@ var SentinelStorage = class {
2432
2510
  this.db.run(
2433
2511
  "INSERT OR REPLACE INTO metadata (key, value) VALUES ('schema_version', '2')"
2434
2512
  );
2513
+ currentVersion = 2;
2514
+ }
2515
+ if (currentVersion < 3) {
2516
+ try {
2517
+ this.db.run(`
2518
+ CREATE TABLE IF NOT EXISTS logs (
2519
+ id TEXT PRIMARY KEY,
2520
+ timestamp TEXT NOT NULL,
2521
+ level TEXT NOT NULL CHECK (level IN ('debug','info','warn','error')),
2522
+ symbol TEXT NOT NULL,
2523
+ symbol_type TEXT NOT NULL DEFAULT 'raw',
2524
+ message TEXT NOT NULL,
2525
+ data_json TEXT,
2526
+ service TEXT NOT NULL,
2527
+ session_id TEXT,
2528
+ correlation_id TEXT,
2529
+ duration_ms REAL,
2530
+ environment TEXT
2531
+ );
2532
+
2533
+ CREATE TABLE IF NOT EXISTS services (
2534
+ name TEXT PRIMARY KEY,
2535
+ version TEXT,
2536
+ pid INTEGER,
2537
+ started_at TEXT NOT NULL,
2538
+ last_seen_at TEXT NOT NULL,
2539
+ environment TEXT,
2540
+ metadata_json TEXT
2541
+ );
2542
+
2543
+ CREATE TABLE IF NOT EXISTS app_state (
2544
+ service TEXT NOT NULL,
2545
+ session_id TEXT NOT NULL,
2546
+ timestamp TEXT NOT NULL,
2547
+ state_json TEXT NOT NULL,
2548
+ active_flows_json TEXT,
2549
+ active_gates_json TEXT,
2550
+ PRIMARY KEY (service, session_id)
2551
+ );
2552
+
2553
+ CREATE INDEX IF NOT EXISTS idx_logs_timestamp ON logs(timestamp);
2554
+ CREATE INDEX IF NOT EXISTS idx_logs_level ON logs(level);
2555
+ CREATE INDEX IF NOT EXISTS idx_logs_symbol ON logs(symbol);
2556
+ CREATE INDEX IF NOT EXISTS idx_logs_service ON logs(service);
2557
+ CREATE INDEX IF NOT EXISTS idx_logs_session_id ON logs(session_id);
2558
+ CREATE INDEX IF NOT EXISTS idx_logs_correlation_id ON logs(correlation_id);
2559
+ `);
2560
+ } catch {
2561
+ }
2562
+ this.db.run(
2563
+ "INSERT OR REPLACE INTO metadata (key, value) VALUES ('schema_version', '3')"
2564
+ );
2565
+ currentVersion = 3;
2566
+ }
2567
+ if (currentVersion < 4) {
2568
+ try {
2569
+ this.db.run(`
2570
+ CREATE TABLE IF NOT EXISTS metrics (
2571
+ id TEXT PRIMARY KEY,
2572
+ timestamp TEXT NOT NULL,
2573
+ name TEXT NOT NULL,
2574
+ type TEXT NOT NULL CHECK (type IN ('counter','gauge','histogram')),
2575
+ value REAL NOT NULL,
2576
+ tags_json TEXT DEFAULT '{}',
2577
+ service TEXT NOT NULL,
2578
+ environment TEXT
2579
+ );
2580
+
2581
+ CREATE TABLE IF NOT EXISTS traces (
2582
+ trace_id TEXT NOT NULL,
2583
+ span_id TEXT PRIMARY KEY,
2584
+ parent_span_id TEXT,
2585
+ service TEXT NOT NULL,
2586
+ symbol TEXT NOT NULL,
2587
+ operation TEXT NOT NULL,
2588
+ start_time TEXT NOT NULL,
2589
+ end_time TEXT,
2590
+ duration_ms REAL,
2591
+ status TEXT NOT NULL DEFAULT 'ok',
2592
+ tags_json TEXT DEFAULT '{}',
2593
+ log_ids_json TEXT DEFAULT '[]'
2594
+ );
2595
+
2596
+ CREATE INDEX IF NOT EXISTS idx_metrics_timestamp ON metrics(timestamp);
2597
+ CREATE INDEX IF NOT EXISTS idx_metrics_name ON metrics(name);
2598
+ CREATE INDEX IF NOT EXISTS idx_metrics_service ON metrics(service);
2599
+ CREATE INDEX IF NOT EXISTS idx_traces_trace_id ON traces(trace_id);
2600
+ CREATE INDEX IF NOT EXISTS idx_traces_service ON traces(service);
2601
+ CREATE INDEX IF NOT EXISTS idx_traces_start_time ON traces(start_time);
2602
+ `);
2603
+ } catch {
2604
+ }
2605
+ this.db.run(
2606
+ "INSERT OR REPLACE INTO metadata (key, value) VALUES ('schema_version', '4')"
2607
+ );
2608
+ currentVersion = 4;
2609
+ }
2610
+ if (currentVersion < 5) {
2611
+ try {
2612
+ this.db.run(`
2613
+ CREATE TABLE IF NOT EXISTS schemas (
2614
+ id TEXT PRIMARY KEY,
2615
+ version TEXT NOT NULL,
2616
+ name TEXT NOT NULL,
2617
+ description TEXT,
2618
+ scope_json TEXT NOT NULL,
2619
+ event_types_json TEXT NOT NULL,
2620
+ causality_json TEXT,
2621
+ visualization_json TEXT,
2622
+ tags_json TEXT DEFAULT '[]',
2623
+ registered_at TEXT NOT NULL,
2624
+ updated_at TEXT NOT NULL
2625
+ );
2626
+
2627
+ CREATE TABLE IF NOT EXISTS events (
2628
+ id TEXT PRIMARY KEY,
2629
+ schema_id TEXT NOT NULL,
2630
+ event_type TEXT NOT NULL,
2631
+ category TEXT NOT NULL,
2632
+ timestamp TEXT NOT NULL,
2633
+ scope_value TEXT,
2634
+ scope_ordinal INTEGER,
2635
+ session_id TEXT,
2636
+ service TEXT NOT NULL,
2637
+ data_json TEXT,
2638
+ severity TEXT DEFAULT 'info',
2639
+ parent_event_id TEXT,
2640
+ depth INTEGER DEFAULT 0
2641
+ );
2642
+
2643
+ CREATE INDEX IF NOT EXISTS idx_events_schema ON events(schema_id);
2644
+ CREATE INDEX IF NOT EXISTS idx_events_type ON events(event_type);
2645
+ CREATE INDEX IF NOT EXISTS idx_events_scope ON events(schema_id, scope_value);
2646
+ CREATE INDEX IF NOT EXISTS idx_events_scope_ord ON events(schema_id, scope_ordinal);
2647
+ CREATE INDEX IF NOT EXISTS idx_events_session ON events(session_id);
2648
+ CREATE INDEX IF NOT EXISTS idx_events_timestamp ON events(timestamp);
2649
+ CREATE INDEX IF NOT EXISTS idx_events_service ON events(service);
2650
+ `);
2651
+ } catch {
2652
+ }
2653
+ this.db.run(
2654
+ "INSERT OR REPLACE INTO metadata (key, value) VALUES ('schema_version', '5')"
2655
+ );
2435
2656
  }
2436
2657
  }
2437
2658
  /**
@@ -3406,6 +3627,955 @@ var SentinelStorage = class {
3406
3627
  notes: obj.notes || void 0
3407
3628
  };
3408
3629
  }
3630
+ // ─── Structured Logs ─────────────────────────────────────────────
3631
+ inferSymbolType(symbol) {
3632
+ if (symbol.startsWith("#")) return "component";
3633
+ if (symbol.startsWith("^")) return "gate";
3634
+ if (symbol.startsWith("!")) return "signal";
3635
+ if (symbol.startsWith("$")) return "flow";
3636
+ if (symbol.startsWith("~")) return "aspect";
3637
+ return "raw";
3638
+ }
3639
+ insertLog(input) {
3640
+ this.initializeSync();
3641
+ const id = input.id || v4_default();
3642
+ const timestamp = input.timestamp || (/* @__PURE__ */ new Date()).toISOString();
3643
+ const symbolType = input.symbolType || this.inferSymbolType(input.symbol);
3644
+ this.db.run(
3645
+ `INSERT INTO logs (
3646
+ id, timestamp, level, symbol, symbol_type, message, data_json,
3647
+ service, session_id, correlation_id, duration_ms, environment
3648
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
3649
+ [
3650
+ id,
3651
+ timestamp,
3652
+ input.level,
3653
+ input.symbol,
3654
+ symbolType,
3655
+ input.message,
3656
+ input.data ? JSON.stringify(input.data) : null,
3657
+ input.service,
3658
+ input.sessionId || null,
3659
+ input.correlationId || null,
3660
+ input.durationMs ?? null,
3661
+ input.environment || null
3662
+ ]
3663
+ );
3664
+ this.save();
3665
+ return id;
3666
+ }
3667
+ insertLogBatch(entries) {
3668
+ this.initializeSync();
3669
+ let accepted = 0;
3670
+ const errors = [];
3671
+ for (const input of entries) {
3672
+ try {
3673
+ const id = input.id || v4_default();
3674
+ const timestamp = input.timestamp || (/* @__PURE__ */ new Date()).toISOString();
3675
+ const symbolType = input.symbolType || this.inferSymbolType(input.symbol);
3676
+ this.db.run(
3677
+ `INSERT INTO logs (
3678
+ id, timestamp, level, symbol, symbol_type, message, data_json,
3679
+ service, session_id, correlation_id, duration_ms, environment
3680
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
3681
+ [
3682
+ id,
3683
+ timestamp,
3684
+ input.level,
3685
+ input.symbol,
3686
+ symbolType,
3687
+ input.message,
3688
+ input.data ? JSON.stringify(input.data) : null,
3689
+ input.service,
3690
+ input.sessionId || null,
3691
+ input.correlationId || null,
3692
+ input.durationMs ?? null,
3693
+ input.environment || null
3694
+ ]
3695
+ );
3696
+ accepted++;
3697
+ } catch (err) {
3698
+ errors.push(err instanceof Error ? err.message : String(err));
3699
+ }
3700
+ }
3701
+ this.save();
3702
+ return { accepted, errors };
3703
+ }
3704
+ queryLogs(options = {}) {
3705
+ this.initializeSync();
3706
+ const { limit = 100, offset = 0 } = options;
3707
+ const conditions = [];
3708
+ const params = [];
3709
+ if (options.level) {
3710
+ conditions.push("level = ?");
3711
+ params.push(options.level);
3712
+ }
3713
+ if (options.symbol) {
3714
+ conditions.push("symbol LIKE ?");
3715
+ params.push(`%${options.symbol}%`);
3716
+ }
3717
+ if (options.service) {
3718
+ conditions.push("service = ?");
3719
+ params.push(options.service);
3720
+ }
3721
+ if (options.sessionId) {
3722
+ conditions.push("session_id = ?");
3723
+ params.push(options.sessionId);
3724
+ }
3725
+ if (options.correlationId) {
3726
+ conditions.push("correlation_id = ?");
3727
+ params.push(options.correlationId);
3728
+ }
3729
+ if (options.search) {
3730
+ conditions.push("message LIKE ?");
3731
+ params.push(`%${options.search}%`);
3732
+ }
3733
+ if (options.since) {
3734
+ conditions.push("timestamp >= ?");
3735
+ params.push(options.since);
3736
+ }
3737
+ if (options.until) {
3738
+ conditions.push("timestamp <= ?");
3739
+ params.push(options.until);
3740
+ }
3741
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
3742
+ const result = this.db.exec(
3743
+ `SELECT * FROM logs ${whereClause} ORDER BY timestamp DESC LIMIT ? OFFSET ?`,
3744
+ [...params, limit, offset]
3745
+ );
3746
+ if (result.length === 0) return [];
3747
+ return result[0].values.map(
3748
+ (row) => this.rowToLogEntry(result[0].columns, row)
3749
+ );
3750
+ }
3751
+ getLogCount(options = {}) {
3752
+ this.initializeSync();
3753
+ const conditions = [];
3754
+ const params = [];
3755
+ if (options.level) {
3756
+ conditions.push("level = ?");
3757
+ params.push(options.level);
3758
+ }
3759
+ if (options.symbol) {
3760
+ conditions.push("symbol LIKE ?");
3761
+ params.push(`%${options.symbol}%`);
3762
+ }
3763
+ if (options.service) {
3764
+ conditions.push("service = ?");
3765
+ params.push(options.service);
3766
+ }
3767
+ if (options.since) {
3768
+ conditions.push("timestamp >= ?");
3769
+ params.push(options.since);
3770
+ }
3771
+ if (options.until) {
3772
+ conditions.push("timestamp <= ?");
3773
+ params.push(options.until);
3774
+ }
3775
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
3776
+ const result = this.db.exec(
3777
+ `SELECT COUNT(*) as count FROM logs ${whereClause}`,
3778
+ params
3779
+ );
3780
+ if (result.length === 0 || result[0].values.length === 0) return 0;
3781
+ return result[0].values[0][0];
3782
+ }
3783
+ pruneLogs(maxCount) {
3784
+ this.initializeSync();
3785
+ if (maxCount <= 0) return 0;
3786
+ const currentCount = this.getLogCount();
3787
+ if (currentCount <= maxCount) return 0;
3788
+ const deleteCount = currentCount - maxCount;
3789
+ this.db.run(
3790
+ `DELETE FROM logs WHERE id IN (
3791
+ SELECT id FROM logs ORDER BY timestamp ASC LIMIT ?
3792
+ )`,
3793
+ [deleteCount]
3794
+ );
3795
+ this.save();
3796
+ return deleteCount;
3797
+ }
3798
+ rowToLogEntry(columns, row) {
3799
+ const obj = {};
3800
+ columns.forEach((col, i) => {
3801
+ obj[col] = row[i];
3802
+ });
3803
+ return {
3804
+ id: obj.id,
3805
+ timestamp: obj.timestamp,
3806
+ level: obj.level,
3807
+ symbol: obj.symbol,
3808
+ symbolType: obj.symbol_type || "raw",
3809
+ message: obj.message,
3810
+ data: obj.data_json ? JSON.parse(obj.data_json) : void 0,
3811
+ service: obj.service,
3812
+ sessionId: obj.session_id || void 0,
3813
+ correlationId: obj.correlation_id || void 0,
3814
+ durationMs: obj.duration_ms || void 0,
3815
+ environment: obj.environment || void 0
3816
+ };
3817
+ }
3818
+ // ─── Service Registry ──────────────────────────────────────────
3819
+ registerService(reg) {
3820
+ this.initializeSync();
3821
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3822
+ this.db.run(
3823
+ `INSERT INTO services (name, version, pid, started_at, last_seen_at, environment, metadata_json)
3824
+ VALUES (?, ?, ?, ?, ?, ?, ?)
3825
+ ON CONFLICT(name) DO UPDATE SET
3826
+ version = excluded.version,
3827
+ pid = excluded.pid,
3828
+ last_seen_at = excluded.last_seen_at,
3829
+ environment = excluded.environment,
3830
+ metadata_json = excluded.metadata_json`,
3831
+ [
3832
+ reg.name,
3833
+ reg.version || null,
3834
+ reg.pid ?? null,
3835
+ now,
3836
+ now,
3837
+ reg.environment || null,
3838
+ reg.metadata ? JSON.stringify(reg.metadata) : null
3839
+ ]
3840
+ );
3841
+ this.save();
3842
+ }
3843
+ updateServiceLastSeen(name) {
3844
+ this.initializeSync();
3845
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3846
+ this.db.run(
3847
+ "UPDATE services SET last_seen_at = ? WHERE name = ?",
3848
+ [now, name]
3849
+ );
3850
+ this.save();
3851
+ }
3852
+ getServices() {
3853
+ this.initializeSync();
3854
+ const result = this.db.exec(
3855
+ "SELECT * FROM services ORDER BY last_seen_at DESC"
3856
+ );
3857
+ if (result.length === 0) return [];
3858
+ return result[0].values.map((row) => {
3859
+ const obj = {};
3860
+ result[0].columns.forEach((col, i) => {
3861
+ obj[col] = row[i];
3862
+ });
3863
+ return {
3864
+ name: obj.name,
3865
+ version: obj.version || void 0,
3866
+ pid: obj.pid || void 0,
3867
+ startedAt: obj.started_at,
3868
+ lastSeenAt: obj.last_seen_at,
3869
+ environment: obj.environment || void 0,
3870
+ metadata: obj.metadata_json ? JSON.parse(obj.metadata_json) : void 0
3871
+ };
3872
+ });
3873
+ }
3874
+ // ─── App State ──────────────────────────────────────────────────
3875
+ upsertAppState(state) {
3876
+ this.initializeSync();
3877
+ this.db.run(
3878
+ `INSERT INTO app_state (service, session_id, timestamp, state_json, active_flows_json, active_gates_json)
3879
+ VALUES (?, ?, ?, ?, ?, ?)
3880
+ ON CONFLICT(service, session_id) DO UPDATE SET
3881
+ timestamp = excluded.timestamp,
3882
+ state_json = excluded.state_json,
3883
+ active_flows_json = excluded.active_flows_json,
3884
+ active_gates_json = excluded.active_gates_json`,
3885
+ [
3886
+ state.service,
3887
+ state.sessionId,
3888
+ state.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
3889
+ JSON.stringify(state.state),
3890
+ state.activeFlows ? JSON.stringify(state.activeFlows) : null,
3891
+ state.activeGates ? JSON.stringify(state.activeGates) : null
3892
+ ]
3893
+ );
3894
+ this.save();
3895
+ }
3896
+ getAppState(service, sessionId) {
3897
+ this.initializeSync();
3898
+ let query = "SELECT * FROM app_state WHERE service = ?";
3899
+ const params = [service];
3900
+ if (sessionId) {
3901
+ query += " AND session_id = ?";
3902
+ params.push(sessionId);
3903
+ }
3904
+ query += " ORDER BY timestamp DESC";
3905
+ const result = this.db.exec(query, params);
3906
+ if (result.length === 0) return [];
3907
+ return result[0].values.map((row) => this.rowToAppState(result[0].columns, row));
3908
+ }
3909
+ getAllAppStates() {
3910
+ this.initializeSync();
3911
+ const result = this.db.exec(
3912
+ "SELECT * FROM app_state ORDER BY timestamp DESC"
3913
+ );
3914
+ if (result.length === 0) return [];
3915
+ return result[0].values.map((row) => this.rowToAppState(result[0].columns, row));
3916
+ }
3917
+ rowToAppState(columns, row) {
3918
+ const obj = {};
3919
+ columns.forEach((col, i) => {
3920
+ obj[col] = row[i];
3921
+ });
3922
+ return {
3923
+ service: obj.service,
3924
+ sessionId: obj.session_id,
3925
+ timestamp: obj.timestamp,
3926
+ state: JSON.parse(obj.state_json),
3927
+ activeFlows: obj.active_flows_json ? JSON.parse(obj.active_flows_json) : void 0,
3928
+ activeGates: obj.active_gates_json ? JSON.parse(obj.active_gates_json) : void 0
3929
+ };
3930
+ }
3931
+ // ─── Metrics ───────────────────────────────────────────────────
3932
+ insertMetric(input) {
3933
+ this.initializeSync();
3934
+ const id = v4_default();
3935
+ const timestamp = input.timestamp || (/* @__PURE__ */ new Date()).toISOString();
3936
+ this.db.run(
3937
+ `INSERT INTO metrics (
3938
+ id, timestamp, name, type, value, tags_json, service, environment
3939
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
3940
+ [
3941
+ id,
3942
+ timestamp,
3943
+ input.name,
3944
+ input.type,
3945
+ input.value,
3946
+ JSON.stringify(input.tags || {}),
3947
+ input.service,
3948
+ input.environment || null
3949
+ ]
3950
+ );
3951
+ this.save();
3952
+ return id;
3953
+ }
3954
+ insertMetricBatch(entries) {
3955
+ this.initializeSync();
3956
+ let accepted = 0;
3957
+ const errors = [];
3958
+ for (const input of entries) {
3959
+ try {
3960
+ const id = v4_default();
3961
+ const timestamp = input.timestamp || (/* @__PURE__ */ new Date()).toISOString();
3962
+ this.db.run(
3963
+ `INSERT INTO metrics (
3964
+ id, timestamp, name, type, value, tags_json, service, environment
3965
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
3966
+ [
3967
+ id,
3968
+ timestamp,
3969
+ input.name,
3970
+ input.type,
3971
+ input.value,
3972
+ JSON.stringify(input.tags || {}),
3973
+ input.service,
3974
+ input.environment || null
3975
+ ]
3976
+ );
3977
+ accepted++;
3978
+ } catch (err) {
3979
+ errors.push(err instanceof Error ? err.message : String(err));
3980
+ }
3981
+ }
3982
+ this.save();
3983
+ return { accepted, errors };
3984
+ }
3985
+ queryMetrics(options = {}) {
3986
+ this.initializeSync();
3987
+ const { limit = 100, offset = 0 } = options;
3988
+ const conditions = [];
3989
+ const params = [];
3990
+ if (options.name) {
3991
+ conditions.push("name = ?");
3992
+ params.push(options.name);
3993
+ }
3994
+ if (options.type) {
3995
+ conditions.push("type = ?");
3996
+ params.push(options.type);
3997
+ }
3998
+ if (options.service) {
3999
+ conditions.push("service = ?");
4000
+ params.push(options.service);
4001
+ }
4002
+ if (options.tag) {
4003
+ const eqIdx = options.tag.indexOf("=");
4004
+ if (eqIdx > 0) {
4005
+ const tagKey = options.tag.substring(0, eqIdx);
4006
+ const tagValue = options.tag.substring(eqIdx + 1);
4007
+ conditions.push("tags_json LIKE ?");
4008
+ params.push(`%"${tagKey}":"${tagValue}"%`);
4009
+ }
4010
+ }
4011
+ if (options.since) {
4012
+ conditions.push("timestamp >= ?");
4013
+ params.push(options.since);
4014
+ }
4015
+ if (options.until) {
4016
+ conditions.push("timestamp <= ?");
4017
+ params.push(options.until);
4018
+ }
4019
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
4020
+ const result = this.db.exec(
4021
+ `SELECT * FROM metrics ${whereClause} ORDER BY timestamp DESC LIMIT ? OFFSET ?`,
4022
+ [...params, limit, offset]
4023
+ );
4024
+ if (result.length === 0) return [];
4025
+ return result[0].values.map(
4026
+ (row) => this.rowToMetricEntry(result[0].columns, row)
4027
+ );
4028
+ }
4029
+ getMetricCount(options = {}) {
4030
+ this.initializeSync();
4031
+ const conditions = [];
4032
+ const params = [];
4033
+ if (options.name) {
4034
+ conditions.push("name = ?");
4035
+ params.push(options.name);
4036
+ }
4037
+ if (options.type) {
4038
+ conditions.push("type = ?");
4039
+ params.push(options.type);
4040
+ }
4041
+ if (options.service) {
4042
+ conditions.push("service = ?");
4043
+ params.push(options.service);
4044
+ }
4045
+ if (options.tag) {
4046
+ const eqIdx = options.tag.indexOf("=");
4047
+ if (eqIdx > 0) {
4048
+ const tagKey = options.tag.substring(0, eqIdx);
4049
+ const tagValue = options.tag.substring(eqIdx + 1);
4050
+ conditions.push("tags_json LIKE ?");
4051
+ params.push(`%"${tagKey}":"${tagValue}"%`);
4052
+ }
4053
+ }
4054
+ if (options.since) {
4055
+ conditions.push("timestamp >= ?");
4056
+ params.push(options.since);
4057
+ }
4058
+ if (options.until) {
4059
+ conditions.push("timestamp <= ?");
4060
+ params.push(options.until);
4061
+ }
4062
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
4063
+ const result = this.db.exec(
4064
+ `SELECT COUNT(*) as count FROM metrics ${whereClause}`,
4065
+ params
4066
+ );
4067
+ if (result.length === 0 || result[0].values.length === 0) return 0;
4068
+ return result[0].values[0][0];
4069
+ }
4070
+ aggregateMetric(name, options) {
4071
+ this.initializeSync();
4072
+ const conditions = ["name = ?"];
4073
+ const params = [name];
4074
+ if (options?.service) {
4075
+ conditions.push("service = ?");
4076
+ params.push(options.service);
4077
+ }
4078
+ if (options?.since) {
4079
+ conditions.push("timestamp >= ?");
4080
+ params.push(options.since);
4081
+ }
4082
+ if (options?.until) {
4083
+ conditions.push("timestamp <= ?");
4084
+ params.push(options.until);
4085
+ }
4086
+ const whereClause = `WHERE ${conditions.join(" AND ")}`;
4087
+ const result = this.db.exec(
4088
+ `SELECT COUNT(*) as count, SUM(value) as sum, MIN(value) as min, MAX(value) as max, AVG(value) as avg
4089
+ FROM metrics ${whereClause}`,
4090
+ params
4091
+ );
4092
+ if (result.length === 0 || result[0].values.length === 0) {
4093
+ return { name, count: 0, sum: 0, min: 0, max: 0, avg: 0 };
4094
+ }
4095
+ const row = result[0].values[0];
4096
+ return {
4097
+ name,
4098
+ count: row[0] || 0,
4099
+ sum: row[1] || 0,
4100
+ min: row[2] || 0,
4101
+ max: row[3] || 0,
4102
+ avg: row[4] || 0
4103
+ };
4104
+ }
4105
+ pruneMetrics(maxCount) {
4106
+ this.initializeSync();
4107
+ if (maxCount <= 0) return 0;
4108
+ const currentCount = this.getMetricCount();
4109
+ if (currentCount <= maxCount) return 0;
4110
+ const deleteCount = currentCount - maxCount;
4111
+ this.db.run(
4112
+ `DELETE FROM metrics WHERE id IN (
4113
+ SELECT id FROM metrics ORDER BY timestamp ASC LIMIT ?
4114
+ )`,
4115
+ [deleteCount]
4116
+ );
4117
+ this.save();
4118
+ return deleteCount;
4119
+ }
4120
+ rowToMetricEntry(columns, row) {
4121
+ const obj = {};
4122
+ columns.forEach((col, i) => {
4123
+ obj[col] = row[i];
4124
+ });
4125
+ return {
4126
+ id: obj.id,
4127
+ timestamp: obj.timestamp,
4128
+ name: obj.name,
4129
+ type: obj.type,
4130
+ value: obj.value,
4131
+ tags: obj.tags_json ? JSON.parse(obj.tags_json) : {},
4132
+ service: obj.service,
4133
+ environment: obj.environment || void 0
4134
+ };
4135
+ }
4136
+ // ─── Traces ───────────────────────────────────────────────────
4137
+ insertSpan(input) {
4138
+ this.initializeSync();
4139
+ const spanId = input.spanId || v4_default();
4140
+ const startTime = input.startTime || (/* @__PURE__ */ new Date()).toISOString();
4141
+ this.db.run(
4142
+ `INSERT INTO traces (
4143
+ trace_id, span_id, parent_span_id, service, symbol, operation,
4144
+ start_time, end_time, duration_ms, status, tags_json, log_ids_json
4145
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
4146
+ [
4147
+ input.traceId,
4148
+ spanId,
4149
+ input.parentSpanId || null,
4150
+ input.service,
4151
+ input.symbol,
4152
+ input.operation,
4153
+ startTime,
4154
+ input.endTime || null,
4155
+ input.durationMs ?? null,
4156
+ input.status || "ok",
4157
+ JSON.stringify(input.tags || {}),
4158
+ JSON.stringify(input.logIds || [])
4159
+ ]
4160
+ );
4161
+ this.save();
4162
+ return spanId;
4163
+ }
4164
+ getTrace(traceId) {
4165
+ this.initializeSync();
4166
+ const result = this.db.exec(
4167
+ "SELECT * FROM traces WHERE trace_id = ? ORDER BY start_time ASC",
4168
+ [traceId]
4169
+ );
4170
+ if (result.length === 0 || result[0].values.length === 0) return null;
4171
+ const spans = result[0].values.map(
4172
+ (row) => this.rowToTraceSpan(result[0].columns, row)
4173
+ );
4174
+ const services = [...new Set(spans.map((s) => s.service))];
4175
+ const startTimes = spans.map((s) => s.startTime);
4176
+ const endTimes = spans.filter((s) => s.endTime).map((s) => s.endTime);
4177
+ const startTime = startTimes.sort()[0];
4178
+ const endTime = endTimes.length > 0 ? endTimes.sort().reverse()[0] : startTime;
4179
+ const startMs = new Date(startTime).getTime();
4180
+ const endMs = new Date(endTime).getTime();
4181
+ const totalDurationMs = endMs - startMs;
4182
+ return {
4183
+ traceId,
4184
+ spans,
4185
+ services,
4186
+ totalDurationMs: totalDurationMs > 0 ? totalDurationMs : 0,
4187
+ startTime,
4188
+ endTime
4189
+ };
4190
+ }
4191
+ queryTraces(options = {}) {
4192
+ this.initializeSync();
4193
+ const conditions = [];
4194
+ const params = [];
4195
+ if (options.service) {
4196
+ conditions.push("service = ?");
4197
+ params.push(options.service);
4198
+ }
4199
+ if (options.symbol) {
4200
+ conditions.push("symbol = ?");
4201
+ params.push(options.symbol);
4202
+ }
4203
+ if (options.since) {
4204
+ conditions.push("start_time >= ?");
4205
+ params.push(options.since);
4206
+ }
4207
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
4208
+ const traceLimit = Math.min(options.limit || 20, 20);
4209
+ const result = this.db.exec(
4210
+ `SELECT DISTINCT trace_id FROM traces ${whereClause} ORDER BY start_time DESC LIMIT ?`,
4211
+ [...params, traceLimit]
4212
+ );
4213
+ if (result.length === 0) return [];
4214
+ const traces = [];
4215
+ for (const row of result[0].values) {
4216
+ const traceId = row[0];
4217
+ const trace = this.getTrace(traceId);
4218
+ if (trace) {
4219
+ traces.push(trace);
4220
+ }
4221
+ }
4222
+ return traces;
4223
+ }
4224
+ rowToTraceSpan(columns, row) {
4225
+ const obj = {};
4226
+ columns.forEach((col, i) => {
4227
+ obj[col] = row[i];
4228
+ });
4229
+ return {
4230
+ traceId: obj.trace_id,
4231
+ spanId: obj.span_id,
4232
+ parentSpanId: obj.parent_span_id || void 0,
4233
+ service: obj.service,
4234
+ symbol: obj.symbol,
4235
+ operation: obj.operation,
4236
+ startTime: obj.start_time,
4237
+ endTime: obj.end_time || void 0,
4238
+ durationMs: obj.duration_ms || void 0,
4239
+ status: obj.status || "ok",
4240
+ tags: obj.tags_json ? JSON.parse(obj.tags_json) : {},
4241
+ logs: obj.log_ids_json ? JSON.parse(obj.log_ids_json) : []
4242
+ };
4243
+ }
4244
+ // ─── Schema Registry ─────────────────────────────────────────────
4245
+ registerSchema(schema) {
4246
+ this.initializeSync();
4247
+ const now = (/* @__PURE__ */ new Date()).toISOString();
4248
+ this.db.run(
4249
+ `INSERT INTO schemas (
4250
+ id, version, name, description, scope_json, event_types_json,
4251
+ causality_json, visualization_json, tags_json, registered_at, updated_at
4252
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
4253
+ ON CONFLICT(id) DO UPDATE SET
4254
+ version = excluded.version,
4255
+ name = excluded.name,
4256
+ description = excluded.description,
4257
+ scope_json = excluded.scope_json,
4258
+ event_types_json = excluded.event_types_json,
4259
+ causality_json = excluded.causality_json,
4260
+ visualization_json = excluded.visualization_json,
4261
+ tags_json = excluded.tags_json,
4262
+ updated_at = excluded.updated_at`,
4263
+ [
4264
+ schema.id,
4265
+ schema.version,
4266
+ schema.name,
4267
+ schema.description || null,
4268
+ JSON.stringify(schema.scope),
4269
+ JSON.stringify(schema.eventTypes),
4270
+ schema.causality ? JSON.stringify(schema.causality) : null,
4271
+ schema.visualization ? JSON.stringify(schema.visualization) : null,
4272
+ JSON.stringify(schema.tags || []),
4273
+ now,
4274
+ now
4275
+ ]
4276
+ );
4277
+ this.save();
4278
+ return {
4279
+ id: schema.id,
4280
+ version: schema.version,
4281
+ name: schema.name,
4282
+ description: schema.description,
4283
+ scope: schema.scope,
4284
+ eventTypes: schema.eventTypes,
4285
+ causality: schema.causality,
4286
+ visualization: schema.visualization,
4287
+ tags: schema.tags || [],
4288
+ registeredAt: now,
4289
+ updatedAt: now
4290
+ };
4291
+ }
4292
+ getSchema(id) {
4293
+ this.initializeSync();
4294
+ const result = this.db.exec("SELECT * FROM schemas WHERE id = ?", [id]);
4295
+ if (result.length === 0 || result[0].values.length === 0) return null;
4296
+ return this.rowToSchema(result[0].columns, result[0].values[0]);
4297
+ }
4298
+ listSchemas() {
4299
+ this.initializeSync();
4300
+ const result = this.db.exec("SELECT * FROM schemas ORDER BY name ASC");
4301
+ if (result.length === 0) return [];
4302
+ return result[0].values.map(
4303
+ (row) => this.rowToSchema(result[0].columns, row)
4304
+ );
4305
+ }
4306
+ rowToSchema(columns, row) {
4307
+ const obj = {};
4308
+ columns.forEach((col, i) => {
4309
+ obj[col] = row[i];
4310
+ });
4311
+ return {
4312
+ id: obj.id,
4313
+ version: obj.version,
4314
+ name: obj.name,
4315
+ description: obj.description || void 0,
4316
+ scope: JSON.parse(obj.scope_json),
4317
+ eventTypes: JSON.parse(obj.event_types_json),
4318
+ causality: obj.causality_json ? JSON.parse(obj.causality_json) : void 0,
4319
+ visualization: obj.visualization_json ? JSON.parse(obj.visualization_json) : void 0,
4320
+ tags: JSON.parse(obj.tags_json || "[]"),
4321
+ registeredAt: obj.registered_at,
4322
+ updatedAt: obj.updated_at
4323
+ };
4324
+ }
4325
+ // ─── Generic Events ────────────────────────────────────────────
4326
+ insertEventBatch(schemaId, service, inputs) {
4327
+ this.initializeSync();
4328
+ const schema = this.getSchema(schemaId);
4329
+ const typeMap = /* @__PURE__ */ new Map();
4330
+ if (schema) {
4331
+ for (const et of schema.eventTypes) {
4332
+ typeMap.set(et.type, {
4333
+ category: et.category,
4334
+ severity: et.severity || "info"
4335
+ });
4336
+ }
4337
+ }
4338
+ let accepted = 0;
4339
+ const errors = [];
4340
+ for (const input of inputs) {
4341
+ try {
4342
+ const id = input.id || v4_default();
4343
+ const timestamp = input.timestamp || (/* @__PURE__ */ new Date()).toISOString();
4344
+ const resolved = typeMap.get(input.type);
4345
+ const category = resolved?.category || "unknown";
4346
+ const severity = input.severity || resolved?.severity || "info";
4347
+ const scopeValue = input.scopeValue != null ? String(input.scopeValue) : null;
4348
+ const scopeOrdinal = typeof input.scopeValue === "number" ? input.scopeValue : null;
4349
+ this.db.run(
4350
+ `INSERT INTO events (
4351
+ id, schema_id, event_type, category, timestamp, scope_value,
4352
+ scope_ordinal, session_id, service, data_json, severity,
4353
+ parent_event_id, depth
4354
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
4355
+ [
4356
+ id,
4357
+ schemaId,
4358
+ input.type,
4359
+ category,
4360
+ timestamp,
4361
+ scopeValue,
4362
+ scopeOrdinal,
4363
+ input.sessionId || null,
4364
+ service,
4365
+ input.data ? JSON.stringify(input.data) : null,
4366
+ severity,
4367
+ input.parentEventId || null,
4368
+ input.depth ?? 0
4369
+ ]
4370
+ );
4371
+ accepted++;
4372
+ } catch (err) {
4373
+ errors.push(err instanceof Error ? err.message : String(err));
4374
+ }
4375
+ }
4376
+ this.save();
4377
+ return { accepted, errors };
4378
+ }
4379
+ queryEvents(options = {}) {
4380
+ this.initializeSync();
4381
+ const { limit = 100, offset = 0 } = options;
4382
+ const conditions = [];
4383
+ const params = [];
4384
+ if (options.schemaId) {
4385
+ conditions.push("schema_id = ?");
4386
+ params.push(options.schemaId);
4387
+ }
4388
+ if (options.eventType) {
4389
+ conditions.push("event_type = ?");
4390
+ params.push(options.eventType);
4391
+ }
4392
+ if (options.category) {
4393
+ conditions.push("category = ?");
4394
+ params.push(options.category);
4395
+ }
4396
+ if (options.service) {
4397
+ conditions.push("service = ?");
4398
+ params.push(options.service);
4399
+ }
4400
+ if (options.sessionId) {
4401
+ conditions.push("session_id = ?");
4402
+ params.push(options.sessionId);
4403
+ }
4404
+ if (options.scopeValue) {
4405
+ conditions.push("scope_value = ?");
4406
+ params.push(options.scopeValue);
4407
+ }
4408
+ if (options.scopeFrom) {
4409
+ conditions.push("scope_value >= ?");
4410
+ params.push(options.scopeFrom);
4411
+ }
4412
+ if (options.scopeTo) {
4413
+ conditions.push("scope_value <= ?");
4414
+ params.push(options.scopeTo);
4415
+ }
4416
+ if (options.severity) {
4417
+ conditions.push("severity = ?");
4418
+ params.push(options.severity);
4419
+ }
4420
+ if (options.since) {
4421
+ conditions.push("timestamp >= ?");
4422
+ params.push(options.since);
4423
+ }
4424
+ if (options.until) {
4425
+ conditions.push("timestamp <= ?");
4426
+ params.push(options.until);
4427
+ }
4428
+ if (options.search) {
4429
+ conditions.push("data_json LIKE ?");
4430
+ params.push(`%${options.search}%`);
4431
+ }
4432
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
4433
+ const result = this.db.exec(
4434
+ `SELECT * FROM events ${whereClause} ORDER BY timestamp DESC LIMIT ? OFFSET ?`,
4435
+ [...params, limit, offset]
4436
+ );
4437
+ if (result.length === 0) return [];
4438
+ return result[0].values.map(
4439
+ (row) => this.rowToGenericEvent(result[0].columns, row)
4440
+ );
4441
+ }
4442
+ queryEventsByScope(schemaId, scopeValue) {
4443
+ this.initializeSync();
4444
+ const result = this.db.exec(
4445
+ `SELECT * FROM events
4446
+ WHERE schema_id = ? AND scope_value = ?
4447
+ ORDER BY timestamp ASC`,
4448
+ [schemaId, scopeValue]
4449
+ );
4450
+ if (result.length === 0) return [];
4451
+ return result[0].values.map(
4452
+ (row) => this.rowToGenericEvent(result[0].columns, row)
4453
+ );
4454
+ }
4455
+ getEventScopes(schemaId, options = {}) {
4456
+ this.initializeSync();
4457
+ const { limit = 100, offset = 0 } = options;
4458
+ const conditions = ["schema_id = ?"];
4459
+ const params = [schemaId];
4460
+ if (options.sessionId) {
4461
+ conditions.push("session_id = ?");
4462
+ params.push(options.sessionId);
4463
+ }
4464
+ const whereClause = `WHERE ${conditions.join(" AND ")}`;
4465
+ const result = this.db.exec(
4466
+ `SELECT
4467
+ scope_value,
4468
+ MIN(scope_ordinal) as scope_ordinal,
4469
+ COUNT(*) as event_count,
4470
+ MIN(timestamp) as first_timestamp,
4471
+ MAX(timestamp) as last_timestamp
4472
+ FROM events
4473
+ ${whereClause}
4474
+ AND scope_value IS NOT NULL
4475
+ GROUP BY scope_value
4476
+ ORDER BY MIN(COALESCE(scope_ordinal, 0)) DESC, MIN(timestamp) DESC
4477
+ LIMIT ? OFFSET ?`,
4478
+ [...params, limit, offset]
4479
+ );
4480
+ if (result.length === 0) return [];
4481
+ const scopes = [];
4482
+ for (const row of result[0].values) {
4483
+ const scopeValue = row[0];
4484
+ const scopeOrdinal = row[1] != null ? row[1] : void 0;
4485
+ const eventCount = row[2];
4486
+ const firstTimestamp = row[3];
4487
+ const lastTimestamp = row[4];
4488
+ const catResult = this.db.exec(
4489
+ `SELECT category, COUNT(*) as count FROM events
4490
+ WHERE schema_id = ? AND scope_value = ?
4491
+ GROUP BY category`,
4492
+ [schemaId, scopeValue]
4493
+ );
4494
+ const categories = {};
4495
+ if (catResult.length > 0) {
4496
+ for (const catRow of catResult[0].values) {
4497
+ categories[catRow[0]] = catRow[1];
4498
+ }
4499
+ }
4500
+ scopes.push({
4501
+ scopeValue,
4502
+ scopeOrdinal,
4503
+ eventCount,
4504
+ categories,
4505
+ firstTimestamp,
4506
+ lastTimestamp
4507
+ });
4508
+ }
4509
+ return scopes;
4510
+ }
4511
+ getEventCount(options = {}) {
4512
+ this.initializeSync();
4513
+ const conditions = [];
4514
+ const params = [];
4515
+ if (options.schemaId) {
4516
+ conditions.push("schema_id = ?");
4517
+ params.push(options.schemaId);
4518
+ }
4519
+ if (options.eventType) {
4520
+ conditions.push("event_type = ?");
4521
+ params.push(options.eventType);
4522
+ }
4523
+ if (options.service) {
4524
+ conditions.push("service = ?");
4525
+ params.push(options.service);
4526
+ }
4527
+ if (options.since) {
4528
+ conditions.push("timestamp >= ?");
4529
+ params.push(options.since);
4530
+ }
4531
+ if (options.until) {
4532
+ conditions.push("timestamp <= ?");
4533
+ params.push(options.until);
4534
+ }
4535
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
4536
+ const result = this.db.exec(
4537
+ `SELECT COUNT(*) as count FROM events ${whereClause}`,
4538
+ params
4539
+ );
4540
+ if (result.length === 0 || result[0].values.length === 0) return 0;
4541
+ return result[0].values[0][0];
4542
+ }
4543
+ pruneEvents(maxCount) {
4544
+ this.initializeSync();
4545
+ if (maxCount <= 0) return 0;
4546
+ const currentCount = this.getEventCount();
4547
+ if (currentCount <= maxCount) return 0;
4548
+ const deleteCount = currentCount - maxCount;
4549
+ this.db.run(
4550
+ `DELETE FROM events WHERE id IN (
4551
+ SELECT id FROM events ORDER BY timestamp ASC LIMIT ?
4552
+ )`,
4553
+ [deleteCount]
4554
+ );
4555
+ this.save();
4556
+ return deleteCount;
4557
+ }
4558
+ rowToGenericEvent(columns, row) {
4559
+ const obj = {};
4560
+ columns.forEach((col, i) => {
4561
+ obj[col] = row[i];
4562
+ });
4563
+ return {
4564
+ id: obj.id,
4565
+ schemaId: obj.schema_id,
4566
+ eventType: obj.event_type,
4567
+ category: obj.category,
4568
+ timestamp: obj.timestamp,
4569
+ scopeValue: obj.scope_value || void 0,
4570
+ scopeOrdinal: obj.scope_ordinal != null ? obj.scope_ordinal : void 0,
4571
+ sessionId: obj.session_id || void 0,
4572
+ service: obj.service,
4573
+ data: obj.data_json ? JSON.parse(obj.data_json) : void 0,
4574
+ severity: obj.severity || "info",
4575
+ parentEventId: obj.parent_event_id || void 0,
4576
+ depth: obj.depth || 0
4577
+ };
4578
+ }
3409
4579
  close() {
3410
4580
  if (this.db) {
3411
4581
  this.save();
@@ -3414,7 +4584,207 @@ var SentinelStorage = class {
3414
4584
  }
3415
4585
  }
3416
4586
  };
4587
+ var DEFAULT_AUTH_CONFIG = {
4588
+ enabled: false,
4589
+ tokens: []
4590
+ };
4591
+ var DEFAULT_RATE_LIMIT_CONFIG = {
4592
+ enabled: false,
4593
+ global: {
4594
+ maxRequestsPerMinute: 600,
4595
+ maxEntriesPerBatch: 500,
4596
+ samplingRate: 1
4597
+ },
4598
+ perService: {}
4599
+ };
4600
+ var DEFAULT_SERVER_CONFIG = {
4601
+ port: 3838,
4602
+ maxLogs: 1e4,
4603
+ maxBatchSize: 500,
4604
+ wsMaxSubscribers: 256,
4605
+ pruneIntervalInserts: 100,
4606
+ logRetentionDays: 0,
4607
+ auth: DEFAULT_AUTH_CONFIG,
4608
+ rateLimit: DEFAULT_RATE_LIMIT_CONFIG
4609
+ };
4610
+ var CONFIG_FILES = [".sentinel.yaml", ".sentinel.yml"];
4611
+ function loadConfig(projectDir) {
4612
+ for (const filename of CONFIG_FILES) {
4613
+ const filePath = path2.join(projectDir, filename);
4614
+ if (fs2.existsSync(filePath)) {
4615
+ const content = fs2.readFileSync(filePath, "utf-8");
4616
+ return parseSimpleYaml(content);
4617
+ }
4618
+ }
4619
+ return null;
4620
+ }
4621
+ function writeConfig(projectDir, config) {
4622
+ const filePath = path2.join(projectDir, ".sentinel.yaml");
4623
+ const content = serializeSimpleYaml(config);
4624
+ fs2.writeFileSync(filePath, content, "utf-8");
4625
+ }
4626
+ function parseSimpleYaml(content) {
4627
+ const config = { version: "1.0", project: "" };
4628
+ const lines = content.split("\n");
4629
+ let currentSection = null;
4630
+ let currentSubSection = null;
4631
+ for (const line of lines) {
4632
+ const trimmed = line.trimEnd();
4633
+ if (!trimmed || trimmed.startsWith("#")) continue;
4634
+ const topMatch = trimmed.match(/^(\w+):\s*(.+)$/);
4635
+ if (topMatch) {
4636
+ const [, key, value] = topMatch;
4637
+ if (key === "version") config.version = value.replace(/['"]/g, "");
4638
+ else if (key === "project") config.project = value.replace(/['"]/g, "");
4639
+ else if (key === "environment") config.environment = value.replace(/['"]/g, "");
4640
+ currentSection = null;
4641
+ currentSubSection = null;
4642
+ continue;
4643
+ }
4644
+ const sectionMatch = trimmed.match(/^(\w+):$/);
4645
+ if (sectionMatch) {
4646
+ currentSection = sectionMatch[1];
4647
+ currentSubSection = null;
4648
+ if (currentSection === "symbols" && !config.symbols) {
4649
+ config.symbols = {};
4650
+ }
4651
+ if (currentSection === "routes" && !config.routes) {
4652
+ config.routes = {};
4653
+ }
4654
+ if (currentSection === "scrub" && !config.scrub) {
4655
+ config.scrub = {};
4656
+ }
4657
+ if (currentSection === "server" && !config.server) {
4658
+ config.server = {};
4659
+ }
4660
+ continue;
4661
+ }
4662
+ const subMatch = trimmed.match(/^\s{2}(\w+):$/);
4663
+ if (subMatch && currentSection) {
4664
+ currentSubSection = subMatch[1];
4665
+ if (currentSection === "symbols" && config.symbols) {
4666
+ config.symbols[currentSubSection] = [];
4667
+ }
4668
+ if (currentSection === "scrub" && config.scrub) {
4669
+ config.scrub[currentSubSection] = [];
4670
+ }
4671
+ continue;
4672
+ }
4673
+ const listMatch = trimmed.match(/^\s+-\s+(.+)$/);
4674
+ if (listMatch && currentSection && currentSubSection) {
4675
+ const value = listMatch[1].replace(/['"]/g, "");
4676
+ if (currentSection === "symbols" && config.symbols) {
4677
+ const arr = config.symbols[currentSubSection];
4678
+ if (Array.isArray(arr)) arr.push(value);
4679
+ }
4680
+ if (currentSection === "scrub" && config.scrub) {
4681
+ const arr = config.scrub[currentSubSection];
4682
+ if (Array.isArray(arr)) arr.push(value);
4683
+ }
4684
+ continue;
4685
+ }
4686
+ const routeMatch = trimmed.match(/^\s+(['"]?\/[^'"]+['"]?):\s+['"]?([^'"]+)['"]?$/);
4687
+ if (routeMatch && currentSection === "routes" && config.routes) {
4688
+ const route = routeMatch[1].replace(/['"]/g, "");
4689
+ config.routes[route] = routeMatch[2];
4690
+ continue;
4691
+ }
4692
+ const serverKvMatch = trimmed.match(/^\s+(\w+):\s+(\d+)$/);
4693
+ if (serverKvMatch && currentSection === "server" && config.server) {
4694
+ const key = serverKvMatch[1];
4695
+ const value = parseInt(serverKvMatch[2], 10);
4696
+ if (key in { port: 1, maxLogs: 1, maxBatchSize: 1, wsMaxSubscribers: 1, pruneIntervalInserts: 1, logRetentionDays: 1 }) {
4697
+ config.server[key] = value;
4698
+ }
4699
+ continue;
4700
+ }
4701
+ }
4702
+ return config;
4703
+ }
4704
+ function serializeSimpleYaml(config) {
4705
+ const lines = [];
4706
+ lines.push(`# Sentinel Configuration`);
4707
+ lines.push(`# Auto-generated \u2014 edit freely`);
4708
+ lines.push("");
4709
+ lines.push(`version: "${config.version}"`);
4710
+ lines.push(`project: "${config.project}"`);
4711
+ if (config.environment) {
4712
+ lines.push(`environment: "${config.environment}"`);
4713
+ }
4714
+ if (config.symbols) {
4715
+ lines.push("");
4716
+ lines.push("symbols:");
4717
+ for (const [key, values] of Object.entries(config.symbols)) {
4718
+ if (values && values.length > 0) {
4719
+ lines.push(` ${key}:`);
4720
+ for (const v of values) {
4721
+ lines.push(` - ${v}`);
4722
+ }
4723
+ }
4724
+ }
4725
+ }
4726
+ if (config.routes && Object.keys(config.routes).length > 0) {
4727
+ lines.push("");
4728
+ lines.push("routes:");
4729
+ for (const [route, symbol] of Object.entries(config.routes)) {
4730
+ lines.push(` "${route}": ${symbol}`);
4731
+ }
4732
+ }
4733
+ if (config.scrub) {
4734
+ lines.push("");
4735
+ lines.push("scrub:");
4736
+ if (config.scrub.headers?.length) {
4737
+ lines.push(" headers:");
4738
+ for (const h of config.scrub.headers) {
4739
+ lines.push(` - ${h}`);
4740
+ }
4741
+ }
4742
+ if (config.scrub.fields?.length) {
4743
+ lines.push(" fields:");
4744
+ for (const f of config.scrub.fields) {
4745
+ lines.push(` - ${f}`);
4746
+ }
4747
+ }
4748
+ }
4749
+ if (config.server && Object.keys(config.server).length > 0) {
4750
+ lines.push("");
4751
+ lines.push("server:");
4752
+ for (const [key, value] of Object.entries(config.server)) {
4753
+ if (value !== void 0) {
4754
+ lines.push(` ${key}: ${value}`);
4755
+ }
4756
+ }
4757
+ }
4758
+ lines.push("");
4759
+ return lines.join("\n");
4760
+ }
4761
+ function loadServerConfig(projectDir) {
4762
+ const config = { ...DEFAULT_SERVER_CONFIG };
4763
+ const yamlConfig = projectDir ? loadConfig(projectDir) : null;
4764
+ const globalDir = path2.join(process.env.HOME || "~", ".paradigm");
4765
+ const globalConfig = loadConfig(globalDir);
4766
+ for (const src of [globalConfig, yamlConfig]) {
4767
+ if (src?.server) {
4768
+ if (src.server.port !== void 0) config.port = src.server.port;
4769
+ if (src.server.maxLogs !== void 0) config.maxLogs = src.server.maxLogs;
4770
+ if (src.server.maxBatchSize !== void 0) config.maxBatchSize = src.server.maxBatchSize;
4771
+ if (src.server.wsMaxSubscribers !== void 0) config.wsMaxSubscribers = src.server.wsMaxSubscribers;
4772
+ if (src.server.pruneIntervalInserts !== void 0) config.pruneIntervalInserts = src.server.pruneIntervalInserts;
4773
+ if (src.server.logRetentionDays !== void 0) config.logRetentionDays = src.server.logRetentionDays;
4774
+ }
4775
+ }
4776
+ if (process.env.SENTINEL_PORT) config.port = parseInt(process.env.SENTINEL_PORT, 10);
4777
+ if (process.env.SENTINEL_MAX_LOGS) config.maxLogs = parseInt(process.env.SENTINEL_MAX_LOGS, 10);
4778
+ return config;
4779
+ }
3417
4780
 
3418
4781
  export {
3419
- SentinelStorage
4782
+ v4_default,
4783
+ SentinelStorage,
4784
+ DEFAULT_AUTH_CONFIG,
4785
+ DEFAULT_RATE_LIMIT_CONFIG,
4786
+ DEFAULT_SERVER_CONFIG,
4787
+ loadConfig,
4788
+ writeConfig,
4789
+ loadServerConfig
3420
4790
  };