0xray 3.3.1 → 3.4.1

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.
@@ -1,7 +1,5 @@
1
1
  {
2
- "framework": "xray 2.0",
3
- "version": "3.1.0",
4
- "description": "Codex-compliant framework configuration for Credible UI project",
2
+ "description": "Codex-compliant framework configuration",
5
3
  "thresholds": {
6
4
  "bundleSize": {
7
5
  "maxSize": "3MB",
@@ -220,7 +218,6 @@
220
218
  }
221
219
  },
222
220
  "codex": {
223
- "version": "3.1.0",
224
221
  "terms": [
225
222
  1,
226
223
  2,
package/dist/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Conventional Commits](https://www.conventionalcommits.org/).
6
6
 
7
+ ## [3.4.1] - 2026-06-17
8
+
9
+ ### ✨ Features
10
+ - Unified 4-platform bridge installer (`install-bridges.cjs`) runs on consumer `npm i 0xray` postinstall — OpenCode, Grok, Hermes, OpenClaw
11
+ - All 7 MCP servers registered via `npx -y 0xray mcp <cmd>` (no brittle `dist/` paths)
12
+ - `npx 0xray grok install` aligned with postinstall: 7 servers via npx, idempotent skill/MCP sync on re-run
13
+ - Grok skills synced to both `~/.grok/plugins/0xray/skills/` and `~/.grok/skills/` (Grok Build / Cursor)
14
+
15
+ ### 🐛 Bug Fixes
16
+ - `setup.cjs` consumer detection uses `isConsumerInstall()` — works for both `node_modules/0xray` and `node_modules/xray`
17
+ - Hermes bridge honors `XRAY_ROOT` env and `xray-consumer-root.txt` marker for correct project root resolution
18
+
7
19
  ## [3.3.0] - 2026-06-18
8
20
 
9
21
  ### 🔄 Changes
@@ -35,7 +35,6 @@ class RoutingRefiner {
35
35
  const optimizations = this.suggestMappingOptimizations(promptAnalysis, performanceReport);
36
36
  const warnings = this.generateWarnings(newMappings, optimizations);
37
37
  return {
38
- version: "3.1.0",
39
38
  generatedAt: new Date(),
40
39
  summary: {
41
40
  newMappings: newMappings.length,
@@ -247,7 +246,6 @@ class RoutingRefiner {
247
246
  lines.push("╚════════════════════════════════════════════════════════════╝");
248
247
  lines.push("");
249
248
  lines.push(`Generated: ${report.configurationUpdate.generatedAt.toISOString()}`);
250
- lines.push(`Version: ${report.configurationUpdate.version}`);
251
249
  lines.push("");
252
250
  lines.push("=== Summary ===");
253
251
  lines.push(`New Mappings: ${report.configurationUpdate.summary.newMappings}`);
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Boot Orchestrator (min documented consumer runtime compat shim from prior 0xRay releases; primary Xray paths + .xray fallbacks only; 1-line per Scope Rule).
3
3
  */
4
+ import { readFileSync } from "fs";
4
5
  import { XrayContextLoader } from "./context-loader.js";
5
6
  import { XrayStateManager } from "../state/state-manager.js";
6
7
  import { ProcessorManager } from "../processors/processor-manager.js";
@@ -721,7 +722,14 @@ export class BootOrchestrator {
721
722
  try {
722
723
  // Consumer runtime compat shim from prior 0xRay releases (1-line min per Scope Rule; primary xray paths + .xray fallbacks)
723
724
  const xrayConfig = {
724
- version: "3.1.0",
725
+ version: (() => {
726
+ try {
727
+ return JSON.parse(readFileSync(path.join(process.cwd(), "package.json"), "utf-8")).version;
728
+ }
729
+ catch {
730
+ return "unknown";
731
+ }
732
+ })(),
725
733
  codex_enabled: true,
726
734
  codex_version: "v1.7.5",
727
735
  codex_terms: [
@@ -285,7 +285,6 @@ export class FeaturesConfigLoader {
285
285
  */
286
286
  getDefaultConfig() {
287
287
  return {
288
- version: "3.1.0",
289
288
  description: "0xRay Framework - Unified Feature Configuration",
290
289
  token_optimization: {
291
290
  enabled: true,
@@ -18,9 +18,44 @@ import { frameworkLogger } from '../../core/framework-logger.js';
18
18
  import fs from 'fs';
19
19
  import path from 'path';
20
20
  import { execSync } from 'child_process';
21
+ import { createRequire } from 'module';
21
22
  import { syncBuiltinSkills } from '../../cli/commands/skill-install.js';
22
23
  // ESM-compatible __dirname (this file is compiled to ESM)
23
24
  const __dirname = path.dirname(new URL(import.meta.url).pathname);
25
+ const packageRoot = path.resolve(__dirname, '..', '..', '..');
26
+ const requireCjs = createRequire(import.meta.url);
27
+ const { resolveConsumerTargetDir } = requireCjs(path.join(packageRoot, 'scripts/node/install-bridges.cjs'));
28
+ /** Canonical 7-server MCP surface — matches install-bridges.cjs and package .mcp.json */
29
+ const XRAY_MCP_SERVERS = [
30
+ { name: 'xray-governance', mcpCmd: 'governance', env: { XRAY_FORCE_MCP_GOVERNANCE: 'true' } },
31
+ { name: 'xray-skills', mcpCmd: 'skills', env: {} },
32
+ { name: 'xray-orchestrator', mcpCmd: 'orchestrator', env: {} },
33
+ { name: 'xray-enforcer', mcpCmd: 'enforcer', env: {} },
34
+ { name: 'xray-researcher', mcpCmd: 'researcher', env: {} },
35
+ { name: 'xray-code-review', mcpCmd: 'code-review', env: {} },
36
+ { name: 'xray-architect-tools', mcpCmd: 'architect-tools', env: {} },
37
+ ];
38
+ function registerGrokMcpServers(targetDir) {
39
+ try {
40
+ execSync('which grok', { stdio: 'ignore' });
41
+ }
42
+ catch {
43
+ console.log('[Grok] grok CLI not on PATH — plugin .mcp.json still configured');
44
+ return;
45
+ }
46
+ for (const s of XRAY_MCP_SERVERS) {
47
+ try {
48
+ const envEntries = { ...s.env, XRAY_ROOT: targetDir };
49
+ const envFlags = Object.entries(envEntries)
50
+ .map(([k, v]) => `--env "${k}=${v}"`)
51
+ .join(' ');
52
+ execSync(`grok mcp add ${s.name} --command npx --args "-y" "0xray" "mcp" "${s.mcpCmd}" ${envFlags}`, { stdio: 'pipe' });
53
+ }
54
+ catch {
55
+ // already registered or grok config conflict — non-blocking
56
+ }
57
+ }
58
+ }
24
59
  export async function installForGrokCLI(options = {}) {
25
60
  frameworkLogger.log('grok-integration', 'install-start', 'info', { options });
26
61
  const home = process.env.HOME || process.env.USERPROFILE || '';
@@ -39,15 +74,18 @@ export async function installForGrokCLI(options = {}) {
39
74
  console.log(`[Grok] Dry run: Would copy plugin from ${sourceDir} → ${targetPluginDir}`);
40
75
  return;
41
76
  }
77
+ const targetDir = resolveConsumerTargetDir(packageRoot, process.cwd());
42
78
  try {
43
- if (fs.existsSync(targetPluginDir) && !options.force) {
79
+ const pluginExists = fs.existsSync(targetPluginDir);
80
+ if (pluginExists && !options.force) {
44
81
  console.log('[Grok] 0xray Grok plugin is already installed.');
45
- console.log('Use --force to reinstall.');
46
- return;
82
+ console.log('Use --force to reinstall plugin files.');
83
+ }
84
+ else {
85
+ fs.cpSync(sourceDir, targetPluginDir, { recursive: true, force: true });
86
+ frameworkLogger.log('grok-integration', 'plugin-copied', 'info', { destination: targetPluginDir });
87
+ console.log(`\x1b[32m✓ Copied Grok plugin to ${targetPluginDir}\x1b[0m`);
47
88
  }
48
- fs.cpSync(sourceDir, targetPluginDir, { recursive: true, force: true });
49
- frameworkLogger.log('grok-integration', 'plugin-copied', 'info', { destination: targetPluginDir });
50
- console.log(`\x1b[32m✓ Copied Grok plugin to ${targetPluginDir}\x1b[0m`);
51
89
  // Sync builtin skills to Grok plugin skills dir
52
90
  const grokSkillsDir = path.join(targetPluginDir, 'skills');
53
91
  const skillsCopied = syncBuiltinSkills(grokSkillsDir);
@@ -70,25 +108,9 @@ export async function installForGrokCLI(options = {}) {
70
108
  console.log('\nPlease run this command to fully trust the plugin:');
71
109
  console.log(` grok plugins trust "${targetPluginDir}"`);
72
110
  }
73
- // Register MCP servers via grok mcp add (most reliable mechanism)
74
- const govMcpPath = path.resolve(__dirname, '..', '..', '..', 'dist/mcps/governance.server.js');
75
- const skillsMcpPath = path.resolve(__dirname, '..', '..', '..', 'dist/mcps/knowledge-skills/skill-invocation.server.js');
76
- const orchMcpPath = path.resolve(__dirname, '..', '..', '..', 'dist/mcps/orchestrator.server.js');
77
- const enforcerMcpPath = path.resolve(__dirname, '..', '..', '..', 'dist/mcps/enforcer-tools.server.js');
78
- try {
79
- execSync(`grok mcp add xray-governance --command node --args "${govMcpPath}" --env "XRAY_FORCE_MCP_GOVERNANCE=true" --env "XRAY_ROOT=${process.cwd()}"`, { stdio: 'pipe' });
80
- execSync(`grok mcp add xray-skills --command node --args "${skillsMcpPath}" --env "XRAY_ROOT=${process.cwd()}"`, { stdio: 'pipe' });
81
- execSync(`grok mcp add xray-orchestrator --command node --args "${orchMcpPath}" --env "XRAY_ROOT=${process.cwd()}"`, { stdio: 'pipe' });
82
- execSync(`grok mcp add xray-enforcer --command node --args "${enforcerMcpPath}" --env "XRAY_ROOT=${process.cwd()}"`, { stdio: 'pipe' });
83
- console.log('\x1b[32m✓ Registered xray MCP servers with Grok CLI\x1b[0m');
84
- }
85
- catch {
86
- console.log('\nCould not auto-register MCP servers. Run manually:');
87
- console.log(` grok mcp add xray-governance --command node --args "${govMcpPath}"`);
88
- console.log(` grok mcp add xray-skills --command node --args "${skillsMcpPath}"`);
89
- console.log(` grok mcp add xray-orchestrator --command node --args "${orchMcpPath}"`);
90
- console.log(` grok mcp add xray-enforcer --command node --args "${enforcerMcpPath}"`);
91
- }
111
+ // Register MCP servers via grok mcp add (npx -y 0xray mcp — matches install-bridges)
112
+ registerGrokMcpServers(targetDir);
113
+ console.log('\x1b[32m✓ Registered 7 xray MCP servers with Grok CLI (npx)\x1b[0m');
92
114
  console.log('\n✅ 0xRay is now installed as a first-class Grok CLI plugin!');
93
115
  console.log('Restart Grok or run `grok` to load the new hooks and MCP servers.');
94
116
  }
@@ -53,9 +53,19 @@ let frameworkLoadAttempted = false;
53
53
 
54
54
  // ── Project root detection ───────────────────────────────────
55
55
  function findProjectRoot() {
56
- const envHome = process.env.XRAY_HOME;
56
+ const envHome = process.env.XRAY_HOME || process.env.XRAY_ROOT;
57
57
  if (envHome && existsSync(join(envHome, "package.json"))) return envHome;
58
58
 
59
+ const consumerMarker = join(__dirname, "xray-consumer-root.txt");
60
+ if (existsSync(consumerMarker)) {
61
+ try {
62
+ const marked = readFileSync(consumerMarker, "utf-8").trim();
63
+ if (marked && existsSync(join(marked, "package.json"))) return marked;
64
+ } catch {
65
+ // fall through
66
+ }
67
+ }
68
+
59
69
  const candidates = [
60
70
  process.cwd(),
61
71
  join(homedir(), "dev", "xray"),
@@ -1,5 +1,4 @@
1
1
  {
2
- "version": "3.1.0",
3
2
  "description": "0xRay Community MCPs Registry - curated API-focused MCP servers",
4
3
  "sources": [
5
4
  {
@@ -113,7 +113,7 @@ export class UniversalRegistryBridge {
113
113
  currentAgent = {
114
114
  name: nameMatch[1].trim(),
115
115
  description: "",
116
- version: "3.1.0",
116
+ version: "",
117
117
  };
118
118
  inAgent = true;
119
119
  continue;
@@ -1,5 +1,4 @@
1
1
  {
2
- "version": "3.1.0",
3
2
  "description": "0xRay Skills Registry - recommended skill sources for consumers",
4
3
  "sources": [
5
4
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0xray",
3
- "version": "3.3.1",
3
+ "version": "3.4.1",
4
4
  "description": "Multi-agent orchestration and Codex governance for OpenCode, Hermes, Grok Build, and OpenClaw",
5
5
  "readme": "README.md",
6
6
  "license": "MIT",
@@ -1,12 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * AGENTS.md Enforcement Script
4
- *
5
- * Validates that AGENTS.md exists, is up-to-date, and follows the required format.
6
- * This script should be run in CI/CD, pre-commit hooks, and local validation.
7
- *
8
- * @version 1.0.0
9
- * @framework xray v2
10
3
  */
11
4
 
12
5
  import fs from 'fs';
@@ -62,7 +55,6 @@ class AgentsMdEnforcer {
62
55
  }
63
56
 
64
57
  /**
65
- * Run all validation checks
66
58
  */
67
59
  async validate() {
68
60
  console.log('🔍 AGENTS.md Enforcement Check');
@@ -148,14 +140,12 @@ class AgentsMdEnforcer {
148
140
  }
149
141
 
150
142
  /**
151
- * Check if AGENTS.md file exists
152
143
  */
153
144
  checkFileExists() {
154
145
  return fs.existsSync(this.agentsPath);
155
146
  }
156
147
 
157
148
  /**
158
- * Check for required sections
159
149
  */
160
150
  checkRequiredSections(content) {
161
151
  const missing = [];
@@ -188,7 +178,6 @@ class AgentsMdEnforcer {
188
178
  }
189
179
 
190
180
  /**
191
- * Check for required agent definitions
192
181
  */
193
182
  checkRequiredAgents(content) {
194
183
  // Be flexible - check for agent names with or without @ prefix
@@ -199,7 +188,6 @@ class AgentsMdEnforcer {
199
188
  }
200
189
 
201
190
  /**
202
- * Extract version from header
203
191
  */
204
192
  extractVersion(content) {
205
193
  const match = content.match(/\*\*Version\*\*:\s*(\d+\.\d+\.\d+)/);
@@ -207,7 +195,6 @@ class AgentsMdEnforcer {
207
195
  }
208
196
 
209
197
  /**
210
- * Extract date from header
211
198
  */
212
199
  extractDate(content) {
213
200
  const match = content.match(/\*\*Updated\*\*:\s*(\d{4}-\d{2}-\d{2})/);
@@ -215,7 +202,6 @@ class AgentsMdEnforcer {
215
202
  }
216
203
 
217
204
  /**
218
- * Calculate how many days old the file is
219
205
  */
220
206
  calculateDaysOld(dateString) {
221
207
  const date = new Date(dateString);
@@ -225,18 +211,12 @@ class AgentsMdEnforcer {
225
211
  }
226
212
 
227
213
  /**
228
- * Calculate content hash
229
214
  */
230
215
  calculateHash(content) {
231
216
  return crypto.createHash('sha256').update(content).digest('hex');
232
217
  }
233
218
 
234
219
  /**
235
- * Count codex terms (numbered rules or sections with multiple items)
236
- * Looks for patterns like:
237
- * - #### 1. Something
238
- * - 1. **Something**
239
- * - ## CRITICAL RULES (count as one term block)
240
220
  */
241
221
  countCodexTerms(content) {
242
222
  // Count #### numbered items
@@ -257,7 +237,6 @@ class AgentsMdEnforcer {
257
237
  }
258
238
 
259
239
  /**
260
- * Log individual check result
261
240
  */
262
241
  logResult(check, status, message) {
263
242
  const icon = status === 'PASS' ? '✅' : status === 'FAIL' ? '❌' : status === 'WARN' ? '⚠️' : 'ℹ️';
@@ -266,7 +245,6 @@ class AgentsMdEnforcer {
266
245
  }
267
246
 
268
247
  /**
269
- * Generate and display report
270
248
  */
271
249
  report(exitCode) {
272
250
  console.log('\n================================');
@@ -309,7 +287,6 @@ class AgentsMdEnforcer {
309
287
  }
310
288
 
311
289
  /**
312
- * Auto-generate AGENTS.md from current agent configuration
313
290
  */
314
291
  async generate() {
315
292
  console.log('📝 Generating AGENTS.md...\n');
@@ -325,7 +302,6 @@ class AgentsMdEnforcer {
325
302
  }
326
303
 
327
304
  /**
328
- * Load template file
329
305
  */
330
306
  async loadTemplate() {
331
307
  const templatePath = path.join(__dirname, '..', '..', '..', 'docs', 'AGENTS_TEMPLATE.md');
@@ -342,7 +318,6 @@ class AgentsMdEnforcer {
342
318
  }
343
319
 
344
320
  /**
345
- * Discover agents from configuration
346
321
  */
347
322
  async discoverAgents() {
348
323
  const agents = [];
@@ -366,7 +341,6 @@ class AgentsMdEnforcer {
366
341
  }
367
342
 
368
343
  /**
369
- * Populate template with agent data
370
344
  */
371
345
  populateTemplate(template, agents) {
372
346
  const now = new Date().toISOString().split('T')[0];
@@ -7,7 +7,6 @@
7
7
  #
8
8
  # Usage: ./scripts/node/enforce-version-compliance.sh
9
9
  #
10
- # @version 1.0.0
11
10
  # @since 2026-01-15
12
11
 
13
12
  set -e
@@ -1,15 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Version Compliance Enforcement Script
4
- *
5
- * Thin CLI wrapper around VersionComplianceProcessor.
6
- * Called by CI/CD, pre-commit hooks, and manual runs.
7
- *
8
- * This script should NOT contain enforcement logic -
9
- * all logic lives in src/processors/version-compliance-processor.ts
10
- *
11
- * @version 1.0.0
12
- * @deprecated Use VersionComplianceProcessor directly in new code
13
3
  */
14
4
 
15
5
  import path from 'path';
@@ -10,19 +10,37 @@ const os = require("os");
10
10
  const { execSync } = require("child_process");
11
11
 
12
12
  const SKIP_DIRS = new Set(["node_modules", "logs"]);
13
- const MERGE_FILES = new Set(["xray/features.json", "enforcer-config.json"]);
13
+ const MERGE_FILES = new Set(["enforcer-config.json"]);
14
14
  const KEEP_IF_EXISTS = new Set([".yml", ".yaml", ".md"]);
15
15
 
16
+ /** Canonical 7-server MCP surface — matches package .mcp.json and Grok plugin */
17
+ const XRAY_MCP_SERVERS = [
18
+ { name: "xray-governance", mcpCmd: "governance", env: { XRAY_FORCE_MCP_GOVERNANCE: "true" } },
19
+ { name: "xray-skills", mcpCmd: "skills", env: {} },
20
+ { name: "xray-orchestrator", mcpCmd: "orchestrator", env: {} },
21
+ { name: "xray-enforcer", mcpCmd: "enforcer", env: {} },
22
+ { name: "xray-researcher", mcpCmd: "researcher", env: {} },
23
+ { name: "xray-code-review", mcpCmd: "code-review", env: {} },
24
+ { name: "xray-architect-tools", mcpCmd: "architect-tools", env: {} },
25
+ ];
26
+
16
27
  function resolveConsumerTargetDir(packageRoot, fallbackDir) {
17
- const resolvedPackage = path.resolve(packageRoot);
18
- if (resolvedPackage.includes(`${path.sep}node_modules${path.sep}`)) {
19
- let current = resolvedPackage;
20
- while (current.includes(`${path.sep}node_modules${path.sep}`)) {
21
- current = path.dirname(current);
22
- }
23
- return current;
28
+ const resolved = path.resolve(packageRoot);
29
+ const inNodeModules =
30
+ resolved.includes(`${path.sep}node_modules${path.sep}`) ||
31
+ resolved.endsWith(`${path.sep}node_modules`);
32
+
33
+ if (!inNodeModules) {
34
+ return fallbackDir || process.env.PWD || process.cwd();
35
+ }
36
+
37
+ let current = resolved;
38
+ while (path.basename(current) !== "node_modules") {
39
+ const parent = path.dirname(current);
40
+ if (parent === current) return fallbackDir || process.cwd();
41
+ current = parent;
24
42
  }
25
- return fallbackDir || process.env.PWD || process.cwd();
43
+ return path.dirname(current);
26
44
  }
27
45
 
28
46
  function isConsumerInstall(packageRoot, targetDir) {
@@ -108,6 +126,91 @@ function copyPluginDir(src, dest) {
108
126
  return true;
109
127
  }
110
128
 
129
+ function buildConsumerMcpConfig(targetDir) {
130
+ const mcpServers = {};
131
+ for (const s of XRAY_MCP_SERVERS) {
132
+ mcpServers[s.name] = {
133
+ command: "npx",
134
+ args: ["-y", "0xray", "mcp", s.mcpCmd],
135
+ env: { ...s.env, XRAY_ROOT: targetDir },
136
+ };
137
+ }
138
+ return { mcpServers };
139
+ }
140
+
141
+ function deployProjectMcpJson(targetDir, log) {
142
+ const destPath = path.join(targetDir, ".mcp.json");
143
+ const consumerConfig = buildConsumerMcpConfig(targetDir);
144
+ let existing = { mcpServers: {} };
145
+ if (fs.existsSync(destPath)) {
146
+ try {
147
+ existing = JSON.parse(fs.readFileSync(destPath, "utf8"));
148
+ } catch {
149
+ existing = { mcpServers: {} };
150
+ }
151
+ }
152
+ const merged = {
153
+ ...existing,
154
+ mcpServers: { ...(existing.mcpServers || {}), ...consumerConfig.mcpServers },
155
+ };
156
+ fs.writeFileSync(destPath, JSON.stringify(merged, null, 2) + "\n");
157
+ log("mcp-config", "project .mcp.json deployed (7 xray servers)", "info");
158
+ }
159
+
160
+ function writePluginMcpJson(pluginDir, targetDir, log, label) {
161
+ if (!fs.existsSync(pluginDir)) return;
162
+ const dest = path.join(pluginDir, ".mcp.json");
163
+ fs.writeFileSync(dest, JSON.stringify(buildConsumerMcpConfig(targetDir), null, 2) + "\n");
164
+ log(label, "plugin .mcp.json patched for consumer", "info");
165
+ }
166
+
167
+ function mergeOpencodeJson(targetDir, packageRoot, log) {
168
+ const rootOpencode = path.join(packageRoot, "opencode.json");
169
+ const userOpencode = path.join(targetDir, "opencode.json");
170
+ if (!fs.existsSync(rootOpencode)) return;
171
+
172
+ try {
173
+ const srcData = JSON.parse(fs.readFileSync(rootOpencode, "utf8"));
174
+ if (fs.existsSync(userOpencode)) {
175
+ const destData = JSON.parse(fs.readFileSync(userOpencode, "utf8"));
176
+ const merged = { ...destData };
177
+ if (srcData.agent) merged.agent = srcData.agent;
178
+ if (srcData.mcp) merged.mcp = { ...destData.mcp, ...srcData.mcp };
179
+ if (srcData.compaction) merged.compaction = srcData.compaction;
180
+ fs.writeFileSync(userOpencode, JSON.stringify(merged, null, 2) + "\n");
181
+ } else {
182
+ fs.copyFileSync(rootOpencode, userOpencode);
183
+ }
184
+ log("opencode-bridge", "opencode.json merged", "info");
185
+ } catch (e) {
186
+ log("opencode-bridge", "opencode.json merge failed", "warn", { error: e.message });
187
+ }
188
+ }
189
+
190
+ function patchGrokHooks(pluginDir, packageRoot, targetDir, log, label) {
191
+ const hooksPath = path.join(pluginDir, "hooks", "hooks.json");
192
+ const hookScript = path.join(packageRoot, "dist", "integrations", "grok", "hooks", "pre-tool-use.js");
193
+ if (!fs.existsSync(hooksPath)) return;
194
+
195
+ try {
196
+ const hooks = JSON.parse(fs.readFileSync(hooksPath, "utf8"));
197
+ const preTool = hooks.hooks?.PreToolUse?.[0]?.hooks?.[0];
198
+ if (preTool && fs.existsSync(hookScript)) {
199
+ preTool.command = "node";
200
+ preTool.args = [hookScript];
201
+ preTool.env = {
202
+ ...(preTool.env || {}),
203
+ XRAY_ROOT: targetDir,
204
+ XRAY_AI_PATH: packageRoot,
205
+ };
206
+ fs.writeFileSync(hooksPath, JSON.stringify(hooks, null, 2) + "\n");
207
+ log(label, "hooks.json patched → enforcement gate", "info");
208
+ }
209
+ } catch (e) {
210
+ log(label, "hooks.json patch failed", "warn", { error: e.message });
211
+ }
212
+ }
213
+
111
214
  function installOpencodeBridge(targetDir, packageRoot, log) {
112
215
  const opencodeSource = path.join(packageRoot, ".opencode");
113
216
  const opencodeDest = path.join(targetDir, ".opencode");
@@ -149,37 +252,25 @@ function findGrokPluginSource(packageRoot) {
149
252
  return candidates.find((p) => fs.existsSync(p));
150
253
  }
151
254
 
152
- function registerGrokMcpServers(packageRoot, targetDir, log) {
255
+ function registerGrokMcpServers(targetDir, log) {
153
256
  try {
154
257
  execSync("which grok", { stdio: "ignore" });
155
258
  } catch {
156
- log("grok-bridge", "grok CLI not on PATH — skipped MCP registration", "info");
259
+ log("grok-bridge", "grok CLI not on PATH — plugin .mcp.json still configured", "info");
157
260
  return;
158
261
  }
159
262
 
160
- const govServer = path.join(packageRoot, "dist/mcps/governance.server.js");
161
- const skillsServer = path.join(packageRoot, "dist/mcps/knowledge-skills/skill-invocation.server.js");
162
- const orchServer = path.join(packageRoot, "dist/mcps/orchestrator.server.js");
163
- const enforcerServer = path.join(packageRoot, "dist/mcps/enforcer-tools.server.js");
164
-
165
- const servers = [
166
- ["xray-governance", govServer, `XRAY_FORCE_MCP_GOVERNANCE=true`],
167
- ["xray-skills", skillsServer, null],
168
- ["xray-orchestrator", orchServer, null],
169
- ["xray-enforcer", enforcerServer, null],
170
- ];
171
-
172
- for (const [name, serverPath, extraEnv] of servers) {
173
- if (!fs.existsSync(serverPath)) continue;
263
+ for (const s of XRAY_MCP_SERVERS) {
174
264
  try {
175
- const envFlags = extraEnv
176
- ? `--env "${extraEnv}" --env "XRAY_ROOT=${targetDir}"`
177
- : `--env "XRAY_ROOT=${targetDir}"`;
265
+ const envEntries = { ...s.env, XRAY_ROOT: targetDir };
266
+ const envFlags = Object.entries(envEntries)
267
+ .map(([k, v]) => `--env "${k}=${v}"`)
268
+ .join(" ");
178
269
  execSync(
179
- `grok mcp add ${name} --command node --args "${serverPath}" ${envFlags}`,
270
+ `grok mcp add ${s.name} --command npx --args "-y" "0xray" "mcp" "${s.mcpCmd}" ${envFlags}`,
180
271
  { stdio: "pipe" }
181
272
  );
182
- log("grok-bridge", `registered ${name}`, "info");
273
+ log("grok-bridge", `registered ${s.name} (npx)`, "info");
183
274
  } catch {
184
275
  // already registered or grok config conflict — non-blocking
185
276
  }
@@ -217,6 +308,8 @@ function installGrokBridge(targetDir, packageRoot, log) {
217
308
  if (copyPluginDir(sourceDir, dest)) {
218
309
  const rel = dest.startsWith(home) ? dest.replace(home, "~") : path.relative(targetDir, dest);
219
310
  log("grok-bridge", "plugin copied", "info", { path: rel || dest });
311
+ writePluginMcpJson(dest, targetDir, log, "grok-bridge");
312
+ patchGrokHooks(dest, packageRoot, targetDir, log, "grok-bridge");
220
313
  const copied = syncBuiltinSkills(path.join(dest, "skills"), packageRoot);
221
314
  if (copied > 0) log("grok-bridge", `plugin skills synced (${copied})`, "info", { path: rel });
222
315
  }
@@ -229,10 +322,10 @@ function installGrokBridge(targetDir, packageRoot, log) {
229
322
  log("grok-bridge", `global skills synced (${globalCopied})`, "info", { path: "~/.grok/skills/" });
230
323
  }
231
324
 
232
- registerGrokMcpServers(packageRoot, targetDir, log);
325
+ registerGrokMcpServers(targetDir, log);
233
326
  }
234
327
 
235
- function installHermesBridge(packageRoot, log) {
328
+ function installHermesBridge(targetDir, packageRoot, log) {
236
329
  const sources = [
237
330
  path.join(packageRoot, "dist", "integrations", "hermes-agent"),
238
331
  path.join(packageRoot, "src", "integrations", "hermes-agent"),
@@ -256,8 +349,15 @@ function installHermesBridge(packageRoot, log) {
256
349
  }
257
350
  log("hermes-bridge", "plugin copied", "info", { path: "~/.hermes/plugins/xray-hermes" });
258
351
 
352
+ writePluginMcpJson(targetPluginDir, targetDir, log, "hermes-bridge");
353
+
259
354
  const copied = syncBuiltinSkills(path.join(targetPluginDir, "skills"), packageRoot);
260
355
  if (copied > 0) log("hermes-bridge", `skills synced (${copied})`, "info");
356
+
357
+ // Marker so bridge.mjs resolves the consumer project on hook invocation
358
+ const rootMarker = path.join(targetPluginDir, "xray-consumer-root.txt");
359
+ fs.writeFileSync(rootMarker, targetDir + "\n");
360
+ log("hermes-bridge", "consumer root marker written", "info");
261
361
  }
262
362
 
263
363
  function installOpenclawBridge(targetDir, packageRoot, log) {
@@ -347,9 +447,11 @@ function installAllBridges(opts) {
347
447
  log("install-bridges", "starting 4-platform install", "info");
348
448
 
349
449
  deployXrayConfig(targetDir, packageRoot, log);
450
+ deployProjectMcpJson(targetDir, log);
451
+ mergeOpencodeJson(targetDir, packageRoot, log);
350
452
  installOpencodeBridge(targetDir, packageRoot, log);
351
453
  installGrokBridge(targetDir, packageRoot, log);
352
- installHermesBridge(packageRoot, log);
454
+ installHermesBridge(targetDir, packageRoot, log);
353
455
  installOpenclawBridge(targetDir, packageRoot, log);
354
456
  installGitHooks(packageRoot, log);
355
457
 
@@ -92,6 +92,7 @@ function checkGitStatus() {
92
92
  'logs/',
93
93
  'backups/',
94
94
  'Users/',
95
+ '.xray/inference/',
95
96
  ];
96
97
 
97
98
  const realChanges = lines.filter(l => {
@@ -128,32 +129,35 @@ function checkGitStatus() {
128
129
 
129
130
  function checkVersionSync() {
130
131
  log('Checking version synchronization...', 'step');
131
-
132
- // Load version manager
132
+
133
+ const pkgPath = path.join(rootDir, 'package.json');
134
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
135
+ const pkgVersion = pkg.version;
136
+
133
137
  const vmPath = path.join(rootDir, 'scripts/node/universal-version-manager.js');
134
138
  const vmContent = fs.readFileSync(vmPath, 'utf-8');
135
- const versionMatch = vmContent.match(/version:\s*"([^"]+)"/);
136
-
139
+ const usesPackageSsot =
140
+ vmContent.includes('readPackageVersion()') &&
141
+ /version:\s*PACKAGE_VERSION/.test(vmContent);
142
+
143
+ if (usesPackageSsot) {
144
+ log(`Version SSOT: package.json (${pkgVersion})`, 'success');
145
+ return true;
146
+ }
147
+
148
+ const versionMatch = vmContent.match(/framework:\s*\{[\s\S]*?version:\s*"([^"]+)"/);
137
149
  if (!versionMatch) {
138
- errors.push('Cannot find version in version manager');
150
+ errors.push('Cannot find framework version in version manager');
139
151
  return false;
140
152
  }
141
-
153
+
142
154
  const vmVersion = versionMatch[1];
143
-
144
- // Load package.json
145
- const pkgPath = path.join(rootDir, 'package.json');
146
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
147
- const pkgVersion = pkg.version;
148
-
149
155
  if (pkgVersion !== vmVersion) {
150
- // package.json is often 1 ahead of UVM after npm version patch — non-blocking
151
156
  warnings.push(`Version mismatch: package.json (${pkgVersion}) != version manager (${vmVersion})`);
152
157
  log(`Version mismatch: package.json=${pkgVersion}, version-manager=${vmVersion}`, 'warn');
153
- return true; // non-blocking — matches pre-commit hook behavior
158
+ } else {
159
+ log(`Versions aligned: ${pkgVersion}`, 'success');
154
160
  }
155
-
156
- log(`Versions aligned: ${pkgVersion}`, 'success');
157
161
  return true;
158
162
  }
159
163
 
@@ -6,7 +6,7 @@ const path = require("path");
6
6
  const packageRoot = path.join(__dirname, "..", "..");
7
7
  const homeDir = require("os").homedir();
8
8
 
9
- const { resolveConsumerTargetDir } = require("./install-bridges.cjs");
9
+ const { resolveConsumerTargetDir, isConsumerInstall } = require("./install-bridges.cjs");
10
10
  let targetDir = resolveConsumerTargetDir(packageRoot, process.env.PWD || process.cwd());
11
11
 
12
12
  const resolvedPackage = path.resolve(packageRoot);
@@ -155,8 +155,13 @@ if (fs.existsSync(distSource)) {
155
155
  }
156
156
 
157
157
  // 6. Convert MCP paths in consumer opencode.json
158
- const isConsumer = fs.existsSync(path.join(targetDir, "node_modules", "xray", "package.json"));
159
- if (!hasHermes && isConsumer) {
158
+ const isConsumer = isConsumerInstall(packageRoot, targetDir);
159
+ const consumerPkgName = isConsumer
160
+ ? ["0xray", "xray"].find((name) =>
161
+ fs.existsSync(path.join(targetDir, "node_modules", name, "package.json"))
162
+ )
163
+ : null;
164
+ if (!hasHermes && isConsumer && consumerPkgName) {
160
165
  const mainOpencodePath = path.join(targetDir, "opencode.json");
161
166
  if (fs.existsSync(mainOpencodePath)) {
162
167
  try {
@@ -167,13 +172,13 @@ if (!hasHermes && isConsumer) {
167
172
  if (server.command && typeof server.command === "string") {
168
173
  const normalized = server.command.replace(
169
174
  /^[.]{0,2}\/dist\/mcps\//,
170
- "node_modules/xray/dist/mcps/"
175
+ `node_modules/${consumerPkgName}/dist/mcps/`
171
176
  );
172
177
  if (normalized !== server.command) { server.command = normalized; modified = true; }
173
178
  }
174
179
  if (Array.isArray(server.command)) {
175
180
  server.command = server.command.map(a =>
176
- a.replace(/^[.]{0,2}\/dist\/mcps\//, "node_modules/xray/dist/mcps/")
181
+ a.replace(/^[.]{0,2}\/dist\/mcps\//, `node_modules/${consumerPkgName}/dist/mcps/`)
177
182
  );
178
183
  modified = true;
179
184
  }
@@ -17,7 +17,6 @@
17
17
  * - Historical docs (docs/reflections, docs/archive)
18
18
  * - Test files with assertions
19
19
  *
20
- * @version 2.0.0
21
20
  * @since 2026-01-15
22
21
  * @updated 2026-03-09 - Enhanced with documentation management, validation, and backup
23
22
  */
@@ -28,6 +27,19 @@ const require = createRequire(import.meta.url);
28
27
  import fs from "fs";
29
28
  import path from "path";
30
29
  import { execSync } from "child_process";
30
+ import { fileURLToPath } from "url";
31
+
32
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
33
+ const rootDir = path.resolve(__dirname, "../..");
34
+
35
+ function readPackageVersion() {
36
+ try {
37
+ const pkg = JSON.parse(fs.readFileSync(path.join(rootDir, "package.json"), "utf-8"));
38
+ return pkg.version;
39
+ } catch {
40
+ return "0.0.0";
41
+ }
42
+ }
31
43
 
32
44
  /**
33
45
  * Auto-calculate framework counts from filesystem
@@ -133,12 +145,14 @@ const CALCULATED_COUNTS = calculateCounts();
133
145
  * Framework version information - SINGLE SOURCE OF TRUTH
134
146
  * Version manager updates this, then propagates to all files
135
147
  */
148
+ const PACKAGE_VERSION = readPackageVersion();
149
+
136
150
  const OFFICIAL_VERSIONS = {
137
- // Framework version
151
+ // Framework version — SSOT: package.json
138
152
  framework: {
139
- version: "3.3.0",
153
+ version: PACKAGE_VERSION,
140
154
  displayName: "xray: Self-Healing AI Governance OS",
141
- lastUpdated: "2026-06-18",
155
+ lastUpdated: "2026-06-17",
142
156
  // Counts (auto-calculated, but can be overridden)
143
157
  ...CALCULATED_COUNTS,
144
158
  },
@@ -1,5 +1,4 @@
1
1
  {
2
- "version": "3.1.0",
3
2
  "description": "0xRay Community MCPs Registry - curated API-focused MCP servers",
4
3
  "sources": [
5
4
  {
@@ -1,7 +1,5 @@
1
1
  {
2
- "framework": "xray 2.0",
3
- "version": "3.1.0",
4
- "description": "Codex-compliant framework configuration for Credible UI project",
2
+ "description": "Codex-compliant framework configuration",
5
3
  "thresholds": {
6
4
  "bundleSize": {
7
5
  "maxSize": "3MB",
@@ -220,7 +218,6 @@
220
218
  }
221
219
  },
222
220
  "codex": {
223
- "version": "3.1.0",
224
221
  "terms": [
225
222
  1,
226
223
  2,
@@ -1,5 +1,4 @@
1
1
  {
2
- "version": "3.1.0",
3
2
  "description": "0xRay Skills Registry - recommended skill sources for consumers",
4
3
  "sources": [
5
4
  {