0xray 3.4.8 → 3.4.9

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 (35) 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 +16 -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/memory-routing-bridge.js +2 -1
  14. package/dist/mcps/orchestrator/execution/execution-planner.d.ts +2 -0
  15. package/dist/mcps/orchestrator/execution/execution-planner.js +22 -11
  16. package/dist/mcps/orchestrator/handlers/complexity-handler.d.ts +13 -1
  17. package/dist/mcps/orchestrator/handlers/complexity-handler.js +40 -4
  18. package/dist/mcps/orchestrator/handlers/task-handler.js +13 -6
  19. package/dist/mcps/orchestrator/server.js +9 -1
  20. package/dist/mcps/orchestrator/types.d.ts +4 -1
  21. package/dist/mcps/researcher.server.js +1 -1
  22. package/dist/nucleus/autonomy-kernel.d.ts +5 -1
  23. package/dist/nucleus/autonomy-kernel.js +20 -16
  24. package/dist/skills/orchestrator/SKILL.md +3 -2
  25. package/package.json +1 -1
  26. package/src/mcps/knowledge-skills/code-review.server.ts +1 -1
  27. package/src/mcps/knowledge-skills/security-audit.server.ts +1 -1
  28. package/src/mcps/orchestrator/config/memory-routing-bridge.ts +3 -1
  29. package/src/mcps/orchestrator/execution/execution-planner.ts +26 -11
  30. package/src/mcps/orchestrator/handlers/complexity-handler.ts +62 -5
  31. package/src/mcps/orchestrator/handlers/task-handler.ts +22 -6
  32. package/src/mcps/orchestrator/server.ts +9 -1
  33. package/src/mcps/orchestrator/types.ts +4 -1
  34. package/src/mcps/researcher.server.ts +1 -1
  35. package/src/skills/orchestrator/SKILL.md +3 -2
@@ -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.8** — 7 MCP servers · 45 skills · 68 codex terms · 4 platform bridges
7
+ **v3.4.9** — 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.8**).
3
+ Quick reference for the xray AI orchestration framework (**v3.4.9**).
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,20 @@
1
1
  # xray — MCP-Centric AI Governance OS
2
2
 
3
- **v3.4.8** — 42 agents · 45 skills · 7 MCP servers · 68 codex terms · 3,226 tests
3
+ **v3.4.9** — 42 agents · 45 skills · 7 MCP servers · 68 codex terms · 3,226 tests
4
+
5
+ ## Your AI Power Suit
6
+
7
+ **Your AI Power ⚡️ Suit 🦾** — an exoskeleton that blocks AI slop from becoming real damage.
8
+
9
+ - learns with **Repertoire** 🧠
10
+ - has a **Solar Ban Hammer** ☀️🔨 (Dynamo governance)
11
+ - can also **Confer** 🗣️ (3-agent internal deliberation)
12
+
13
+ The core AI Governance OS stack is **complete and open source**. A commercial version is next — powers up the suit further.
14
+
15
+ ```bash
16
+ npm install 0xray@latest
17
+ ```
4
18
 
5
19
  xray is the pure v2 three-subsystem AI orchestration framework — **MCP-centric**, governed by Dynamo, and autonomous via thinDispatch. Consumer `npm install 0xray` auto-wires all four platform bridges and seven MCP servers with zero manual config.
6
20
 
package/SKILLS.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # 0xray Skills
2
2
 
3
- **v3.4.8** — **45 skills** · invoked via `xray-skills` MCP · synced on postinstall
3
+ **v3.4.9** — **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.8**).
3
+ Quick reference for the xray AI orchestration framework (**v3.4.9**).
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,22 @@ 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.9] - 2026-06-19
8
+
9
+ ### ⚠️ Breaking Changes
10
+ - **`orchestrate-task`** — returns `success: false` when implementation agents (backend-engineer, frontend-engineer, bug-triage, etc.) are **deferred**. Only MCP consult skills execute in-process. Callers must not treat a completed response as work done; delegate via host `Task` / `spawn_subagent` per lead-dev-plan.
11
+
12
+ ### 🐛 Bug Fixes
13
+ - **Orchestrator honesty** — no fake-complete for implementation agents; `delegate-deferred` + `lead-dev-plan-persisted` logged to `activity.log`
14
+ - **`analyze-complexity` NaN** — `dependencyCount` + `dependencies[]` schema; numeric dependency hints no longer produce NaN scores
15
+ - **Lead-dev plan** — `buildLeadDevPlan` uses per-task inputs; multi-task intake forces phased plan (not collapsed "Direct execution")
16
+ - **Hermes governance voters** — route through `hermes -z` CLI (same path as groover `hermes-runner`); honor `HERMES_BIN`, `HERMES_HOME`
17
+
18
+ ### ✅ Tests
19
+ - Unit coverage: `execution-planner-dependencies`, deferred task-handler, per-task lead-dev todos
20
+
21
+ ---
22
+
7
23
  ## [3.4.8] - 2026-06-19
8
24
 
9
25
  ### 🐛 Bug Fixes
package/dist/README.md CHANGED
@@ -1,6 +1,20 @@
1
1
  # xray — MCP-Centric AI Governance OS
2
2
 
3
- **v3.4.8** — 42 agents · 45 skills · 7 MCP servers · 68 codex terms · 3,226 tests
3
+ **v3.4.9** — 42 agents · 45 skills · 7 MCP servers · 68 codex terms · 3,226 tests
4
+
5
+ ## Your AI Power Suit
6
+
7
+ **Your AI Power ⚡️ Suit 🦾** — an exoskeleton that blocks AI slop from becoming real damage.
8
+
9
+ - learns with **Repertoire** 🧠
10
+ - has a **Solar Ban Hammer** ☀️🔨 (Dynamo governance)
11
+ - can also **Confer** 🗣️ (3-agent internal deliberation)
12
+
13
+ The core AI Governance OS stack is **complete and open source**. A commercial version is next — powers up the suit further.
14
+
15
+ ```bash
16
+ npm install 0xray@latest
17
+ ```
4
18
 
5
19
  xray is the pure v2 three-subsystem AI orchestration framework — **MCP-centric**, governed by Dynamo, and autonomous via thinDispatch. Consumer `npm install 0xray` auto-wires all four platform bridges and seven MCP servers with zero manual config.
6
20
 
package/dist/SKILLS.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # 0xray Skills
2
2
 
3
- **v3.4.8** — **45 skills** · invoked via `xray-skills` MCP · synced on postinstall
3
+ **v3.4.9** — **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
 
@@ -4,6 +4,8 @@ export interface GovernanceVote {
4
4
  confidence: number;
5
5
  reasoning: string;
6
6
  }
7
+ export declare function resolveHermesBin(): string;
8
+ export declare function hermesCliAvailable(): boolean;
7
9
  export declare function tryLLMGovernance(role: GovernanceRole, proposalTitle: string, proposalDescription: string, evidence: string[], proposalType: string): Promise<GovernanceVote | null>;
8
10
  export declare function checkHermesOAuthStatus(): {
9
11
  configured: boolean;
@@ -1,9 +1,8 @@
1
- import { readFileSync, existsSync } from "node:fs";
2
- import { homedir } from "node:os";
3
- import { join } from "node:path";
1
+ import { execFileSync } from "node:child_process";
4
2
  import { frameworkLogger } from "../core/framework-logger.js";
5
- const XAI_ENDPOINT = "https://api.x.ai/v1/chat/completions";
6
- const XAI_MODEL = "grok-4.3";
3
+ const DEFAULT_HERMES_PROVIDER = "xai-oauth";
4
+ const DEFAULT_HERMES_MODEL = "grok-4.3";
5
+ const DEFAULT_HERMES_TIMEOUT_MS = 120_000;
7
6
  const ROLE_PROMPTS = {
8
7
  "code-review": `You are a senior code reviewer on a governance committee for a software project. Analyze the following proposal from a code quality, maintainability, readability, and engineering best practices perspective.
9
8
 
@@ -42,125 +41,97 @@ DECISION: approve|reject|abstain
42
41
  CONFIDENCE: <0.0-1.0>
43
42
  REASONING: <2-4 sentence analysis of the proposal's broader project impact>`,
44
43
  };
45
- function resolveHermesExpiresAt(provider, tokens) {
46
- if (typeof provider.expires_at === "number")
47
- return provider.expires_at;
48
- const expiresIn = tokens?.expires_in ?? provider.expires_in;
49
- if (typeof expiresIn !== "number")
50
- return undefined;
51
- const refreshCandidates = [provider.last_refresh, tokens?.last_refresh];
52
- for (const lastRefresh of refreshCandidates) {
53
- if (typeof lastRefresh !== "string")
54
- continue;
55
- const base = Date.parse(lastRefresh);
56
- if (!Number.isNaN(base)) {
57
- return Math.floor((base + expiresIn * 1000) / 1000);
58
- }
59
- }
60
- return undefined;
44
+ function resolveHermesProvider() {
45
+ return process.env.HERMES_PROVIDER?.trim() || DEFAULT_HERMES_PROVIDER;
61
46
  }
62
- function extractHermesOAuthEntry(data) {
63
- if (!data || typeof data !== "object")
64
- return undefined;
65
- if (Array.isArray(data)) {
66
- return data.find((e) => e.provider === "xai-oauth" || !!e.access_token);
67
- }
68
- const record = data;
69
- const legacy = record["xai-oauth"];
70
- if (legacy && typeof legacy === "object") {
71
- const entry = legacy;
72
- if (entry.access_token)
73
- return entry;
74
- }
75
- if (typeof record.access_token === "string") {
76
- return record;
77
- }
78
- for (const bucket of ["providers", "credential_pool"]) {
79
- const pool = record[bucket];
80
- if (!pool || typeof pool !== "object")
81
- continue;
82
- const provider = pool["xai-oauth"];
83
- if (!provider || typeof provider !== "object")
84
- continue;
85
- const prov = provider;
86
- const tokens = prov.tokens && typeof prov.tokens === "object"
87
- ? prov.tokens
88
- : undefined;
89
- if (tokens && typeof tokens.access_token === "string") {
90
- const entry = {
91
- access_token: tokens.access_token,
92
- provider: "xai-oauth",
93
- };
94
- if (typeof tokens.refresh_token === "string") {
95
- entry.refresh_token = tokens.refresh_token;
96
- }
97
- const expiresAt = resolveHermesExpiresAt(prov, tokens);
98
- if (expiresAt !== undefined)
99
- entry.expires_at = expiresAt;
100
- if (typeof tokens.token_type === "string")
101
- entry.token_type = tokens.token_type;
102
- return entry;
103
- }
104
- if (typeof prov.access_token === "string") {
105
- return prov;
106
- }
107
- }
108
- return undefined;
47
+ function resolveHermesModel() {
48
+ return process.env.HERMES_MODEL?.trim() || DEFAULT_HERMES_MODEL;
109
49
  }
110
- function readHermesOAuthToken() {
111
- try {
112
- const authPath = join(homedir(), ".hermes", "auth.json");
113
- if (!existsSync(authPath))
114
- return null;
115
- const raw = readFileSync(authPath, "utf-8");
116
- const data = JSON.parse(raw);
117
- const entry = extractHermesOAuthEntry(data);
118
- if (!entry?.access_token) {
119
- process.stderr.write("[llm] readHermesOAuthToken: no access_token in auth file\n");
120
- return null;
121
- }
122
- if (entry.expires_at && Date.now() / 1000 > entry.expires_at) {
123
- frameworkLogger.log("llm-governance", "hermes-token-expired", "warning", { expiresAt: entry.expires_at });
124
- return null;
125
- }
126
- return entry.access_token;
127
- }
128
- catch (err) {
129
- frameworkLogger.log("llm-governance", "hermes-auth-read-error", "warning", { error: String(err) });
130
- return null;
131
- }
50
+ function resolveHermesTimeoutMs() {
51
+ const raw = process.env.HERMES_TIMEOUT_MS?.trim();
52
+ if (!raw)
53
+ return DEFAULT_HERMES_TIMEOUT_MS;
54
+ const parsed = Number(raw);
55
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_HERMES_TIMEOUT_MS;
132
56
  }
133
- function getConfig() {
134
- const directEndpoint = process.env.XRAY_LLM_ENDPOINT ||
57
+ export function resolveHermesBin() {
58
+ const explicit = process.env.HERMES_BIN?.trim();
59
+ if (explicit)
60
+ return explicit;
61
+ return "hermes";
62
+ }
63
+ function getDirectLlmConfig() {
64
+ const endpoint = process.env.XRAY_LLM_ENDPOINT ||
135
65
  process.env.XRAY_GOVERNANCE_LLM_ENDPOINT ||
136
66
  "";
137
- const directApiKey = process.env.XRAY_LLM_API_KEY ||
67
+ const apiKey = process.env.XRAY_LLM_API_KEY ||
138
68
  process.env.XRAY_GOVERNANCE_LLM_API_KEY ||
139
69
  "";
140
- const directModel = process.env.XRAY_LLM_MODEL ||
70
+ const model = process.env.XRAY_LLM_MODEL ||
141
71
  process.env.XRAY_GOVERNANCE_LLM_MODEL ||
142
72
  "gpt-4o";
143
- // First try: direct env-var config (highest priority)
144
73
  const directEnabled = process.env.XRAY_GOVERNANCE_LLM_ENABLED === "true" ||
145
74
  process.env.XRAY_LLM_ENABLED === "true";
146
- if (directEnabled && directEndpoint && directApiKey) {
147
- return { endpoint: directEndpoint, apiKey: directApiKey, model: directModel };
148
- }
149
- // Second try: Hermes xAI OAuth token from ~/.hermes/auth.json
150
- const hermesToken = readHermesOAuthToken();
151
- if (hermesToken) {
152
- frameworkLogger.log("llm-governance", "using-hermes-oauth", "info", { provider: "xai-oauth", endpoint: XAI_ENDPOINT, model: XAI_MODEL });
153
- return { endpoint: XAI_ENDPOINT, apiKey: hermesToken, model: XAI_MODEL };
75
+ if (directEnabled && endpoint && apiKey) {
76
+ return { mode: "direct", endpoint, apiKey, model };
154
77
  }
155
- // Third try: direct endpoint even without explicit enable flag (if endpoint+key set)
156
- if (directEndpoint && directApiKey) {
157
- return { endpoint: directEndpoint, apiKey: directApiKey, model: directModel };
78
+ if (endpoint && apiKey) {
79
+ return { mode: "direct", endpoint, apiKey, model };
158
80
  }
159
- if (process.env.DEBUG_LLM) {
160
- process.stderr.write("[llm-debug] No config found. directEnabled=" + directEnabled + " endpoint=" + !!directEndpoint + " apiKey=" + !!directApiKey + " hermes=" + !!hermesToken + "\n");
81
+ return null;
82
+ }
83
+ function getConfig() {
84
+ const direct = getDirectLlmConfig();
85
+ if (direct)
86
+ return direct;
87
+ if (hermesCliAvailable()) {
88
+ return {
89
+ mode: "hermes",
90
+ provider: resolveHermesProvider(),
91
+ model: resolveHermesModel(),
92
+ timeoutMs: resolveHermesTimeoutMs(),
93
+ };
161
94
  }
162
95
  return null;
163
96
  }
97
+ export function hermesCliAvailable() {
98
+ try {
99
+ execFileSync(resolveHermesBin(), ["--version"], {
100
+ encoding: "utf8",
101
+ stdio: ["ignore", "pipe", "pipe"],
102
+ timeout: 5_000,
103
+ });
104
+ return true;
105
+ }
106
+ catch {
107
+ return false;
108
+ }
109
+ }
110
+ function buildGovernancePrompt(role, proposalTitle, proposalDescription, evidence, proposalType) {
111
+ const evidenceBlock = evidence.length > 0
112
+ ? `**Supporting Evidence:**\n${evidence.map((entry, index) => `${index + 1}. ${entry}`).join("\n")}\n\n`
113
+ : "";
114
+ return `${ROLE_PROMPTS[role]}
115
+
116
+ ## Proposal
117
+
118
+ **Title:** ${proposalTitle}
119
+
120
+ **Description:** ${proposalDescription}
121
+
122
+ **Type:** ${proposalType}
123
+
124
+ ${evidenceBlock}---
125
+
126
+ Please provide your structured vote.`;
127
+ }
128
+ function runHermesGovernanceInference(prompt, config) {
129
+ return execFileSync(resolveHermesBin(), ["-z", prompt, "--provider", config.provider, "--model", config.model], {
130
+ encoding: "utf8",
131
+ timeout: config.timeoutMs,
132
+ maxBuffer: 10 * 1024 * 1024,
133
+ }).trim();
134
+ }
164
135
  function parseVote(text) {
165
136
  const decisionMatch = text.match(/DECISION:\s*(approve|reject|abstain)/i);
166
137
  const confidenceMatch = text.match(/CONFIDENCE:\s*([0-9.]+)/i);
@@ -175,13 +146,7 @@ function parseVote(text) {
175
146
  reasoning: reasoningMatch?.[1]?.trim() || "No reasoning provided",
176
147
  };
177
148
  }
178
- export async function tryLLMGovernance(role, proposalTitle, proposalDescription, evidence, proposalType) {
179
- const config = getConfig();
180
- if (!config) {
181
- process.stderr.write("[llm] no config for role=" + role + "\n");
182
- return null;
183
- }
184
- process.stderr.write("[llm] using config endpoint=" + config.endpoint + " model=" + config.model + "\n");
149
+ async function callDirectLlm(role, config, proposalTitle, proposalDescription, evidence, proposalType) {
185
150
  const systemPrompt = ROLE_PROMPTS[role];
186
151
  const userMessage = `## Proposal
187
152
 
@@ -191,40 +156,61 @@ export async function tryLLMGovernance(role, proposalTitle, proposalDescription,
191
156
 
192
157
  **Type:** ${proposalType}
193
158
 
194
- ${evidence.length > 0 ? `**Supporting Evidence:**\n${evidence.map((e, i) => `${i + 1}. ${e}`).join("\n")}` : ""}
159
+ ${evidence.length > 0 ? `**Supporting Evidence:**\n${evidence.map((entry, index) => `${index + 1}. ${entry}`).join("\n")}` : ""}
195
160
 
196
161
  ---
197
162
 
198
163
  Please provide your structured vote.`;
199
- try {
200
- const response = await fetch(config.endpoint, {
201
- method: "POST",
202
- headers: {
203
- "Content-Type": "application/json",
204
- Authorization: `Bearer ${config.apiKey}`,
205
- },
206
- body: JSON.stringify({
207
- model: config.model,
208
- messages: [
209
- { role: "system", content: systemPrompt },
210
- { role: "user", content: userMessage },
211
- ],
212
- temperature: 0.3,
213
- max_tokens: 500,
214
- }),
164
+ const response = await fetch(config.endpoint, {
165
+ method: "POST",
166
+ headers: {
167
+ "Content-Type": "application/json",
168
+ Authorization: `Bearer ${config.apiKey}`,
169
+ },
170
+ body: JSON.stringify({
171
+ model: config.model,
172
+ messages: [
173
+ { role: "system", content: systemPrompt },
174
+ { role: "user", content: userMessage },
175
+ ],
176
+ temperature: 0.3,
177
+ max_tokens: 500,
178
+ }),
179
+ });
180
+ if (!response.ok) {
181
+ frameworkLogger.log("llm-governance", "api-call", "error", {
182
+ status: response.status,
183
+ statusText: response.statusText,
184
+ role,
215
185
  });
216
- if (!response.ok) {
217
- frameworkLogger.log("llm-governance", "api-call", "error", {
218
- status: response.status,
219
- statusText: response.statusText,
220
- role,
221
- });
222
- return null;
223
- }
224
- const data = (await response.json());
225
- const choices = data?.choices;
226
- const message = choices?.[0]?.message;
227
- const content = message?.content;
186
+ return null;
187
+ }
188
+ const data = (await response.json());
189
+ const choices = data?.choices;
190
+ const message = choices?.[0]?.message;
191
+ return message?.content ?? null;
192
+ }
193
+ export async function tryLLMGovernance(role, proposalTitle, proposalDescription, evidence, proposalType) {
194
+ const config = getConfig();
195
+ if (!config) {
196
+ process.stderr.write(`[llm] no config for role=${role}\n`);
197
+ return null;
198
+ }
199
+ if (config.mode === "hermes") {
200
+ process.stderr.write(`[llm] using hermes -z provider=${config.provider} model=${config.model}\n`);
201
+ frameworkLogger.log("llm-governance", "using-hermes-cli", "info", {
202
+ provider: config.provider,
203
+ model: config.model,
204
+ role,
205
+ });
206
+ }
207
+ else {
208
+ process.stderr.write(`[llm] using direct endpoint=${config.endpoint} model=${config.model}\n`);
209
+ }
210
+ try {
211
+ const content = config.mode === "hermes"
212
+ ? runHermesGovernanceInference(buildGovernancePrompt(role, proposalTitle, proposalDescription, evidence, proposalType), config)
213
+ : await callDirectLlm(role, config, proposalTitle, proposalDescription, evidence, proposalType);
228
214
  if (!content) {
229
215
  frameworkLogger.log("llm-governance", "parse", "warning", {
230
216
  issue: "missing content in response",
@@ -257,23 +243,23 @@ Please provide your structured vote.`;
257
243
  }
258
244
  }
259
245
  export function checkHermesOAuthStatus() {
260
- const config = getConfig();
261
- if (!config) {
262
- const hermesPath = join(homedir(), ".hermes", "auth.json");
263
- if (existsSync(hermesPath)) {
264
- return {
265
- configured: false,
266
- error: "Hermes auth file found but no valid xai-oauth token. Run: hermes auth add xai-oauth --no-browser",
267
- };
268
- }
246
+ const direct = getDirectLlmConfig();
247
+ if (direct) {
248
+ return {
249
+ configured: true,
250
+ endpoint: direct.endpoint,
251
+ model: direct.model,
252
+ };
253
+ }
254
+ if (hermesCliAvailable()) {
269
255
  return {
270
- configured: false,
271
- error: "No Hermes auth file found (~/.hermes/auth.json). Install Hermes and run: hermes auth add xai-oauth --no-browser",
256
+ configured: true,
257
+ endpoint: "hermes-cli",
258
+ model: resolveHermesModel(),
272
259
  };
273
260
  }
274
261
  return {
275
- configured: true,
276
- endpoint: XAI_ENDPOINT,
277
- model: XAI_MODEL,
262
+ configured: false,
263
+ error: "Hermes CLI not found on PATH. Install Hermes and ensure xai-oauth is configured (same path as gateway/cron: hermes auth add xai-oauth).",
278
264
  };
279
265
  }
@@ -321,7 +321,7 @@ class XrayCodeReviewServer extends XrayKnowledgeSkillBase {
321
321
  content: [
322
322
  {
323
323
  type: "text",
324
- text: "DECISION: abstain\nCONFIDENCE: 0.50\nREASONING: 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",
324
+ text: "DECISION: abstain\nCONFIDENCE: 0.50\nREASONING: No LLM governance provider configured. Install Hermes on PATH (hermes -z) with xai-oauth, or set XRAY_GOVERNANCE_LLM_ENABLED=true + XRAY_LLM_ENDPOINT.",
325
325
  },
326
326
  ],
327
327
  };
@@ -666,7 +666,7 @@ class XraySecurityAuditServer extends XrayKnowledgeSkillBase {
666
666
  content: [
667
667
  {
668
668
  type: "text",
669
- text: "DECISION: abstain\nCONFIDENCE: 0.50\nREASONING: 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",
669
+ text: "DECISION: abstain\nCONFIDENCE: 0.50\nREASONING: No LLM governance provider configured. Install Hermes on PATH (hermes -z) with xai-oauth, or set XRAY_GOVERNANCE_LLM_ENABLED=true + XRAY_LLM_ENDPOINT.",
670
670
  },
671
671
  ],
672
672
  };
@@ -34,8 +34,9 @@ export function toMemoryTask(task) {
34
34
  };
35
35
  if (task.priority)
36
36
  result.priority = task.priority;
37
- if (task.dependencies)
37
+ if (Array.isArray(task.dependencies) && task.dependencies.length > 0) {
38
38
  result.dependencies = task.dependencies;
39
+ }
39
40
  if (task.estimatedComplexity !== undefined)
40
41
  result.estimatedComplexity = task.estimatedComplexity;
41
42
  if (task.metadata)
@@ -4,6 +4,8 @@
4
4
  * Creates optimized execution plans for orchestration tasks
5
5
  */
6
6
  import type { OrchestrationTask, ExecutionPlan, ComplexityAnalysis, TaskValidation } from '../types.js';
7
+ /** Dependency count from task-ID list or numeric hint from analyze-complexity */
8
+ export declare function dependencyCount(deps: OrchestrationTask['dependencies'] | undefined): number;
7
9
  /**
8
10
  * Execution Planner
9
11
  * Plans and optimizes task execution strategies
@@ -5,6 +5,20 @@
5
5
  */
6
6
  import { getAgentCapabilitiesManager } from '../config/agent-capabilities.js';
7
7
  import { getProvider, toMemoryTask, fromMemoryTask, } from '../config/memory-routing-bridge.js';
8
+ /** Dependency count from task-ID list or numeric hint from analyze-complexity */
9
+ export function dependencyCount(deps) {
10
+ if (deps == null)
11
+ return 0;
12
+ if (typeof deps === 'number' && Number.isFinite(deps)) {
13
+ return Math.max(0, Math.round(deps));
14
+ }
15
+ if (Array.isArray(deps))
16
+ return deps.length;
17
+ return 0;
18
+ }
19
+ function isDependencyIdList(deps) {
20
+ return Array.isArray(deps) && deps.length > 0;
21
+ }
8
22
  /**
9
23
  * Execution Planner
10
24
  * Plans and optimizes task execution strategies
@@ -33,8 +47,8 @@ export class ExecutionPlanner {
33
47
  if (!task.type) {
34
48
  errors.push(`Task ${i}: Missing required field 'type'`);
35
49
  }
36
- // Check dependencies exist
37
- if (task.dependencies && task.id) {
50
+ // Check task-ID dependencies exist (numeric hints skip graph validation)
51
+ if (isDependencyIdList(task.dependencies) && task.id) {
38
52
  const taskIds = new Set(tasks.map(t => t.id).filter((id) => !!id));
39
53
  for (const depId of task.dependencies) {
40
54
  if (!taskIds.has(depId)) {
@@ -117,11 +131,11 @@ export class ExecutionPlanner {
117
131
  const independentTasks = [];
118
132
  const dependentTasks = [];
119
133
  for (const task of sortedTasks) {
120
- if (!task.dependencies || task.dependencies.length === 0) {
121
- independentTasks.push(task);
134
+ if (isDependencyIdList(task.dependencies)) {
135
+ dependentTasks.push(task);
122
136
  }
123
137
  else {
124
- dependentTasks.push(task);
138
+ independentTasks.push(task);
125
139
  }
126
140
  }
127
141
  // Assign independent tasks in parallel
@@ -140,7 +154,7 @@ export class ExecutionPlanner {
140
154
  if (visited.has(task.id))
141
155
  return;
142
156
  visited.add(task.id);
143
- if (task.dependencies) {
157
+ if (isDependencyIdList(task.dependencies)) {
144
158
  for (const depId of task.dependencies) {
145
159
  const depTask = taskMap.get(depId);
146
160
  if (depTask)
@@ -263,10 +277,7 @@ export class ExecutionPlanner {
263
277
  if (task.estimatedComplexity) {
264
278
  complexity = (complexity + task.estimatedComplexity) / 2;
265
279
  }
266
- // Adjust based on dependencies
267
- if (task.dependencies) {
268
- complexity += task.dependencies.length * 5;
269
- }
280
+ complexity += dependencyCount(task.dependencies) * 5;
270
281
  if (task.metadata?.memoryComplexityBoost !== undefined) {
271
282
  complexity += task.metadata.memoryComplexityBoost;
272
283
  }
@@ -295,7 +306,7 @@ export class ExecutionPlanner {
295
306
  */
296
307
  calculateParallelPotential(tasks) {
297
308
  // Tasks without dependencies can run in parallel
298
- const independent = tasks.filter(t => !t.dependencies || t.dependencies.length === 0);
309
+ const independent = tasks.filter((t) => !isDependencyIdList(t.dependencies));
299
310
  return independent.length / tasks.length;
300
311
  }
301
312
  }
@@ -4,6 +4,17 @@
4
4
  * Handles complexity analysis requests
5
5
  */
6
6
  import type { OrchestrationTask } from '../types.js';
7
+ type AnalyzeComplexityInput = {
8
+ id?: string;
9
+ description?: string;
10
+ type?: string;
11
+ files?: string[];
12
+ dependencyCount?: number;
13
+ dependencies?: string[] | number;
14
+ riskLevel?: string;
15
+ estimatedComplexity?: number;
16
+ priority?: OrchestrationTask['priority'];
17
+ };
7
18
  /**
8
19
  * Complexity Handler
9
20
  * Processes analyze-complexity requests
@@ -14,7 +25,7 @@ export declare class ComplexityHandler {
14
25
  * Handle analyze-complexity request
15
26
  */
16
27
  handleAnalyzeComplexity(args: {
17
- tasks: OrchestrationTask[];
28
+ tasks: AnalyzeComplexityInput[];
18
29
  }, asideId?: string): Promise<{
19
30
  content: Array<{
20
31
  type: string;
@@ -30,3 +41,4 @@ export declare class ComplexityHandler {
30
41
  */
31
42
  private formatComplexityResponse;
32
43
  }
44
+ export {};