chainlesschain 0.47.8 → 0.49.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 (86) hide show
  1. package/bin/chainlesschain.js +0 -0
  2. package/package.json +10 -8
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AppLayout-6SPt_8Y_.js → AppLayout-Rvi759IS.js} +1 -1
  5. package/src/assets/web-panel/assets/Dashboard-BS-tzGNj.css +1 -0
  6. package/src/assets/web-panel/assets/{Dashboard-Br7kCwKJ.js → Dashboard-DBhFxXYQ.js} +2 -2
  7. package/src/assets/web-panel/assets/{index-tN-8TosE.js → index-uL0cZ8N_.js} +2 -2
  8. package/src/assets/web-panel/index.html +2 -2
  9. package/src/commands/activitypub.js +533 -0
  10. package/src/commands/codegen.js +303 -0
  11. package/src/commands/collab.js +482 -0
  12. package/src/commands/compliance.js +597 -6
  13. package/src/commands/crosschain.js +382 -0
  14. package/src/commands/dbevo.js +388 -0
  15. package/src/commands/dev.js +411 -0
  16. package/src/commands/federation.js +427 -0
  17. package/src/commands/fusion.js +332 -0
  18. package/src/commands/governance.js +505 -0
  19. package/src/commands/hardening.js +110 -0
  20. package/src/commands/incentive.js +373 -0
  21. package/src/commands/inference.js +304 -0
  22. package/src/commands/infra.js +361 -0
  23. package/src/commands/kg.js +371 -0
  24. package/src/commands/marketplace.js +326 -0
  25. package/src/commands/matrix.js +283 -0
  26. package/src/commands/mcp.js +441 -18
  27. package/src/commands/nlprog.js +329 -0
  28. package/src/commands/nostr.js +196 -7
  29. package/src/commands/ops.js +408 -0
  30. package/src/commands/perception.js +385 -0
  31. package/src/commands/pqc.js +34 -0
  32. package/src/commands/privacy.js +345 -0
  33. package/src/commands/quantization.js +280 -0
  34. package/src/commands/recommend.js +336 -0
  35. package/src/commands/reputation.js +349 -0
  36. package/src/commands/runtime.js +500 -0
  37. package/src/commands/sla.js +352 -0
  38. package/src/commands/social.js +265 -0
  39. package/src/commands/stress.js +252 -0
  40. package/src/commands/tech.js +268 -0
  41. package/src/commands/tenant.js +576 -0
  42. package/src/commands/trust.js +366 -0
  43. package/src/harness/mcp-client.js +330 -54
  44. package/src/index.js +114 -0
  45. package/src/lib/activitypub-bridge.js +623 -0
  46. package/src/lib/aiops.js +523 -0
  47. package/src/lib/autonomous-developer.js +524 -0
  48. package/src/lib/code-agent.js +442 -0
  49. package/src/lib/collaboration-governance.js +556 -0
  50. package/src/lib/community-governance.js +649 -0
  51. package/src/lib/compliance-framework-reporter.js +600 -0
  52. package/src/lib/content-recommendation.js +600 -0
  53. package/src/lib/cross-chain.js +669 -0
  54. package/src/lib/dbevo.js +669 -0
  55. package/src/lib/decentral-infra.js +445 -0
  56. package/src/lib/federation-hardening.js +587 -0
  57. package/src/lib/hardening-manager.js +409 -0
  58. package/src/lib/inference-network.js +407 -0
  59. package/src/lib/knowledge-graph.js +530 -0
  60. package/src/lib/matrix-bridge.js +252 -0
  61. package/src/lib/mcp-client.js +3 -0
  62. package/src/lib/mcp-registry.js +347 -0
  63. package/src/lib/mcp-scaffold.js +385 -0
  64. package/src/lib/multimodal.js +698 -0
  65. package/src/lib/nl-programming.js +595 -0
  66. package/src/lib/nostr-bridge.js +214 -38
  67. package/src/lib/perception.js +500 -0
  68. package/src/lib/pqc-manager.js +141 -9
  69. package/src/lib/privacy-computing.js +575 -0
  70. package/src/lib/protocol-fusion.js +535 -0
  71. package/src/lib/quantization.js +362 -0
  72. package/src/lib/reputation-optimizer.js +509 -0
  73. package/src/lib/skill-marketplace.js +397 -0
  74. package/src/lib/sla-manager.js +484 -0
  75. package/src/lib/social-graph.js +408 -0
  76. package/src/lib/stix-parser.js +167 -0
  77. package/src/lib/stress-tester.js +383 -0
  78. package/src/lib/tech-learning-engine.js +651 -0
  79. package/src/lib/tenant-saas.js +831 -0
  80. package/src/lib/threat-intel.js +268 -0
  81. package/src/lib/token-incentive.js +513 -0
  82. package/src/lib/topic-classifier.js +400 -0
  83. package/src/lib/trust-security.js +473 -0
  84. package/src/lib/ueba.js +403 -0
  85. package/src/lib/universal-runtime.js +771 -0
  86. package/src/assets/web-panel/assets/Dashboard-CKeMmCoT.css +0 -1
@@ -0,0 +1,484 @@
1
+ /**
2
+ * SLA Manager — cross-org service-level agreements with tier-based
3
+ * thresholds, metric recording, violation detection and compensation
4
+ * calculation (Phase 61 design, CLI port).
5
+ *
6
+ * The Desktop build plugs SLA monitoring into live federation telemetry.
7
+ * The CLI doesn't have a federation fixture, so operators drive metrics
8
+ * in manually via `sla record`; everything else (tiers, violation
9
+ * detection, compensation formula, reports) is identical to the Desktop
10
+ * implementation.
11
+ */
12
+
13
+ import crypto from "crypto";
14
+
15
+ /* ── Tier catalog ──────────────────────────────────────────── */
16
+
17
+ export const SLA_TIERS = Object.freeze({
18
+ GOLD: Object.freeze({
19
+ name: "gold",
20
+ availability: 0.999,
21
+ maxResponseTime: 100,
22
+ minThroughput: 1000,
23
+ maxErrorRate: 0.001,
24
+ compensationRate: 0.05,
25
+ }),
26
+ SILVER: Object.freeze({
27
+ name: "silver",
28
+ availability: 0.995,
29
+ maxResponseTime: 200,
30
+ minThroughput: 500,
31
+ maxErrorRate: 0.005,
32
+ compensationRate: 0.03,
33
+ }),
34
+ BRONZE: Object.freeze({
35
+ name: "bronze",
36
+ availability: 0.99,
37
+ maxResponseTime: 500,
38
+ minThroughput: 200,
39
+ maxErrorRate: 0.01,
40
+ compensationRate: 0.01,
41
+ }),
42
+ });
43
+
44
+ const TIER_INDEX = new Map(Object.values(SLA_TIERS).map((t) => [t.name, t]));
45
+
46
+ export function resolveTier(name) {
47
+ if (!name) return null;
48
+ return TIER_INDEX.get(String(name).toLowerCase()) || null;
49
+ }
50
+
51
+ export function listTiers() {
52
+ return Object.values(SLA_TIERS).map((t) => ({ ...t }));
53
+ }
54
+
55
+ export const SLA_TERMS = Object.freeze({
56
+ AVAILABILITY: "availability",
57
+ RESPONSE_TIME: "response_time",
58
+ THROUGHPUT: "throughput",
59
+ ERROR_RATE: "error_rate",
60
+ });
61
+
62
+ export const VIOLATION_SEVERITY = Object.freeze({
63
+ MINOR: "minor",
64
+ MODERATE: "moderate",
65
+ MAJOR: "major",
66
+ CRITICAL: "critical",
67
+ });
68
+
69
+ export const SLA_STATUS = Object.freeze({
70
+ ACTIVE: "active",
71
+ EXPIRED: "expired",
72
+ TERMINATED: "terminated",
73
+ });
74
+
75
+ function _classifySeverity(deviationPercent) {
76
+ const d = Math.abs(deviationPercent);
77
+ if (d > 50) return VIOLATION_SEVERITY.CRITICAL;
78
+ if (d > 25) return VIOLATION_SEVERITY.MAJOR;
79
+ if (d > 10) return VIOLATION_SEVERITY.MODERATE;
80
+ return VIOLATION_SEVERITY.MINOR;
81
+ }
82
+
83
+ /* ── In-memory stores ─────────────────────────────────────── */
84
+ const _contracts = new Map();
85
+ const _metrics = new Map(); // slaId → [{term, value, recordedAt}]
86
+ const _violations = new Map(); // violationId → record
87
+ let _seq = 0;
88
+
89
+ /* ── Schema ────────────────────────────────────────────────── */
90
+
91
+ export function ensureSlaTables(db) {
92
+ db.exec(`
93
+ CREATE TABLE IF NOT EXISTS sla_contracts (
94
+ sla_id TEXT PRIMARY KEY,
95
+ org_id TEXT NOT NULL,
96
+ tier TEXT NOT NULL,
97
+ terms TEXT NOT NULL,
98
+ monthly_fee REAL DEFAULT 0,
99
+ start_date INTEGER NOT NULL,
100
+ end_date INTEGER NOT NULL,
101
+ status TEXT DEFAULT 'active',
102
+ created_at INTEGER NOT NULL,
103
+ updated_at INTEGER NOT NULL
104
+ )
105
+ `);
106
+ db.exec(`
107
+ CREATE TABLE IF NOT EXISTS sla_metrics (
108
+ metric_id TEXT PRIMARY KEY,
109
+ sla_id TEXT NOT NULL,
110
+ term TEXT NOT NULL,
111
+ value REAL NOT NULL,
112
+ recorded_at INTEGER NOT NULL
113
+ )
114
+ `);
115
+ db.exec(`
116
+ CREATE TABLE IF NOT EXISTS sla_violations (
117
+ violation_id TEXT PRIMARY KEY,
118
+ sla_id TEXT NOT NULL,
119
+ term TEXT NOT NULL,
120
+ severity TEXT NOT NULL,
121
+ expected_value REAL NOT NULL,
122
+ actual_value REAL NOT NULL,
123
+ deviation_percent REAL,
124
+ compensation_amount REAL,
125
+ occurred_at INTEGER NOT NULL,
126
+ resolved_at INTEGER
127
+ )
128
+ `);
129
+ }
130
+
131
+ /* ── Contracts ─────────────────────────────────────────────── */
132
+
133
+ export function createSLA(db, config = {}) {
134
+ const orgId = config.orgId;
135
+ if (!orgId) throw new Error("orgId is required");
136
+ const tier = resolveTier(config.tier || "silver");
137
+ if (!tier) {
138
+ throw new Error(
139
+ `Unknown SLA tier: ${config.tier} (known: gold/silver/bronze)`,
140
+ );
141
+ }
142
+ const durationMs = Number(config.duration ?? 30 * 86400000);
143
+ if (!Number.isFinite(durationMs) || durationMs <= 0) {
144
+ throw new Error("duration must be a positive number (ms)");
145
+ }
146
+ const monthlyFee = Number(config.monthlyFee ?? 0);
147
+ if (monthlyFee < 0) throw new Error("monthlyFee must be >= 0");
148
+
149
+ const now = Date.now();
150
+ const slaId = crypto.randomUUID();
151
+ // Terms merge tier defaults with caller overrides (caller can tighten
152
+ // individual thresholds without abandoning the tier).
153
+ const terms = {
154
+ availability: tier.availability,
155
+ maxResponseTime: tier.maxResponseTime,
156
+ minThroughput: tier.minThroughput,
157
+ maxErrorRate: tier.maxErrorRate,
158
+ ...(config.terms || {}),
159
+ };
160
+
161
+ const contract = {
162
+ slaId,
163
+ orgId,
164
+ tier: tier.name,
165
+ terms,
166
+ monthlyFee,
167
+ startDate: now,
168
+ endDate: now + durationMs,
169
+ status: SLA_STATUS.ACTIVE,
170
+ createdAt: now,
171
+ updatedAt: now,
172
+ _seq: ++_seq,
173
+ };
174
+ _contracts.set(slaId, contract);
175
+
176
+ db.prepare(
177
+ `INSERT INTO sla_contracts (sla_id, org_id, tier, terms, monthly_fee, start_date, end_date, status, created_at, updated_at)
178
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
179
+ ).run(
180
+ slaId,
181
+ orgId,
182
+ tier.name,
183
+ JSON.stringify(terms),
184
+ monthlyFee,
185
+ now,
186
+ now + durationMs,
187
+ contract.status,
188
+ now,
189
+ now,
190
+ );
191
+
192
+ const { _seq: _omit, ...rest } = contract;
193
+ void _omit;
194
+ return rest;
195
+ }
196
+
197
+ export function listSLAs(opts = {}) {
198
+ let rows = [..._contracts.values()];
199
+ if (opts.orgId) rows = rows.filter((c) => c.orgId === opts.orgId);
200
+ if (opts.status) rows = rows.filter((c) => c.status === opts.status);
201
+ if (opts.tier) rows = rows.filter((c) => c.tier === opts.tier);
202
+ rows.sort((a, b) => b.createdAt - a.createdAt || b._seq - a._seq);
203
+ const limit = opts.limit || 50;
204
+ return rows.slice(0, limit).map((c) => {
205
+ const { _seq: _omit, ...rest } = c;
206
+ void _omit;
207
+ return rest;
208
+ });
209
+ }
210
+
211
+ export function getSLA(slaId) {
212
+ const contract = _contracts.get(slaId);
213
+ if (!contract) throw new Error(`SLA not found: ${slaId}`);
214
+ const { _seq: _omit, ...rest } = contract;
215
+ void _omit;
216
+ return rest;
217
+ }
218
+
219
+ export function terminateSLA(db, slaId) {
220
+ const contract = _contracts.get(slaId);
221
+ if (!contract) throw new Error(`SLA not found: ${slaId}`);
222
+ contract.status = SLA_STATUS.TERMINATED;
223
+ contract.updatedAt = Date.now();
224
+ db.prepare(
225
+ `UPDATE sla_contracts SET status = ?, updated_at = ? WHERE sla_id = ?`,
226
+ ).run(contract.status, contract.updatedAt, slaId);
227
+ return { slaId, status: contract.status };
228
+ }
229
+
230
+ /* ── Metrics ───────────────────────────────────────────────── */
231
+
232
+ const VALID_TERMS = new Set(Object.values(SLA_TERMS));
233
+
234
+ export function recordMetric(db, slaId, term, value, opts = {}) {
235
+ if (!_contracts.has(slaId)) {
236
+ throw new Error(`SLA not found: ${slaId}`);
237
+ }
238
+ if (!VALID_TERMS.has(term)) {
239
+ throw new Error(
240
+ `Unknown SLA term: ${term} (known: ${[...VALID_TERMS].join("/")})`,
241
+ );
242
+ }
243
+ const v = Number(value);
244
+ if (!Number.isFinite(v)) throw new Error("metric value must be finite");
245
+
246
+ const metricId = crypto.randomUUID();
247
+ const recordedAt = Number(opts.recordedAt ?? Date.now());
248
+ const metric = { metricId, slaId, term, value: v, recordedAt };
249
+
250
+ if (!_metrics.has(slaId)) _metrics.set(slaId, []);
251
+ _metrics.get(slaId).push(metric);
252
+
253
+ db.prepare(
254
+ `INSERT INTO sla_metrics (metric_id, sla_id, term, value, recorded_at)
255
+ VALUES (?, ?, ?, ?, ?)`,
256
+ ).run(metricId, slaId, term, v, recordedAt);
257
+
258
+ return metric;
259
+ }
260
+
261
+ function _aggregateMetrics(metrics, term) {
262
+ const values = metrics.filter((m) => m.term === term).map((m) => m.value);
263
+ if (values.length === 0) return null;
264
+ const sum = values.reduce((a, b) => a + b, 0);
265
+ const sorted = [...values].sort((a, b) => a - b);
266
+ const p95Idx = Math.min(sorted.length - 1, Math.floor(sorted.length * 0.95));
267
+ return {
268
+ count: values.length,
269
+ mean: sum / values.length,
270
+ min: sorted[0],
271
+ max: sorted[sorted.length - 1],
272
+ p95: sorted[p95Idx],
273
+ };
274
+ }
275
+
276
+ export function getSLAMetrics(slaId) {
277
+ if (!_contracts.has(slaId)) {
278
+ throw new Error(`SLA not found: ${slaId}`);
279
+ }
280
+ const raw = _metrics.get(slaId) || [];
281
+ const result = { slaId, totalSamples: raw.length, byTerm: {} };
282
+ for (const term of VALID_TERMS) {
283
+ const agg = _aggregateMetrics(raw, term);
284
+ if (agg) result.byTerm[term] = agg;
285
+ }
286
+ return result;
287
+ }
288
+
289
+ /* ── Violations ────────────────────────────────────────────── */
290
+
291
+ // Deviation is "% worse than threshold". For availability/throughput (higher
292
+ // is better) deviation = (expected - actual) / expected × 100. For
293
+ // response_time/error_rate (lower is better) deviation = (actual - expected)
294
+ // / expected × 100. A positive deviation means the term is violated.
295
+ function _computeDeviation(term, expected, actual) {
296
+ if (expected === 0) return 0;
297
+ switch (term) {
298
+ case SLA_TERMS.AVAILABILITY:
299
+ case SLA_TERMS.THROUGHPUT:
300
+ return ((expected - actual) / expected) * 100;
301
+ case SLA_TERMS.RESPONSE_TIME:
302
+ case SLA_TERMS.ERROR_RATE:
303
+ return ((actual - expected) / expected) * 100;
304
+ default:
305
+ return 0;
306
+ }
307
+ }
308
+
309
+ function _expectedFor(terms, term) {
310
+ switch (term) {
311
+ case SLA_TERMS.AVAILABILITY:
312
+ return terms.availability;
313
+ case SLA_TERMS.RESPONSE_TIME:
314
+ return terms.maxResponseTime;
315
+ case SLA_TERMS.THROUGHPUT:
316
+ return terms.minThroughput;
317
+ case SLA_TERMS.ERROR_RATE:
318
+ return terms.maxErrorRate;
319
+ default:
320
+ return null;
321
+ }
322
+ }
323
+
324
+ export function checkViolations(db, slaId) {
325
+ const contract = _contracts.get(slaId);
326
+ if (!contract) throw new Error(`SLA not found: ${slaId}`);
327
+
328
+ const metrics = _metrics.get(slaId) || [];
329
+ const found = [];
330
+ const now = Date.now();
331
+
332
+ for (const term of VALID_TERMS) {
333
+ const expected = _expectedFor(contract.terms, term);
334
+ if (expected == null) continue;
335
+ const agg = _aggregateMetrics(metrics, term);
336
+ if (!agg) continue;
337
+
338
+ // Use p95 for response time (tail matters); mean for everything else.
339
+ const actual = term === SLA_TERMS.RESPONSE_TIME ? agg.p95 : agg.mean;
340
+ const deviation = _computeDeviation(term, expected, actual);
341
+ if (deviation <= 0) continue; // within SLA
342
+
343
+ const severity = _classifySeverity(deviation);
344
+ const violationId = crypto.randomUUID();
345
+ const violation = {
346
+ violationId,
347
+ slaId,
348
+ term,
349
+ severity,
350
+ expectedValue: expected,
351
+ actualValue: Number(actual.toFixed(6)),
352
+ deviationPercent: Number(deviation.toFixed(4)),
353
+ compensationAmount: null,
354
+ occurredAt: now,
355
+ resolvedAt: null,
356
+ };
357
+ _violations.set(violationId, violation);
358
+ db.prepare(
359
+ `INSERT INTO sla_violations (violation_id, sla_id, term, severity, expected_value, actual_value, deviation_percent, compensation_amount, occurred_at, resolved_at)
360
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
361
+ ).run(
362
+ violationId,
363
+ slaId,
364
+ term,
365
+ severity,
366
+ expected,
367
+ violation.actualValue,
368
+ violation.deviationPercent,
369
+ null,
370
+ now,
371
+ null,
372
+ );
373
+ found.push(violation);
374
+ }
375
+
376
+ return {
377
+ slaId,
378
+ checkedAt: now,
379
+ totalViolations: found.length,
380
+ violations: found,
381
+ };
382
+ }
383
+
384
+ export function listViolations(opts = {}) {
385
+ let rows = [..._violations.values()];
386
+ if (opts.slaId) rows = rows.filter((v) => v.slaId === opts.slaId);
387
+ if (opts.severity) rows = rows.filter((v) => v.severity === opts.severity);
388
+ rows.sort((a, b) => b.occurredAt - a.occurredAt);
389
+ const limit = opts.limit || 50;
390
+ return rows.slice(0, limit);
391
+ }
392
+
393
+ export function calculateCompensation(db, violationId) {
394
+ const violation = _violations.get(violationId);
395
+ if (!violation) throw new Error(`Violation not found: ${violationId}`);
396
+ const contract = _contracts.get(violation.slaId);
397
+ if (!contract) {
398
+ throw new Error(`SLA not found for violation: ${violation.slaId}`);
399
+ }
400
+ const tier = resolveTier(contract.tier);
401
+
402
+ // baseCompensation = monthlyFee × compensationRate
403
+ // deviationMultiplier ∈ [0, 2], capped at 50% deviation
404
+ // finalCompensation = base × multiplier
405
+ const base = contract.monthlyFee * tier.compensationRate;
406
+ const multiplier = Math.min(violation.deviationPercent / 50, 2.0);
407
+ const amount = Number((base * multiplier).toFixed(4));
408
+
409
+ violation.compensationAmount = amount;
410
+ db.prepare(
411
+ `UPDATE sla_violations SET compensation_amount = ? WHERE violation_id = ?`,
412
+ ).run(amount, violationId);
413
+
414
+ return {
415
+ violationId,
416
+ slaId: violation.slaId,
417
+ severity: violation.severity,
418
+ base: Number(base.toFixed(4)),
419
+ multiplier: Number(multiplier.toFixed(4)),
420
+ amount,
421
+ };
422
+ }
423
+
424
+ /* ── Reports ───────────────────────────────────────────────── */
425
+
426
+ export function generateReport(slaId, opts = {}) {
427
+ const contract = _contracts.get(slaId);
428
+ if (!contract) throw new Error(`SLA not found: ${slaId}`);
429
+
430
+ const start = Number(opts.startDate ?? contract.startDate);
431
+ const end = Number(opts.endDate ?? Date.now());
432
+ if (end < start) throw new Error("endDate must be >= startDate");
433
+
434
+ const allMetrics = _metrics.get(slaId) || [];
435
+ const inWindow = allMetrics.filter(
436
+ (m) => m.recordedAt >= start && m.recordedAt <= end,
437
+ );
438
+ const metricsByTerm = {};
439
+ for (const term of VALID_TERMS) {
440
+ const agg = _aggregateMetrics(inWindow, term);
441
+ if (agg) metricsByTerm[term] = agg;
442
+ }
443
+
444
+ const violations = [..._violations.values()].filter(
445
+ (v) => v.slaId === slaId && v.occurredAt >= start && v.occurredAt <= end,
446
+ );
447
+ const severityCounts = { minor: 0, moderate: 0, major: 0, critical: 0 };
448
+ let totalCompensation = 0;
449
+ for (const v of violations) {
450
+ severityCounts[v.severity] = (severityCounts[v.severity] || 0) + 1;
451
+ if (v.compensationAmount) totalCompensation += v.compensationAmount;
452
+ }
453
+
454
+ // Compliance = % of terms that had NO violation in window
455
+ const termsWithViolation = new Set(violations.map((v) => v.term));
456
+ const compliantTerms = [...VALID_TERMS].filter(
457
+ (t) => !termsWithViolation.has(t),
458
+ );
459
+ const compliance =
460
+ VALID_TERMS.size > 0 ? compliantTerms.length / VALID_TERMS.size : 1;
461
+
462
+ return {
463
+ slaId,
464
+ orgId: contract.orgId,
465
+ tier: contract.tier,
466
+ period: { startDate: start, endDate: end },
467
+ metrics: metricsByTerm,
468
+ violations: {
469
+ total: violations.length,
470
+ bySeverity: severityCounts,
471
+ totalCompensation: Number(totalCompensation.toFixed(4)),
472
+ },
473
+ compliance: Number(compliance.toFixed(4)),
474
+ };
475
+ }
476
+
477
+ /* ── State reset (tests) ───────────────────────────────────── */
478
+
479
+ export function _resetState() {
480
+ _contracts.clear();
481
+ _metrics.clear();
482
+ _violations.clear();
483
+ _seq = 0;
484
+ }