0xray 3.4.9 → 3.4.10

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.
@@ -4,7 +4,7 @@
4
4
 
5
5
  Quick reference for the 0xRay AI orchestration framework (shipped to your project on `npm install 0xray`).
6
6
 
7
- **v3.4.9** — 7 MCP servers · 45 skills · 68 codex terms · 4 platform bridges
7
+ **v3.4.10** — 7 MCP servers · 45 skills · 68 codex terms · 4 platform bridges
8
8
 
9
9
  ## Postinstall (automatic)
10
10
 
package/AGENTS.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # xray Agents
2
2
 
3
- Quick reference for the xray AI orchestration framework (**v3.4.9**).
3
+ Quick reference for the xray AI orchestration framework (**v3.4.10**).
4
4
 
5
5
  **42 agents** · **45 skills** · **7 consumer MCP servers** · **68 codex terms** · **3,226 tests**
6
6
 
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # xray — MCP-Centric AI Governance OS
2
2
 
3
- **v3.4.9** — 42 agents · 45 skills · 7 MCP servers · 68 codex terms · 3,226 tests
3
+ **v3.4.10** — 42 agents · 45 skills · 7 MCP servers · 68 codex terms · 3,226 tests
4
4
 
5
5
  ## Your AI Power Suit
6
6
 
package/SKILLS.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # 0xray Skills
2
2
 
3
- **v3.4.9** — **45 skills** · invoked via `xray-skills` MCP · synced on postinstall
3
+ **v3.4.10** — **45 skills** · invoked via `xray-skills` MCP · synced on postinstall
4
4
 
5
5
  xray ships 45 knowledge skills (`src/skills/<name>/SKILL.md`) across the full software lifecycle. Lead-dev operating model lives in **`orchestrator`** skill + `multi_agent_orchestration.lead_dev_mode` in features.json. Skills load on demand via the **xray-skills** MCP server (`npx -y 0xray mcp skills`), agent `@mentions`, or platform skill directories after postinstall.
6
6
 
package/dist/AGENTS.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # xray Agents
2
2
 
3
- Quick reference for the xray AI orchestration framework (**v3.4.9**).
3
+ Quick reference for the xray AI orchestration framework (**v3.4.10**).
4
4
 
5
5
  **42 agents** · **45 skills** · **7 consumer MCP servers** · **68 codex terms** · **3,226 tests**
6
6
 
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.10] - 2026-06-19
8
+
9
+ ### 🐛 Bug Fixes
10
+ - **Routing SSOT** — `selectAgentForTask` checks `routeSubagent(taskType)` before capability scoring or memory routing; `type: implement` → `backend-engineer` (not `code-reviewer`)
11
+ - **Unified complexity** — `buildLeadDevPlan` uses `max(thin-dispatch, MCP overallComplexity)`; `dependencyCount: 8` at complexity 70 forces phased plan
12
+
13
+ ### ✅ Tests
14
+ - `verify-orchestrator-behavior.mjs` ships in tarball — 5 behavior assertions (NaN, multi-task todos, implement routing, phased plan, honest deferral)
15
+ - Unit coverage: `agent-capabilities-routing`, extended `autonomy-kernel` + `execution-planner-dependencies`
16
+
17
+ ---
18
+
7
19
  ## [3.4.9] - 2026-06-19
8
20
 
9
21
  ### ⚠️ Breaking Changes
package/dist/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # xray — MCP-Centric AI Governance OS
2
2
 
3
- **v3.4.9** — 42 agents · 45 skills · 7 MCP servers · 68 codex terms · 3,226 tests
3
+ **v3.4.10** — 42 agents · 45 skills · 7 MCP servers · 68 codex terms · 3,226 tests
4
4
 
5
5
  ## Your AI Power Suit
6
6
 
package/dist/SKILLS.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # 0xray Skills
2
2
 
3
- **v3.4.9** — **45 skills** · invoked via `xray-skills` MCP · synced on postinstall
3
+ **v3.4.10** — **45 skills** · invoked via `xray-skills` MCP · synced on postinstall
4
4
 
5
5
  xray ships 45 knowledge skills (`src/skills/<name>/SKILL.md`) across the full software lifecycle. Lead-dev operating model lives in **`orchestrator`** skill + `multi_agent_orchestration.lead_dev_mode` in features.json. Skills load on demand via the **xray-skills** MCP server (`npx -y 0xray mcp skills`), agent `@mentions`, or platform skill directories after postinstall.
6
6
 
@@ -29,7 +29,7 @@ export declare class AgentCapabilitiesManager {
29
29
  /**
30
30
  * Select the best agent for a task based on complexity, capabilities, and memory routing.
31
31
  */
32
- selectAgentForTask(requiredCapabilities: string[], complexity: number, operationDescription?: string): string | null;
32
+ selectAgentForTask(requiredCapabilities: string[], complexity: number, operationDescription?: string, taskType?: string): string | null;
33
33
  /**
34
34
  * Get all available agents for a given complexity level
35
35
  */
@@ -7,6 +7,22 @@
7
7
  import { AGENT_REGISTRY } from "../../../agents/registry.js";
8
8
  import { initializeMemoryRouting } from '../../../memory-routing/index.js';
9
9
  import { getProvider, toMemoryCapabilityMap, fromMemoryCapabilityMap, } from './memory-routing-bridge.js';
10
+ import { routeSubagent } from '../../../nucleus/autonomy-kernel.js';
11
+ /** routeSubagent names → AGENT_REGISTRY keys */
12
+ const ROUTE_AGENT_ALIASES = {
13
+ 'code-review': 'code-reviewer',
14
+ 'security-audit': 'security-auditor',
15
+ 'bug-triage': 'bug-triage-specialist',
16
+ 'architect-tools': 'architect',
17
+ };
18
+ function resolveRoutedAgent(routed, capabilities) {
19
+ const candidate = ROUTE_AGENT_ALIASES[routed] ?? routed;
20
+ if (capabilities.has(candidate))
21
+ return candidate;
22
+ if (capabilities.has(routed))
23
+ return routed;
24
+ return null;
25
+ }
10
26
  const DEFAULT_AGENT_CAPABILITIES = Object.fromEntries(Object.entries(AGENT_REGISTRY).map(([name, entry]) => [
11
27
  name,
12
28
  {
@@ -61,7 +77,13 @@ export class AgentCapabilitiesManager {
61
77
  /**
62
78
  * Select the best agent for a task based on complexity, capabilities, and memory routing.
63
79
  */
64
- selectAgentForTask(requiredCapabilities, complexity, operationDescription = '') {
80
+ selectAgentForTask(requiredCapabilities, complexity, operationDescription = '', taskType = '') {
81
+ if (taskType.trim()) {
82
+ const routed = routeSubagent(taskType);
83
+ const resolved = resolveRoutedAgent(routed, this.capabilities);
84
+ if (resolved)
85
+ return resolved;
86
+ }
65
87
  const provider = getProvider();
66
88
  if (provider.id !== 'null' && operationDescription) {
67
89
  const memoryCaps = toMemoryCapabilityMap(this.getAllCapabilities());
@@ -181,7 +181,7 @@ export class ExecutionPlanner {
181
181
  const operationDescription = task.metadata?.memoryHighConfidenceTrap
182
182
  ? `${task.description} TYPE: ontological-trap`
183
183
  : task.description;
184
- const agent = this.capabilitiesManager.selectAgentForTask(requiredCaps, complexity, operationDescription) || 'orchestrator';
184
+ const agent = this.capabilitiesManager.selectAgentForTask(requiredCaps, complexity, operationDescription, task.type) || 'orchestrator';
185
185
  if (!agentAssignments.has(agent)) {
186
186
  agentAssignments.set(agent, []);
187
187
  }
@@ -223,7 +223,7 @@ export class ExecutionPlanner {
223
223
  task.type,
224
224
  ...(task.metadata?.memorySignals ?? []),
225
225
  ];
226
- const agent = this.capabilitiesManager.selectAgentForTask(requiredCaps, complexity, task.description) || 'orchestrator';
226
+ const agent = this.capabilitiesManager.selectAgentForTask(requiredCaps, complexity, task.description, task.type) || 'orchestrator';
227
227
  if (!assignments.has(agent)) {
228
228
  assignments.set(agent, []);
229
229
  }
@@ -59,7 +59,7 @@ export class ComplexityHandler {
59
59
  .filter((t) => t.description?.trim())
60
60
  .map((t) => ({ description: t.description, type: t.type }));
61
61
  const leadDevPlan = isLeadDevModeActive() && (primaryDescription || planTaskInputs.length > 0)
62
- ? buildLeadDevPlan(primaryDescription, taskTypes.length ? taskTypes : ['implement'], planTaskInputs)
62
+ ? buildLeadDevPlan(primaryDescription, taskTypes.length ? taskTypes : ['implement'], planTaskInputs, analysis.overallComplexity)
63
63
  : null;
64
64
  if (leadDevPlan) {
65
65
  try {
@@ -41,7 +41,7 @@ export interface LeadDevPlan {
41
41
  export declare function isLeadDevModeActive(): boolean;
42
42
  export declare function routeSubagent(taskType: string): SubagentRoute;
43
43
  export declare function shouldFlagFullTestSuite(command: string): boolean;
44
- export declare function buildLeadDevPlan(description: string, taskTypes?: string[], taskInputs?: LeadDevPlanTaskInput[]): LeadDevPlan | null;
44
+ export declare function buildLeadDevPlan(description: string, taskTypes?: string[], taskInputs?: LeadDevPlanTaskInput[], mcpOverallComplexity?: number): LeadDevPlan | null;
45
45
  export declare function buildSessionBootContext(): Record<string, unknown>;
46
46
  /** Persist plan for PreToolUse spawn_subagent gate */
47
47
  export declare function persistLeadDevPlan(plan: LeadDevPlan, projectRoot?: string): string;
@@ -73,13 +73,16 @@ function buildImplementationTodos(description, taskTypes, taskInputs, idPrefix)
73
73
  status: 'pending',
74
74
  }));
75
75
  }
76
- export function buildLeadDevPlan(description, taskTypes = ['implement'], taskInputs = []) {
76
+ export function buildLeadDevPlan(description, taskTypes = ['implement'], taskInputs = [], mcpOverallComplexity) {
77
77
  if (!isLeadDevModeActive())
78
78
  return null;
79
79
  const cfg = orchestrationConfig();
80
80
  const threshold = cfg.phased_plan_threshold ?? 25;
81
81
  const score = scoreComplexity(description, { taskTypes });
82
- const complexity = score.score;
82
+ const mcpScore = mcpOverallComplexity !== undefined && Number.isFinite(mcpOverallComplexity)
83
+ ? Math.round(mcpOverallComplexity)
84
+ : 0;
85
+ const complexity = Math.max(score.score, mcpScore);
83
86
  const requiresPhasedPlan = complexity > threshold || taskInputs.length > 1;
84
87
  const mandatoryConsults = cfg.auto_consult_major_work !== false && requiresPhasedPlan
85
88
  ? [...MANDATORY_MAJOR_CONSULTS]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0xray",
3
- "version": "3.4.9",
3
+ "version": "3.4.10",
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",
@@ -125,7 +125,8 @@
125
125
  "pre-publish-guard": "node scripts/node/pre-publish-guard.js",
126
126
  "safe-publish": "npm run prepare-consumer && npm run build",
127
127
  "publish": "npm run release:gate && npm run safe-publish && npm publish --access public",
128
- "release:patch": "node scripts/node/release.mjs patch"
128
+ "release:patch": "node scripts/node/release.mjs patch",
129
+ "verify:orchestrator-behavior": "npm run build && node scripts/mjs/verify-orchestrator-behavior.mjs"
129
130
  },
130
131
  "files": [
131
132
  "dist/",
@@ -137,6 +138,7 @@
137
138
  "scripts/mjs/test-mcp-functionality.mjs",
138
139
  "scripts/mjs/validate-mcp-connectivity.cjs",
139
140
  "scripts/mjs/validate-postinstall-config.mjs",
141
+ "scripts/mjs/verify-orchestrator-behavior.mjs",
140
142
  "src/opencode/",
141
143
  "src/opencode/codex.codex",
142
144
  "src/opencode/commands/",
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Consumer behavior verify — orchestrator honesty (ships in 0xray tarball).
4
+ * Run: node node_modules/0xray/scripts/mjs/verify-orchestrator-behavior.mjs
5
+ */
6
+ import { dirname, join } from 'path';
7
+ import { fileURLToPath, pathToFileURL } from 'url';
8
+
9
+ const __dirname = dirname(fileURLToPath(import.meta.url));
10
+ const packageRoot = join(__dirname, '../..');
11
+ const dist = (rel) => pathToFileURL(join(packageRoot, 'dist', rel)).href;
12
+
13
+ let failed = 0;
14
+
15
+ function pass(name) {
16
+ console.log(`✅ ${name}`);
17
+ }
18
+
19
+ function fail(name, detail = '') {
20
+ failed++;
21
+ console.error(`❌ ${name}${detail ? ` — ${detail}` : ''}`);
22
+ }
23
+
24
+ const { dependencyCount, getExecutionPlanner } = await import(
25
+ dist('mcps/orchestrator/execution/execution-planner.js')
26
+ );
27
+ const { buildLeadDevPlan } = await import(dist('nucleus/autonomy-kernel.js'));
28
+ const { TaskHandler } = await import(
29
+ dist('mcps/orchestrator/handlers/task-handler.js')
30
+ );
31
+
32
+ const planner = getExecutionPlanner();
33
+
34
+ // 1. numeric deps ≠ NaN
35
+ const analysis = await planner.analyzeTaskComplexity([
36
+ {
37
+ id: 't1',
38
+ description: 'Jelly migration',
39
+ type: 'implement',
40
+ dependencies: 8,
41
+ },
42
+ ]);
43
+ if (Number.isFinite(analysis.overallComplexity) && analysis.overallComplexity > 0) {
44
+ pass('numeric dependencyCount produces finite MCP complexity');
45
+ } else {
46
+ fail('NaN guard', `overallComplexity=${analysis.overallComplexity}`);
47
+ }
48
+
49
+ // 2. multi-task → ≥3 todos
50
+ const multiPlan = buildLeadDevPlan(
51
+ 'G0 J1 J2',
52
+ ['implement'],
53
+ [
54
+ { description: 'Publish 0xray', type: 'release' },
55
+ { description: 'Jelly swap', type: 'migration' },
56
+ { description: 'Wire tests', type: 'test' },
57
+ ],
58
+ 70,
59
+ );
60
+ const todoCount =
61
+ multiPlan?.phases.reduce((n, p) => n + p.todos.length, 0) ?? 0;
62
+ if (multiPlan?.requiresPhasedPlan && todoCount >= 3) {
63
+ pass(`multi-task phased plan (${todoCount} todos)`);
64
+ } else {
65
+ fail('multi-task plan', `requiresPhasedPlan=${multiPlan?.requiresPhasedPlan} todos=${todoCount}`);
66
+ }
67
+
68
+ // 3. implement → backend-engineer
69
+ const implAnalysis = await planner.analyzeTaskComplexity([
70
+ { id: 'impl-1', description: 'swap deps', type: 'implement' },
71
+ ]);
72
+ const implAgent = implAnalysis.agentAssignments[0]?.agent;
73
+ if (implAgent === 'backend-engineer') {
74
+ pass('implement routes to backend-engineer');
75
+ } else {
76
+ fail('implement routing', `got ${implAgent}`);
77
+ }
78
+
79
+ // 4. MCP complexity drives phased plan (single task, high MCP score)
80
+ const singleHigh = buildLeadDevPlan(
81
+ 'single complex migration',
82
+ ['implement'],
83
+ [{ description: 'single complex migration', type: 'implement' }],
84
+ 70,
85
+ );
86
+ if (singleHigh?.requiresPhasedPlan && (singleHigh.phases.length ?? 0) > 1) {
87
+ pass('MCP overallComplexity 70 forces phased plan');
88
+ } else {
89
+ fail('MCP phased plan', `requiresPhasedPlan=${singleHigh?.requiresPhasedPlan}`);
90
+ }
91
+
92
+ // 5. orchestrate-task defers implement (not fake-complete)
93
+ const handler = new TaskHandler();
94
+ const orch = await handler.handleOrchestrateTask(
95
+ {
96
+ description: 'implement feature',
97
+ sessionId: 'verify-behavior',
98
+ tasks: [
99
+ {
100
+ id: 'be-1',
101
+ description: 'implementation work',
102
+ type: 'implement',
103
+ estimatedComplexity: 40,
104
+ },
105
+ ],
106
+ },
107
+ { taskHistory: [], activeTasks: new Map() },
108
+ );
109
+ const text = orch.content[0]?.text ?? '';
110
+ if (text.includes('Deferred') && text.includes('❌ FAILED')) {
111
+ pass('orchestrate-task defers implement (success: false)');
112
+ } else {
113
+ fail('defer honesty', text.slice(0, 200));
114
+ }
115
+
116
+ console.log(
117
+ '\n' +
118
+ (failed === 0
119
+ ? '🎉 Orchestrator behavior verify passed (5/5).'
120
+ : `⚠️ ${failed} behavior check(s) failed.`),
121
+ );
122
+ process.exit(failed === 0 ? 0 : 1);
@@ -13,6 +13,25 @@ import {
13
13
  toMemoryCapabilityMap,
14
14
  fromMemoryCapabilityMap,
15
15
  } from './memory-routing-bridge.js';
16
+ import { routeSubagent } from '../../../nucleus/autonomy-kernel.js';
17
+
18
+ /** routeSubagent names → AGENT_REGISTRY keys */
19
+ const ROUTE_AGENT_ALIASES: Record<string, string> = {
20
+ 'code-review': 'code-reviewer',
21
+ 'security-audit': 'security-auditor',
22
+ 'bug-triage': 'bug-triage-specialist',
23
+ 'architect-tools': 'architect',
24
+ };
25
+
26
+ function resolveRoutedAgent(
27
+ routed: string,
28
+ capabilities: Map<string, AgentCapability>,
29
+ ): string | null {
30
+ const candidate = ROUTE_AGENT_ALIASES[routed] ?? routed;
31
+ if (capabilities.has(candidate)) return candidate;
32
+ if (capabilities.has(routed)) return routed;
33
+ return null;
34
+ }
16
35
 
17
36
  const DEFAULT_AGENT_CAPABILITIES: Record<string, AgentCapability> = Object.fromEntries(
18
37
  Object.entries(AGENT_REGISTRY).map(([name, entry]) => [
@@ -81,7 +100,14 @@ export class AgentCapabilitiesManager {
81
100
  requiredCapabilities: string[],
82
101
  complexity: number,
83
102
  operationDescription = '',
103
+ taskType = '',
84
104
  ): string | null {
105
+ if (taskType.trim()) {
106
+ const routed = routeSubagent(taskType);
107
+ const resolved = resolveRoutedAgent(routed, this.capabilities);
108
+ if (resolved) return resolved;
109
+ }
110
+
85
111
  const provider = getProvider();
86
112
 
87
113
  if (provider.id !== 'null' && operationDescription) {
@@ -243,6 +243,7 @@ export class ExecutionPlanner {
243
243
  requiredCaps,
244
244
  complexity,
245
245
  operationDescription,
246
+ task.type,
246
247
  ) || 'orchestrator';
247
248
 
248
249
  if (!agentAssignments.has(agent)) {
@@ -298,6 +299,7 @@ export class ExecutionPlanner {
298
299
  requiredCaps,
299
300
  complexity,
300
301
  task.description,
302
+ task.type,
301
303
  ) || 'orchestrator';
302
304
 
303
305
  if (!assignments.has(agent)) {
@@ -96,6 +96,7 @@ export class ComplexityHandler {
96
96
  primaryDescription,
97
97
  taskTypes.length ? taskTypes : ['implement'],
98
98
  planTaskInputs,
99
+ analysis.overallComplexity,
99
100
  )
100
101
  : null;
101
102