0xray 4.0.34 → 4.0.35

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 (155) hide show
  1. package/.grok-plugin/plugin.json +1 -1
  2. package/.xray/codex.json +12 -4
  3. package/.xray/features.json +1 -1
  4. package/AGENTS-consumer.md +6 -6
  5. package/AGENTS.md +5 -5
  6. package/README.md +2 -2
  7. package/dist/AGENTS.md +5 -5
  8. package/dist/CHANGELOG.md +16 -0
  9. package/dist/README.md +2 -2
  10. package/dist/cli/index.js +2 -5
  11. package/dist/governance/governance-service.js +1 -1
  12. package/dist/integrations/base/README.md +1 -9
  13. package/dist/integrations/base/index.d.ts +0 -1
  14. package/dist/integrations/base/index.js +0 -2
  15. package/dist/integrations/governance/index.js +31 -8
  16. package/dist/integrations/grok/hooks/grok-hook-utils.js +1 -1
  17. package/dist/integrations/grok/hooks/session-start.js +12 -0
  18. package/dist/integrations/hooks/goggles-pipeline.mjs +62 -11
  19. package/dist/integrations/hooks/host-truth.mjs +74 -0
  20. package/dist/integrations/hooks/station-hook-runtime.cjs +3 -0
  21. package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
  22. package/dist/mcps/knowledge-skills/storyteller.server.js +0 -1
  23. package/dist/nucleus/delegation-gate.d.ts +2 -2
  24. package/dist/nucleus/delegation-gate.js +13 -2
  25. package/dist/nucleus/work-freshness.mjs +189 -0
  26. package/dist/processors/implementations/agents-md-validation-processor.js +1 -1
  27. package/docs-site/docs/plates/boot.md +17 -2
  28. package/docs-site/docs/plates/governance.md +3 -2
  29. package/docs-site/docs/plates/index.md +3 -1
  30. package/docs-site/docs/plates/memory-recall.md +26 -35
  31. package/docs-site/docs/plates/orchestration.md +39 -35
  32. package/docs-site/docs/plates/processor.md +34 -36
  33. package/docs-site/docs/plates/reporting.md +3 -8
  34. package/docs-site/docs/plates/routing.md +22 -11
  35. package/package.json +2 -2
  36. package/scripts/foundry/release.mjs +48 -5
  37. package/scripts/mjs/test-consumer-readiness.mjs +1 -0
  38. package/scripts/mjs/test-mcp-functionality.mjs +14 -9
  39. package/scripts/node/basic-security-audit.cjs +0 -1
  40. package/scripts/node/bridge-mcp-wiring.cjs +66 -3
  41. package/scripts/node/postinstall.cjs +1 -1
  42. package/scripts/node/prepare-consumer.cjs +11 -7
  43. package/scripts/node/setup-dev.cjs +18 -26
  44. package/scripts/node/validate-mcp-connectivity.js +2 -1
  45. package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
  46. package/src/mcps/knowledge-skills/storyteller.server.ts +0 -1
  47. package/xray/agents_template.md +5 -5
  48. package/xray/codex.json +12 -4
  49. package/xray/features.json +1 -1
  50. package/dist/agents/known-names.d.ts +0 -26
  51. package/dist/agents/known-names.js +0 -72
  52. package/dist/analytics/consent-manager.d.ts +0 -92
  53. package/dist/analytics/consent-manager.js +0 -257
  54. package/dist/benchmark/performance-benchmark.d.ts +0 -103
  55. package/dist/benchmark/performance-benchmark.js +0 -373
  56. package/dist/cli/commands/analytics-disable.d.ts +0 -9
  57. package/dist/cli/commands/analytics-disable.js +0 -72
  58. package/dist/cli/commands/analytics-enable-action.d.ts +0 -8
  59. package/dist/cli/commands/analytics-enable-action.js +0 -82
  60. package/dist/cli/commands/analytics-preview.d.ts +0 -9
  61. package/dist/cli/commands/analytics-preview.js +0 -106
  62. package/dist/cli/commands/analytics-status.d.ts +0 -9
  63. package/dist/cli/commands/analytics-status.js +0 -68
  64. package/dist/cli/commands/enforce.d.ts +0 -12
  65. package/dist/cli/commands/enforce.js +0 -78
  66. package/dist/cli/commands/govern.d.ts +0 -29
  67. package/dist/cli/commands/govern.js +0 -149
  68. package/dist/cli/commands/security-audit.d.ts +0 -23
  69. package/dist/cli/commands/security-audit.js +0 -219
  70. package/dist/cli/server.d.ts +0 -1
  71. package/dist/cli/server.js +0 -147
  72. package/dist/config/routing-mappings.d.ts +0 -26
  73. package/dist/config/routing-mappings.js +0 -151
  74. package/dist/core/bridge.mjs +0 -922
  75. package/dist/core/trace-context.d.ts +0 -12
  76. package/dist/core/trace-context.js +0 -33
  77. package/dist/enforcement/index.d.ts +0 -22
  78. package/dist/enforcement/index.js +0 -40
  79. package/dist/enforcement/loaders/index.d.ts +0 -36
  80. package/dist/enforcement/loaders/index.js +0 -39
  81. package/dist/enforcement/test-auto-healing.d.ts +0 -83
  82. package/dist/enforcement/test-auto-healing.js +0 -325
  83. package/dist/inference/index.d.ts +0 -10
  84. package/dist/inference/index.js +0 -5
  85. package/dist/infrastructure/iac-validator.d.ts +0 -150
  86. package/dist/infrastructure/iac-validator.js +0 -465
  87. package/dist/infrastructure/schemas/cloud-schemas.d.ts +0 -482
  88. package/dist/infrastructure/schemas/cloud-schemas.js +0 -488
  89. package/dist/integrations/base/ExampleIntegration.d.ts +0 -46
  90. package/dist/integrations/base/ExampleIntegration.js +0 -180
  91. package/dist/integrations/enforcement-gate.d.ts +0 -44
  92. package/dist/integrations/enforcement-gate.js +0 -348
  93. package/dist/mcps/connection/connection-manager.d.ts +0 -39
  94. package/dist/mcps/connection/connection-manager.js +0 -79
  95. package/dist/mcps/index.d.ts +0 -17
  96. package/dist/mcps/index.js +0 -65
  97. package/dist/mcps/orchestrator/index.d.ts +0 -6
  98. package/dist/mcps/orchestrator/index.js +0 -5
  99. package/dist/metrics/index.d.ts +0 -6
  100. package/dist/metrics/index.js +0 -6
  101. package/dist/orchestrator/self-direction-activation.d.ts +0 -108
  102. package/dist/orchestrator/self-direction-activation.js +0 -244
  103. package/dist/orchestrator/universal-registry-bridge.d.ts +0 -84
  104. package/dist/orchestrator/universal-registry-bridge.js +0 -246
  105. package/dist/performance/performance-budget-enforcer.d.ts +0 -157
  106. package/dist/performance/performance-budget-enforcer.js +0 -433
  107. package/dist/performance/performance-regression-tester.d.ts +0 -107
  108. package/dist/performance/performance-regression-tester.js +0 -341
  109. package/dist/postprocessor/analysis/CodeChangeAnalyzer.d.ts +0 -11
  110. package/dist/postprocessor/analysis/CodeChangeAnalyzer.js +0 -50
  111. package/dist/postprocessor/config/ProcessorConfigLoader.d.ts +0 -44
  112. package/dist/postprocessor/config/ProcessorConfigLoader.js +0 -16
  113. package/dist/postprocessor/integration.d.ts +0 -156
  114. package/dist/postprocessor/integration.js +0 -194
  115. package/dist/postprocessor/metamorphosis/index.d.ts +0 -2
  116. package/dist/postprocessor/metamorphosis/index.js +0 -1
  117. package/dist/postprocessor/redeploy/RetryHandler.d.ts +0 -49
  118. package/dist/postprocessor/redeploy/RetryHandler.js +0 -118
  119. package/dist/processors/implementations/session-capture-processor.d.ts +0 -14
  120. package/dist/processors/implementations/session-capture-processor.js +0 -37
  121. package/dist/public/XrayService.d.ts +0 -17
  122. package/dist/public/XrayService.js +0 -40
  123. package/dist/public/index.d.ts +0 -4
  124. package/dist/public/index.js +0 -2
  125. package/dist/security/comprehensive-security-audit.d.ts +0 -157
  126. package/dist/security/comprehensive-security-audit.js +0 -1004
  127. package/dist/security/index.d.ts +0 -13
  128. package/dist/security/index.js +0 -13
  129. package/dist/security/security-agent-coordinator.d.ts +0 -71
  130. package/dist/security/security-agent-coordinator.js +0 -203
  131. package/dist/security/security-hardening-system.d.ts +0 -238
  132. package/dist/security/security-hardening-system.js +0 -726
  133. package/dist/security/security-orchestration-layer.d.ts +0 -118
  134. package/dist/security/security-orchestration-layer.js +0 -495
  135. package/dist/testing/memory-regression-suite.d.ts +0 -105
  136. package/dist/testing/memory-regression-suite.js +0 -258
  137. package/dist/tools/assess-complexity-tool.d.ts +0 -28
  138. package/dist/tools/assess-complexity-tool.js +0 -44
  139. package/dist/tools/query-routing-tool.d.ts +0 -17
  140. package/dist/tools/query-routing-tool.js +0 -59
  141. package/dist/utils/batch-operations.d.ts +0 -25
  142. package/dist/utils/batch-operations.js +0 -292
  143. package/dist/utils/task-graph.d.ts +0 -29
  144. package/dist/utils/task-graph.js +0 -106
  145. package/dist/utils/test-template-generator.d.ts +0 -25
  146. package/dist/utils/test-template-generator.js +0 -178
  147. package/dist/utils/token-manager.d.ts +0 -48
  148. package/dist/utils/token-manager.js +0 -163
  149. package/dist/validation/agent-config-validator.d.ts +0 -110
  150. package/dist/validation/agent-config-validator.js +0 -280
  151. package/dist/validation/orchestration-flow-validator.d.ts +0 -87
  152. package/dist/validation/orchestration-flow-validator.js +0 -606
  153. package/src/mcps/connection/connection-manager.ts +0 -91
  154. package/src/mcps/index.ts +0 -80
  155. package/src/mcps/orchestrator/index.ts +0 -29
@@ -5,14 +5,14 @@ sidebar_label: Routing
5
5
 
6
6
  # Routing
7
7
 
8
- Task text becomes an agent. thinDispatch scores the work. Repertoire may adjust the score when the organ is worn.
8
+ Task text becomes an agent. `scoreAndRoute` scores the work, then `routeToAgent` picks the tier agent. Repertoire may replace that agent when a law matches. Naming no plane stops before that pick and returns nobody.
9
9
 
10
10
  ```
11
11
  ┌──────────────────────────────────────────────────────────────┐
12
12
  │ INPUT LAYER │
13
13
  │ │
14
14
  │ ┌──────────────┐ ┌──────────────┐ ┌────────────────┐ │
15
- │ │ task text │ │ @agent │ │ scoreAndRoute │ │
15
+ │ │ task text │ │ context │ │ thresholds │ │
16
16
  │ └──────┬───────┘ └──────┬───────┘ └───────┬────────┘ │
17
17
  │ └──────────────────┴─────────┬─────────┘ │
18
18
  └────────────────────────────────────────┼─────────────────────┘
@@ -21,22 +21,30 @@ Task text becomes an agent. thinDispatch scores the work. Repertoire may adjust
21
21
  │ PROCESSING LAYER │ │
22
22
  │ v │
23
23
  │ ┌──────────────────────────────────────────────────────┐ │
24
- │ │ TaskSkillRouter │ │
25
- │ │ keyword facade into the route │ │
24
+ │ │ scoreComplexity │ │
25
+ │ │ ≤15 simple · single-agent │ │
26
+ │ │ ≤25 moderate · multi-agent │ │
27
+ │ │ ≤50 complex · orchestrator-led │ │
28
+ │ │ >50 enterprise · orchestrator-led │ │
26
29
  │ └──────────────────────────┬───────────────────────────┘ │
27
30
  │ v │
28
31
  │ ┌──────────────────────────────────────────────────────┐ │
29
- │ │ thinDispatch │ │
30
- │ │ ≤15 single agent │ │
31
- │ │ ≤25 single agent with tools │ │
32
- │ │ ≤50 multi-agent │ │
33
- │ │ >50 orchestrator-led │ │
32
+ │ │ lensPlane │ │
33
+ │ │ no plane named stops here and the agent is empty │ │
34
+ │ │ one plane attaches that file │ │
34
35
  │ └──────────────────────────┬───────────────────────────┘ │
35
36
  │ v │
36
37
  │ ┌──────────────────────────────────────────────────────┐ │
37
- │ │ Repertoire resolveThinDispatch │ │
38
- │ │ worn organ may change agent and score │ │
38
+ │ │ routeToAgent │ │
39
+ │ │ simple → code-reviewer │ │
40
+ │ │ moderate, complex, enterprise → architect │ │
41
+ │ └──────────────────────────┬───────────────────────────┘ │
42
+ │ v │
43
+ │ ┌──────────────────────────────────────────────────────┐ │
44
+ │ │ resolveThinDispatch │ │
45
+ │ │ worn repertoire may change agent and score │ │
39
46
  │ │ null provider leaves the score alone │ │
47
+ │ │ a stop never reaches this step │ │
40
48
  │ └──────────────────────────┬───────────────────────────┘ │
41
49
  └──────────────────────────────┼──────────────────────────────┘
42
50
  v
@@ -45,5 +53,8 @@ Task text becomes an agent. thinDispatch scores the work. Repertoire may adjust
45
53
  │ ┌────────────┐ ┌────────────────┐ ┌────────────────┐ │
46
54
  │ │ agent │ │ strategy │ │ adjusted score │ │
47
55
  │ └────────────┘ └────────────────┘ └────────────────┘ │
56
+ │ ┌────────────┐ │
57
+ │ │ file │ │
58
+ │ └────────────┘ │
48
59
  └──────────────────────────────────────────────────────────────┘
49
60
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0xray",
3
- "version": "4.0.34",
3
+ "version": "4.0.35",
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",
@@ -73,7 +73,7 @@
73
73
  "test": "vitest run",
74
74
  "test:batch": "npm test",
75
75
  "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",
76
- "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",
76
+ "test:core-framework": "npm test -- src/__tests__/unit/v2-deletion-protection.test.ts",
77
77
  "test:security": "npm test -- src/__tests__/unit/security/security-hardener.test.ts src/__tests__/unit/security/security-headers.test.ts src/__tests__/unit/security/security-auditor.test.ts",
78
78
  "test:performance": "npm test -- src/__tests__/unit/monitoring.test.ts src/__tests__/unit/benchmark.test.ts src/__tests__/unit/analytics.test.ts",
79
79
  "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",
@@ -9,7 +9,8 @@
9
9
  * 4. Commit release artifacts → push
10
10
  * 5. Verify gate (reconcile + git + release docs + smoke)
11
11
  * 6. npm publish (idempotent — skip if version already on registry)
12
- * 7. Tag → push tag (only after successful publish)
12
+ * 7. Poll npm view until the registry lists that version
13
+ * 8. Tag → push tag (only after the registry lists it)
13
14
  *
14
15
  * Usage:
15
16
  * npx @0xray/foundry release [patch|minor|major] --dry-run
@@ -90,9 +91,13 @@ function currentBranch() {
90
91
  return execSync("git rev-parse --abbrev-ref HEAD", { cwd: rootDir, encoding: "utf-8" }).trim();
91
92
  }
92
93
 
94
+ function say(line) {
95
+ process.stdout.write(`${line}\n`);
96
+ }
97
+
93
98
  function npmVersionPublished(version) {
94
99
  try {
95
- const out = execSync(`npm view ${packageName()}@${version} version`, {
100
+ const out = execSync(`npm view ${packageName()}@${version} version --prefer-online`, {
96
101
  cwd: rootDir,
97
102
  encoding: "utf-8",
98
103
  stdio: ["pipe", "pipe", "pipe"],
@@ -103,20 +108,58 @@ function npmVersionPublished(version) {
103
108
  }
104
109
  }
105
110
 
111
+ function sleepMs(ms) {
112
+ const seconds = Math.max(1, Math.round(Number(ms) / 1000));
113
+ execSync(`sleep ${seconds}`, { stdio: "ignore" });
114
+ }
115
+
116
+ /**
117
+ * npm publish exits 0 while the registry still says the version is processing.
118
+ * Tag only after npm view lists it. Returns false when the wait runs out.
119
+ * @param {string} version
120
+ * @param {object} [hooks]
121
+ */
122
+ export function waitUntilListed(version, hooks = {}) {
123
+ const name = hooks.name ?? packageName();
124
+ const listed = hooks.listed ?? (() => npmVersionPublished(version));
125
+ const sleep = hooks.sleep ?? sleepMs;
126
+ const now = hooks.now ?? Date.now;
127
+ const log = hooks.log ?? say;
128
+ const fail = hooks.fail ?? ((line) => {
129
+ process.stderr.write(`${line}\n`);
130
+ process.exit(1);
131
+ });
132
+ const intervalMs = hooks.intervalMs ?? Number(process.env.FOUNDRY_PUBLISH_POLL_MS || 15000);
133
+ const timeoutMs = hooks.timeoutMs ?? Number(process.env.FOUNDRY_PUBLISH_TIMEOUT_MS || 20 * 60 * 1000);
134
+ const started = now();
135
+ let attempt = 0;
136
+ while (!listed()) {
137
+ if (now() - started >= timeoutMs) {
138
+ fail(`❌ ${name}@${version} was uploaded but the registry has not listed it. Tag not pushed.`);
139
+ return false;
140
+ }
141
+ attempt += 1;
142
+ log(`… registry has not listed ${name}@${version} yet (try ${attempt})`);
143
+ sleep(intervalMs);
144
+ }
145
+ return true;
146
+ }
147
+
106
148
  function publishIdempotent(version) {
107
149
  if (dryRun) {
108
- console.log(` would: ${npmPublishCmd()} (check ${packageName()}@${version} first)`);
150
+ say(` would: ${npmPublishCmd()} then poll npm view ${packageName()}@${version} until listed`);
109
151
  return;
110
152
  }
111
153
  if (npmVersionPublished(version)) {
112
- console.log(`ℹ️ ${packageName()}@${version} already on npm — skipping publish`);
154
+ say(`ℹ️ ${packageName()}@${version} already on npm — skipping publish`);
113
155
  return;
114
156
  }
115
157
  if (isXrayExoRepo(rootDir)) {
116
158
  runMill("assert-packed-dist-cli.mjs", [], "packed dist/cli");
117
159
  }
118
160
  execSync(npmPublishCmd(), { cwd: rootDir, stdio: "inherit", encoding: "utf-8" });
119
- console.log(`✅ Published ${packageName()}@${version}`);
161
+ if (!waitUntilListed(version)) process.exit(1);
162
+ say(`✅ Published ${packageName()}@${version}`);
120
163
  }
121
164
 
122
165
  async function main() {
@@ -213,6 +213,7 @@ class ConsumerReadinessCheck {
213
213
  async function runPathVerification() {
214
214
  const isConsumerEnv = process.cwd().includes('test-') ||
215
215
  process.cwd().includes('tmp') ||
216
+ fs.existsSync('node_modules/0xray') ||
216
217
  fs.existsSync('node_modules/xray');
217
218
 
218
219
  if (isConsumerEnv) {
@@ -14,10 +14,15 @@ import { fileURLToPath } from "url";
14
14
  const __filename = fileURLToPath(import.meta.url);
15
15
  const __dirname = path.dirname(__filename);
16
16
 
17
+ function isInstalledPackagePath(value) {
18
+ const normalized = String(value).replace(/\\/g, "/");
19
+ return normalized.includes("node_modules/0xray") || normalized.includes("node_modules/xray");
20
+ }
21
+
17
22
  class MCPFunctionalityTest {
18
23
  constructor() {
19
24
  this.results = { passed: [], failed: [] };
20
- this.isConsumerEnvironment = __dirname.includes("node_modules/xray");
25
+ this.isConsumerEnvironment = isInstalledPackagePath(__dirname);
21
26
  }
22
27
 
23
28
  async testMCPFunctionality() {
@@ -95,9 +100,9 @@ class MCPFunctionalityTest {
95
100
  // Determine environment: dev vs consumer vs CI
96
101
  // - Dev: running from project root with src/ directory
97
102
  // - CI: running from project root but building first (has dist/)
98
- // - Consumer: running from node_modules/xray/
103
+ // - Consumer: running from node_modules/0xray/ (legacy node_modules/xray/)
99
104
  const cwd = process.cwd();
100
- const isConsumerEnv = cwd.includes("node_modules/xray");
105
+ const isConsumerEnv = isInstalledPackagePath(cwd);
101
106
  const hasPackageJson = fs.existsSync(path.join(cwd, "package.json"));
102
107
  const hasDistDir = fs.existsSync(path.join(cwd, "dist"));
103
108
 
@@ -155,16 +160,16 @@ class MCPFunctionalityTest {
155
160
  if (serverPath) {
156
161
  // Handle various path formats:
157
162
  // - ./dist/mcps/xxx.js (local dev)
158
- // - node_modules/xray/dist/mcps/xxx.js (consumer)
163
+ // - node_modules/0xray/dist/mcps/xxx.js (consumer; legacy node_modules/xray/)
159
164
  // - dist/mcps/xxx.js (after stripping ./)
160
165
  let normalizedPath = serverPath.startsWith("./")
161
166
  ? serverPath.slice(2)
162
167
  : serverPath;
163
168
 
164
- // If path contains node_modules/xray/, extract just the relative part
165
- if (normalizedPath.includes("node_modules/xray/")) {
166
- normalizedPath = normalizedPath.replace("node_modules/xray/", "");
167
- }
169
+ normalizedPath = normalizedPath
170
+ .replace(/\\/g, "/")
171
+ .replace("node_modules/0xray/", "")
172
+ .replace("node_modules/xray/", "");
168
173
 
169
174
  // In CI/build environment, files are in cwd/dist/, not in node_modules
170
175
  // Try local paths first, then fall back to node_modules
@@ -249,7 +254,7 @@ class MCPFunctionalityTest {
249
254
  try {
250
255
  // Determine environment - reuse same logic
251
256
  const cwd = process.cwd();
252
- const isConsumerEnv = cwd.includes("node_modules/xray");
257
+ const isConsumerEnv = isInstalledPackagePath(cwd);
253
258
  const hasPackageJson = fs.existsSync(path.join(cwd, "package.json"));
254
259
  const isDevOrCi = hasPackageJson && !isConsumerEnv;
255
260
 
@@ -150,7 +150,6 @@ class BasicSecurityAuditor {
150
150
  /LightweightValidator\.ts$/,
151
151
  /codex-parser\.ts$/,
152
152
  /openclaw/,
153
- /advanced-features/,
154
153
  /tests\//,
155
154
  /global-processor-mocks/,
156
155
  ];
@@ -218,10 +218,69 @@ function readInstalledXrayVersion() {
218
218
  return pkg.version;
219
219
  }
220
220
 
221
+ /**
222
+ * npm installs the package named `0xray` at `node_modules/0xray`.
223
+ * `node_modules/xray` is the pre-rename folder. Use it only when that tree
224
+ * is the one on disk. Never prefer the old name over the real install.
225
+ */
226
+ const INSTALLED_PACKAGE_DIRS = ["0xray", "xray"];
227
+
228
+ function normalizeLaunchToken(token) {
229
+ return String(token).replace(/\\/g, "/");
230
+ }
231
+
221
232
  function localXrayCli(targetDir) {
222
233
  if (!targetDir) return null;
223
- const cli = path.join(targetDir, "node_modules", "0xray", "dist", "cli", "index.js");
224
- return fs.existsSync(cli) ? cli : null;
234
+ for (const dirName of INSTALLED_PACKAGE_DIRS) {
235
+ const cli = path.join(targetDir, "node_modules", dirName, "dist", "cli", "index.js");
236
+ if (fs.existsSync(cli)) return cli;
237
+ }
238
+ return null;
239
+ }
240
+
241
+ function isInstalledPackageCli(token) {
242
+ const normalized = normalizeLaunchToken(token);
243
+ return INSTALLED_PACKAGE_DIRS.some((dirName) =>
244
+ normalized.includes(`node_modules/${dirName}/dist/cli/index.js`),
245
+ );
246
+ }
247
+
248
+ /** Project-root `dist/cli/index.js` is the factory checkout. It is gitignored and goes stale. */
249
+ function isCheckoutDistCliLaunch(server) {
250
+ return launchTokens(server).some((token) => {
251
+ const normalized = normalizeLaunchToken(token);
252
+ const isDistCli =
253
+ normalized === "dist/cli/index.js" ||
254
+ normalized === "./dist/cli/index.js" ||
255
+ normalized.endsWith("/dist/cli/index.js");
256
+ return isDistCli && !isInstalledPackageCli(normalized);
257
+ });
258
+ }
259
+
260
+ function isLegacyXrayCliLaunch(server) {
261
+ return launchTokens(server).some((token) => {
262
+ const normalized = normalizeLaunchToken(token);
263
+ return normalized.includes("node_modules/xray/dist/cli/index.js");
264
+ });
265
+ }
266
+
267
+ function mcpSubcommand(inner) {
268
+ if (!inner || !Array.isArray(inner.args)) return null;
269
+ const idx = inner.args.indexOf("mcp");
270
+ if (idx >= 0 && inner.args[idx + 1]) return inner.args[idx + 1];
271
+ return null;
272
+ }
273
+
274
+ /**
275
+ * A checkout `dist/cli` launch is replaced with the installed package.
276
+ * A legacy `node_modules/xray` launch is replaced only when `node_modules/0xray` exists.
277
+ */
278
+ function shouldRepinToInstalledCli(inner, targetDir) {
279
+ if (!inner || hasVersionPin(inner)) return false;
280
+ if (isCheckoutDistCliLaunch(inner)) return true;
281
+ if (!isLegacyXrayCliLaunch(inner)) return false;
282
+ const cli = localXrayCli(targetDir);
283
+ return Boolean(cli && normalizeLaunchToken(cli).includes("/node_modules/0xray/"));
225
284
  }
226
285
 
227
286
  /** Prefer the installed CLI. Else pin npx to this package version. Never bare `0xray`. */
@@ -388,7 +447,7 @@ function mcpCmdFromInner(inner) {
388
447
  return inner.args.length > 0 ? inner.args[inner.args.length - 1] : null;
389
448
  }
390
449
 
391
- /** Framework fills gaps. User env, enabled/disabled, and version pins win. Unpinned `0xray` is repinned. Launch is `node mcp-launch.cjs --keep names -- cmd`. */
450
+ /** Framework fills gaps. User env, enabled/disabled, and version pins win. Unpinned `0xray` and a checkout `dist/cli` launch are repinned to the installed package. Launch is `node mcp-launch.cjs --keep names -- cmd`. */
392
451
  function mergeUserWinsServer(framework, user, targetDir) {
393
452
  if (!user || typeof user !== "object") return framework;
394
453
  if (!framework || typeof framework !== "object") return user;
@@ -403,6 +462,10 @@ function mergeUserWinsServer(framework, user, targetDir) {
403
462
  const mcpCmd = mcpCmdFromInner(inner);
404
463
  if (mcpCmd) inner = pinnedMcpLaunch(targetDir, mcpCmd);
405
464
  }
465
+ if (inner && shouldRepinToInstalledCli(inner, targetDir)) {
466
+ const mcpCmd = mcpSubcommand(inner);
467
+ if (mcpCmd) inner = pinnedMcpLaunch(targetDir, mcpCmd);
468
+ }
406
469
  if (!inner) return framework;
407
470
  const mergedEnv = mergeScopedEnv([
408
471
  baseScopedEnv(targetDir),
@@ -75,7 +75,7 @@ function deployManagedAgents(packageRoot, targetDir, log) {
75
75
  if (updated !== current) fs.writeFileSync(agentsDest, updated);
76
76
  }
77
77
 
78
- /** npm install links vendored @0xray/repertoire and nothing else. The suit is `npx 0xray wear`. */
78
+ /** npm install links vendored @0xray/repertoire and does not write `.mcp.json`. `npx 0xray wear` rewrites a checkout `dist/cli` launch to `node_modules/0xray`. */
79
79
  function runPostinstall(packageRoot, targetDir, _log) {
80
80
  linkVendoredRepertoire(packageRoot, targetDir);
81
81
  console.log("Run `npx 0xray wear`");
@@ -33,21 +33,25 @@ function updatePathsInFile(filePath) {
33
33
  let content = fs.readFileSync(filePath, 'utf-8');
34
34
  let updated = false;
35
35
 
36
- // Transform development paths back to consumer paths (plain xray; legacy @0xray/xray removed)
37
- // Only transform if it's not already a consumer path
38
- if (content.includes('dist/plugin/mcps/') && !content.includes('node_modules/xray/dist/plugin/mcps/')) {
36
+ // The published package name is 0xray, so the installed tree is node_modules/0xray.
37
+ // Upgrade a pre-rename node_modules/xray path before prefixing bare dist/ paths.
38
+ if (content.includes('node_modules/xray/')) {
39
+ content = content.replace(/node_modules\/xray\//g, 'node_modules/0xray/');
40
+ updated = true;
41
+ }
42
+
43
+ if (content.includes('dist/plugin/mcps/') && !content.includes('node_modules/0xray/dist/plugin/mcps/')) {
39
44
  content = content.replace(
40
45
  /dist\/plugin\/mcps\//g,
41
- 'node_modules/xray/dist/plugin/mcps/'
46
+ 'node_modules/0xray/dist/plugin/mcps/'
42
47
  );
43
48
  updated = true;
44
49
  }
45
50
 
46
- // Transform plugin paths back to consumer format (only the relative dev paths)
47
51
  if (content.includes('../../../dist/plugin/')) {
48
52
  content = content.replace(
49
53
  /\.\.\/\.\.\/\.\.\/dist\/plugin\//g,
50
- 'node_modules/xray/dist/plugin/'
54
+ 'node_modules/0xray/dist/plugin/'
51
55
  );
52
56
  updated = true;
53
57
  }
@@ -140,4 +144,4 @@ function addJsExtensionsToDist() {
140
144
  addJsExtensionsToDist();
141
145
 
142
146
  structuredLog('prepare-consumer', 'xray v2 Consumer Preparation: Complete!', 'success');
143
- structuredLog('prepare-consumer', 'Package is now ready for consumer installation (plain xray technical identity).', 'info');
147
+ structuredLog('prepare-consumer', 'Package is now ready for consumer installation (node_modules/0xray).', 'info');
@@ -23,32 +23,24 @@ function updatePathsInFile(filePath) {
23
23
  let content = fs.readFileSync(filePath, 'utf-8');
24
24
  let updated = false;
25
25
 
26
- // Transform MCP server paths (specific first)
27
- if (content.includes('node_modules/xray/dist/plugin/mcps/')) {
28
- content = content.replace(
29
- /node_modules\/xray\/dist\/plugin\/mcps\//g,
30
- 'dist/plugin/mcps/'
31
- );
32
- updated = true;
33
- }
34
-
35
- // Transform plugin paths (go up 3 directories from .opencode to project root)
36
- if (content.includes('node_modules/xray/dist/plugin/plugins/')) {
37
- content = content.replace(
38
- /node_modules\/xray\/dist\/plugin\/plugins\//g,
39
- '../../../dist/plugin/plugins/'
40
- );
41
- updated = true;
42
- }
43
-
44
- // Transform any remaining node_modules paths (but not plugin-specific ones we already handled)
45
- if (content.includes('node_modules/xray/dist/') &&
46
- !content.includes('dist/plugin/')) { // Avoid double transformation
47
- content = content.replace(
48
- /node_modules\/xray\/dist\//g,
49
- 'dist/'
50
- );
51
- updated = true;
26
+ // npm installs at node_modules/0xray. node_modules/xray is the pre-rename folder.
27
+ // Specific plugin paths first so the general dist/ strip does not flatten them.
28
+ for (const dirName of ['0xray', 'xray']) {
29
+ const plugins = `node_modules/${dirName}/dist/plugin/plugins/`;
30
+ if (content.includes(plugins)) {
31
+ content = content.replaceAll(plugins, '../../../dist/plugin/plugins/');
32
+ updated = true;
33
+ }
34
+ const mcps = `node_modules/${dirName}/dist/plugin/mcps/`;
35
+ if (content.includes(mcps)) {
36
+ content = content.replaceAll(mcps, 'dist/plugin/mcps/');
37
+ updated = true;
38
+ }
39
+ const prefix = `node_modules/${dirName}/dist/`;
40
+ if (content.includes(prefix)) {
41
+ content = content.replaceAll(prefix, 'dist/');
42
+ updated = true;
43
+ }
52
44
  }
53
45
 
54
46
  if (updated) {
@@ -18,7 +18,8 @@ const __filename = fileURLToPath(import.meta.url);
18
18
  const __dirname = path.dirname(__filename);
19
19
 
20
20
  // Detect if running in consumer environment (node_modules)
21
- const isConsumerEnvironment = __dirname.includes("node_modules/xray");
21
+ const isConsumerEnvironment = __dirname.includes(`${path.sep}node_modules${path.sep}0xray${path.sep}`)
22
+ || __dirname.includes(`${path.sep}node_modules${path.sep}xray${path.sep}`);
22
23
  const pathPrefix = isConsumerEnvironment ? "" : "";
23
24
 
24
25
  const MCP_SERVERS = [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xray-pre-tool",
3
- "version": "4.0.34",
3
+ "version": "4.0.35",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "0xRay constitution + temperament PreToolUse for OpenClaw",
@@ -24,7 +24,6 @@ interface WriteStoryArgs {
24
24
  function resolveSkillMd(): string {
25
25
  const here = dirname(fileURLToPath(import.meta.url));
26
26
  const candidates = [
27
- join(here, '../../../skills/storyteller/SKILL.md'),
28
27
  join(here, '../../skills/storyteller/SKILL.md'),
29
28
  join(process.cwd(), 'node_modules/0xray/dist/skills/storyteller/SKILL.md'),
30
29
  join(process.cwd(), 'node_modules/xray/dist/skills/storyteller/SKILL.md'),
@@ -30,14 +30,14 @@ All seven use `npx -y 0xray mcp <cmd>`:
30
30
 
31
31
  xray operates under the three-subsystem model: Inference + External Governance (Dynamo Solar SSOT) + Autonomous Engine (thinDispatch 7-flow in MCP orchestrator). All actions are validated against the Universal Development Codex before execution.
32
32
 
33
- **Codex**: `.xray/codex.json` — **69 terms** across all agent interactions.
33
+ **Codex**: `.xray/codex.json` — **70 terms** across all agent interactions.
34
34
 
35
35
  ## thinDispatch Routing
36
36
 
37
- - Simple (≤15): Single agent
38
- - Moderate (≤25): Single agent with tools
39
- - Complex (≤50): Multi-agent coordination
40
- - Enterprise (>50): Orchestrator-led team
37
+ - Simple (≤15): single-agent
38
+ - Moderate (≤25): multi-agent
39
+ - Complex (≤50): orchestrator-led
40
+ - Enterprise (>50): orchestrator-led
41
41
 
42
42
  ## File Organization
43
43
 
package/xray/codex.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "3.1.0",
3
- "lastUpdated": "2026-08-24",
3
+ "lastUpdated": "2026-10-01",
4
4
  "errorPreventionTarget": 0.998,
5
5
  "terms": {
6
6
  "1": {
@@ -62,7 +62,7 @@
62
62
  "8": {
63
63
  "number": 8,
64
64
  "title": "Prevent Infinite Loops",
65
- "description": "Guarantee termination in all iterative processes. All loops must have clear termination conditions. Recursive functions must have base cases. Event loops must have exit strategies. Async operations must have timeout mechanisms.",
65
+ "description": "Guarantee termination in all iterative processes. All loops must have clear termination conditions. Recursive functions must have base cases. Event loops must have exit strategies. Async operations must have timeout mechanisms. A job names when it is done and when it stops.",
66
66
  "category": "core",
67
67
  "zeroTolerance": true,
68
68
  "enforcementLevel": "blocking"
@@ -230,7 +230,7 @@
230
230
  "29": {
231
231
  "number": 29,
232
232
  "title": "Security by Design",
233
- "description": "Validate all inputs. Sanitize data before rendering. Use HTTPS for all requests. Implement rate limiting. Never expose sensitive data.",
233
+ "description": "Validate all inputs. Sanitize data before rendering. Use HTTPS for all requests. Implement rate limiting. Never expose sensitive data. Do not trust Host or X-Forwarded-Host to choose an environment. A refusal in the UI needs the same check on the server.",
234
234
  "category": "security",
235
235
  "zeroTolerance": true,
236
236
  "enforcementLevel": "blocking"
@@ -534,7 +534,7 @@
534
534
  "67": {
535
535
  "number": 67,
536
536
  "title": "Use Best Subagents, Reuse Session Context",
537
- "description": "Delegate work to the best-suited subagent for each task. Stay responsive to user inquiries, additional todos, and course corrections. Reuse the same subagent via session ID to preserve context and avoid restarting from zero. Do not spawn fresh agents when an existing one has the relevant context.",
537
+ "description": "Delegate work to the best-suited subagent for each task. Stay responsive to user inquiries, additional todos, and course corrections. Reuse the same subagent via session ID to preserve context and avoid restarting from zero. Do not spawn fresh agents when an existing one has the relevant context. Reuse one cloud for a workstream. Do not launch a new agent for a check the seat can run.",
538
538
  "category": "process",
539
539
  "zeroTolerance": false,
540
540
  "enforcementLevel": "high"
@@ -554,6 +554,14 @@
554
554
  "category": "process",
555
555
  "zeroTolerance": true,
556
556
  "enforcementLevel": "blocking"
557
+ },
558
+ "70": {
559
+ "number": 70,
560
+ "title": "Current Copy Before Edits",
561
+ "description": "Before an edit, be on the latest main and run the current package. If this repo is 0xray, this repo is that package. An older package waits. Compare set-aside work to main before you throw it away.",
562
+ "category": "process",
563
+ "zeroTolerance": true,
564
+ "enforcementLevel": "blocking"
557
565
  }
558
566
  },
559
567
  "interweaves": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "./features.schema.json",
3
- "version": "4.0.34",
3
+ "version": "4.0.35",
4
4
  "description": "0xRay Framework - Unified Feature Configuration",
5
5
  "suit_temperament": {
6
6
  "profile": "auto",
@@ -1,26 +0,0 @@
1
- /**
2
- * Known Names — Single combined vocabulary for agent names, skill names,
3
- * system service names, and opencode built-in types. All consumers import
4
- * from here instead of defining their own hardcoded lists.
5
- *
6
- * Imports:
7
- * - registry.ts (AGENT_REGISTRY, AGENT_KEYS) — canonical agent definitions
8
- * - mcps/index.ts (MCP_SERVERS) — canonical MCP server manifest
9
- */
10
- import { AGENT_KEYS, type AgentKey } from "./registry.js";
11
- import { MCP_SERVERS } from "../mcps/index.js";
12
- export { AGENT_KEYS, type AgentKey };
13
- export type { AgentKey as AgentName };
14
- /** All agent names as a mutable array */
15
- export declare function getAgentNames(): string[];
16
- export declare const SYSTEM_SERVICE_NAMES: readonly ["enforcer", "orchestrator", "analyzer"];
17
- export declare const OPENCODE_BUILTIN_TYPES: readonly ["explore", "general"];
18
- export declare const ALL_KNOWN_NAMES: readonly [...string[], "enforcer", "orchestrator", "analyzer", "explore", "general"];
19
- export type KnownName = typeof ALL_KNOWN_NAMES[number];
20
- export declare const BOOT_AGENTS: readonly ["enforcer", "architect", "bug-triage-specialist", "code-reviewer", "security-auditor", "refactorer", "testing-lead"];
21
- export declare function isValidType(name: string): boolean;
22
- export declare const AGENT_TO_SKILL_MAP: Record<string, string>;
23
- /** Resolve agent name to skill name via alias map, fallback to identity */
24
- export declare function resolveSkill(agentOrSkill: string): string;
25
- export { MCP_SERVERS };
26
- export declare function getSkillNames(): string[];