0xray 4.0.36 → 4.0.38

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 (169) hide show
  1. package/.grok-plugin/plugin.json +1 -1
  2. package/.xray/features.json +1 -1
  3. package/dist/CHANGELOG.md +28 -0
  4. package/dist/analytics/emerging-pattern-detector.d.ts +12 -1
  5. package/dist/analytics/emerging-pattern-detector.js +37 -12
  6. package/dist/analytics/pattern-learning-engine.js +1 -9
  7. package/dist/analytics/predictive-analytics.js +51 -33
  8. package/dist/analytics/prompt-pattern-analyzer.d.ts +1 -0
  9. package/dist/analytics/prompt-pattern-analyzer.js +39 -20
  10. package/dist/analytics/routing-performance-analyzer.d.ts +2 -0
  11. package/dist/analytics/routing-performance-analyzer.js +89 -37
  12. package/dist/analytics/simple-pattern-analyzer.d.ts +4 -0
  13. package/dist/analytics/simple-pattern-analyzer.js +66 -28
  14. package/dist/architect/architect-tools.d.ts +3 -0
  15. package/dist/architect/architect-tools.js +22 -0
  16. package/dist/cli/commands/grok-install.js +1 -1
  17. package/dist/cli/commands/hermes-install.js +11 -5
  18. package/dist/cli/commands/openclaw-install.js +13 -7
  19. package/dist/cli/commands/opencode-install.js +7 -4
  20. package/dist/cli/commands/suit-monitor.d.ts +30 -0
  21. package/dist/cli/commands/suit-monitor.js +128 -0
  22. package/dist/cli/index.js +52 -15
  23. package/dist/cli/suit-pulse.d.ts +29 -0
  24. package/dist/cli/suit-pulse.js +270 -0
  25. package/dist/delegation/agent-delegator.d.ts +4 -2
  26. package/dist/delegation/agent-delegator.js +46 -27
  27. package/dist/delegation/agent-expertise.js +2 -1
  28. package/dist/delegation/analytics/outcome-tracker.d.ts +6 -0
  29. package/dist/delegation/analytics/outcome-tracker.js +17 -3
  30. package/dist/delegation/ast-code-parser.d.ts +5 -0
  31. package/dist/delegation/ast-code-parser.js +53 -48
  32. package/dist/delegation/codebase-context-analyzer.d.ts +3 -7
  33. package/dist/delegation/codebase-context-analyzer.js +188 -159
  34. package/dist/delegation/session-coordinator.js +3 -2
  35. package/dist/enforcement/loaders/codex-loader.js +18 -14
  36. package/dist/enforcement/validators/architecture-validators.js +115 -9
  37. package/dist/governance/codex-policy.service.d.ts +12 -2
  38. package/dist/governance/codex-policy.service.js +91 -16
  39. package/dist/integrations/grok/hooks/session-start.js +6 -6
  40. package/dist/integrations/hooks/goggles-pipeline.mjs +169 -28
  41. package/dist/integrations/hooks/goggles-planes.json +172 -8
  42. package/dist/integrations/hooks/plates.cjs +138 -0
  43. package/dist/integrations/hooks/station-hook-runtime.cjs +63 -5
  44. package/dist/integrations/hooks/write-home.cjs +59 -0
  45. package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
  46. package/dist/mcps/architect-tools.server.d.ts +6 -0
  47. package/dist/mcps/architect-tools.server.js +19 -18
  48. package/dist/mcps/orchestrator/server.d.ts +4 -3
  49. package/dist/mcps/orchestrator/server.js +29 -17
  50. package/dist/memory-routing/lookup-cache.d.ts +8 -0
  51. package/dist/memory-routing/lookup-cache.js +72 -0
  52. package/dist/memory-routing/plates.d.ts +1 -1
  53. package/dist/memory-routing/plates.js +26 -0
  54. package/dist/memory-routing/provider-loader.js +3 -0
  55. package/dist/metrics/agent-metrics.d.ts +14 -5
  56. package/dist/metrics/agent-metrics.js +362 -224
  57. package/dist/nucleus/synthesis-consult-receipt.js +38 -16
  58. package/dist/orchestrator/enhanced-multi-agent-orchestrator.d.ts +5 -0
  59. package/dist/orchestrator/enhanced-multi-agent-orchestrator.js +9 -0
  60. package/dist/orchestrator/multi-agent-orchestration-coordinator.js +1 -2
  61. package/dist/orchestrator/orchestrator.js +1 -2
  62. package/dist/processors/implementations/agents-md-validation-processor.d.ts +0 -1
  63. package/dist/processors/implementations/agents-md-validation-processor.js +0 -11
  64. package/dist/processors/implementations/console-log-guard-processor.js +39 -50
  65. package/dist/processors/implementations/performance-budget-processor.d.ts +0 -5
  66. package/dist/processors/implementations/performance-budget-processor.js +29 -38
  67. package/dist/processors/implementations/storytelling-trigger-processor.d.ts +5 -0
  68. package/dist/processors/implementations/storytelling-trigger-processor.js +69 -16
  69. package/dist/processors/implementations/test-auto-creation-processor.js +39 -36
  70. package/dist/reporting/framework-reporting-system.d.ts +3 -0
  71. package/dist/reporting/framework-reporting-system.js +61 -8
  72. package/dist/reporting/log-parser.js +188 -105
  73. package/dist/reporting/metrics.js +42 -18
  74. package/dist/security/prompt-security-validator.js +8 -7
  75. package/dist/security/security-auditor.d.ts +4 -0
  76. package/dist/security/security-auditor.js +132 -57
  77. package/dist/security/security-hardener.d.ts +2 -0
  78. package/dist/security/security-hardener.js +31 -6
  79. package/dist/security/security-headers.d.ts +2 -0
  80. package/dist/security/security-headers.js +23 -21
  81. package/dist/security/security-scanner.js +18 -4
  82. package/dist/session/session-cleanup-manager.d.ts +2 -0
  83. package/dist/session/session-cleanup-manager.js +29 -8
  84. package/dist/session/session-monitor.d.ts +14 -4
  85. package/dist/session/session-monitor.js +208 -106
  86. package/dist/session/session-state-manager.d.ts +11 -0
  87. package/dist/session/session-state-manager.js +90 -8
  88. package/docs-site/docs/plates/activity-log.md +38 -0
  89. package/docs-site/docs/plates/cursor-compact.md +35 -0
  90. package/docs-site/docs/plates/grok-compact.md +35 -0
  91. package/docs-site/docs/plates/index.md +25 -3
  92. package/docs-site/docs/plates/inference-files.md +35 -0
  93. package/docs-site/docs/plates/kept-line.md +35 -0
  94. package/docs-site/docs/plates/lens-gate.md +35 -0
  95. package/docs-site/docs/plates/lens-page.md +35 -0
  96. package/docs-site/docs/plates/notes-page.md +35 -0
  97. package/docs-site/docs/plates/package-face.md +35 -0
  98. package/docs-site/docs/plates/payload-heat.md +35 -0
  99. package/docs-site/docs/plates/pickup-stamp.md +35 -0
  100. package/docs-site/docs/plates/pre-tool.md +35 -0
  101. package/docs-site/docs/plates/record-map.md +41 -0
  102. package/docs-site/docs/plates/reflection-page.md +35 -0
  103. package/docs-site/docs/plates/review.md +57 -0
  104. package/docs-site/docs/plates/session-capture.md +38 -0
  105. package/docs-site/docs/plates/site-manual.md +35 -0
  106. package/docs-site/docs/plates/stamp-plate.md +35 -0
  107. package/docs-site/docs/plates/station-card.md +35 -0
  108. package/docs-site/docs/plates/station-heat.md +35 -0
  109. package/docs-site/docs/plates/suit-organs.md +38 -0
  110. package/docs-site/docs/plates/suit-settings.md +35 -0
  111. package/docs-site/docs/plates/suit-wear.md +37 -0
  112. package/docs-site/docs/plates/trail-state.md +35 -0
  113. package/docs-site/docs/plates/work-fresh.md +35 -0
  114. package/docs-site/docs/plates/write-home.md +38 -0
  115. package/package.json +3 -2
  116. package/scripts/node/install-bridges.cjs +302 -78
  117. package/scripts/node/postinstall.cjs +14 -3
  118. package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
  119. package/src/mcps/architect-tools.server.ts +25 -20
  120. package/src/mcps/orchestrator/server.ts +33 -19
  121. package/xray/features.json +1 -1
  122. package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts.map +0 -1
  123. package/vendor/@0xray/repertoire/dist/RepertoireService.js.map +0 -1
  124. package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.d.ts.map +0 -1
  125. package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.js.map +0 -1
  126. package/vendor/@0xray/repertoire/dist/index.d.ts.map +0 -1
  127. package/vendor/@0xray/repertoire/dist/index.js.map +0 -1
  128. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.d.ts.map +0 -1
  129. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.js.map +0 -1
  130. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.d.ts.map +0 -1
  131. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.js.map +0 -1
  132. package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.d.ts.map +0 -1
  133. package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.js.map +0 -1
  134. package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.d.ts.map +0 -1
  135. package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.js.map +0 -1
  136. package/vendor/@0xray/repertoire/dist/mcp/server.d.ts.map +0 -1
  137. package/vendor/@0xray/repertoire/dist/mcp/server.js.map +0 -1
  138. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.d.ts.map +0 -1
  139. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.js.map +0 -1
  140. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.d.ts.map +0 -1
  141. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.js.map +0 -1
  142. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.d.ts.map +0 -1
  143. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js.map +0 -1
  144. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.d.ts.map +0 -1
  145. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.js.map +0 -1
  146. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.d.ts.map +0 -1
  147. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js.map +0 -1
  148. package/vendor/@0xray/repertoire/dist/paths.d.ts.map +0 -1
  149. package/vendor/@0xray/repertoire/dist/paths.js.map +0 -1
  150. package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts.map +0 -1
  151. package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js.map +0 -1
  152. package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts.map +0 -1
  153. package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js.map +0 -1
  154. package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.d.ts.map +0 -1
  155. package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.js.map +0 -1
  156. package/vendor/@0xray/repertoire/dist/registry/confidence-decay.d.ts.map +0 -1
  157. package/vendor/@0xray/repertoire/dist/registry/confidence-decay.js.map +0 -1
  158. package/vendor/@0xray/repertoire/dist/registry/signal-prune.d.ts.map +0 -1
  159. package/vendor/@0xray/repertoire/dist/registry/signal-prune.js.map +0 -1
  160. package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.d.ts.map +0 -1
  161. package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.js.map +0 -1
  162. package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.d.ts.map +0 -1
  163. package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.js.map +0 -1
  164. package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.d.ts.map +0 -1
  165. package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.js.map +0 -1
  166. package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.d.ts.map +0 -1
  167. package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.js.map +0 -1
  168. package/vendor/@0xray/repertoire/dist/types.d.ts.map +0 -1
  169. package/vendor/@0xray/repertoire/dist/types.js.map +0 -1
@@ -13,6 +13,8 @@ export class SessionCleanupManager {
13
13
  cleanupInterval;
14
14
  _sessionMetadata;
15
15
  _metadataLoaded = false;
16
+ /** Same object the store holds, so a one-field write does not clone every session. */
17
+ metadataRecord = {};
16
18
  sessionMonitor;
17
19
  constructor(stateManager, config = {}, sessionMonitor) {
18
20
  this.stateManager = stateManager;
@@ -40,6 +42,7 @@ export class SessionCleanupManager {
40
42
  set sessionMetadata(value) {
41
43
  this._sessionMetadata = value;
42
44
  this._metadataLoaded = true;
45
+ this.metadataRecord = Object.fromEntries(value);
43
46
  }
44
47
  /**
45
48
  * Initialize cleanup manager and start auto-cleanup if enabled
@@ -228,19 +231,21 @@ export class SessionCleanupManager {
228
231
  const now = Date.now();
229
232
  let expiredCount = 0;
230
233
  let idleCount = 0;
234
+ let activeSessions = 0;
231
235
  for (const metadata of this.sessionMetadata.values()) {
232
236
  if (!metadata.isActive)
233
237
  continue;
238
+ activeSessions += 1;
234
239
  if (now - metadata.createdAt > metadata.ttlMs) {
235
- expiredCount++;
240
+ expiredCount += 1;
236
241
  }
237
242
  else if (now - metadata.lastActivity > this.config.idleTimeoutMs) {
238
- idleCount++;
243
+ idleCount += 1;
239
244
  }
240
245
  }
241
246
  return {
242
247
  totalSessions: this.sessionMetadata.size,
243
- activeSessions: Array.from(this.sessionMetadata.values()).filter((m) => m.isActive).length,
248
+ activeSessions,
244
249
  expiredSessions: expiredCount,
245
250
  idleSessions: idleCount,
246
251
  nextCleanup: this.cleanupInterval
@@ -292,19 +297,29 @@ export class SessionCleanupManager {
292
297
  * Load session metadata from state manager (lazy loading)
293
298
  */
294
299
  loadSessionMetadata() {
300
+ this._sessionMetadata = new Map();
301
+ this.metadataRecord = {};
295
302
  try {
296
303
  const storedMetadata = this.stateManager.get("cleanup:session_metadata");
297
- this._sessionMetadata = new Map();
298
304
  if (storedMetadata &&
299
305
  typeof storedMetadata === "object" &&
300
306
  !Array.isArray(storedMetadata)) {
307
+ const loaded = new Map();
308
+ this._sessionMetadata = loaded;
309
+ let dropped = false;
301
310
  for (const [sessionId, metadata] of Object.entries(storedMetadata)) {
302
311
  if (metadata && typeof metadata === "object" && metadata.sessionId) {
303
- this._sessionMetadata.set(sessionId, metadata);
312
+ loaded.set(sessionId, metadata);
313
+ }
314
+ else {
315
+ dropped = true;
304
316
  }
305
317
  }
318
+ this.metadataRecord = dropped
319
+ ? Object.fromEntries(loaded)
320
+ : storedMetadata;
306
321
  frameworkLogger.log("session-cleanup", "load-metadata", "info", {
307
- sessionsLoaded: this._sessionMetadata.size,
322
+ sessionsLoaded: loaded.size,
308
323
  });
309
324
  }
310
325
  else if (storedMetadata) {
@@ -316,13 +331,19 @@ export class SessionCleanupManager {
316
331
  error,
317
332
  });
318
333
  }
334
+ this._metadataLoaded = true;
319
335
  }
320
336
  /**
321
337
  * Persist session metadata to state manager
322
338
  */
323
339
  persistSessionMetadata(sessionId, metadata) {
324
- const allMetadata = Object.fromEntries(this.sessionMetadata);
325
- this.stateManager.set("cleanup:session_metadata", allMetadata);
340
+ if (this._sessionMetadata?.has(sessionId)) {
341
+ this.metadataRecord[sessionId] = metadata;
342
+ }
343
+ else {
344
+ delete this.metadataRecord[sessionId];
345
+ }
346
+ this.stateManager.set("cleanup:session_metadata", this.metadataRecord);
326
347
  }
327
348
  /**
328
349
  * Cleanup a specific session
@@ -74,6 +74,13 @@ export declare class SessionMonitor {
74
74
  private interactionHistory;
75
75
  private sessionResponseTimes;
76
76
  private sessionErrors;
77
+ /** Stable store records. A field write patches one session instead of cloning the map. */
78
+ private healthRecord;
79
+ private metricsRecord;
80
+ private alertRecord;
81
+ private interactionRecord;
82
+ private responseTotals;
83
+ private outcomeTotals;
77
84
  constructor(stateManager: XrayStateManager, sessionCoordinator: SessionCoordinator, cleanupManager: SessionCleanupManager, config?: Partial<MonitorConfig>);
78
85
  start(): void;
79
86
  registerSession(sessionId: string): void;
@@ -96,14 +103,15 @@ export declare class SessionMonitor {
96
103
  private startMetricsCollection;
97
104
  private generateAlerts;
98
105
  private loadPersistedData;
99
- private persistHealthData;
100
- private persistMetricsData;
101
- private persistAlertData;
106
+ private persistHealth;
102
107
  shutdown(): void;
103
108
  /**
104
109
  * Record an interaction for tracking
105
110
  */
106
111
  recordInteraction(sessionId: string, interaction: InteractionRecord): void;
112
+ private persistInteractions;
113
+ private seedInteractionTotals;
114
+ private adoptStoreRecord;
107
115
  /**
108
116
  * Get interaction history for a session
109
117
  */
@@ -115,6 +123,9 @@ export declare class SessionMonitor {
115
123
  /**
116
124
  * Calculate failure ratio from interactions
117
125
  */
126
+ private outcomeOf;
127
+ private responseAverage;
128
+ private hasDiverseRecentAgents;
118
129
  private calculateFailureRatio;
119
130
  /**
120
131
  * Calculate conflict resolution rate from interactions
@@ -124,7 +135,6 @@ export declare class SessionMonitor {
124
135
  * Calculate coordination efficiency from interactions
125
136
  */
126
137
  private calculateCoordinationEfficiency;
127
- private persistInteractionData;
128
138
  private calculateSessionMemoryUsage;
129
139
  private countSessionConflicts;
130
140
  private calculateAverageResponseTime;
@@ -20,6 +20,13 @@ export class SessionMonitor {
20
20
  interactionHistory = new Map();
21
21
  sessionResponseTimes = new Map();
22
22
  sessionErrors = new Map();
23
+ /** Stable store records. A field write patches one session instead of cloning the map. */
24
+ healthRecord = {};
25
+ metricsRecord = {};
26
+ alertRecord = {};
27
+ interactionRecord = {};
28
+ responseTotals = new Map();
29
+ outcomeTotals = new Map();
23
30
  constructor(stateManager, sessionCoordinator, cleanupManager, config = {}) {
24
31
  this.stateManager = stateManager;
25
32
  this.sessionCoordinator = sessionCoordinator;
@@ -61,7 +68,7 @@ export class SessionMonitor {
61
68
  };
62
69
  this.healthChecks.set(sessionId, health);
63
70
  this.metricsHistory.set(sessionId, []);
64
- this.persistHealthData();
71
+ this.persistHealth(sessionId);
65
72
  frameworkLogger.log("session-monitor", "session-registered", "info", {
66
73
  sessionId,
67
74
  });
@@ -75,7 +82,7 @@ export class SessionMonitor {
75
82
  alert.resolvedAt = Date.now();
76
83
  }
77
84
  }
78
- this.persistHealthData();
85
+ this.persistHealth(sessionId);
79
86
  frameworkLogger.log("session-monitor", "session-unregistered", "info", {
80
87
  sessionId,
81
88
  });
@@ -83,10 +90,15 @@ export class SessionMonitor {
83
90
  async performHealthCheck(sessionId) {
84
91
  const jobId = `session-health-check-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
85
92
  const startTime = Date.now();
86
- const health = this.healthChecks.get(sessionId);
87
- if (!health) {
93
+ const current = this.healthChecks.get(sessionId);
94
+ if (!current) {
88
95
  throw new Error(`Session ${sessionId} not registered for monitoring`);
89
96
  }
97
+ // Readers keep the last published session until every field is ready.
98
+ const health = {
99
+ ...current,
100
+ issues: [...current.issues],
101
+ };
90
102
  const issues = [];
91
103
  let status = "healthy";
92
104
  try {
@@ -109,7 +121,9 @@ export class SessionMonitor {
109
121
  }
110
122
  else {
111
123
  health.activeAgents = sessionStatus.agentCount;
112
- this.performComprehensiveHealthChecks(sessionId, health, issues, sessionStatus);
124
+ const checked = this.performComprehensiveHealthChecks(sessionId, issues, sessionStatus);
125
+ if (status === "healthy")
126
+ status = checked;
113
127
  if (health.errorCount > 10) {
114
128
  issues.push(`High error count: ${health.errorCount} errors detected`);
115
129
  status = "degraded";
@@ -118,8 +132,7 @@ export class SessionMonitor {
118
132
  issues.push(`Critical response time: ${health.responseTime}ms (exceeded 2x threshold)`);
119
133
  status = "critical";
120
134
  }
121
- const recentInteractions = this.interactionHistory.get(sessionId) || [];
122
- const failedRatio = this.calculateFailureRatio(recentInteractions);
135
+ const failedRatio = this.calculateFailureRatio(sessionId);
123
136
  if (failedRatio > this.config.alertThresholds.maxErrorRate) {
124
137
  issues.push(`High failure rate: ${(failedRatio * 100).toFixed(1)}% failed interactions`);
125
138
  status = status === "healthy" ? "degraded" : status;
@@ -166,11 +179,12 @@ export class SessionMonitor {
166
179
  health.lastCheck = Date.now();
167
180
  health.responseTime = responseTime;
168
181
  health.issues = issues;
169
- this.persistHealthData();
182
+ this.healthChecks.set(sessionId, health);
183
+ this.persistHealth(sessionId);
170
184
  if (issues.length > 0 && this.config.enableAlerts) {
171
185
  this.generateAlerts(sessionId, issues, status);
172
186
  }
173
- return { ...health };
187
+ return health;
174
188
  }
175
189
  collectMetrics(sessionId) {
176
190
  const sessionStatus = this.sessionCoordinator.getSessionStatus(sessionId);
@@ -178,16 +192,10 @@ export class SessionMonitor {
178
192
  return null;
179
193
  const metadata = this.cleanupManager?.getSessionMetadata(sessionId);
180
194
  const interactions = this.interactionHistory.get(sessionId) || [];
181
- const responseTimes = this.sessionResponseTimes.get(sessionId) || [];
182
- const errorCount = this.sessionErrors.get(sessionId) || 0;
183
- const successfulInteractions = interactions.filter(i => i.success).length;
184
- const failedInteractions = interactions.filter(i => !i.success).length;
185
- const totalInteractions = interactions.length;
186
- const avgResponseTime = responseTimes.length > 0
187
- ? responseTimes.reduce((a, b) => a + b, 0) / responseTimes.length
188
- : 0;
189
- const conflictResolutionRate = this.calculateConflictResolutionRate(sessionId, interactions);
190
- const coordinationEfficiency = this.calculateCoordinationEfficiency(sessionId, interactions);
195
+ const { success: successfulInteractions, failed: failedInteractions, total: totalInteractions } = this.outcomeOf(sessionId);
196
+ const avgResponseTime = this.responseAverage(sessionId);
197
+ const conflictResolutionRate = this.calculateConflictResolutionRate(sessionId);
198
+ const coordinationEfficiency = this.calculateCoordinationEfficiency(sessionId, interactions ?? []);
191
199
  const metrics = {
192
200
  timestamp: Date.now(),
193
201
  sessionId,
@@ -200,13 +208,21 @@ export class SessionMonitor {
200
208
  memoryUsage: metadata?.memoryUsage || this.calculateSessionMemoryUsage(sessionId),
201
209
  agentCount: sessionStatus.agentCount,
202
210
  };
203
- const history = this.metricsHistory.get(sessionId) || [];
211
+ let history = this.metricsHistory.get(sessionId);
212
+ if (!history) {
213
+ history = [];
214
+ this.metricsHistory.set(sessionId, history);
215
+ }
204
216
  history.push(metrics);
205
217
  if (history.length > 100) {
206
218
  history.shift();
207
219
  }
208
- this.metricsHistory.set(sessionId, history);
209
- this.persistMetricsData();
220
+ this.metricsRecord[sessionId] = history;
221
+ for (const key of Object.keys(this.metricsRecord)) {
222
+ if (!this.metricsHistory.has(key))
223
+ delete this.metricsRecord[key];
224
+ }
225
+ this.stateManager.set("monitor:metrics", this.metricsRecord);
210
226
  return metrics;
211
227
  }
212
228
  getHealthStatus(sessionId) {
@@ -217,11 +233,14 @@ export class SessionMonitor {
217
233
  return history.slice(-limit);
218
234
  }
219
235
  getActiveAlerts(sessionId) {
220
- const alerts = Array.from(this.activeAlerts.values());
221
- if (sessionId) {
222
- return alerts.filter((alert) => alert.sessionId === sessionId);
236
+ if (!sessionId)
237
+ return Array.from(this.activeAlerts.values());
238
+ const matched = [];
239
+ for (const alert of this.activeAlerts.values()) {
240
+ if (alert.sessionId === sessionId)
241
+ matched.push(alert);
223
242
  }
224
- return alerts;
243
+ return matched;
225
244
  }
226
245
  resolveAlert(alertId) {
227
246
  const alert = this.activeAlerts.get(alertId);
@@ -229,7 +248,8 @@ export class SessionMonitor {
229
248
  alert.resolved = true;
230
249
  alert.resolvedAt = Date.now();
231
250
  this.activeAlerts.delete(alertId);
232
- this.persistAlertData();
251
+ delete this.alertRecord[alertId];
252
+ this.stateManager.set("monitor:alerts", this.alertRecord);
233
253
  frameworkLogger.log("session-monitor", "alert-resolved", "info", {
234
254
  alertId,
235
255
  });
@@ -314,44 +334,56 @@ export class SessionMonitor {
314
334
  resolved: false,
315
335
  };
316
336
  this.activeAlerts.set(alert.id, alert);
337
+ this.alertRecord[alert.id] = alert;
317
338
  frameworkLogger.log("session-monitor", "alert-generated", "info", {
318
339
  sessionId,
319
340
  issue,
320
341
  });
321
342
  }
322
- this.persistAlertData();
343
+ this.stateManager.set("monitor:alerts", this.alertRecord);
323
344
  }
324
345
  loadPersistedData() {
325
346
  const healthData = this.stateManager.get("monitor:health");
326
- if (healthData) {
347
+ if (healthData && typeof healthData === "object" && !Array.isArray(healthData)) {
348
+ this.healthRecord = healthData;
327
349
  for (const [sessionId, health] of Object.entries(healthData)) {
328
350
  this.healthChecks.set(sessionId, health);
329
351
  }
330
352
  }
331
353
  const metricsData = this.stateManager.get("monitor:metrics");
332
- if (metricsData) {
354
+ if (metricsData && typeof metricsData === "object" && !Array.isArray(metricsData)) {
355
+ this.metricsRecord = metricsData;
333
356
  for (const [sessionId, history] of Object.entries(metricsData)) {
334
357
  this.metricsHistory.set(sessionId, history);
335
358
  }
336
359
  }
337
360
  const alertData = this.stateManager.get("monitor:alerts");
338
- if (alertData) {
361
+ if (alertData && typeof alertData === "object" && !Array.isArray(alertData)) {
362
+ this.alertRecord = alertData;
339
363
  for (const [alertId, alert] of Object.entries(alertData)) {
340
364
  this.activeAlerts.set(alertId, alert);
341
365
  }
342
366
  }
367
+ const interactionData = this.stateManager.get("monitor:interactions");
368
+ if (interactionData &&
369
+ typeof interactionData === "object" &&
370
+ !Array.isArray(interactionData)) {
371
+ this.interactionRecord = interactionData;
372
+ for (const [sessionId, history] of Object.entries(interactionData)) {
373
+ if (!Array.isArray(history))
374
+ continue;
375
+ this.interactionHistory.set(sessionId, history);
376
+ this.seedInteractionTotals(sessionId, history);
377
+ }
378
+ }
343
379
  }
344
- persistHealthData() {
345
- const healthData = Object.fromEntries(this.healthChecks);
346
- this.stateManager.set("monitor:health", healthData);
347
- }
348
- persistMetricsData() {
349
- const metricsData = Object.fromEntries(this.metricsHistory);
350
- this.stateManager.set("monitor:metrics", metricsData);
351
- }
352
- persistAlertData() {
353
- const alertData = Object.fromEntries(this.activeAlerts);
354
- this.stateManager.set("monitor:alerts", alertData);
380
+ persistHealth(sessionId) {
381
+ const health = this.healthChecks.get(sessionId);
382
+ if (health)
383
+ this.healthRecord[sessionId] = health;
384
+ else
385
+ delete this.healthRecord[sessionId];
386
+ this.stateManager.set("monitor:health", this.healthRecord);
355
387
  }
356
388
  shutdown() {
357
389
  if (this.healthCheckInterval) {
@@ -368,23 +400,77 @@ export class SessionMonitor {
368
400
  * Record an interaction for tracking
369
401
  */
370
402
  recordInteraction(sessionId, interaction) {
371
- if (!this.interactionHistory.has(sessionId)) {
372
- this.interactionHistory.set(sessionId, []);
403
+ let interactions = this.interactionHistory.get(sessionId);
404
+ if (!interactions) {
405
+ interactions = [];
406
+ this.interactionHistory.set(sessionId, interactions);
373
407
  }
374
- const interactions = this.interactionHistory.get(sessionId);
408
+ this.interactionRecord[sessionId] = interactions;
375
409
  interactions.push(interaction);
410
+ let outcomes = this.outcomeTotals.get(sessionId);
411
+ if (!outcomes) {
412
+ outcomes = { success: 0, failed: 0 };
413
+ this.outcomeTotals.set(sessionId, outcomes);
414
+ }
415
+ if (interaction.success)
416
+ outcomes.success += 1;
417
+ else
418
+ outcomes.failed += 1;
376
419
  if (interactions.length > 100) {
377
- interactions.shift();
420
+ const removed = interactions.shift();
421
+ if (removed) {
422
+ if (removed.success)
423
+ outcomes.success -= 1;
424
+ else
425
+ outcomes.failed -= 1;
426
+ }
378
427
  }
379
- if (!this.sessionResponseTimes.has(sessionId)) {
380
- this.sessionResponseTimes.set(sessionId, []);
428
+ let responseTimes = this.sessionResponseTimes.get(sessionId);
429
+ if (!responseTimes) {
430
+ responseTimes = [];
431
+ this.sessionResponseTimes.set(sessionId, responseTimes);
381
432
  }
382
- this.sessionResponseTimes.get(sessionId).push(interaction.duration);
433
+ responseTimes.push(interaction.duration);
434
+ const totals = this.responseTotals.get(sessionId) ?? { sum: 0, count: 0 };
435
+ totals.sum += interaction.duration;
436
+ totals.count += 1;
437
+ this.responseTotals.set(sessionId, totals);
383
438
  if (!interaction.success) {
384
439
  const currentErrors = this.sessionErrors.get(sessionId) || 0;
385
440
  this.sessionErrors.set(sessionId, currentErrors + 1);
386
441
  }
387
- this.persistInteractionData();
442
+ this.persistInteractions();
443
+ }
444
+ persistInteractions() {
445
+ this.interactionRecord = this.adoptStoreRecord("monitor:interactions", this.interactionRecord);
446
+ this.stateManager.set("monitor:interactions", this.interactionRecord);
447
+ }
448
+ seedInteractionTotals(sessionId, history) {
449
+ let success = 0;
450
+ let failed = 0;
451
+ let sum = 0;
452
+ for (const item of history) {
453
+ if (item.success)
454
+ success += 1;
455
+ else
456
+ failed += 1;
457
+ sum += item.duration;
458
+ }
459
+ this.outcomeTotals.set(sessionId, { success, failed });
460
+ this.responseTotals.set(sessionId, { sum, count: history.length });
461
+ }
462
+ adoptStoreRecord(key, record) {
463
+ const existing = this.stateManager.get(key);
464
+ if (!existing ||
465
+ typeof existing !== "object" ||
466
+ Array.isArray(existing) ||
467
+ existing === record) {
468
+ return record;
469
+ }
470
+ for (const [id, value] of Object.entries(record)) {
471
+ existing[id] = value;
472
+ }
473
+ return existing;
388
474
  }
389
475
  /**
390
476
  * Get interaction history for a session
@@ -396,75 +482,90 @@ export class SessionMonitor {
396
482
  /**
397
483
  * Perform comprehensive health checks on a session
398
484
  */
399
- performComprehensiveHealthChecks(sessionId, health, issues, sessionStatus) {
485
+ performComprehensiveHealthChecks(sessionId, issues, sessionStatus) {
486
+ let status = "healthy";
400
487
  if (!sessionStatus.active) {
401
488
  issues.push("Session is not active");
402
- health.status = "degraded";
489
+ status = "degraded";
403
490
  }
404
- const interactions = this.interactionHistory.get(sessionId) || [];
405
- const recentWindow = interactions.slice(-20);
491
+ const interactions = this.interactionHistory.get(sessionId);
492
+ const lastInteraction = interactions && interactions.length > 0
493
+ ? interactions[interactions.length - 1]
494
+ : undefined;
406
495
  const staleThreshold = 5 * 60 * 1000;
407
- if (recentWindow.length > 0) {
408
- const lastInteraction = recentWindow[recentWindow.length - 1];
409
- if (lastInteraction) {
410
- const timeSinceLastInteraction = Date.now() - lastInteraction.timestamp;
411
- if (timeSinceLastInteraction > staleThreshold) {
412
- issues.push(`Stale session: no activity for ${Math.round(timeSinceLastInteraction / 1000)}s`);
413
- health.status = "degraded";
414
- }
496
+ if (lastInteraction) {
497
+ const timeSinceLastInteraction = Date.now() - lastInteraction.timestamp;
498
+ if (timeSinceLastInteraction > staleThreshold) {
499
+ issues.push(`Stale session: no activity for ${Math.round(timeSinceLastInteraction / 1000)}s`);
500
+ status = "degraded";
415
501
  }
416
502
  }
417
- const responseTimes = this.sessionResponseTimes.get(sessionId) || [];
418
- if (responseTimes.length > 0) {
419
- const avgResponseTime = responseTimes.reduce((a, b) => a + b, 0) / responseTimes.length;
420
- if (avgResponseTime > this.config.alertThresholds.maxResponseTime * 1.5) {
421
- issues.push(`Elevated response time: ${avgResponseTime.toFixed(0)}ms average`);
422
- }
503
+ const avgResponseTime = this.responseAverage(sessionId);
504
+ if (avgResponseTime > this.config.alertThresholds.maxResponseTime * 1.5) {
505
+ issues.push(`Elevated response time: ${avgResponseTime.toFixed(0)}ms average`);
423
506
  }
424
- const coordinationEfficiency = this.calculateCoordinationEfficiency(sessionId, interactions);
507
+ const coordinationEfficiency = this.calculateCoordinationEfficiency(sessionId, interactions ?? []);
425
508
  if (coordinationEfficiency < this.config.alertThresholds.minCoordinationEfficiency) {
426
509
  issues.push(`Low coordination efficiency: ${(coordinationEfficiency * 100).toFixed(0)}%`);
427
- health.status = "degraded";
510
+ status = "degraded";
428
511
  }
512
+ return status;
429
513
  }
430
514
  /**
431
515
  * Calculate failure ratio from interactions
432
516
  */
433
- calculateFailureRatio(interactions) {
434
- if (interactions.length === 0)
517
+ outcomeOf(sessionId) {
518
+ const outcomes = this.outcomeTotals.get(sessionId);
519
+ const success = outcomes?.success ?? 0;
520
+ const failed = outcomes?.failed ?? 0;
521
+ return { success, failed, total: success + failed };
522
+ }
523
+ responseAverage(sessionId) {
524
+ const totals = this.responseTotals.get(sessionId);
525
+ if (!totals || totals.count === 0)
526
+ return 0;
527
+ return totals.sum / totals.count;
528
+ }
529
+ hasDiverseRecentAgents(interactions) {
530
+ const start = Math.max(0, interactions.length - 10);
531
+ let first;
532
+ for (let index = start; index < interactions.length; index += 1) {
533
+ const agentId = interactions[index]?.agentId;
534
+ if (!agentId)
535
+ continue;
536
+ if (first === undefined)
537
+ first = agentId;
538
+ else if (agentId !== first)
539
+ return true;
540
+ }
541
+ return false;
542
+ }
543
+ calculateFailureRatio(sessionId) {
544
+ const { failed, total } = this.outcomeOf(sessionId);
545
+ if (total === 0)
435
546
  return 0;
436
- const failures = interactions.filter(i => !i.success).length;
437
- return failures / interactions.length;
547
+ return failed / total;
438
548
  }
439
549
  /**
440
550
  * Calculate conflict resolution rate from interactions
441
551
  */
442
- calculateConflictResolutionRate(sessionId, interactions) {
443
- if (interactions.length === 0)
552
+ calculateConflictResolutionRate(sessionId) {
553
+ const { success, total } = this.outcomeOf(sessionId);
554
+ if (total === 0)
444
555
  return 1.0;
445
- const successfulInteractions = interactions.filter(i => i.success).length;
446
- return successfulInteractions / interactions.length;
556
+ return success / total;
447
557
  }
448
558
  /**
449
559
  * Calculate coordination efficiency from interactions
450
560
  */
451
561
  calculateCoordinationEfficiency(sessionId, interactions) {
452
- if (interactions.length === 0)
562
+ const { success, total } = this.outcomeOf(sessionId);
563
+ if (total === 0)
453
564
  return 1.0;
454
- const successfulInteractions = interactions.filter(i => i.success).length;
455
- const baseEfficiency = successfulInteractions / interactions.length;
456
- const recentInteractions = interactions.slice(-10);
457
- const hasMultipleAgents = new Set(recentInteractions.map(i => i.agentId).filter(Boolean)).size > 1;
458
- const agentDiversityBonus = hasMultipleAgents ? 0.1 : 0;
565
+ const baseEfficiency = success / total;
566
+ const agentDiversityBonus = this.hasDiverseRecentAgents(interactions) ? 0.1 : 0;
459
567
  return Math.min(1.0, baseEfficiency + agentDiversityBonus);
460
568
  }
461
- persistInteractionData() {
462
- const interactionData = {};
463
- for (const [sessionId, history] of this.interactionHistory) {
464
- interactionData[sessionId] = history;
465
- }
466
- this.stateManager.set("monitor:interactions", interactionData);
467
- }
468
569
  calculateSessionMemoryUsage(sessionId) {
469
570
  // Estimate memory usage based on session activity
470
571
  const interactions = this.interactionHistory.get(sessionId) || [];
@@ -475,26 +576,27 @@ export class SessionMonitor {
475
576
  return baseMemory + totalInteractions * perInteractionMemory;
476
577
  }
477
578
  countSessionConflicts(sessionId) {
478
- // Estimate conflicts based on failed interactions
479
- const interactions = this.interactionHistory.get(sessionId) || [];
480
- const failedInteractions = interactions.filter(i => !i.success).length;
481
579
  // Conflicts are estimated as failed interactions that might indicate coordination issues
482
- return Math.floor(failedInteractions * 0.1); // Assume 10% of failures are conflicts
580
+ return Math.floor(this.outcomeOf(sessionId).failed * 0.1);
483
581
  }
484
582
  calculateAverageResponseTime(sessionId) {
485
- // Calculate average response time from recent metrics
486
- const history = this.getMetricsHistory(sessionId, 10); // Last 10 metrics
487
- if (history.length === 0)
583
+ const history = this.metricsHistory.get(sessionId);
584
+ if (!history || history.length === 0)
488
585
  return 0;
489
- const totalResponseTime = history.reduce((sum, metric) => {
490
- // Estimate response time based on coordination efficiency
491
- // This is a simplified calculation
492
- return (sum +
493
- (metric.successfulInteractions > 0
586
+ const start = Math.max(0, history.length - 10);
587
+ let totalResponseTime = 0;
588
+ let counted = 0;
589
+ for (let index = start; index < history.length; index += 1) {
590
+ const metric = history[index];
591
+ if (!metric)
592
+ continue;
593
+ totalResponseTime +=
594
+ metric.successfulInteractions > 0
494
595
  ? 1000 / metric.successfulInteractions
495
- : 1000));
496
- }, 0);
497
- return totalResponseTime / history.length;
596
+ : 1000;
597
+ counted += 1;
598
+ }
599
+ return counted === 0 ? 0 : totalResponseTime / counted;
498
600
  }
499
601
  }
500
602
  export const createSessionMonitor = (stateManager, sessionCoordinator, cleanupManager, config) => {
@@ -48,6 +48,10 @@ export declare class SessionStateManager {
48
48
  private dependencies;
49
49
  private sessionGroups;
50
50
  private failoverConfigs;
51
+ /** Stable store records. A field write patches one key instead of cloning the map. */
52
+ private dependencyRecord;
53
+ private groupRecord;
54
+ private failoverRecord;
51
55
  constructor(stateManager: XrayStateManager, sessionCoordinator: SessionCoordinator);
52
56
  /**
53
57
  * Share state between sessions
@@ -136,9 +140,16 @@ export declare class SessionStateManager {
136
140
  };
137
141
  private propagateDependencyUpdate;
138
142
  private rollbackMigration;
143
+ private trackDependency;
144
+ private trackGroup;
145
+ private trackFailover;
139
146
  private persistDependencies;
140
147
  private persistSessionGroups;
141
148
  private persistFailoverConfigs;
149
+ private loadPersistedRecords;
150
+ private readStoreRecord;
151
+ /** Patch the stored object so a pre-seeded key survives the first write. */
152
+ private adoptStoreRecord;
142
153
  shutdown(): void;
143
154
  }
144
155
  export declare const createSessionStateManager: (stateManager: XrayStateManager, sessionCoordinator: SessionCoordinator) => SessionStateManager;