0xray 3.3.0 → 3.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/.opencode/codex.codex +1 -1
  2. package/.opencode/enforcer-config.json +1 -4
  3. package/dist/CHANGELOG.md +22 -0
  4. package/dist/analytics/routing-refiner.js +0 -2
  5. package/dist/core/boot-orchestrator.js +9 -1
  6. package/dist/core/features-config.js +0 -1
  7. package/dist/integrations/grok/grok-cli.js +53 -25
  8. package/dist/integrations/hermes-agent/bridge.mjs +11 -1
  9. package/dist/mcps/index.js +1 -0
  10. package/dist/mcps/knowledge-skills/skill-invocation.server.js +3 -2
  11. package/dist/mcps/knowledge-skills/storyteller.server.js +167 -0
  12. package/dist/mcps/orchestrator/execution/execution-planner.js +14 -2
  13. package/dist/mcps/registry.json +0 -1
  14. package/dist/mcps/researcher-confidence.js +92 -0
  15. package/dist/mcps/researcher.server.js +19 -3
  16. package/dist/memory-routing/null-provider.js +12 -0
  17. package/dist/orchestrator/universal-registry-bridge.js +1 -1
  18. package/dist/skills/registry.json +0 -1
  19. package/package.json +1 -1
  20. package/scripts/node/enforce-agents-md.mjs +0 -26
  21. package/scripts/node/enforce-version-compliance.sh +0 -1
  22. package/scripts/node/enforce-version-compliance.ts +0 -10
  23. package/scripts/node/install-bridges.cjs +466 -0
  24. package/scripts/node/postinstall.cjs +24 -83
  25. package/scripts/node/pre-publish-guard.js +20 -16
  26. package/scripts/node/setup.cjs +11 -10
  27. package/scripts/node/universal-version-manager.js +17 -3
  28. package/src/mcps/index.ts +1 -0
  29. package/src/mcps/knowledge-skills/skill-invocation.server.ts +3 -2
  30. package/src/mcps/knowledge-skills/storyteller.server.ts +206 -0
  31. package/src/mcps/orchestrator/execution/execution-planner.ts +14 -2
  32. package/src/mcps/orchestrator/types.ts +4 -0
  33. package/src/mcps/registry.json +0 -1
  34. package/src/mcps/researcher-confidence.ts +144 -0
  35. package/src/mcps/researcher.server.ts +28 -3
  36. package/src/opencode/codex.codex +1 -1
  37. package/src/opencode/enforcer-config.json +1 -4
  38. package/src/skills/registry.json +0 -1
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.3.0",
2
+ "version": "3.3.1",
3
3
  "terms": [
4
4
  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60
5
5
  ],
@@ -1,7 +1,5 @@
1
1
  {
2
- "framework": "xray 2.0",
3
- "version": "3.1.0",
4
- "description": "Codex-compliant framework configuration for Credible UI project",
2
+ "description": "Codex-compliant framework configuration",
5
3
  "thresholds": {
6
4
  "bundleSize": {
7
5
  "maxSize": "3MB",
@@ -220,7 +218,6 @@
220
218
  }
221
219
  },
222
220
  "codex": {
223
- "version": "3.1.0",
224
221
  "terms": [
225
222
  1,
226
223
  2,
package/dist/CHANGELOG.md CHANGED
@@ -4,6 +4,28 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Conventional Commits](https://www.conventionalcommits.org/).
6
6
 
7
+ ## [3.4.1] - 2026-06-17
8
+
9
+ ### ✨ Features
10
+ - Unified 4-platform bridge installer (`install-bridges.cjs`) runs on consumer `npm i 0xray` postinstall — OpenCode, Grok, Hermes, OpenClaw
11
+ - All 7 MCP servers registered via `npx -y 0xray mcp <cmd>` (no brittle `dist/` paths)
12
+ - `npx 0xray grok install` aligned with postinstall: 7 servers via npx, idempotent skill/MCP sync on re-run
13
+ - Grok skills synced to both `~/.grok/plugins/0xray/skills/` and `~/.grok/skills/` (Grok Build / Cursor)
14
+
15
+ ### 🐛 Bug Fixes
16
+ - `setup.cjs` consumer detection uses `isConsumerInstall()` — works for both `node_modules/0xray` and `node_modules/xray`
17
+ - Hermes bridge honors `XRAY_ROOT` env and `xray-consumer-root.txt` marker for correct project root resolution
18
+
19
+ ## [3.3.0] - 2026-06-18
20
+
21
+ ### 🔄 Changes
22
+
23
+ ### 🔎 Other Changes
24
+ - Wire orchestrator confidence gate into execution planning (d7910b610)
25
+ - tweet: v3.3.0 release tweet — Pluggable Memory Routing (7fb6c9f70)
26
+
27
+ ---
28
+
7
29
  ## [3.2.0] - 2026-06-17
8
30
 
9
31
  ### 🔄 Changes
@@ -35,7 +35,6 @@ class RoutingRefiner {
35
35
  const optimizations = this.suggestMappingOptimizations(promptAnalysis, performanceReport);
36
36
  const warnings = this.generateWarnings(newMappings, optimizations);
37
37
  return {
38
- version: "3.1.0",
39
38
  generatedAt: new Date(),
40
39
  summary: {
41
40
  newMappings: newMappings.length,
@@ -247,7 +246,6 @@ class RoutingRefiner {
247
246
  lines.push("╚════════════════════════════════════════════════════════════╝");
248
247
  lines.push("");
249
248
  lines.push(`Generated: ${report.configurationUpdate.generatedAt.toISOString()}`);
250
- lines.push(`Version: ${report.configurationUpdate.version}`);
251
249
  lines.push("");
252
250
  lines.push("=== Summary ===");
253
251
  lines.push(`New Mappings: ${report.configurationUpdate.summary.newMappings}`);
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Boot Orchestrator (min documented consumer runtime compat shim from prior 0xRay releases; primary Xray paths + .xray fallbacks only; 1-line per Scope Rule).
3
3
  */
4
+ import { readFileSync } from "fs";
4
5
  import { XrayContextLoader } from "./context-loader.js";
5
6
  import { XrayStateManager } from "../state/state-manager.js";
6
7
  import { ProcessorManager } from "../processors/processor-manager.js";
@@ -721,7 +722,14 @@ export class BootOrchestrator {
721
722
  try {
722
723
  // Consumer runtime compat shim from prior 0xRay releases (1-line min per Scope Rule; primary xray paths + .xray fallbacks)
723
724
  const xrayConfig = {
724
- version: "3.1.0",
725
+ version: (() => {
726
+ try {
727
+ return JSON.parse(readFileSync(path.join(process.cwd(), "package.json"), "utf-8")).version;
728
+ }
729
+ catch {
730
+ return "unknown";
731
+ }
732
+ })(),
725
733
  codex_enabled: true,
726
734
  codex_version: "v1.7.5",
727
735
  codex_terms: [
@@ -285,7 +285,6 @@ export class FeaturesConfigLoader {
285
285
  */
286
286
  getDefaultConfig() {
287
287
  return {
288
- version: "3.1.0",
289
288
  description: "0xRay Framework - Unified Feature Configuration",
290
289
  token_optimization: {
291
290
  enabled: true,
@@ -18,9 +18,44 @@ import { frameworkLogger } from '../../core/framework-logger.js';
18
18
  import fs from 'fs';
19
19
  import path from 'path';
20
20
  import { execSync } from 'child_process';
21
+ import { createRequire } from 'module';
21
22
  import { syncBuiltinSkills } from '../../cli/commands/skill-install.js';
22
23
  // ESM-compatible __dirname (this file is compiled to ESM)
23
24
  const __dirname = path.dirname(new URL(import.meta.url).pathname);
25
+ const packageRoot = path.resolve(__dirname, '..', '..', '..');
26
+ const requireCjs = createRequire(import.meta.url);
27
+ const { resolveConsumerTargetDir } = requireCjs(path.join(packageRoot, 'scripts/node/install-bridges.cjs'));
28
+ /** Canonical 7-server MCP surface — matches install-bridges.cjs and package .mcp.json */
29
+ const XRAY_MCP_SERVERS = [
30
+ { name: 'xray-governance', mcpCmd: 'governance', env: { XRAY_FORCE_MCP_GOVERNANCE: 'true' } },
31
+ { name: 'xray-skills', mcpCmd: 'skills', env: {} },
32
+ { name: 'xray-orchestrator', mcpCmd: 'orchestrator', env: {} },
33
+ { name: 'xray-enforcer', mcpCmd: 'enforcer', env: {} },
34
+ { name: 'xray-researcher', mcpCmd: 'researcher', env: {} },
35
+ { name: 'xray-code-review', mcpCmd: 'code-review', env: {} },
36
+ { name: 'xray-architect-tools', mcpCmd: 'architect-tools', env: {} },
37
+ ];
38
+ function registerGrokMcpServers(targetDir) {
39
+ try {
40
+ execSync('which grok', { stdio: 'ignore' });
41
+ }
42
+ catch {
43
+ console.log('[Grok] grok CLI not on PATH — plugin .mcp.json still configured');
44
+ return;
45
+ }
46
+ for (const s of XRAY_MCP_SERVERS) {
47
+ try {
48
+ const envEntries = { ...s.env, XRAY_ROOT: targetDir };
49
+ const envFlags = Object.entries(envEntries)
50
+ .map(([k, v]) => `--env "${k}=${v}"`)
51
+ .join(' ');
52
+ execSync(`grok mcp add ${s.name} --command npx --args "-y" "0xray" "mcp" "${s.mcpCmd}" ${envFlags}`, { stdio: 'pipe' });
53
+ }
54
+ catch {
55
+ // already registered or grok config conflict — non-blocking
56
+ }
57
+ }
58
+ }
24
59
  export async function installForGrokCLI(options = {}) {
25
60
  frameworkLogger.log('grok-integration', 'install-start', 'info', { options });
26
61
  const home = process.env.HOME || process.env.USERPROFILE || '';
@@ -39,15 +74,18 @@ export async function installForGrokCLI(options = {}) {
39
74
  console.log(`[Grok] Dry run: Would copy plugin from ${sourceDir} → ${targetPluginDir}`);
40
75
  return;
41
76
  }
77
+ const targetDir = resolveConsumerTargetDir(packageRoot, process.cwd());
42
78
  try {
43
- if (fs.existsSync(targetPluginDir) && !options.force) {
79
+ const pluginExists = fs.existsSync(targetPluginDir);
80
+ if (pluginExists && !options.force) {
44
81
  console.log('[Grok] 0xray Grok plugin is already installed.');
45
- console.log('Use --force to reinstall.');
46
- return;
82
+ console.log('Use --force to reinstall plugin files.');
83
+ }
84
+ else {
85
+ fs.cpSync(sourceDir, targetPluginDir, { recursive: true, force: true });
86
+ frameworkLogger.log('grok-integration', 'plugin-copied', 'info', { destination: targetPluginDir });
87
+ console.log(`\x1b[32m✓ Copied Grok plugin to ${targetPluginDir}\x1b[0m`);
47
88
  }
48
- fs.cpSync(sourceDir, targetPluginDir, { recursive: true, force: true });
49
- frameworkLogger.log('grok-integration', 'plugin-copied', 'info', { destination: targetPluginDir });
50
- console.log(`\x1b[32m✓ Copied Grok plugin to ${targetPluginDir}\x1b[0m`);
51
89
  // Sync builtin skills to Grok plugin skills dir
52
90
  const grokSkillsDir = path.join(targetPluginDir, 'skills');
53
91
  const skillsCopied = syncBuiltinSkills(grokSkillsDir);
@@ -55,6 +93,12 @@ export async function installForGrokCLI(options = {}) {
55
93
  console.log(`\x1b[32m✓ Synced ${skillsCopied} builtin skills to Grok plugin\x1b[0m`);
56
94
  }
57
95
  frameworkLogger.log('grok-integration', 'skills-synced', 'info', { count: skillsCopied });
96
+ // Grok Build / Cursor also reads ~/.grok/skills/ for agent_skills
97
+ const globalSkillsDir = path.join(home, '.grok', 'skills');
98
+ const globalCopied = syncBuiltinSkills(globalSkillsDir);
99
+ if (globalCopied > 0) {
100
+ console.log(`\x1b[32m✓ Synced ${globalCopied} builtin skills to ~/.grok/skills/\x1b[0m`);
101
+ }
58
102
  // Attempt auto-trust (best effort)
59
103
  try {
60
104
  execSync(`grok plugins trust "${targetPluginDir}"`, { stdio: 'ignore' });
@@ -64,25 +108,9 @@ export async function installForGrokCLI(options = {}) {
64
108
  console.log('\nPlease run this command to fully trust the plugin:');
65
109
  console.log(` grok plugins trust "${targetPluginDir}"`);
66
110
  }
67
- // Register MCP servers via grok mcp add (most reliable mechanism)
68
- const govMcpPath = path.resolve(__dirname, '..', '..', '..', 'dist/mcps/governance.server.js');
69
- const skillsMcpPath = path.resolve(__dirname, '..', '..', '..', 'dist/mcps/knowledge-skills/skill-invocation.server.js');
70
- const orchMcpPath = path.resolve(__dirname, '..', '..', '..', 'dist/mcps/orchestrator.server.js');
71
- const enforcerMcpPath = path.resolve(__dirname, '..', '..', '..', 'dist/mcps/enforcer-tools.server.js');
72
- try {
73
- execSync(`grok mcp add xray-governance --command node --args "${govMcpPath}" --env "XRAY_FORCE_MCP_GOVERNANCE=true" --env "XRAY_ROOT=${process.cwd()}"`, { stdio: 'pipe' });
74
- execSync(`grok mcp add xray-skills --command node --args "${skillsMcpPath}" --env "XRAY_ROOT=${process.cwd()}"`, { stdio: 'pipe' });
75
- execSync(`grok mcp add xray-orchestrator --command node --args "${orchMcpPath}" --env "XRAY_ROOT=${process.cwd()}"`, { stdio: 'pipe' });
76
- execSync(`grok mcp add xray-enforcer --command node --args "${enforcerMcpPath}" --env "XRAY_ROOT=${process.cwd()}"`, { stdio: 'pipe' });
77
- console.log('\x1b[32m✓ Registered xray MCP servers with Grok CLI\x1b[0m');
78
- }
79
- catch {
80
- console.log('\nCould not auto-register MCP servers. Run manually:');
81
- console.log(` grok mcp add xray-governance --command node --args "${govMcpPath}"`);
82
- console.log(` grok mcp add xray-skills --command node --args "${skillsMcpPath}"`);
83
- console.log(` grok mcp add xray-orchestrator --command node --args "${orchMcpPath}"`);
84
- console.log(` grok mcp add xray-enforcer --command node --args "${enforcerMcpPath}"`);
85
- }
111
+ // Register MCP servers via grok mcp add (npx -y 0xray mcp — matches install-bridges)
112
+ registerGrokMcpServers(targetDir);
113
+ console.log('\x1b[32m✓ Registered 7 xray MCP servers with Grok CLI (npx)\x1b[0m');
86
114
  console.log('\n✅ 0xRay is now installed as a first-class Grok CLI plugin!');
87
115
  console.log('Restart Grok or run `grok` to load the new hooks and MCP servers.');
88
116
  }
@@ -53,9 +53,19 @@ let frameworkLoadAttempted = false;
53
53
 
54
54
  // ── Project root detection ───────────────────────────────────
55
55
  function findProjectRoot() {
56
- const envHome = process.env.XRAY_HOME;
56
+ const envHome = process.env.XRAY_HOME || process.env.XRAY_ROOT;
57
57
  if (envHome && existsSync(join(envHome, "package.json"))) return envHome;
58
58
 
59
+ const consumerMarker = join(__dirname, "xray-consumer-root.txt");
60
+ if (existsSync(consumerMarker)) {
61
+ try {
62
+ const marked = readFileSync(consumerMarker, "utf-8").trim();
63
+ if (marked && existsSync(join(marked, "package.json"))) return marked;
64
+ } catch {
65
+ // fall through
66
+ }
67
+ }
68
+
59
69
  const candidates = [
60
70
  process.cwd(),
61
71
  join(homedir(), "dev", "xray"),
@@ -40,6 +40,7 @@ export const MCP_SERVERS = [
40
40
  { serverName: "refactoring-strategies", sourceFile: "mcps/knowledge-skills/refactoring-strategies.server.ts", type: "knowledge-skill", registered: true, description: "Refactoring strategies" },
41
41
  { serverName: "security-audit", sourceFile: "mcps/knowledge-skills/security-audit.server.ts", type: "knowledge-skill", registered: true, description: "Security auditing" },
42
42
  { serverName: "seo-consultant", sourceFile: "mcps/knowledge-skills/seo-consultant.server.ts", type: "knowledge-skill", registered: false, description: "SEO consulting" },
43
+ { serverName: "storyteller", sourceFile: "mcps/knowledge-skills/storyteller.server.ts", type: "knowledge-skill", registered: false, description: "Reflections, sagas, and technical narratives" },
43
44
  { serverName: "session-management", sourceFile: "mcps/knowledge-skills/session-management.server.ts", type: "knowledge-skill", registered: true, description: "Session management" },
44
45
  { serverName: "skill-invocation", sourceFile: "mcps/knowledge-skills/skill-invocation.server.ts", type: "knowledge-skill", registered: true, description: "Skill invocation" },
45
46
  { serverName: "strategist", sourceFile: "mcps/knowledge-skills/strategist.server.ts", type: "knowledge-skill", registered: false, description: "Strategic planning" },
@@ -87,7 +87,7 @@ class SkillInvocationServer extends XrayKnowledgeSkillBase {
87
87
  "strategist", "skill-invocation",
88
88
  ];
89
89
  const knowledgeSkills = [
90
- "architecture-patterns", "strategist", "tech-writer",
90
+ "architecture-patterns", "strategist", "tech-writer", "storyteller",
91
91
  "seo-consultant", "content-creator", "growth-strategist",
92
92
  "bug-triage-specialist", "log-monitor",
93
93
  "mobile-development", "git-workflow", "session-management",
@@ -132,6 +132,7 @@ class SkillInvocationServer extends XrayKnowledgeSkillBase {
132
132
  "tech-writer": "documentation-generation",
133
133
  "frontend-ui-ux-engineer": "ui-ux-design",
134
134
  "frontend-engineer": "project-analysis",
135
+ "storyteller": "storyteller",
135
136
  };
136
137
  const resolvedSkill = skillAliases[skillName] || skillName;
137
138
  const availableServers = [
@@ -147,7 +148,7 @@ class SkillInvocationServer extends XrayKnowledgeSkillBase {
147
148
  "git-workflow", "content-creator", "ui-ux-design",
148
149
  "multimodal-looker", "refactoring-strategies",
149
150
  "project-analysis", "testing-best-practices",
150
- "architecture-patterns",
151
+ "architecture-patterns", "storyteller",
151
152
  ];
152
153
  if (!availableServers.includes(resolvedSkill)) {
153
154
  return {
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Storyteller MCP Server
3
+ *
4
+ * Returns storyteller SKILL.md guidance plus a session-aware writing prompt.
5
+ * The host LLM writes the story; this server supplies the contract.
6
+ */
7
+ import { execSync } from 'node:child_process';
8
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
9
+ import { dirname, join } from 'node:path';
10
+ import { fileURLToPath } from 'node:url';
11
+ import { XrayKnowledgeSkillBase } from '../shared/knowledge-skill-base.js';
12
+ const STORY_TYPES = ['reflection', 'saga', 'journey', 'narrative'];
13
+ function resolveSkillMd() {
14
+ const here = dirname(fileURLToPath(import.meta.url));
15
+ const candidates = [
16
+ join(here, '../../../skills/storyteller/SKILL.md'),
17
+ join(here, '../../skills/storyteller/SKILL.md'),
18
+ join(process.cwd(), 'node_modules/0xray/dist/skills/storyteller/SKILL.md'),
19
+ join(process.cwd(), 'node_modules/xray/dist/skills/storyteller/SKILL.md'),
20
+ ];
21
+ for (const path of candidates) {
22
+ if (existsSync(path)) {
23
+ return readFileSync(path, 'utf-8');
24
+ }
25
+ }
26
+ return '# Storyteller\n\nWrite warmly candid technical reflections with scene-first openings.';
27
+ }
28
+ function getStoryMeta(storyType) {
29
+ const defaults = {
30
+ reflection: {
31
+ location: 'docs/reflections/',
32
+ min_words: 2000,
33
+ ideal_words: 5000,
34
+ framework: 'three_act_structure',
35
+ },
36
+ saga: {
37
+ location: 'docs/reflections/deep/',
38
+ min_words: 5000,
39
+ ideal_words: 15000,
40
+ framework: 'hero_journey',
41
+ },
42
+ journey: {
43
+ location: 'docs/reflections/deep/',
44
+ min_words: 1500,
45
+ ideal_words: 4000,
46
+ framework: 'three_act_structure',
47
+ },
48
+ narrative: {
49
+ location: 'docs/reflections/',
50
+ min_words: 1000,
51
+ ideal_words: 3000,
52
+ framework: 'three_act_structure',
53
+ },
54
+ };
55
+ return defaults[storyType];
56
+ }
57
+ function gitContext() {
58
+ try {
59
+ const commits = execSync('git log --oneline -20 2>/dev/null', { encoding: 'utf-8' });
60
+ const files = execSync('git diff --name-only HEAD~10 2>/dev/null || git ls-files 2>/dev/null | head -50', { encoding: 'utf-8' });
61
+ return `Recent commits:\n${commits}\n\nRecent files:\n${files}`;
62
+ }
63
+ catch {
64
+ return 'No git context available in this workspace.';
65
+ }
66
+ }
67
+ function buildPrompt(storyType, title, meta, extraContext) {
68
+ const contextBlock = extraContext
69
+ ? `\n## Provided context\n${JSON.stringify(extraContext, null, 2)}\n`
70
+ : '';
71
+ return `Write a ${storyType} titled "${title}".
72
+
73
+ ## Requirements
74
+ - Framework: ${meta.framework}
75
+ - Target length: ${meta.ideal_words} words (minimum: ${meta.min_words})
76
+ - Save to: ${meta.location}
77
+ - Follow storyteller SKILL.md voice (warmly candid, scene-first, no executive summary)
78
+ - Include Key Takeaways and What Next sections
79
+
80
+ ## Session / repo context
81
+ ${gitContext()}
82
+ ${contextBlock}
83
+
84
+ Write the complete ${storyType} now.`;
85
+ }
86
+ function writeStoryTool(storyType, args) {
87
+ const meta = getStoryMeta(storyType);
88
+ if (args.framework)
89
+ meta.framework = args.framework;
90
+ const title = args.title ??
91
+ `${storyType.charAt(0).toUpperCase() + storyType.slice(1)} - ${new Date().toISOString().split('T')[0]}`;
92
+ const skillMd = resolveSkillMd();
93
+ const prompt = buildPrompt(storyType, title, meta, args.context);
94
+ const slug = title
95
+ .toLowerCase()
96
+ .replace(/[^a-z0-9]+/g, '-')
97
+ .replace(/^-|-$/g, '');
98
+ const filename = `${storyType}-${slug}-${new Date().toISOString().split('T')[0]}.md`;
99
+ const outputPath = args.output ?? join(meta.location, filename);
100
+ const outputDir = join(process.cwd(), dirname(outputPath));
101
+ if (!existsSync(outputDir))
102
+ mkdirSync(outputDir, { recursive: true });
103
+ const fullPath = join(process.cwd(), outputPath);
104
+ const frontmatter = `---
105
+ story_type: ${storyType}
106
+ title: "${title}"
107
+ framework: ${meta.framework}
108
+ target_words: ${meta.ideal_words}
109
+ ---
110
+
111
+ `;
112
+ writeFileSync(fullPath, `${frontmatter}\n${prompt}\n`, 'utf-8');
113
+ return {
114
+ content: [
115
+ {
116
+ type: 'text',
117
+ text: [
118
+ `Storyteller ${storyType} brief prepared.`,
119
+ `Output template: ${outputPath}`,
120
+ '',
121
+ '--- SKILL (excerpt) ---',
122
+ skillMd.slice(0, 4000),
123
+ skillMd.length > 4000 ? '\n...(truncated; full SKILL.md on disk)' : '',
124
+ '',
125
+ '--- WRITING PROMPT ---',
126
+ prompt,
127
+ '',
128
+ 'Host LLM: write the full story into the output path using the prompt above.',
129
+ ].join('\n'),
130
+ },
131
+ ],
132
+ };
133
+ }
134
+ class StorytellerServer extends XrayKnowledgeSkillBase {
135
+ constructor() {
136
+ super('storyteller', '1.0.0');
137
+ const writeSchema = {
138
+ type: 'object',
139
+ properties: {
140
+ title: { type: 'string', description: 'Story title' },
141
+ context: { type: 'object', description: 'Session context (commits, changes, notes)' },
142
+ framework: { type: 'string', description: 'Storytelling framework override' },
143
+ output: { type: 'string', description: 'Relative output path' },
144
+ },
145
+ };
146
+ this.tools = STORY_TYPES.map((storyType) => ({
147
+ name: `write_${storyType}`,
148
+ description: `Prepare ${storyType} story brief using storyteller SKILL.md`,
149
+ inputSchema: writeSchema,
150
+ }));
151
+ this.handlers = {
152
+ write_reflection: async (args) => writeStoryTool('reflection', args),
153
+ write_saga: async (args) => writeStoryTool('saga', args),
154
+ write_journey: async (args) => writeStoryTool('journey', args),
155
+ write_narrative: async (args) => writeStoryTool('narrative', args),
156
+ };
157
+ this.setupToolHandlers();
158
+ }
159
+ }
160
+ if (import.meta.url === `file://${fileURLToPath(import.meta.url)}`) {
161
+ const server = new StorytellerServer();
162
+ server.run().catch((error) => {
163
+ process.stderr.write(`FATAL: ${String(error)}\n`);
164
+ process.exit(1);
165
+ });
166
+ }
167
+ export { StorytellerServer };
@@ -159,12 +159,15 @@ export class ExecutionPlanner {
159
159
  */
160
160
  assignTasksToAgents(tasks, agentAssignments) {
161
161
  for (const task of tasks) {
162
- const complexity = task.estimatedComplexity || 30;
162
+ const complexity = this.calculateTaskComplexity(task);
163
163
  const requiredCaps = [
164
164
  task.type,
165
165
  ...(task.metadata?.memorySignals ?? []),
166
166
  ];
167
- const agent = this.capabilitiesManager.selectAgentForTask(requiredCaps, complexity, task.description) || 'orchestrator';
167
+ const operationDescription = task.metadata?.memoryHighConfidenceTrap
168
+ ? `${task.description} TYPE: ontological-trap`
169
+ : task.description;
170
+ const agent = this.capabilitiesManager.selectAgentForTask(requiredCaps, complexity, operationDescription) || 'orchestrator';
168
171
  if (!agentAssignments.has(agent)) {
169
172
  agentAssignments.set(agent, []);
170
173
  }
@@ -264,6 +267,15 @@ export class ExecutionPlanner {
264
267
  if (task.dependencies) {
265
268
  complexity += task.dependencies.length * 5;
266
269
  }
270
+ if (task.metadata?.memoryComplexityBoost !== undefined) {
271
+ complexity += task.metadata.memoryComplexityBoost;
272
+ }
273
+ else {
274
+ const provider = getProvider();
275
+ if (provider.id !== 'null' && provider.getTaskConfidence) {
276
+ complexity += provider.getTaskConfidence(toMemoryTask(task)).complexityBoost;
277
+ }
278
+ }
267
279
  return Math.min(Math.max(Math.round(complexity), 1), 100);
268
280
  }
269
281
  /**
@@ -1,5 +1,4 @@
1
1
  {
2
- "version": "3.1.0",
3
2
  "description": "0xRay Community MCPs Registry - curated API-focused MCP servers",
4
3
  "sources": [
5
4
  {
@@ -0,0 +1,92 @@
1
+ import { frameworkLogger } from '../core/framework-logger.js';
2
+ import { getMemoryRoutingProviderSync } from '../memory-routing/index.js';
3
+ const TRAP_LANGUAGE = /TYPE:\s*ontological-trap|ontological[- ]trap/i;
4
+ const DEFAULT_MIN_CONFIDENCE_GATE = 0.55;
5
+ export function shouldQueryRepertoireConfidence(description, proposalType = '') {
6
+ const text = `${description} ${proposalType}`.trim();
7
+ return TRAP_LANGUAGE.test(text);
8
+ }
9
+ export function hasHighConfidencePrimitiveMatch(routingContext, minConfidence = DEFAULT_MIN_CONFIDENCE_GATE) {
10
+ const confidences = routingContext.signalConfidences ?? {};
11
+ return Object.values(confidences).some((confidence) => confidence >= minConfidence);
12
+ }
13
+ function buildTaskText(proposalTitle, proposalDescription, proposalType) {
14
+ return [proposalTitle, proposalDescription, proposalType].filter(Boolean).join('\n');
15
+ }
16
+ /**
17
+ * Resolve Repertoire task confidence for researcher proposal analysis.
18
+ * Triggered by ontological-trap language or high-confidence primitive matches.
19
+ */
20
+ export function resolveResearcherMemoryContext(input) {
21
+ const proposalTitle = input.proposalTitle ?? '';
22
+ const proposalDescription = input.proposalDescription ?? '';
23
+ const proposalType = input.proposalType ?? '';
24
+ const taskText = buildTaskText(proposalTitle, proposalDescription, proposalType);
25
+ const provider = getMemoryRoutingProviderSync();
26
+ if (provider.id === 'null' || !provider.getTaskConfidence) {
27
+ return null;
28
+ }
29
+ const trapLanguageDetected = shouldQueryRepertoireConfidence(proposalDescription, proposalType);
30
+ const routingContext = provider.buildRoutingContext(taskText);
31
+ const primitiveMatchDetected = hasHighConfidencePrimitiveMatch(routingContext);
32
+ if (!trapLanguageDetected && !primitiveMatchDetected) {
33
+ return null;
34
+ }
35
+ const confidence = provider.getTaskConfidence({
36
+ id: 'researcher-proposal',
37
+ description: taskText,
38
+ type: proposalType || 'governance',
39
+ });
40
+ const matchedSignals = confidence.matchedSignals.length > 0
41
+ ? confidence.matchedSignals
42
+ : routingContext.matchedSignals;
43
+ const context = {
44
+ providerId: provider.id,
45
+ confidence,
46
+ matchedSignals,
47
+ recommendedAgent: confidence.recommendedAgent,
48
+ triggeredBy: trapLanguageDetected ? 'trap-language' : 'high-confidence-primitives',
49
+ };
50
+ if (confidence.highConfidenceTrapPresent) {
51
+ frameworkLogger.log('mcps/researcher', 'repertoire-trap-detected', 'info', {
52
+ providerId: provider.id,
53
+ matchedSignals,
54
+ complexityBoost: confidence.complexityBoost,
55
+ recommendedAgent: confidence.recommendedAgent,
56
+ triggeredBy: context.triggeredBy,
57
+ });
58
+ }
59
+ return context;
60
+ }
61
+ export function buildMemoryRoutingEvidence(context) {
62
+ const { confidence, matchedSignals, recommendedAgent } = context;
63
+ const signalSummary = confidence.signals
64
+ .map((entry) => `${entry.name} (${entry.confidence.toFixed(2)})`)
65
+ .join(', ');
66
+ const lines = [
67
+ `Repertoire memory routing (${context.providerId}, trigger: ${context.triggeredBy})`,
68
+ `Matched signals: ${matchedSignals.join(', ') || 'none'}`,
69
+ `Signal confidences: ${signalSummary || 'none'}`,
70
+ `High-confidence trap present: ${confidence.highConfidenceTrapPresent}`,
71
+ `Complexity boost: ${confidence.complexityBoost}`,
72
+ ];
73
+ if (recommendedAgent) {
74
+ lines.push(`Recommended agent for trap handling: ${recommendedAgent}`);
75
+ }
76
+ return lines;
77
+ }
78
+ export function formatMemoryRoutingBlock(context) {
79
+ const { confidence, matchedSignals, recommendedAgent } = context;
80
+ const lines = [
81
+ 'MEMORY_ROUTING:',
82
+ ` provider: ${context.providerId}`,
83
+ ` trigger: ${context.triggeredBy}`,
84
+ ` matchedSignals: ${matchedSignals.join(', ') || 'none'}`,
85
+ ` highConfidenceTrapPresent: ${confidence.highConfidenceTrapPresent}`,
86
+ ` complexityBoost: ${confidence.complexityBoost}`,
87
+ ];
88
+ if (recommendedAgent) {
89
+ lines.push(` recommendedAgent: ${recommendedAgent}`);
90
+ }
91
+ return lines.join('\n');
92
+ }
@@ -11,6 +11,7 @@ import * as fs from "fs";
11
11
  import * as path from "path";
12
12
  import { frameworkLogger } from "../core/framework-logger.js";
13
13
  import { tryLLMGovernance } from "../governance/llm-governance-provider.js";
14
+ import { buildMemoryRoutingEvidence, formatMemoryRoutingBlock, resolveResearcherMemoryContext, } from "./researcher-confidence.js";
14
15
  import { XrayKnowledgeSkillBase } from "./shared/knowledge-skill-base.js";
15
16
  class XrayLibrarianServer extends XrayKnowledgeSkillBase {
16
17
  constructor() {
@@ -377,13 +378,28 @@ class XrayLibrarianServer extends XrayKnowledgeSkillBase {
377
378
  */
378
379
  async analyzeProposal(args) {
379
380
  const { proposalTitle = "", proposalDescription = "", evidence = [], proposalType = "" } = args || {};
380
- const vote = await tryLLMGovernance("researcher", proposalTitle || "", proposalDescription || "", evidence || [], proposalType || "");
381
+ const memoryContext = resolveResearcherMemoryContext({
382
+ proposalTitle,
383
+ proposalDescription,
384
+ proposalType,
385
+ });
386
+ const enrichedEvidence = [...(evidence || [])];
387
+ if (memoryContext?.confidence.highConfidenceTrapPresent) {
388
+ enrichedEvidence.push(...buildMemoryRoutingEvidence(memoryContext));
389
+ }
390
+ const vote = await tryLLMGovernance("researcher", proposalTitle || "", proposalDescription || "", enrichedEvidence, proposalType || "");
391
+ const memoryRoutingBlock = memoryContext?.confidence.highConfidenceTrapPresent
392
+ ? `\n${formatMemoryRoutingBlock(memoryContext)}`
393
+ : "";
381
394
  if (!vote) {
395
+ const abstainReason = memoryContext?.confidence.highConfidenceTrapPresent
396
+ ? "No LLM governance provider configured. Repertoire detected a high-confidence ontological trap — route to the recommended agent before proceeding."
397
+ : "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";
382
398
  return {
383
399
  content: [
384
400
  {
385
401
  type: "text",
386
- 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",
402
+ text: `DECISION: abstain\nCONFIDENCE: 0.50\nREASONING: ${abstainReason}${memoryRoutingBlock}`,
387
403
  },
388
404
  ],
389
405
  };
@@ -392,7 +408,7 @@ class XrayLibrarianServer extends XrayKnowledgeSkillBase {
392
408
  content: [
393
409
  {
394
410
  type: "text",
395
- text: `DECISION: ${vote.decision}\nCONFIDENCE: ${vote.confidence.toFixed(2)}\nREASONING: ${vote.reasoning}`,
411
+ text: `DECISION: ${vote.decision}\nCONFIDENCE: ${vote.confidence.toFixed(2)}\nREASONING: ${vote.reasoning}${memoryRoutingBlock}`,
396
412
  },
397
413
  ],
398
414
  };
@@ -45,6 +45,18 @@ export class NullMemoryRoutingProvider {
45
45
  context: { ...EMPTY_CONTEXT },
46
46
  };
47
47
  }
48
+ getTaskConfidence() {
49
+ return {
50
+ signals: [],
51
+ matchedSignals: [],
52
+ avgConfidence: 0,
53
+ maxConfidence: 0,
54
+ highConfidenceTrapPresent: false,
55
+ ontologicalTrapDetected: false,
56
+ complexityBoost: 0,
57
+ recommendedAgent: null,
58
+ };
59
+ }
48
60
  }
49
61
  export function createMemoryRoutingProvider() {
50
62
  return new NullMemoryRoutingProvider();
@@ -113,7 +113,7 @@ export class UniversalRegistryBridge {
113
113
  currentAgent = {
114
114
  name: nameMatch[1].trim(),
115
115
  description: "",
116
- version: "3.1.0",
116
+ version: "",
117
117
  };
118
118
  inAgent = true;
119
119
  continue;