0xray 3.4.8 → 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.
Files changed (39) hide show
  1. package/AGENTS-consumer.md +1 -1
  2. package/AGENTS.md +1 -1
  3. package/README.md +15 -1
  4. package/SKILLS.md +1 -1
  5. package/dist/AGENTS.md +1 -1
  6. package/dist/CHANGELOG.md +28 -0
  7. package/dist/README.md +15 -1
  8. package/dist/SKILLS.md +1 -1
  9. package/dist/governance/llm-governance-provider.d.ts +2 -0
  10. package/dist/governance/llm-governance-provider.js +144 -158
  11. package/dist/mcps/knowledge-skills/code-review.server.js +1 -1
  12. package/dist/mcps/knowledge-skills/security-audit.server.js +1 -1
  13. package/dist/mcps/orchestrator/config/agent-capabilities.d.ts +1 -1
  14. package/dist/mcps/orchestrator/config/agent-capabilities.js +23 -1
  15. package/dist/mcps/orchestrator/config/memory-routing-bridge.js +2 -1
  16. package/dist/mcps/orchestrator/execution/execution-planner.d.ts +2 -0
  17. package/dist/mcps/orchestrator/execution/execution-planner.js +24 -13
  18. package/dist/mcps/orchestrator/handlers/complexity-handler.d.ts +13 -1
  19. package/dist/mcps/orchestrator/handlers/complexity-handler.js +40 -4
  20. package/dist/mcps/orchestrator/handlers/task-handler.js +13 -6
  21. package/dist/mcps/orchestrator/server.js +9 -1
  22. package/dist/mcps/orchestrator/types.d.ts +4 -1
  23. package/dist/mcps/researcher.server.js +1 -1
  24. package/dist/nucleus/autonomy-kernel.d.ts +5 -1
  25. package/dist/nucleus/autonomy-kernel.js +24 -17
  26. package/dist/skills/orchestrator/SKILL.md +3 -2
  27. package/package.json +4 -2
  28. package/scripts/mjs/verify-orchestrator-behavior.mjs +122 -0
  29. package/src/mcps/knowledge-skills/code-review.server.ts +1 -1
  30. package/src/mcps/knowledge-skills/security-audit.server.ts +1 -1
  31. package/src/mcps/orchestrator/config/agent-capabilities.ts +26 -0
  32. package/src/mcps/orchestrator/config/memory-routing-bridge.ts +3 -1
  33. package/src/mcps/orchestrator/execution/execution-planner.ts +28 -11
  34. package/src/mcps/orchestrator/handlers/complexity-handler.ts +63 -5
  35. package/src/mcps/orchestrator/handlers/task-handler.ts +22 -6
  36. package/src/mcps/orchestrator/server.ts +9 -1
  37. package/src/mcps/orchestrator/types.ts +4 -1
  38. package/src/mcps/researcher.server.ts +1 -1
  39. package/src/skills/orchestrator/SKILL.md +3 -2
@@ -17,6 +17,24 @@ import {
17
17
  fromMemoryTask,
18
18
  } from '../config/memory-routing-bridge.js';
19
19
 
20
+ /** Dependency count from task-ID list or numeric hint from analyze-complexity */
21
+ export function dependencyCount(
22
+ deps: OrchestrationTask['dependencies'] | undefined,
23
+ ): number {
24
+ if (deps == null) return 0;
25
+ if (typeof deps === 'number' && Number.isFinite(deps)) {
26
+ return Math.max(0, Math.round(deps));
27
+ }
28
+ if (Array.isArray(deps)) return deps.length;
29
+ return 0;
30
+ }
31
+
32
+ function isDependencyIdList(
33
+ deps: OrchestrationTask['dependencies'] | undefined,
34
+ ): deps is string[] {
35
+ return Array.isArray(deps) && deps.length > 0;
36
+ }
37
+
20
38
  /**
21
39
  * Execution Planner
22
40
  * Plans and optimizes task execution strategies
@@ -51,8 +69,8 @@ export class ExecutionPlanner {
51
69
  errors.push(`Task ${i}: Missing required field 'type'`);
52
70
  }
53
71
 
54
- // Check dependencies exist
55
- if (task.dependencies && task.id) {
72
+ // Check task-ID dependencies exist (numeric hints skip graph validation)
73
+ if (isDependencyIdList(task.dependencies) && task.id) {
56
74
  const taskIds = new Set(tasks.map(t => t.id).filter((id): id is string => !!id));
57
75
  for (const depId of task.dependencies) {
58
76
  if (!taskIds.has(depId)) {
@@ -162,10 +180,10 @@ export class ExecutionPlanner {
162
180
  const dependentTasks: OrchestrationTask[] = [];
163
181
 
164
182
  for (const task of sortedTasks) {
165
- if (!task.dependencies || task.dependencies.length === 0) {
166
- independentTasks.push(task);
167
- } else {
183
+ if (isDependencyIdList(task.dependencies)) {
168
184
  dependentTasks.push(task);
185
+ } else {
186
+ independentTasks.push(task);
169
187
  }
170
188
  }
171
189
 
@@ -188,7 +206,7 @@ export class ExecutionPlanner {
188
206
  if (visited.has(task.id)) return;
189
207
  visited.add(task.id);
190
208
 
191
- if (task.dependencies) {
209
+ if (isDependencyIdList(task.dependencies)) {
192
210
  for (const depId of task.dependencies) {
193
211
  const depTask = taskMap.get(depId);
194
212
  if (depTask) visit(depTask);
@@ -225,6 +243,7 @@ export class ExecutionPlanner {
225
243
  requiredCaps,
226
244
  complexity,
227
245
  operationDescription,
246
+ task.type,
228
247
  ) || 'orchestrator';
229
248
 
230
249
  if (!agentAssignments.has(agent)) {
@@ -280,6 +299,7 @@ export class ExecutionPlanner {
280
299
  requiredCaps,
281
300
  complexity,
282
301
  task.description,
302
+ task.type,
283
303
  ) || 'orchestrator';
284
304
 
285
305
  if (!assignments.has(agent)) {
@@ -344,10 +364,7 @@ export class ExecutionPlanner {
344
364
  complexity = (complexity + task.estimatedComplexity) / 2;
345
365
  }
346
366
 
347
- // Adjust based on dependencies
348
- if (task.dependencies) {
349
- complexity += task.dependencies.length * 5;
350
- }
367
+ complexity += dependencyCount(task.dependencies) * 5;
351
368
 
352
369
  if (task.metadata?.memoryComplexityBoost !== undefined) {
353
370
  complexity += task.metadata.memoryComplexityBoost;
@@ -376,7 +393,7 @@ export class ExecutionPlanner {
376
393
  */
377
394
  private calculateParallelPotential(tasks: OrchestrationTask[]): number {
378
395
  // Tasks without dependencies can run in parallel
379
- const independent = tasks.filter(t => !t.dependencies || t.dependencies.length === 0);
396
+ const independent = tasks.filter((t) => !isDependencyIdList(t.dependencies));
380
397
  return independent.length / tasks.length;
381
398
  }
382
399
  }
@@ -14,6 +14,46 @@ import { getExecutionPlanner } from '../execution/execution-planner.js';
14
14
  import { addObservations, extractComplexityObservations } from '../aside-context.js';
15
15
  import type { OrchestrationTask, ComplexityAnalysis } from '../types.js';
16
16
 
17
+ type AnalyzeComplexityInput = {
18
+ id?: string;
19
+ description?: string;
20
+ type?: string;
21
+ files?: string[];
22
+ dependencyCount?: number;
23
+ dependencies?: string[] | number;
24
+ riskLevel?: string;
25
+ estimatedComplexity?: number;
26
+ priority?: OrchestrationTask['priority'];
27
+ };
28
+
29
+ function normalizeAnalyzeTasks(raw: AnalyzeComplexityInput[]): OrchestrationTask[] {
30
+ return raw.map((task, index) => {
31
+ let deps: OrchestrationTask['dependencies'];
32
+ if (Array.isArray(task.dependencies)) {
33
+ deps = task.dependencies;
34
+ } else if (typeof task.dependencies === 'number' && Number.isFinite(task.dependencies)) {
35
+ deps = task.dependencies;
36
+ } else if (
37
+ typeof task.dependencyCount === 'number' &&
38
+ Number.isFinite(task.dependencyCount)
39
+ ) {
40
+ deps = task.dependencyCount;
41
+ }
42
+
43
+ const normalized: OrchestrationTask = {
44
+ id: task.id ?? `task-${index + 1}`,
45
+ description: task.description ?? '',
46
+ type: task.type ?? 'implement',
47
+ };
48
+ if (task.priority) normalized.priority = task.priority;
49
+ if (deps !== undefined) normalized.dependencies = deps;
50
+ if (task.estimatedComplexity !== undefined) {
51
+ normalized.estimatedComplexity = task.estimatedComplexity;
52
+ }
53
+ return normalized;
54
+ });
55
+ }
56
+
17
57
  /**
18
58
  * Complexity Handler
19
59
  * Processes analyze-complexity requests
@@ -25,10 +65,10 @@ export class ComplexityHandler {
25
65
  * Handle analyze-complexity request
26
66
  */
27
67
  async handleAnalyzeComplexity(
28
- args: { tasks: OrchestrationTask[] },
68
+ args: { tasks: AnalyzeComplexityInput[] },
29
69
  asideId?: string,
30
70
  ): Promise<{ content: Array<{ type: string; text: string }> }> {
31
- const { tasks = [] } = args;
71
+ const tasks = normalizeAnalyzeTasks(args.tasks ?? []);
32
72
 
33
73
  await frameworkLogger.log(
34
74
  'orchestrator.server',
@@ -47,14 +87,32 @@ export class ComplexityHandler {
47
87
 
48
88
  const primaryDescription = tasks.map((t) => t.description).filter(Boolean).join(' ');
49
89
  const taskTypes = tasks.map((t) => t.type).filter(Boolean) as string[];
90
+ const planTaskInputs = tasks
91
+ .filter((t) => t.description?.trim())
92
+ .map((t) => ({ description: t.description, type: t.type }));
50
93
  const leadDevPlan =
51
- isLeadDevModeActive() && primaryDescription
52
- ? buildLeadDevPlan(primaryDescription, taskTypes.length ? taskTypes : ['implement'])
94
+ isLeadDevModeActive() && (primaryDescription || planTaskInputs.length > 0)
95
+ ? buildLeadDevPlan(
96
+ primaryDescription,
97
+ taskTypes.length ? taskTypes : ['implement'],
98
+ planTaskInputs,
99
+ analysis.overallComplexity,
100
+ )
53
101
  : null;
54
102
 
55
103
  if (leadDevPlan) {
56
104
  try {
57
- persistLeadDevPlan(leadDevPlan);
105
+ const planPath = persistLeadDevPlan(leadDevPlan);
106
+ await frameworkLogger.log(
107
+ 'orchestrator.server',
108
+ 'lead-dev-plan-persisted',
109
+ 'info',
110
+ {
111
+ planPath,
112
+ phaseCount: leadDevPlan.phases.length,
113
+ todoCount: leadDevPlan.phases.reduce((n, p) => n + p.todos.length, 0),
114
+ },
115
+ );
58
116
  } catch (err) {
59
117
  await frameworkLogger.log(
60
118
  'orchestrator.server',
@@ -88,7 +88,6 @@ export class TaskHandler {
88
88
  });
89
89
  }
90
90
 
91
- // Execute orchestration (simulated for MCP server)
92
91
  const results = await this.executePlan(executionPlan, sessionId, timeout);
93
92
 
94
93
  // Feed per-task outcomes back to memory provider (not aggregate session stats)
@@ -118,6 +117,8 @@ export class TaskHandler {
118
117
  orchestrationResult.success = results.success;
119
118
  orchestrationResult.completedTasks = results.completedTasks;
120
119
  orchestrationResult.failedTasks = results.failedTasks;
120
+ orchestrationResult.deferredTasks = results.deferredTasks;
121
+ orchestrationResult.recommendations.push(...results.recommendations);
121
122
  orchestrationResult.agentUtilization = results.agentUtilization;
122
123
  orchestrationResult.bottlenecks = results.bottlenecks;
123
124
  orchestrationResult.recommendations = results.recommendations;
@@ -167,6 +168,7 @@ export class TaskHandler {
167
168
  success: boolean;
168
169
  completedTasks: number;
169
170
  failedTasks: number;
171
+ deferredTasks: number;
170
172
  agentUtilization: Record<string, number>;
171
173
  bottlenecks: string[];
172
174
  recommendations: string[];
@@ -181,6 +183,7 @@ export class TaskHandler {
181
183
  const agentUtilization: Record<string, number> = {};
182
184
  let completedTasks = 0;
183
185
  let failedTasks = 0;
186
+ let deferredTasks = 0;
184
187
  const agentOutputs: Record<string, string> = {};
185
188
  const taskOutcomes: Array<{
186
189
  taskId: string;
@@ -240,15 +243,20 @@ export class TaskHandler {
240
243
  }
241
244
  }
242
245
  } else {
243
- // For non-MCP agents we still count them as "assigned" (they will be handled by the caller or legacy path)
244
246
  for (const task of tasks) {
245
- completedTasks++;
247
+ deferredTasks++;
246
248
  taskOutcomes.push({
247
249
  taskId: task.id,
248
250
  agent,
249
- success: true,
251
+ success: false,
250
252
  durationMs: 0,
251
253
  });
254
+ await frameworkLogger.log(
255
+ 'orchestrator.task-handler',
256
+ 'delegate-deferred',
257
+ 'info',
258
+ { agent, taskId: task.id, sessionId },
259
+ );
252
260
  }
253
261
  }
254
262
  }
@@ -256,6 +264,12 @@ export class TaskHandler {
256
264
  const recommendations: string[] = [];
257
265
  const bottlenecks: string[] = [];
258
266
 
267
+ if (deferredTasks > 0) {
268
+ recommendations.push(
269
+ `${deferredTasks} task(s) require host delegation (Task/spawn_subagent per lead-dev-plan) — orchestrate-task only invokes MCP consult skills directly`,
270
+ );
271
+ }
272
+
259
273
  if (plan.agentAssignments.size > 5) {
260
274
  recommendations.push('Consider reducing the number of agents for better coordination');
261
275
  }
@@ -266,9 +280,10 @@ export class TaskHandler {
266
280
  }
267
281
 
268
282
  return {
269
- success: failedTasks === 0,
283
+ success: failedTasks === 0 && deferredTasks === 0,
270
284
  completedTasks,
271
285
  failedTasks,
286
+ deferredTasks,
272
287
  agentUtilization,
273
288
  bottlenecks,
274
289
  recommendations,
@@ -321,9 +336,10 @@ export class TaskHandler {
321
336
  **Session ID:** ${result.sessionId}
322
337
  **Success:** ${result.success ? '✅ COMPLETED' : '❌ FAILED'}
323
338
  **Duration:** ${result.duration}ms
324
- **Tasks:** ${result.completedTasks + result.failedTasks} total
339
+ **Tasks:** ${result.completedTasks + result.failedTasks + (result.deferredTasks ?? 0)} total
325
340
  - ✅ Completed: ${result.completedTasks}
326
341
  - ❌ Failed: ${result.failedTasks}
342
+ - ⏸ Deferred (host delegation required): ${result.deferredTasks ?? 0}
327
343
 
328
344
  **Agent Utilization:**
329
345
  ${Object.entries(result.agentUtilization)
@@ -152,7 +152,15 @@ export class OrchestratorServer {
152
152
  description: { type: 'string' },
153
153
  type: { type: 'string' },
154
154
  files: { type: 'array', items: { type: 'string' } },
155
- dependencies: { type: 'number' },
155
+ dependencyCount: {
156
+ type: 'number',
157
+ description: 'Upstream dependency count (complexity hint only)',
158
+ },
159
+ dependencies: {
160
+ type: 'array',
161
+ items: { type: 'string' },
162
+ description: 'Task IDs this task depends on',
163
+ },
156
164
  riskLevel: {
157
165
  type: 'string',
158
166
  enum: ['low', 'medium', 'high', 'critical'],
@@ -30,7 +30,8 @@ export interface OrchestrationTask {
30
30
  description: string;
31
31
  type: string;
32
32
  priority?: 'critical' | 'high' | 'medium' | 'low';
33
- dependencies?: string[];
33
+ /** Task IDs (orchestrate-task) or dependency count hint (analyze-complexity) */
34
+ dependencies?: string[] | number;
34
35
  estimatedComplexity?: number;
35
36
  metadata?: OrchestrationTaskMetadata;
36
37
  }
@@ -48,6 +49,8 @@ export interface OrchestrationResult {
48
49
  success: boolean;
49
50
  completedTasks: number;
50
51
  failedTasks: number;
52
+ /** Implementation agents not executed by orchestrate-task — lead must delegate via host Task */
53
+ deferredTasks?: number;
51
54
  duration: number;
52
55
  agentUtilization: Record<string, number>;
53
56
  agentOutputs?: Record<string, string>;
@@ -488,7 +488,7 @@ class XrayLibrarianServer extends XrayKnowledgeSkillBase {
488
488
  if (!vote) {
489
489
  const abstainReason = memoryContext?.confidence.highConfidenceTrapPresent
490
490
  ? "No LLM governance provider configured. Repertoire detected a high-confidence ontological trap — route to the recommended agent before proceeding."
491
- : "No LLM governance provider configured. Set XRAY_GOVERNANCE_LLM_ENABLED=true + XRAY_LLM_ENDPOINT, or install Hermes and run: hermes auth add xai-oauth --no-browser";
491
+ : "No LLM governance provider configured. Install Hermes on PATH (hermes -z) with xai-oauth, or set XRAY_GOVERNANCE_LLM_ENABLED=true + XRAY_LLM_ENDPOINT.";
492
492
 
493
493
  return {
494
494
  content: [
@@ -36,8 +36,9 @@ When `multi_agent_orchestration.lead_dev_mode` is true in `features.json` (defau
36
36
 
37
37
  | Step | MCP tool | Notes |
38
38
  |------|----------|-------|
39
- | **Intake + classify** | `analyze-complexity` | Pass `tasks` array; response includes **lead-dev plan JSON** when mode is on |
40
- | Delegate | `orchestrate-task` | Include agent + sessionId (codex 67) |
39
+ | **Intake + classify** | `analyze-complexity` | Pass `tasks` array; persists `.xray/state/lead-dev-plan.json` when mode is on |
40
+ | Delegate (consult) | `orchestrate-task` | Invokes MCP consult skills (code-review, researcher, security-audit, etc.) |
41
+ | Delegate (implement) | **host `Task` / `spawn_subagent`** | `orchestrate-task` **defers** backend-engineer, frontend-engineer, bug-triage — lead must spawn |
41
42
  | Monitor | `get-orchestration-status` | Lead updates todos |
42
43
  | Major work | researcher + architect-tools + code-review | Auto-listed in plan when complexity > threshold |
43
44