0xray 2.1.3 → 2.2.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 (178) hide show
  1. package/.opencode/codex.codex +1 -1
  2. package/.opencode/commands/dependency-audit.md +3 -3
  3. package/.opencode/enforcer-config.json +2 -2
  4. package/README.md +3 -3
  5. package/dist/CHANGELOG.md +43 -0
  6. package/dist/README.md +3 -3
  7. package/dist/analytics/routing-refiner.js +1 -1
  8. package/dist/cli/commands/govern.d.ts +29 -0
  9. package/dist/cli/commands/govern.js +152 -0
  10. package/dist/cli/index.js +29 -216
  11. package/dist/core/boot-orchestrator.js +1 -1
  12. package/dist/core/features-config.js +1 -1
  13. package/dist/core/framework-logger.js +30 -1
  14. package/dist/delegation/index.d.ts +1 -2
  15. package/dist/delegation/index.js +1 -2
  16. package/dist/enforcement/enforcer-tools.js +1 -1
  17. package/dist/execution/proposal-applier.d.ts +1 -9
  18. package/dist/execution/proposal-applier.js +18 -173
  19. package/dist/governance/codex-policy.service.d.ts +7 -25
  20. package/dist/governance/codex-policy.service.js +8 -26
  21. package/dist/governance/governance-core.d.ts +22 -28
  22. package/dist/governance/governance-core.js +31 -101
  23. package/dist/governance/governance-service.d.ts +1 -0
  24. package/dist/governance/governance-service.js +67 -4
  25. package/dist/governance/governance-types.d.ts +5 -2
  26. package/dist/inference/index.d.ts +3 -4
  27. package/dist/inference/inference-accumulator.js +1 -1
  28. package/dist/inference/inference-cycle.d.ts +12 -18
  29. package/dist/inference/inference-cycle.js +120 -335
  30. package/dist/integrations/base/index.d.ts +0 -1
  31. package/dist/integrations/base/index.js +0 -2
  32. package/dist/integrations/grok/hooks/pre-tool-use.js +4 -18
  33. package/dist/integrations/hermes-agent/bridge.mjs +10 -1
  34. package/dist/mcps/config/server-config-registry.js +1 -1
  35. package/dist/mcps/governance.server.js +4 -5
  36. package/dist/mcps/knowledge-skills/api-design.server.js +10 -0
  37. package/dist/mcps/knowledge-skills/architecture-patterns.server.js +10 -0
  38. package/dist/mcps/knowledge-skills/bug-triage-specialist.server.js +10 -0
  39. package/dist/mcps/knowledge-skills/code-analyzer.server.js +10 -0
  40. package/dist/mcps/knowledge-skills/code-review.server.js +10 -0
  41. package/dist/mcps/knowledge-skills/content-creator.server.js +10 -0
  42. package/dist/mcps/knowledge-skills/database-design.server.js +10 -0
  43. package/dist/mcps/knowledge-skills/devops-deployment.server.js +10 -0
  44. package/dist/mcps/knowledge-skills/git-workflow.server.js +10 -0
  45. package/dist/mcps/knowledge-skills/growth-strategist.server.js +10 -0
  46. package/dist/mcps/knowledge-skills/log-monitor.server.js +10 -0
  47. package/dist/mcps/knowledge-skills/mobile-development.server.js +10 -0
  48. package/dist/mcps/knowledge-skills/multimodal-looker.server.js +10 -0
  49. package/dist/mcps/knowledge-skills/performance-optimization.server.js +10 -0
  50. package/dist/mcps/knowledge-skills/project-analysis.server.js +10 -0
  51. package/dist/mcps/knowledge-skills/refactoring-strategies.server.js +10 -0
  52. package/dist/mcps/knowledge-skills/security-audit.server.js +10 -0
  53. package/dist/mcps/knowledge-skills/seo-consultant.server.js +10 -0
  54. package/dist/mcps/knowledge-skills/skill-invocation.server.d.ts +4 -0
  55. package/dist/mcps/knowledge-skills/skill-invocation.server.js +33 -14
  56. package/dist/mcps/knowledge-skills/strategist.server.js +10 -0
  57. package/dist/mcps/knowledge-skills/tech-writer.server.js +11 -1
  58. package/dist/mcps/knowledge-skills/testing-strategy.server.js +10 -0
  59. package/dist/mcps/knowledge-skills/ui-ux-design.server.js +10 -0
  60. package/dist/mcps/registry.json +1 -1
  61. package/dist/metrics/agent-metrics.d.ts +2 -1
  62. package/dist/nucleus/govern-http.d.ts +59 -0
  63. package/dist/nucleus/govern-http.js +172 -0
  64. package/dist/nucleus/index.d.ts +14 -0
  65. package/dist/nucleus/index.js +9 -0
  66. package/dist/nucleus/kernel.d.ts +51 -0
  67. package/dist/nucleus/kernel.js +62 -0
  68. package/dist/nucleus/plugin-registry.d.ts +104 -0
  69. package/dist/nucleus/plugin-registry.js +147 -0
  70. package/dist/orchestrator/orchestrator.d.ts +0 -1
  71. package/dist/orchestrator/orchestrator.js +0 -21
  72. package/dist/postprocessor/PostProcessor.d.ts +13 -1
  73. package/dist/postprocessor/PostProcessor.js +41 -1
  74. package/dist/postprocessor/autofix/AutoFixEngine.d.ts +0 -8
  75. package/dist/postprocessor/autofix/AutoFixEngine.js +0 -54
  76. package/dist/postprocessor/metamorphosis/MetamorphosisEngine.d.ts +25 -0
  77. package/dist/postprocessor/metamorphosis/MetamorphosisEngine.js +10 -0
  78. package/dist/postprocessor/metamorphosis/SelfProposalEngine.d.ts +68 -0
  79. package/dist/postprocessor/metamorphosis/SelfProposalEngine.js +371 -0
  80. package/dist/skills/orchestrator/SKILL.md +1 -1
  81. package/dist/skills/registry.json +1 -1
  82. package/dist/state/index.d.ts +0 -2
  83. package/package.json +4 -3
  84. package/scripts/node/universal-version-manager.js +3 -3
  85. package/src/mcps/config/__tests__/server-config-registry.test.ts +6 -15
  86. package/src/mcps/config/server-config-registry.ts +1 -1
  87. package/src/mcps/governance.server.ts +4 -6
  88. package/src/mcps/knowledge-skills/api-design.server.ts +9 -0
  89. package/src/mcps/knowledge-skills/architecture-patterns.server.ts +9 -0
  90. package/src/mcps/knowledge-skills/bug-triage-specialist.server.ts +9 -0
  91. package/src/mcps/knowledge-skills/code-analyzer.server.ts +9 -0
  92. package/src/mcps/knowledge-skills/code-review.server.ts +9 -0
  93. package/src/mcps/knowledge-skills/content-creator.server.ts +9 -0
  94. package/src/mcps/knowledge-skills/database-design.server.ts +9 -0
  95. package/src/mcps/knowledge-skills/devops-deployment.server.ts +9 -0
  96. package/src/mcps/knowledge-skills/git-workflow.server.ts +9 -0
  97. package/src/mcps/knowledge-skills/growth-strategist.server.ts +9 -0
  98. package/src/mcps/knowledge-skills/log-monitor.server.ts +9 -0
  99. package/src/mcps/knowledge-skills/mobile-development.server.ts +9 -0
  100. package/src/mcps/knowledge-skills/multimodal-looker.server.ts +9 -0
  101. package/src/mcps/knowledge-skills/performance-optimization.server.ts +9 -0
  102. package/src/mcps/knowledge-skills/project-analysis.server.ts +9 -0
  103. package/src/mcps/knowledge-skills/refactoring-strategies.server.ts +9 -0
  104. package/src/mcps/knowledge-skills/security-audit.server.ts +9 -0
  105. package/src/mcps/knowledge-skills/seo-consultant.server.ts +9 -0
  106. package/src/mcps/knowledge-skills/session-management.server.ts +1 -0
  107. package/src/mcps/knowledge-skills/skill-invocation.server.ts +44 -29
  108. package/src/mcps/knowledge-skills/strategist.server.ts +9 -0
  109. package/src/mcps/knowledge-skills/tech-writer.server.ts +10 -1
  110. package/src/mcps/knowledge-skills/testing-strategy.server.ts +9 -0
  111. package/src/mcps/knowledge-skills/ui-ux-design.server.ts +9 -0
  112. package/src/mcps/registry.json +1 -1
  113. package/src/opencode/codex.codex +1 -1
  114. package/src/opencode/commands/dependency-audit.md +3 -3
  115. package/src/opencode/enforcer-config.json +2 -2
  116. package/src/skills/orchestrator/SKILL.md +1 -1
  117. package/src/skills/registry.json +1 -1
  118. package/xray/codex.json +1 -1
  119. package/xray/config.json +1 -1
  120. package/xray/features.json +1 -1
  121. package/xray/integrations.json +3 -3
  122. package/.opencode/agents/testing-best-practices.yml +0 -12
  123. package/dist/analytics/consent-manager.d.ts +0 -93
  124. package/dist/analytics/consent-manager.js +0 -258
  125. package/dist/analytics/simple-pattern-analyzer.d.ts +0 -80
  126. package/dist/analytics/simple-pattern-analyzer.js +0 -297
  127. package/dist/cli/commands/analytics-disable.d.ts +0 -9
  128. package/dist/cli/commands/analytics-disable.js +0 -72
  129. package/dist/cli/commands/analytics-enable-action.d.ts +0 -8
  130. package/dist/cli/commands/analytics-enable-action.js +0 -82
  131. package/dist/cli/commands/analytics-preview.d.ts +0 -9
  132. package/dist/cli/commands/analytics-preview.js +0 -106
  133. package/dist/cli/commands/analytics-status.d.ts +0 -9
  134. package/dist/cli/commands/analytics-status.js +0 -68
  135. package/dist/cli/server.d.ts +0 -1
  136. package/dist/cli/server.js +0 -147
  137. package/dist/core/errors.d.ts +0 -3
  138. package/dist/core/errors.js +0 -10
  139. package/dist/core/logging-config.d.ts +0 -11
  140. package/dist/core/logging-config.js +0 -43
  141. package/dist/core/trace-context.d.ts +0 -12
  142. package/dist/core/trace-context.js +0 -33
  143. package/dist/delegation/voting-coordinator.d.ts +0 -49
  144. package/dist/delegation/voting-coordinator.js +0 -375
  145. package/dist/enforcement/test-auto-healing.d.ts +0 -83
  146. package/dist/enforcement/test-auto-healing.js +0 -325
  147. package/dist/integrations/base/ExampleIntegration.d.ts +0 -47
  148. package/dist/integrations/base/ExampleIntegration.js +0 -181
  149. package/dist/mcps/knowledge-skills/testing-best-practices.server.d.ts +0 -34
  150. package/dist/mcps/knowledge-skills/testing-best-practices.server.js +0 -831
  151. package/dist/mcps/orchestrator.server.d.ts +0 -10
  152. package/dist/mcps/orchestrator.server.js +0 -19
  153. package/dist/orchestrator/self-direction-activation.d.ts +0 -109
  154. package/dist/orchestrator/self-direction-activation.js +0 -245
  155. package/dist/orchestrator/universal-librarian-consultation.d.ts +0 -98
  156. package/dist/orchestrator/universal-librarian-consultation.js +0 -216
  157. package/dist/orchestrator/universal-registry-bridge.d.ts +0 -85
  158. package/dist/orchestrator/universal-registry-bridge.js +0 -247
  159. package/dist/performance/performance-budget-enforcer.d.ts +0 -158
  160. package/dist/performance/performance-budget-enforcer.js +0 -434
  161. package/dist/performance/performance-regression-tester.d.ts +0 -108
  162. package/dist/performance/performance-regression-tester.js +0 -342
  163. package/dist/skills/testing-best-practices/SKILL.md +0 -37
  164. package/dist/state/context-providers.d.ts +0 -4
  165. package/dist/state/context-providers.js +0 -1
  166. package/dist/state/state-types.d.ts +0 -5
  167. package/dist/state/state-types.js +0 -1
  168. package/dist/utils/batch-operations.d.ts +0 -25
  169. package/dist/utils/batch-operations.js +0 -292
  170. package/dist/utils/test-template-generator.d.ts +0 -25
  171. package/dist/utils/test-template-generator.js +0 -178
  172. package/dist/utils/token-manager.d.ts +0 -48
  173. package/dist/utils/token-manager.js +0 -163
  174. package/src/mcps/knowledge-skills/testing-best-practices.server.test.ts +0 -136
  175. package/src/mcps/knowledge-skills/testing-best-practices.server.ts +0 -1183
  176. package/src/mcps/orchestrator.server.ts +0 -34
  177. package/src/opencode/agents/testing-best-practices.yml +0 -12
  178. package/src/skills/testing-best-practices/SKILL.md +0 -37
@@ -0,0 +1,371 @@
1
+ /**
2
+ * SelfProposalEngine — Phase 2.2
3
+ *
4
+ * Concrete MetamorphosisEngine that reads activity.log, parses structured
5
+ * log entries, detects semantic patterns, generates governance proposals
6
+ * (type: 'metamorphosis'), and submits them through the full 3-agent +
7
+ * Dynamo governance pipeline.
8
+ *
9
+ * Safety constraints:
10
+ * - Max proposals per hour (default 1, configurable)
11
+ * - Circuit breaker: after N consecutive failures, halt for cooldown (default 3/24h)
12
+ * - Only proposes changes to whitelisted targets
13
+ * - All proposals go through full governance with metamorphosisThreshold (default 0.7)
14
+ * - Detection thresholds are configurable (not hard-coded)
15
+ *
16
+ * Coupling note: currently triggered by PostProcessor.onPhase(). A future
17
+ * refactor should extract log-reading into a dedicated LogReader that can
18
+ * run on its own schedule or fs.watch, decoupling from PostProcessor lifecycle.
19
+ */
20
+ import { promises as fs } from 'fs';
21
+ import { join } from 'path';
22
+ import { frameworkLogger } from '../../core/framework-logger.js';
23
+ import { handleGovernRequest } from '../../nucleus/govern-http.js';
24
+ const DEFAULT_CONFIG = {
25
+ maxProposalsPerHour: 1,
26
+ circuitBreakerThreshold: 3,
27
+ circuitBreakerCooldownHours: 24,
28
+ activityLogPath: 'logs/framework/activity.log',
29
+ whitelistedTargets: ['config/', 'features.json', 'src/processors/'],
30
+ maxLogLines: 100,
31
+ errorThreshold: 5,
32
+ warningThreshold: 10,
33
+ governanceRejectionThreshold: 3,
34
+ proposalConfidence: 0.7,
35
+ metamorphosisThreshold: 0.7,
36
+ projectRoot: process.cwd(),
37
+ };
38
+ const LOG_LINE_PATTERN = /^(\d{4}-\d{2}-\d{2}T[^ ]+)\s+(?:\[([^\]]*)\]\s+)?(?:\[([^\]]*)\]\s+)?\[([^\]]*)\]\s+(\S+)\s+-\s+(\w+)(?:\s+\|(.+))?$/;
39
+ function parseLogEntry(line) {
40
+ const match = line.match(LOG_LINE_PATTERN);
41
+ if (!match) {
42
+ // Fallback: try JSON parse for entangled log entries
43
+ try {
44
+ const json = JSON.parse(line);
45
+ if (json && typeof json === 'object' && json.action) {
46
+ return {
47
+ timestamp: json.timestamp ? new Date(json.timestamp).toISOString() : new Date().toISOString(),
48
+ component: json.component || 'unknown',
49
+ action: json.action,
50
+ status: (json.status || json.level || 'info').toLowerCase(),
51
+ details: json.details || json,
52
+ raw: line,
53
+ };
54
+ }
55
+ }
56
+ catch { }
57
+ return null;
58
+ }
59
+ const [, timestamp, , , component, action, status, detailsStr] = match;
60
+ let details;
61
+ if (detailsStr) {
62
+ try {
63
+ details = JSON.parse(detailsStr.trim());
64
+ }
65
+ catch {
66
+ details = { rawDetails: detailsStr.trim() };
67
+ }
68
+ }
69
+ const entry = {
70
+ timestamp: timestamp ?? new Date().toISOString(),
71
+ component: component || 'unknown',
72
+ action: action ?? 'unknown',
73
+ status: (status ?? 'info').toLowerCase(),
74
+ raw: line,
75
+ };
76
+ if (details !== undefined) {
77
+ entry.details = details;
78
+ }
79
+ return entry;
80
+ }
81
+ export class SelfProposalEngine {
82
+ name = 'self-proposal';
83
+ config;
84
+ proposalHistory = [];
85
+ consecutiveFailures = 0;
86
+ circuitBreakerUntil = 0;
87
+ constructor(config) {
88
+ this.config = { ...DEFAULT_CONFIG, ...config };
89
+ }
90
+ async onPhase(phase, context) {
91
+ if (phase !== 'monitoring-complete' && phase !== 'post-process-complete') {
92
+ return;
93
+ }
94
+ await frameworkLogger.log('self-proposal', 'phase-hook', 'info', {
95
+ phase,
96
+ message: 'Self-proposal engine triggered by phase',
97
+ });
98
+ if (this.isCircuitBreakerActive()) {
99
+ await frameworkLogger.log('self-proposal', 'circuit-breaker-active', 'warning', {
100
+ message: `Circuit breaker active until ${new Date(this.circuitBreakerUntil).toISOString()}`,
101
+ consecutiveFailures: this.consecutiveFailures,
102
+ });
103
+ return;
104
+ }
105
+ if (this.isRateLimited()) {
106
+ await frameworkLogger.log('self-proposal', 'rate-limited', 'info', {
107
+ message: 'Max proposals per hour reached',
108
+ });
109
+ return;
110
+ }
111
+ await this.evaluateAndPropose();
112
+ }
113
+ async onProposal(proposal) {
114
+ await frameworkLogger.log('self-proposal', 'external-proposal', 'info', {
115
+ proposalId: proposal.id,
116
+ type: proposal.type,
117
+ target: proposal.target,
118
+ impact: proposal.impact,
119
+ });
120
+ }
121
+ isCircuitBreakerActive() {
122
+ if (this.consecutiveFailures >= this.config.circuitBreakerThreshold) {
123
+ if (Date.now() < this.circuitBreakerUntil) {
124
+ return true;
125
+ }
126
+ this.consecutiveFailures = 0;
127
+ this.circuitBreakerUntil = 0;
128
+ }
129
+ return false;
130
+ }
131
+ isRateLimited() {
132
+ const oneHourAgo = Date.now() - 60 * 60 * 1000;
133
+ const recentProposals = this.proposalHistory.filter(a => a.timestamp > oneHourAgo);
134
+ return recentProposals.length >= this.config.maxProposalsPerHour;
135
+ }
136
+ async evaluateAndPropose() {
137
+ let logEntries = [];
138
+ try {
139
+ const logContent = await fs.readFile(this.config.activityLogPath, 'utf-8');
140
+ const lines = logContent.trim().split('\n');
141
+ logEntries = lines.slice(-this.config.maxLogLines).filter(line => line.trim().length > 0);
142
+ }
143
+ catch {
144
+ await frameworkLogger.log('self-proposal', 'log-read-error', 'warning', {
145
+ path: this.config.activityLogPath,
146
+ message: 'Activity log not found or unreadable — skipping self-proposal',
147
+ });
148
+ return;
149
+ }
150
+ const patterns = this.detectPatterns(logEntries);
151
+ if (patterns.length === 0) {
152
+ await frameworkLogger.log('self-proposal', 'no-patterns', 'info', {
153
+ message: 'No actionable patterns detected in activity log',
154
+ });
155
+ return;
156
+ }
157
+ for (const pattern of patterns) {
158
+ await this.submitProposal(pattern);
159
+ }
160
+ }
161
+ /**
162
+ * Detect actionable patterns from parsed activity log entries.
163
+ * Uses structured parsing instead of raw string matching to handle
164
+ * the actual xray log format:
165
+ * ISO_TIMESTAMP [jobId] [traceId.spanId] [component] action - STATUS | {details}
166
+ */
167
+ detectPatterns(entries) {
168
+ const parsed = entries.map(parseLogEntry).filter((e) => e !== null);
169
+ const proposals = [];
170
+ const errorEntries = parsed.filter(e => e.status === 'error');
171
+ const warningEntries = parsed.filter(e => e.status === 'warning');
172
+ const rejectedEntries = parsed.filter(e => e.component === 'governance' && (e.status === 'rejected' || e.details?.decision === 'reject'));
173
+ if (errorEntries.length >= this.config.errorThreshold) {
174
+ const components = [...new Set(errorEntries.map(e => e.component))];
175
+ proposals.push({
176
+ id: `meta-errors-${Date.now()}`,
177
+ type: 'modify',
178
+ target: 'config/error-handling',
179
+ description: `Elevated error rate: ${errorEntries.length} errors in last ${this.config.maxLogLines} entries. Components: ${components.join(', ')}. Propose adjusting error handling thresholds.`,
180
+ rationale: `High error count (${errorEntries.length}) across ${components.length} component(s) indicates a systemic issue. Affected components: ${components.join(', ')}. Governance review recommended for self-optimization.`,
181
+ impact: 'medium',
182
+ });
183
+ }
184
+ if (warningEntries.length >= this.config.warningThreshold) {
185
+ const components = [...new Set(warningEntries.map(e => e.component))];
186
+ proposals.push({
187
+ id: `meta-warnings-${Date.now()}`,
188
+ type: 'modify',
189
+ target: 'config/monitoring',
190
+ description: `Elevated warning rate: ${warningEntries.length} warnings in last ${this.config.maxLogLines} entries. Components: ${components.join(', ')}. Propose adjusting monitoring sensitivity.`,
191
+ rationale: `Frequent warnings (${warningEntries.length}) across ${components.length} component(s) may indicate configuration drift. Affected: ${components.join(', ')}.`,
192
+ impact: 'low',
193
+ });
194
+ }
195
+ if (rejectedEntries.length >= this.config.governanceRejectionThreshold) {
196
+ proposals.push({
197
+ id: `meta-governance-rejections-${Date.now()}`,
198
+ type: 'modify',
199
+ target: 'config/governance',
200
+ description: `Repeated governance rejections: ${rejectedEntries.length} in last ${this.config.maxLogLines} entries. Propose reviewing governance thresholds or submission patterns.`,
201
+ rationale: `${rejectedEntries.length} governance rejections suggest a pattern mismatch between proposals and governance criteria. Review recommended.`,
202
+ impact: 'medium',
203
+ });
204
+ }
205
+ return proposals.filter(p => this.config.whitelistedTargets.some(t => p.target.startsWith(t)));
206
+ }
207
+ /**
208
+ * Apply an approved self-evolution proposal by recording the change
209
+ * in a state file within the first matching whitelisted target directory.
210
+ * Returns true if the change was written and verified, false otherwise.
211
+ */
212
+ async applySelfProposal(pattern, score, decision) {
213
+ const matchedTarget = this.config.whitelistedTargets.find(t => pattern.target.startsWith(t));
214
+ if (!matchedTarget) {
215
+ await frameworkLogger.log('self-proposal', 'apply-no-matching-target', 'warning', {
216
+ proposalId: pattern.id,
217
+ target: pattern.target,
218
+ message: 'No whitelisted target matches this proposal — skipping apply',
219
+ });
220
+ return false;
221
+ }
222
+ const root = this.config.projectRoot;
223
+ const stateDir = join(root, matchedTarget);
224
+ const statePath = join(stateDir, 'self-evolution-state.json');
225
+ let applied = [];
226
+ try {
227
+ const content = await fs.readFile(statePath, 'utf-8');
228
+ const parsed = JSON.parse(content);
229
+ if (Array.isArray(parsed.applied))
230
+ applied = parsed.applied;
231
+ }
232
+ catch { }
233
+ applied.push({
234
+ proposalId: pattern.id,
235
+ target: pattern.target,
236
+ type: pattern.type,
237
+ description: pattern.description,
238
+ rationale: pattern.rationale,
239
+ impact: pattern.impact,
240
+ metamorphosisScore: score,
241
+ decision: decision,
242
+ appliedAt: new Date().toISOString(),
243
+ });
244
+ try {
245
+ await fs.mkdir(stateDir, { recursive: true });
246
+ await fs.writeFile(statePath, JSON.stringify({ applied }, null, 2), 'utf-8');
247
+ }
248
+ catch (writeError) {
249
+ await frameworkLogger.log('self-proposal', 'apply-write-error', 'error', {
250
+ proposalId: pattern.id,
251
+ path: statePath,
252
+ error: writeError instanceof Error ? writeError.message : String(writeError),
253
+ });
254
+ return false;
255
+ }
256
+ try {
257
+ const verify = await fs.readFile(statePath, 'utf-8');
258
+ const parsed = JSON.parse(verify);
259
+ const found = Array.isArray(parsed.applied) && parsed.applied.some((a) => a.proposalId === pattern.id);
260
+ if (!found) {
261
+ await frameworkLogger.log('self-proposal', 'apply-verify-failed', 'error', {
262
+ proposalId: pattern.id,
263
+ message: 'Applied change not found in state file after write — verification failed',
264
+ });
265
+ }
266
+ return found;
267
+ }
268
+ catch (verifyError) {
269
+ await frameworkLogger.log('self-proposal', 'apply-verify-error', 'error', {
270
+ proposalId: pattern.id,
271
+ error: verifyError instanceof Error ? verifyError.message : String(verifyError),
272
+ });
273
+ return false;
274
+ }
275
+ }
276
+ async submitProposal(pattern) {
277
+ const governanceRequest = {
278
+ proposals: [{
279
+ id: pattern.id,
280
+ type: 'metamorphosis',
281
+ title: `Self-proposal: ${pattern.description.slice(0, 80)}`,
282
+ description: pattern.description,
283
+ evidence: [pattern.rationale],
284
+ source: 'metamorphosis',
285
+ confidence: this.config.proposalConfidence,
286
+ }],
287
+ context: {
288
+ project: 'xray-self',
289
+ phase: 'self-evolution',
290
+ source: 'self-proposal-engine',
291
+ },
292
+ options: {
293
+ requireExternalDynamo: true,
294
+ metamorphosisThreshold: this.config.metamorphosisThreshold,
295
+ },
296
+ };
297
+ await frameworkLogger.log('self-proposal', 'submitting', 'info', {
298
+ proposalId: pattern.id,
299
+ target: pattern.target,
300
+ impact: pattern.impact,
301
+ });
302
+ try {
303
+ const response = await handleGovernRequest(governanceRequest);
304
+ const result = response.results[0];
305
+ if (!result) {
306
+ await frameworkLogger.log('self-proposal', 'no-result', 'warning', {
307
+ proposalId: pattern.id,
308
+ message: 'Governance returned no results',
309
+ });
310
+ return;
311
+ }
312
+ const decision = result.finalDecision;
313
+ const attempt = {
314
+ timestamp: Date.now(),
315
+ result: decision === 'approve' ? 'approved' : decision === 'reject' ? 'rejected' : 'needs_revision',
316
+ };
317
+ if (result.metamorphosisScore !== undefined) {
318
+ attempt.metamorphosisScore = result.metamorphosisScore;
319
+ }
320
+ this.proposalHistory.push(attempt);
321
+ if (decision === 'approve' && (result.metamorphosisScore ?? 0) >= this.config.metamorphosisThreshold) {
322
+ this.consecutiveFailures = 0;
323
+ await frameworkLogger.log('self-proposal', 'approved', 'success', {
324
+ proposalId: pattern.id,
325
+ metamorphosisScore: result.metamorphosisScore,
326
+ message: 'Self-evolution proposal approved by governance — applying change',
327
+ });
328
+ const applied = await this.applySelfProposal(pattern, result.metamorphosisScore, decision);
329
+ if (applied) {
330
+ await frameworkLogger.log('self-proposal', 'applied', 'success', {
331
+ proposalId: pattern.id,
332
+ target: pattern.target,
333
+ message: 'Self-evolution change applied and verified',
334
+ });
335
+ }
336
+ else {
337
+ this.consecutiveFailures++;
338
+ if (this.consecutiveFailures >= this.config.circuitBreakerThreshold) {
339
+ this.circuitBreakerUntil = Date.now() + this.config.circuitBreakerCooldownHours * 60 * 60 * 1000;
340
+ }
341
+ await frameworkLogger.log('self-proposal', 'apply-failed', 'error', {
342
+ proposalId: pattern.id,
343
+ target: pattern.target,
344
+ consecutiveFailures: this.consecutiveFailures,
345
+ message: 'Self-evolution change apply failed — circuit breaker may activate',
346
+ });
347
+ }
348
+ }
349
+ else {
350
+ this.consecutiveFailures++;
351
+ if (this.consecutiveFailures >= this.config.circuitBreakerThreshold) {
352
+ this.circuitBreakerUntil = Date.now() + this.config.circuitBreakerCooldownHours * 60 * 60 * 1000;
353
+ }
354
+ await frameworkLogger.log('self-proposal', 'not-approved', 'warning', {
355
+ proposalId: pattern.id,
356
+ decision: decision,
357
+ metamorphosisScore: result.metamorphosisScore,
358
+ consecutiveFailures: this.consecutiveFailures,
359
+ circuitBreakerUntil: this.circuitBreakerUntil || 'not active',
360
+ });
361
+ }
362
+ }
363
+ catch (error) {
364
+ this.consecutiveFailures++;
365
+ await frameworkLogger.log('self-proposal', 'submission-error', 'error', {
366
+ proposalId: pattern.id,
367
+ error: error instanceof Error ? error.message : String(error),
368
+ });
369
+ }
370
+ }
371
+ }
@@ -15,7 +15,7 @@ dependencies: []
15
15
  mcp:
16
16
  orchestrator:
17
17
  command: node
18
- args: [node_modules/0xray/dist/mcps/orchestrator.server.js]
18
+ args: [node_modules/0xray/dist/mcps/orchestrator/server.js]
19
19
  ---
20
20
 
21
21
  # Orchestrator Skill
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.1.1",
2
+ "version": "2.1.3",
3
3
  "description": "0xRay Skills Registry - recommended skill sources for consumers",
4
4
  "sources": [
5
5
  {
@@ -1,3 +1 @@
1
1
  export { StateManager, XrayStateManager, XrayStateManager as StrRayStateManager } from "./state-manager.js";
2
- export type { StateValue, StateTypes } from "./state-types.js";
3
- export type { ContextProviders } from "./context-providers.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0xray",
3
- "version": "2.1.3",
3
+ "version": "2.2.0",
4
4
  "description": "Multi-agent orchestration and Codex governance for OpenCode, Hermes, Grok Build, and OpenClaw",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -58,10 +58,10 @@
58
58
  "test": "vitest run",
59
59
  "test:batch": "npm test",
60
60
  "test:unit": "npm test -- src/__tests__/unit/config-loader.test.ts src/__tests__/unit/state-manager.test.ts src/__tests__/unit/state-manager-persistence.test.ts src/__tests__/unit/context-loader.test.ts src/__tests__/unit/pattern-analyzer.test.ts src/__tests__/unit/complexity-calibrator.test.ts",
61
- "test:core-framework": "npm test -- src/__tests__/unit/self-direction-activation.test.ts src/__tests__/unit/ast-code-parser.test.ts src/__tests__/unit/v2-deletion-protection.test.ts",
61
+ "test:core-framework": "npm test -- src/__tests__/unit/ast-code-parser.test.ts src/__tests__/unit/v2-deletion-protection.test.ts",
62
62
  "test:security": "npm test -- src/__tests__/unit/security/security-hardener.test.ts src/__tests__/unit/security/security-headers.test.ts",
63
63
  "test:performance": "npm test -- src/__tests__/unit/monitoring.test.ts src/__tests__/unit/benchmark.test.ts src/__tests__/unit/analytics.test.ts",
64
- "test:session-management": "npm test -- src/__tests__/unit/session-state-manager.test.ts src/__tests__/unit/session-security-validator.test.ts src/__tests__/unit/session-coordination-validator.test.ts src/__tests__/unit/session-migration-validator.test.ts src/__tests__/unit/session-migration-logic.test.ts",
64
+ "test:session-management": "npm test -- src/__tests__/unit/session-state-manager.test.ts src/__tests__/unit/session-migration-logic.test.ts",
65
65
  "test:code-analysis": "npm test -- src/__tests__/unit/codebase-context-analyzer.test.ts src/__tests__/unit/dependency-graph-builder.test.ts src/__tests__/unit/rule-enforcer.test.ts src/__tests__/unit/codex-parser.test.ts src/__tests__/unit/codex-injector.test.ts",
66
66
  "test:processors": "npm test -- src/__tests__/unit/processor-activation.test.ts src/__tests__/unit/typescript-compilation-processor.test.ts",
67
67
  "test:miscellaneous": "npm test -- src/__tests__/unit/blocked-test.test.ts",
@@ -87,6 +87,7 @@
87
87
  "test:e2e": "node scripts/node/validate-mcp-connectivity.js && node scripts/node/validate-external-processes.js",
88
88
  "validate": "echo \"[xray] Use 'npm test' or 'npm run test:comprehensive'.\"",
89
89
  "validate:quick": "npm run validate",
90
+ "verify:consumer": "bash scripts/verify-consumer.sh",
90
91
  "debug:inference:force": "STRRAY_FORCE_MCP_GOVERNANCE=true XRAY_DEV_PATH=dist node dist/cli/index.js inference:run --force",
91
92
  "validate:full": "npm run validate",
92
93
  "test:unified": "node scripts/test/test-unified-framework.mjs",
@@ -155,9 +155,9 @@ const detectedCodex = detectCodexInfo();
155
155
  const OFFICIAL_VERSIONS = {
156
156
  // Framework version
157
157
  framework: {
158
- version: "2.1.3",
158
+ version: "2.2.0",
159
159
  displayName: "xray: Self-Healing AI Governance OS",
160
- lastUpdated: "2026-06-09",
160
+ lastUpdated: "2026-06-10",
161
161
  // Counts (auto-calculated, but can be overridden)
162
162
  ...CALCULATED_COUNTS,
163
163
  },
@@ -403,7 +403,7 @@ const UPDATE_PATTERNS = [
403
403
  pattern: /xray AI v[0-9]+\.[0-9]+\.[0-9]+/g,
404
404
  replacement: `xray AI v${OFFICIAL_VERSIONS.framework.version}`,
405
405
  },
406
- // Footer bare version (e.g., "**Version**: 2.1.1")
406
+ // Footer bare version (e.g., "**Version**: 2.1.3")
407
407
  {
408
408
  pattern: /\*\*Version\*\*:\s*[0-9]+\.[0-9]+\.[0-9]+/g,
409
409
  replacement: `**Version**: ${OFFICIAL_VERSIONS.framework.version}`,
@@ -166,45 +166,36 @@ describe('ServerConfigRegistry', () => {
166
166
 
167
167
  it('should use XRAY_DEV_PATH env var in dynamic config', () => {
168
168
  const originalXrayEnv = process.env.XRAY_DEV_PATH;
169
- const originalStrrayEnv = ;
170
169
  process.env.XRAY_DEV_PATH = 'custom-dist';
171
- = 'custom-dist';
172
-
170
+
173
171
  const config = registry.createDynamicConfig('test-server');
174
172
  expect(config.args[0]).toContain('custom-dist');
175
-
173
+
176
174
  process.env.XRAY_DEV_PATH = originalXrayEnv;
177
- = originalStrrayEnv;
178
175
  });
179
176
  });
180
177
 
181
178
  describe('environment path handling', () => {
182
179
  it('should use resolved framework path when XRAY_DEV_PATH is not set', () => {
183
180
  const originalXrayEnv = process.env.XRAY_DEV_PATH;
184
- const originalStrrayEnv = ;
185
181
  delete process.env.XRAY_DEV_PATH;
186
- delete ;
187
-
182
+
188
183
  const freshRegistry = new ServerConfigRegistry();
189
184
  const config = freshRegistry.get('code-review');
190
185
  expect(config?.args[0]).toContain('.server.js');
191
-
186
+
192
187
  process.env.XRAY_DEV_PATH = originalXrayEnv;
193
- = originalStrrayEnv;
194
188
  });
195
189
 
196
190
  it('should use XRAY_DEV_PATH when set', () => {
197
191
  const originalXrayEnv = process.env.XRAY_DEV_PATH;
198
- const originalStrrayEnv = ;
199
192
  process.env.XRAY_DEV_PATH = 'dist';
200
- = 'dist';
201
-
193
+
202
194
  const freshRegistry = new ServerConfigRegistry();
203
195
  const config = freshRegistry.get('code-review');
204
196
  expect(config?.args[0]).toContain('dist/');
205
-
197
+
206
198
  process.env.XRAY_DEV_PATH = originalXrayEnv;
207
- = originalStrrayEnv;
208
199
  });
209
200
  });
210
201
 
@@ -180,7 +180,7 @@ export class ServerConfigRegistry {
180
180
  this.register({
181
181
  serverName: 'orchestrator',
182
182
  command: 'node',
183
- args: [`${basePath}/orchestrator.server.js`],
183
+ args: [`${basePath}/orchestrator/server.js`],
184
184
  timeout: 60000,
185
185
  });
186
186
 
@@ -28,7 +28,7 @@ import * as fs from "fs";
28
28
  import * as path from "path";
29
29
  import { fileURLToPath } from "url";
30
30
  import { randomUUID } from "crypto";
31
- import { getGovernanceService } from "../governance/governance-service.js";
31
+ import { handleGovernRequest } from "../nucleus/index.js";
32
32
  import { getCodexPolicyService } from "../governance/codex-policy.service.js";
33
33
  import { initializeGovernanceIntegration, shutdownGovernanceIntegration } from "../integrations/governance/index.js";
34
34
  import { featuresConfigLoader } from "../core/features-config.js";
@@ -68,7 +68,7 @@ class GovernanceServer {
68
68
  constructor() {
69
69
  this.server = new Server(
70
70
  {
71
- name: "governance", version: "2.1.1",
71
+ name: "governance", version: "2.1.3",
72
72
  },
73
73
  {
74
74
  capabilities: {
@@ -243,8 +243,6 @@ class GovernanceServer {
243
243
  }
244
244
 
245
245
  private async handleGovernProposals(args: GovernProposalsArgs): Promise<CallToolResult> {
246
- const service = getGovernanceService();
247
-
248
246
  const request: GovernanceRequest = {
249
247
  proposals: args.proposals.map((p, i) => ({
250
248
  id: p.id || `prop-${Date.now()}-${i}`,
@@ -261,11 +259,11 @@ class GovernanceServer {
261
259
  },
262
260
  };
263
261
 
264
- frameworkLogger.log("governance-mcp", "delegating-to-governance-service", "info", {
262
+ frameworkLogger.log("governance-mcp", "delegating-to-kernel", "info", {
265
263
  proposalCount: request.proposals.length,
266
264
  });
267
265
 
268
- const response = await service.govern(request);
266
+ const response = await handleGovernRequest(request);
269
267
 
270
268
  return {
271
269
  content: [
@@ -7,6 +7,7 @@
7
7
 
8
8
  import { XrayKnowledgeSkillBase } from "../shared/knowledge-skill-base.js";
9
9
  import { frameworkLogger } from "../../core/framework-logger.js";
10
+ import { pluginRegistry } from "../../nucleus/plugin-registry.js";
10
11
 
11
12
  interface DesignApiEndpointsArgs {
12
13
  resource: string;
@@ -56,6 +57,14 @@ class XrayApiDesignServer extends XrayKnowledgeSkillBase {
56
57
  "validate-api-design": async (args) => this.validateApiDesign(args as unknown as ValidateApiDesignArgs),
57
58
  };
58
59
  this.setupToolHandlers();
60
+ pluginRegistry.registerToolPlugin({
61
+ name: "api-design",
62
+ callTool: async (toolName, args) => {
63
+ const handler = this.handlers[toolName];
64
+ if (!handler) throw new Error(`Unknown tool: ${toolName}`);
65
+ return handler(args);
66
+ },
67
+ });
59
68
  }
60
69
 
61
70
  private async designApiEndpoints(args: DesignApiEndpointsArgs) {
@@ -1,5 +1,6 @@
1
1
  import { XrayKnowledgeSkillBase } from "../shared/knowledge-skill-base.js";
2
2
  import { frameworkLogger } from "../../core/framework-logger.js";
3
+ import { pluginRegistry } from "../../nucleus/plugin-registry.js";
3
4
  import * as fs from "fs";
4
5
  import * as path from "path";
5
6
 
@@ -49,6 +50,14 @@ class XrayArchitecturePatternsServer extends XrayKnowledgeSkillBase {
49
50
  "recommend-patterns": async (args) => this.recommendPatterns(args as unknown as RecommendPatternsArgs),
50
51
  };
51
52
  this.setupToolHandlers();
53
+ pluginRegistry.registerToolPlugin({
54
+ name: "architecture-patterns",
55
+ callTool: async (toolName, args) => {
56
+ const handler = this.handlers[toolName];
57
+ if (!handler) throw new Error(`Unknown tool: ${toolName}`);
58
+ return handler(args);
59
+ },
60
+ });
52
61
  }
53
62
 
54
63
  private async analyzeArchitecture(args: AnalyzeArchitectureArgs) {
@@ -11,6 +11,7 @@ import * as path from "path";
11
11
  import { fileURLToPath } from "url";
12
12
  import { XrayKnowledgeSkillBase } from "../shared/knowledge-skill-base.js";
13
13
  import { frameworkLogger } from "../../core/framework-logger.js";
14
+ import { pluginRegistry } from "../../nucleus/plugin-registry.js";
14
15
 
15
16
  interface BugReport {
16
17
  id: string;
@@ -254,6 +255,14 @@ class BugTriageSpecialistServer extends XrayKnowledgeSkillBase {
254
255
  },
255
256
  };
256
257
  this.setupToolHandlers();
258
+ pluginRegistry.registerToolPlugin({
259
+ name: "bug-triage-specialist",
260
+ callTool: async (toolName, args) => {
261
+ const handler = this.handlers[toolName];
262
+ if (!handler) throw new Error(`Unknown tool: ${toolName}`);
263
+ return handler(args);
264
+ },
265
+ });
257
266
  }
258
267
 
259
268
  private triageBugs(errorLogs: string[], context: Record<string, unknown>): TriageResult {
@@ -12,6 +12,7 @@
12
12
 
13
13
  import { XrayKnowledgeSkillBase } from "../shared/knowledge-skill-base.js";
14
14
  import { frameworkLogger } from "../../core/framework-logger.js";
15
+ import { pluginRegistry } from "../../nucleus/plugin-registry.js";
15
16
  import * as fs from "fs";
16
17
  import * as path from "path";
17
18
 
@@ -310,6 +311,14 @@ class CodeAnalyzerServer extends XrayKnowledgeSkillBase {
310
311
  "find_duplicates": async (args) => this.handleFindDuplicates(args),
311
312
  };
312
313
  this.setupToolHandlers();
314
+ pluginRegistry.registerToolPlugin({
315
+ name: "code-analyzer",
316
+ callTool: async (toolName, args) => {
317
+ const handler = this.handlers[toolName];
318
+ if (!handler) throw new Error(`Unknown tool: ${toolName}`);
319
+ return handler(args);
320
+ },
321
+ });
313
322
  }
314
323
 
315
324
  private handleAnalyzeCode(args: unknown) {
@@ -7,6 +7,7 @@
7
7
 
8
8
  import { XrayKnowledgeSkillBase } from "../shared/knowledge-skill-base.js";
9
9
  import { frameworkLogger } from "../../core/framework-logger.js";
10
+ import { pluginRegistry } from "../../nucleus/plugin-registry.js";
10
11
  import * as fs from "fs";
11
12
  import * as path from "path";
12
13
 
@@ -190,6 +191,14 @@ class XrayCodeReviewServer extends XrayKnowledgeSkillBase {
190
191
  "analyze_proposal": async (args) => this.analyzeProposal(args as AnalyzeProposalArgs),
191
192
  };
192
193
  this.setupToolHandlers();
194
+ pluginRegistry.registerToolPlugin({
195
+ name: "code-review",
196
+ callTool: async (toolName, args) => {
197
+ const handler = this.handlers[toolName];
198
+ if (!handler) throw new Error(`Unknown tool: ${toolName}`);
199
+ return handler(args);
200
+ },
201
+ });
193
202
  }
194
203
 
195
204
  private async analyzeCodeQuality(args: AnalyzeCodeQualityArgs) {