0xray 3.4.1 → 3.4.2

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 (56) hide show
  1. package/.xray/codex.json +598 -0
  2. package/.xray/config.json +25 -0
  3. package/.xray/features.json +146 -0
  4. package/.xray/features.schema.json +33 -0
  5. package/AGENTS-consumer.md +127 -10
  6. package/AGENTS.md +172 -56
  7. package/README.md +159 -82
  8. package/SKILLS.md +79 -53
  9. package/dist/AGENTS.md +172 -56
  10. package/dist/CHANGELOG.md +79 -52
  11. package/dist/README.md +159 -82
  12. package/dist/SKILLS.md +79 -53
  13. package/dist/core/features-config.js +5 -0
  14. package/dist/integrations/grok/hooks/grok-hook-activity.js +53 -0
  15. package/dist/integrations/grok/hooks/grok-hook-utils.js +261 -0
  16. package/dist/integrations/grok/hooks/pre-tool-use.js +85 -115
  17. package/dist/integrations/grok/hooks/session-start.js +52 -0
  18. package/dist/integrations/grok/plugin/0xray/hooks/hooks.json +20 -3
  19. package/dist/mcps/config/server-config-registry.js +4 -3
  20. package/dist/mcps/orchestrator/handlers/complexity-handler.js +33 -3
  21. package/dist/mcps/orchestrator/server.js +1 -1
  22. package/dist/mcps/researcher.server.js +3 -0
  23. package/dist/nucleus/autonomy-kernel.js +176 -0
  24. package/dist/nucleus/index.js +1 -0
  25. package/dist/skills/boot-orchestrator/SKILL.md +1 -5
  26. package/dist/skills/orchestrator/SKILL.md +35 -12
  27. package/dist/skills/researcher/SKILL.md +17 -4
  28. package/dist/skills/strategist/SKILL.md +12 -0
  29. package/dist/skills/testing-strategy/SKILL.md +13 -2
  30. package/package.json +23 -8
  31. package/scripts/node/consumer-install-smoke.mjs +163 -0
  32. package/scripts/node/install-bridges.cjs +19 -6
  33. package/scripts/node/pre-publish-guard.js +107 -168
  34. package/scripts/node/reconcile-version.mjs +147 -0
  35. package/scripts/node/release-gate.mjs +66 -0
  36. package/scripts/node/release.js +5 -147
  37. package/scripts/node/release.mjs +106 -181
  38. package/scripts/node/setup.cjs +12 -22
  39. package/scripts/node/sync-versions.mjs +12 -134
  40. package/scripts/node/universal-version-manager.js +4 -0
  41. package/scripts/node/validate-release-docs.mjs +299 -0
  42. package/scripts/node/version-manager.mjs +225 -49
  43. package/src/integrations/grok/plugin/0xray/hooks/hooks.json +20 -3
  44. package/src/mcps/config/__tests__/server-config-registry.test.ts +9 -0
  45. package/src/mcps/config/server-config-registry.ts +5 -3
  46. package/src/mcps/orchestrator/handlers/complexity-handler.ts +54 -3
  47. package/src/mcps/orchestrator/server.ts +1 -1
  48. package/src/mcps/researcher.server.ts +4 -0
  49. package/src/skills/boot-orchestrator/SKILL.md +1 -5
  50. package/src/skills/orchestrator/SKILL.md +35 -12
  51. package/src/skills/researcher/SKILL.md +17 -4
  52. package/src/skills/strategist/SKILL.md +12 -0
  53. package/src/skills/testing-strategy/SKILL.md +13 -2
  54. package/xray/config.json +25 -0
  55. package/xray/features.json +146 -0
  56. package/xray/features.schema.json +33 -0
@@ -160,8 +160,9 @@ function generateChangelogFromCommits(commits) {
160
160
 
161
161
  /**
162
162
  * Count actual framework components
163
+ * @param {string} [baseDir]
163
164
  */
164
- function getFrameworkCounts() {
165
+ export function getFrameworkCounts(baseDir = rootDir) {
165
166
  const counts = {
166
167
  agents: 0,
167
168
  mcps: 0,
@@ -169,31 +170,29 @@ function getFrameworkCounts() {
169
170
  };
170
171
 
171
172
  // Count agents (.yml files in src/opencode/agents/ — source of truth)
172
- const agentsDir = path.join(rootDir, 'src/opencode/agents');
173
+ const agentsDir = path.join(baseDir, 'src/opencode/agents');
173
174
  if (fs.existsSync(agentsDir)) {
174
175
  counts.agents = fs.readdirSync(agentsDir)
175
176
  .filter(f => f.endsWith('.yml'))
176
177
  .length;
177
178
  }
178
179
 
179
- // Count MCP servers (.server.js files in dist/mcps/)
180
- const mcpsDir = path.join(rootDir, 'dist/mcps');
181
- if (fs.existsSync(mcpsDir)) {
182
- counts.mcps = fs.readdirSync(mcpsDir)
183
- .filter(f => f.endsWith('.server.js'))
184
- .length;
185
- } else {
186
- // Try node_modules path for published package
187
- const nodeModulesMcps = path.join(rootDir, 'node_modules/xray/dist/mcps');
188
- if (fs.existsSync(nodeModulesMcps)) {
189
- counts.mcps = fs.readdirSync(nodeModulesMcps)
190
- .filter(f => f.endsWith('.server.js'))
191
- .length;
180
+ // Consumer MCP count from .mcp.json SSOT (7 servers), not internal dist/mcps inventory
181
+ const mcpJsonPath = path.join(baseDir, '.mcp.json');
182
+ if (fs.existsSync(mcpJsonPath)) {
183
+ try {
184
+ const mcpJson = JSON.parse(fs.readFileSync(mcpJsonPath, 'utf-8'));
185
+ const servers = mcpJson.mcpServers || mcpJson.servers || {};
186
+ counts.mcps = Object.keys(servers).length;
187
+ } catch {
188
+ counts.mcps = 7;
192
189
  }
190
+ } else {
191
+ counts.mcps = 7;
193
192
  }
194
193
 
195
194
  // Count skills (directories in src/skills/ with SKILL.md)
196
- const skillsDir = path.join(rootDir, 'src/skills');
195
+ const skillsDir = path.join(baseDir, 'src/skills');
197
196
  if (fs.existsSync(skillsDir)) {
198
197
  counts.skills = fs.readdirSync(skillsDir)
199
198
  .filter(f => fs.statSync(path.join(skillsDir, f)).isDirectory())
@@ -230,9 +229,21 @@ ${content}
230
229
  `;
231
230
  }
232
231
 
232
+ function changelogHasVersion(newVersion) {
233
+ const changelogPath = path.join(rootDir, 'CHANGELOG.md');
234
+ if (!fs.existsSync(changelogPath)) return false;
235
+ const changelog = fs.readFileSync(changelogPath, 'utf-8');
236
+ return new RegExp(`^## \\[${newVersion.replace(/\./g, '\\.')}\\]`, 'm').test(changelog);
237
+ }
238
+
233
239
  function updateChangelog(newVersion, changeDescription) {
234
240
  const changelogPath = path.join(rootDir, 'CHANGELOG.md');
235
241
  let changelog = fs.readFileSync(changelogPath, 'utf-8');
242
+
243
+ if (changelogHasVersion(newVersion)) {
244
+ console.log(`ℹ️ CHANGELOG.md already has [${newVersion}] — skipping duplicate entry`);
245
+ return;
246
+ }
236
247
 
237
248
  // Find the position after the header and insert new entry
238
249
  const headerEnd = changelog.indexOf('## [');
@@ -259,6 +270,12 @@ function updateReadme(counts, newVersion) {
259
270
  }
260
271
 
261
272
  let readme = fs.readFileSync(readmePath, 'utf-8');
273
+
274
+ // Update header line: **v3.4.1** — 42 agents · 45 skills · 7 MCP servers · ...
275
+ readme = readme.replace(
276
+ /^\*\*v[\d.]+\*\* — \d+ agents · \d+ skills · \d+ MCP servers? · \d+ codex terms(?: · [\d,]+ tests)?/m,
277
+ `**v${newVersion}** — ${counts.agents} agents · ${counts.skills} skills · ${counts.mcps} MCP servers · 68 codex terms · 3,226 tests`
278
+ );
262
279
 
263
280
  // Update version badge: [![Version](https://img.shields.io/badge/version-1.6.x-blue...)]
264
281
  readme = readme.replace(
@@ -294,6 +311,84 @@ function updateReadme(counts, newVersion) {
294
311
  console.log(`✅ Updated README.md (version: ${newVersion}, agents: ${counts.agents}, mcps: ${counts.mcps}, skills: ${counts.skills})`);
295
312
  }
296
313
 
314
+ export const DOCS_SITE_HEADER_FILES = [
315
+ 'docs-site/docs/README.md',
316
+ 'docs-site/docs/index.md',
317
+ 'docs-site/docs/introduction.md',
318
+ 'docs-site/docs/guides/getting-started.md',
319
+ 'docs-site/docs/full-reference.md',
320
+ ];
321
+
322
+ export function buildDocsHeader(counts, newVersion) {
323
+ return `**v${newVersion}** — ${counts.agents} agents · ${counts.skills} skills · ${counts.mcps} MCP servers · 68 codex terms · 3,226 tests`;
324
+ }
325
+
326
+ function syncDocsSiteHeaders(counts, newVersion) {
327
+ const header = buildDocsHeader(counts, newVersion);
328
+ const headerRe = /^\*{0,2}v?[\d.]*\*{0,2}\s*—?\s*\d+ agents · \d+ skills · \d+ MCP servers? · \d+ codex terms(?: · [\d,]+ tests)?/m;
329
+ for (const rel of DOCS_SITE_HEADER_FILES) {
330
+ const filePath = path.join(rootDir, rel);
331
+ if (!fs.existsSync(filePath)) continue;
332
+ let content = fs.readFileSync(filePath, 'utf-8');
333
+ if (headerRe.test(content)) {
334
+ content = content.replace(headerRe, header);
335
+ fs.writeFileSync(filePath, content);
336
+ console.log(`✅ Updated ${rel} header`);
337
+ }
338
+ }
339
+ }
340
+
341
+ function updatePluginJsonVersion(newVersion) {
342
+ const pluginPath = path.join(rootDir, '.grok-plugin/plugin.json');
343
+ if (!fs.existsSync(pluginPath)) return;
344
+ const plugin = JSON.parse(fs.readFileSync(pluginPath, 'utf-8'));
345
+ plugin.version = newVersion;
346
+ fs.writeFileSync(pluginPath, JSON.stringify(plugin, null, 2) + '\n');
347
+ console.log(`✅ Updated .grok-plugin/plugin.json (version: ${newVersion})`);
348
+ }
349
+
350
+ function updateConsumerAgentsHeader(newVersion, counts) {
351
+ const consumerPath = path.join(rootDir, 'AGENTS-consumer.md');
352
+ if (!fs.existsSync(consumerPath)) return;
353
+ let content = fs.readFileSync(consumerPath, 'utf-8');
354
+ content = content.replace(
355
+ /^\*\*v[\d.]+\*\* — \d+ MCP servers · \d+ skills · \d+ codex terms/m,
356
+ `**v${newVersion}** — ${counts.mcps} MCP servers · ${counts.skills} skills · 68 codex terms`
357
+ );
358
+ fs.writeFileSync(consumerPath, content);
359
+ console.log(`✅ Updated AGENTS-consumer.md version header`);
360
+ }
361
+
362
+ function updateSkillsMd(counts, newVersion) {
363
+ const skillsPath = path.join(rootDir, 'SKILLS.md');
364
+ if (!fs.existsSync(skillsPath)) {
365
+ console.log(`⚠️ SKILLS.md not found, skipping`);
366
+ return;
367
+ }
368
+ let content = fs.readFileSync(skillsPath, 'utf-8');
369
+ content = content.replace(
370
+ /^\*\*v[\d.]+\*\* — \*\*\d+ skills\*\*/m,
371
+ `**v${newVersion}** — **${counts.skills} skills**`
372
+ );
373
+ fs.writeFileSync(skillsPath, content);
374
+ console.log(`✅ Updated SKILLS.md version header`);
375
+ }
376
+
377
+ function applyAgentCountUpdates(content, counts) {
378
+ let agentsMd = content;
379
+
380
+ // Legacy header count update (min compat for old consumer AGENTS.md files only; xray v2 YML SSOT primary)
381
+ agentsMd = agentsMd.replace(
382
+ /0xRay\s*2\.0\s*-\s*\d+\s+Agents|0xRay\s*-\s*\d+\s+Agents/,
383
+ `xray v2 - ${counts.agents} Agents`
384
+ );
385
+
386
+ agentsMd = agentsMd.replace(/\d+\s+MCPs?/g, `${counts.mcps} MCPs`);
387
+ agentsMd = agentsMd.replace(/\d+\s+Skills?/g, `${counts.skills} Skills`);
388
+
389
+ return agentsMd;
390
+ }
391
+
297
392
  /**
298
393
  * Update AGENTS.md with actual framework counts
299
394
  */
@@ -303,29 +398,38 @@ function updateAgentsMd(counts) {
303
398
  console.log(`⚠️ AGENTS.md not found, skipping`);
304
399
  return;
305
400
  }
306
-
307
- let agentsMd = fs.readFileSync(agentsPath, 'utf-8');
308
-
309
- // Legacy header count update (min compat for old consumer AGENTS.md files only; xray v2 YML SSOT primary)
310
- agentsMd = agentsMd.replace(
311
- /0xRay\s*2\.0\s*-\s*\d+\s+Agents|0xRay\s*-\s*\d+\s+Agents/,
312
- `xray v2 - ${counts.agents} Agents`
313
- );
314
-
315
- agentsMd = agentsMd.replace(
316
- /\d+\s+MCPs?/g,
317
- `${counts.mcps} MCPs`
318
- );
319
-
320
- agentsMd = agentsMd.replace(
321
- /\d+\s+Skills?/g,
322
- `${counts.skills} Skills`
323
- );
324
-
325
- fs.writeFileSync(agentsPath, agentsMd);
401
+
402
+ fs.writeFileSync(agentsPath, applyAgentCountUpdates(fs.readFileSync(agentsPath, 'utf-8'), counts));
326
403
  console.log(`✅ Updated AGENTS.md`);
327
404
  }
328
405
 
406
+ function updateAgentsConsumerMd(counts) {
407
+ const agentsPath = path.join(rootDir, 'AGENTS-consumer.md');
408
+ if (!fs.existsSync(agentsPath)) {
409
+ console.log(`⚠️ AGENTS-consumer.md not found, skipping`);
410
+ return;
411
+ }
412
+
413
+ fs.writeFileSync(agentsPath, applyAgentCountUpdates(fs.readFileSync(agentsPath, 'utf-8'), counts));
414
+ console.log(`✅ Updated AGENTS-consumer.md`);
415
+ }
416
+
417
+ function updateDocsReadme(newVersion) {
418
+ const docsReadmePath = path.join(rootDir, 'docs/README.md');
419
+ if (!fs.existsSync(docsReadmePath)) {
420
+ console.log(`⚠️ docs/README.md not found, skipping`);
421
+ return;
422
+ }
423
+
424
+ let readme = fs.readFileSync(docsReadmePath, 'utf-8');
425
+ readme = readme.replace(
426
+ /img.shields.io\/badge\/version-[\d.]+/,
427
+ `img.shields.io/badge/version-${newVersion}`
428
+ );
429
+ fs.writeFileSync(docsReadmePath, readme);
430
+ console.log(`✅ Updated docs/README.md (version: ${newVersion})`);
431
+ }
432
+
329
433
  function getCurrentVersion() {
330
434
  const pkg = JSON.parse(fs.readFileSync(path.join(rootDir, 'package.json'), 'utf-8'));
331
435
  return pkg.version;
@@ -375,18 +479,7 @@ function updateVersion(newVersion, changeDescription = '') {
375
479
  console.log(`✅ Updated package.json`);
376
480
 
377
481
  // init.sh legacy version key no longer updated (final xray cutover - no historical scaffolding)
378
-
379
- // Update docs/README.md version badge
380
- const docsReadmePath = path.join(rootDir, 'docs/README.md');
381
- if (fs.existsSync(docsReadmePath)) {
382
- let readme = fs.readFileSync(docsReadmePath, 'utf-8');
383
- readme = readme.replace(
384
- /img.shields.io\/badge\/version-[\d.]+/,
385
- `img.shields.io/badge/version-${newVersion}`
386
- );
387
- fs.writeFileSync(docsReadmePath, readme);
388
- console.log(`✅ Updated docs/README.md (version: ${newVersion})`);
389
- }
482
+ updateDocsReadme(newVersion);
390
483
 
391
484
  // Update UVM's own version string
392
485
  const uvmPath = path.join(rootDir, 'scripts/node/universal-version-manager.js');
@@ -412,7 +505,12 @@ function updateVersion(newVersion, changeDescription = '') {
412
505
  console.log(`\n📊 Framework counts: ${counts.agents} agents, ${counts.mcps} MCPs, ${counts.skills} skills`);
413
506
 
414
507
  updateReadme(counts, newVersion);
508
+ syncDocsSiteHeaders(counts, newVersion);
509
+ updatePluginJsonVersion(newVersion);
510
+ updateConsumerAgentsHeader(newVersion, counts);
415
511
  updateAgentsMd(counts);
512
+ updateAgentsConsumerMd(counts);
513
+ updateSkillsMd(counts, newVersion);
416
514
 
417
515
  console.log(`\n🎉 Version updated to ${newVersion}\n`);
418
516
  }
@@ -437,8 +535,74 @@ function createGitTag(version, message) {
437
535
  }
438
536
  }
439
537
 
538
+ /** Paths written by release artifact updates (existing files only). */
539
+ export function getReleaseArtifactPaths() {
540
+ const candidates = [
541
+ 'package.json',
542
+ 'CHANGELOG.md',
543
+ 'README.md',
544
+ 'AGENTS.md',
545
+ 'AGENTS-consumer.md',
546
+ 'SKILLS.md',
547
+ '.grok-plugin/plugin.json',
548
+ 'docs/README.md',
549
+ 'docs-site/docs/README.md',
550
+ 'docs-site/docs/index.md',
551
+ 'docs-site/docs/introduction.md',
552
+ 'docs-site/docs/guides/getting-started.md',
553
+ 'docs-site/docs/full-reference.md',
554
+ 'docs-site/docs/guides/integrations.md',
555
+ 'docs-site/docs/guides/features-since-3.1.md',
556
+ 'docs-site/docs/guides/features-json.md',
557
+ 'docs-site/docs/guides/memory-routing.md',
558
+ 'docs-site/docs/guides/aside-context.md',
559
+ 'docs-site/docs/guides/repertoire.md',
560
+ 'docs-site/docs/guides/consumer-migration.md',
561
+ 'docs-site/docs/mcp/README.md',
562
+ 'docs-site/docs/agents/README.md',
563
+ 'docs-site/sidebars.ts',
564
+ ];
565
+ return candidates.filter((rel) => fs.existsSync(path.join(rootDir, rel)));
566
+ }
567
+
568
+ /** Update CHANGELOG + README + AGENTS (+ consumer/docs) for current package.json version (no bump). */
569
+ function updateReleaseArtifactsOnly(changeDescription = '') {
570
+ const current = getCurrentVersion();
571
+ console.log(`\n📌 Release artifacts for v${current}\n`);
572
+ const counts = getFrameworkCounts();
573
+ console.log(`📊 Framework counts: ${counts.agents} agents, ${counts.mcps} MCPs, ${counts.skills} skills`);
574
+ updateChangelog(current, changeDescription);
575
+ updateReadme(counts, current);
576
+ syncDocsSiteHeaders(counts, current);
577
+ updatePluginJsonVersion(current);
578
+ updateConsumerAgentsHeader(current, counts);
579
+ updateDocsReadme(current);
580
+ updateAgentsMd(counts);
581
+ updateAgentsConsumerMd(counts);
582
+ updateSkillsMd(counts, current);
583
+ runReleaseDocsValidation();
584
+ console.log(`\n✅ Release artifacts updated for v${current}\n`);
585
+ }
586
+
587
+ function runReleaseDocsValidation() {
588
+ try {
589
+ execSync('node scripts/node/validate-release-docs.mjs', {
590
+ cwd: rootDir,
591
+ stdio: 'inherit',
592
+ });
593
+ } catch {
594
+ console.error('\n❌ Release artifact docs failed validation — fix before tagging\n');
595
+ process.exit(1);
596
+ }
597
+ }
598
+
440
599
  function main() {
441
600
  const args = process.argv.slice(2);
601
+
602
+ if (args.includes('--artifacts-only')) {
603
+ updateReleaseArtifactsOnly('');
604
+ return;
605
+ }
442
606
 
443
607
  // Handle --help flag first
444
608
  if (args.includes('--help') || args.includes('-h')) {
@@ -448,6 +612,7 @@ function main() {
448
612
  console.log(` node scripts/node/version-manager.mjs [major|minor|patch] [description]`);
449
613
  console.log(` node scripts/node/version-manager.mjs 1.6.9 "Description of changes"`);
450
614
  console.log(` node scripts/node/version-manager.mjs patch --tag # auto-changelog + git tag`);
615
+ console.log(` node scripts/node/version-manager.mjs --artifacts-only # CHANGELOG/README/AGENTS/docs`);
451
616
  console.log(`\nExamples:`);
452
617
  console.log(` node scripts/node/version-manager.mjs patch # 1.6.8 -> 1.6.9 (auto-generates changelog from git)`);
453
618
  console.log(` node scripts/node/version-manager.mjs minor # 1.6.8 -> 1.7.0`);
@@ -472,7 +637,13 @@ function main() {
472
637
  console.log(`📊 Framework counts: ${counts.agents} agents, ${counts.mcps} MCPs, ${counts.skills} skills`);
473
638
  updateChangelog(current, '');
474
639
  updateReadme(counts, current);
640
+ syncDocsSiteHeaders(counts, current);
641
+ updatePluginJsonVersion(current);
642
+ updateConsumerAgentsHeader(current, counts);
643
+ updateDocsReadme(current);
475
644
  updateAgentsMd(counts);
645
+ updateAgentsConsumerMd(counts);
646
+ updateSkillsMd(counts, current);
476
647
 
477
648
  // Update UVM's own version string to match package.json
478
649
  const uvmPath = path.join(rootDir, 'scripts/node/universal-version-manager.js');
@@ -521,4 +692,9 @@ function main() {
521
692
  }
522
693
  }
523
694
 
524
- main();
695
+ const isMainModule =
696
+ process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
697
+
698
+ if (isMainModule) {
699
+ main();
700
+ }
@@ -20,11 +20,28 @@
20
20
  "hooks": [
21
21
  {
22
22
  "type": "command",
23
- "command": "echo",
24
- "args": ["[0xRay] Grok session started with 0xRay governance enabled"]
23
+ "command": "node",
24
+ "args": [
25
+ "${XRAY_AI_PATH:-node_modules/0xray}/dist/integrations/grok/hooks/session-start.js"
26
+ ],
27
+ "timeout": 15000
28
+ }
29
+ ]
30
+ }
31
+ ],
32
+ "UserPromptSubmit": [
33
+ {
34
+ "hooks": [
35
+ {
36
+ "type": "command",
37
+ "command": "node",
38
+ "args": [
39
+ "${XRAY_AI_PATH:-node_modules/0xray}/dist/integrations/grok/hooks/session-start.js"
40
+ ],
41
+ "timeout": 15000
25
42
  }
26
43
  ]
27
44
  }
28
45
  ]
29
46
  }
30
- }
47
+ }
@@ -69,6 +69,15 @@ describe('ServerConfigRegistry', () => {
69
69
  });
70
70
  });
71
71
 
72
+ describe('framework path resolution', () => {
73
+ it('should resolve MCP paths from 0xray package without fallback warning', () => {
74
+ const config = registry.get('code-review');
75
+ expect(config?.args?.[0]).toBeDefined();
76
+ expect(String(config?.args?.[0])).toMatch(/mcps\/knowledge-skills\/code-review\.server\.js$/);
77
+ expect(String(config?.args?.[0])).not.toContain('node_modules/0xray/dist/dist');
78
+ });
79
+ });
80
+
72
81
  describe('default servers', () => {
73
82
  it('should have code-review server registered by default', () => {
74
83
  expect(registry.has('code-review')).toBe(true);
@@ -44,10 +44,12 @@ function resolveFrameworkPaths(): { frameworkRoot: string; mcpServersPath: strin
44
44
  if (fs.existsSync(pkgPath)) {
45
45
  try {
46
46
  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
47
- if (pkg.name === '0xray' && pkg.xray) {
48
- const xrayCfg = pkg.xray as Record<string, string>;
47
+ if (pkg.name === '0xray') {
48
+ const xrayCfg = (pkg.xray ?? {}) as Record<string, string>;
49
49
  const frameworkRoot = currentDir;
50
- const declaredMcp = xrayCfg.mcpServersPath || (xrayCfg.dist ? join(xrayCfg.dist, 'mcps') : 'dist/mcps');
50
+ const declaredMcp =
51
+ xrayCfg.mcpServersPath ||
52
+ (xrayCfg.dist ? join(xrayCfg.dist, 'mcps') : 'dist/mcps');
51
53
  return {
52
54
  frameworkRoot,
53
55
  mcpServersPath: join(frameworkRoot, declaredMcp),
@@ -5,6 +5,11 @@
5
5
  */
6
6
 
7
7
  import { frameworkLogger } from '../../../core/framework-logger.js';
8
+ import {
9
+ buildLeadDevPlan,
10
+ isLeadDevModeActive,
11
+ persistLeadDevPlan,
12
+ } from '../../../nucleus/autonomy-kernel.js';
8
13
  import { getExecutionPlanner } from '../execution/execution-planner.js';
9
14
  import { addObservations, extractComplexityObservations } from '../aside-context.js';
10
15
  import type { OrchestrationTask, ComplexityAnalysis } from '../types.js';
@@ -40,11 +45,36 @@ export class ComplexityHandler {
40
45
  addObservations(asideId, extractComplexityObservations(analysis));
41
46
  }
42
47
 
48
+ const primaryDescription = tasks.map((t) => t.description).filter(Boolean).join(' ');
49
+ const taskTypes = tasks.map((t) => t.type).filter(Boolean) as string[];
50
+ const leadDevPlan =
51
+ isLeadDevModeActive() && primaryDescription
52
+ ? buildLeadDevPlan(primaryDescription, taskTypes.length ? taskTypes : ['implement'])
53
+ : null;
54
+
55
+ if (leadDevPlan) {
56
+ try {
57
+ persistLeadDevPlan(leadDevPlan);
58
+ } catch (err) {
59
+ await frameworkLogger.log(
60
+ 'orchestrator.server',
61
+ 'lead-dev-plan-persist-failed',
62
+ 'warning',
63
+ { error: err instanceof Error ? err.message : String(err) },
64
+ );
65
+ }
66
+ }
67
+
43
68
  return {
44
69
  content: [
45
70
  {
46
71
  type: 'text',
47
- text: this.formatComplexityResponse(analysis, recommendations, tasks.length),
72
+ text: this.formatComplexityResponse(
73
+ analysis,
74
+ recommendations,
75
+ tasks.length,
76
+ leadDevPlan,
77
+ ),
48
78
  },
49
79
  ],
50
80
  };
@@ -98,8 +128,29 @@ export class ComplexityHandler {
98
128
  private formatComplexityResponse(
99
129
  analysis: ComplexityAnalysis,
100
130
  recommendations: string[],
101
- taskCount: number
131
+ taskCount: number,
132
+ leadDevPlan: ReturnType<typeof buildLeadDevPlan> = null,
102
133
  ): string {
134
+ const leadDevSection = leadDevPlan
135
+ ? `
136
+
137
+ **Lead-dev plan (codex ${leadDevPlan.codexTerms.join(', ')}):**
138
+ ${leadDevPlan.phases
139
+ .map(
140
+ (p) =>
141
+ `### ${p.id} — ${p.name}\n${p.todos
142
+ .map((t) => `- [ ] ${t.id} (${t.subagent}): ${t.task}`)
143
+ .join('\n')}`,
144
+ )
145
+ .join('\n\n')}
146
+
147
+ **Test protocol:** ${leadDevPlan.testProtocol.hint}
148
+
149
+ \`\`\`json
150
+ ${JSON.stringify(leadDevPlan, null, 2)}
151
+ \`\`\``
152
+ : '';
153
+
103
154
  return `🔍 Complexity Analysis Results
104
155
 
105
156
  **Tasks Analyzed:** ${taskCount}
@@ -126,6 +177,6 @@ ${analysis.agentAssignments
126
177
  ${recommendations.map((r) => `• 💡 ${r}`).join('\n')}
127
178
 
128
179
  **Execution Estimate:** ${analysis.estimatedDuration}ms
129
- **Parallel Potential:** ${Math.round(analysis.parallelPotential * 100)}%`;
180
+ **Parallel Potential:** ${Math.round(analysis.parallelPotential * 100)}%${leadDevSection}`;
130
181
  }
131
182
  }
@@ -140,7 +140,7 @@ export class OrchestratorServer {
140
140
  {
141
141
  name: 'analyze-complexity',
142
142
  description:
143
- 'Analyze task complexity and recommend optimal orchestration strategy',
143
+ 'Analyze task complexity and recommend orchestration strategy. When lead_dev_mode is on (features.json), includes phased plan + todos + subagent routes.',
144
144
  inputSchema: {
145
145
  type: 'object',
146
146
  properties: {
@@ -13,6 +13,7 @@ import * as fs from "fs";
13
13
  import * as path from "path";
14
14
  import { frameworkLogger } from "../core/framework-logger.js";
15
15
  import { tryLLMGovernance } from "../governance/llm-governance-provider.js";
16
+ import { initializeMemoryRouting } from "../memory-routing/index.js";
16
17
  import {
17
18
  buildMemoryRoutingEvidence,
18
19
  formatMemoryRoutingBlock,
@@ -53,6 +54,9 @@ class XrayLibrarianServer extends XrayKnowledgeSkillBase {
53
54
  constructor() {
54
55
  super("researcher", "3.1.0");
55
56
 
57
+ // Kick off MemoryRoutingProvider load so trap routing is ready in MCP subprocess mode.
58
+ initializeMemoryRouting();
59
+
56
60
  this.tools = [
57
61
  {
58
62
  name: "search_codebase",
@@ -28,10 +28,6 @@ Framework initialization and boot orchestration.
28
28
  - **initialization**: Initialization
29
29
  - **framework_startup**: Framework startup
30
30
 
31
- ## Usage
32
-
33
- This skill provides infrastructure capabilities for boot orchestrator functionality.
34
-
35
31
  ## Integration
36
32
 
37
- Activated when infrastructure capabilities are requested through the skills system.
33
+ Lead-dev boot is handled by SessionStart hook + `orchestrator` skill — see `multi_agent_orchestration.lead_dev_mode` in features.json.
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  source: framework
3
3
  name: orchestrator
4
- description: Multi-agent workflow coordination and task delegation
4
+ description: Multi-agent workflow coordination, lead-dev operating model (codex 67-68), and task delegation. Default when suit is worn — no keywords required.
5
5
  author: Xray Framework
6
6
  version: 1.0.0
7
7
  schema_version: "1.0"
8
- tags: [orchestration, orchestrator]
8
+ tags: [orchestration, orchestrator, lead-dev]
9
9
  capabilities:
10
10
  - coordinate_agents
11
11
  - delegate_tasks
@@ -18,20 +18,43 @@ mcp:
18
18
  args: [node_modules/0xray/dist/mcps/orchestrator.server.js]
19
19
  ---
20
20
 
21
- # Orchestrator Skill
21
+ # Orchestrator Skill — includes lead-dev operating model
22
22
 
23
- Multi-agent workflow coordination and task delegation.
23
+ When `multi_agent_orchestration.lead_dev_mode` is true in `features.json` (default when suit is worn), this is the **default OS behavior** — not a separate skill or MCP.
24
24
 
25
- ## Tools Available
25
+ ## Seven rules (codex 67–68)
26
26
 
27
- - **task_coordination**: Task coordination
28
- - **agent_delegation**: Agent delegation
29
- - **workflow_management**: Workflow management
27
+ 1. Phased plan + detailed todos; assign best subagent; monitor output
28
+ 2. Lead dev loops test→fix until green; no permission pings
29
+ 3. Per-suite test triage after major changes; full suite last
30
+ 4. Lead stays main thread; subagents execute; update todos
31
+ 5. Read all console and test output; triage fix rerun
32
+ 6. Never defer errors as "pre-existing" — add todo and resolve
33
+ 7. Resolve all errors before phase completion
30
34
 
31
- ## Usage
35
+ ## MCP loop (one tool surface — no autonomy-intake)
32
36
 
33
- This skill provides orchestration capabilities for orchestrator functionality.
37
+ | Step | MCP tool | Notes |
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) |
41
+ | Monitor | `get-orchestration-status` | Lead updates todos |
42
+ | Major work | researcher + architect-tools + code-review | Auto-listed in plan when complexity > threshold |
34
43
 
35
- ## Integration
44
+ ## Subagent routing
36
45
 
37
- Activated when orchestration capabilities are requested through the skills system.
46
+ | Task | Subagent |
47
+ |------|----------|
48
+ | Phasing | strategist |
49
+ | Architecture | architect-tools |
50
+ | Research | researcher |
51
+ | Implementation | backend-engineer / frontend-engineer |
52
+ | Test failures | bug-triage |
53
+ | Review | code-review |
54
+
55
+ ## Hooks (rewired, not new MCPs)
56
+
57
+ - **SessionStart** → `session-start.js` boots lead_dev_mode
58
+ - **PreToolUse** → hints `per_suite_triage_required` on full `npm test`
59
+
60
+ Config: `features.json` → `multi_agent_orchestration.lead_dev_mode`
@@ -28,10 +28,23 @@ Multi-repo analysis, documentation lookup, and implementation examples.
28
28
  - **find_implementations**: Find implementations
29
29
  - **analyze_documentation**: Analyze documentation
30
30
 
31
- ## Usage
31
+ ## When to invoke (autonomy-command)
32
32
 
33
- This skill provides research capabilities for researcher functionality.
33
+ Lead dev dispatches researcher **before** major planning, refactors, or cross-repo work — not only when user says "research."
34
34
 
35
- ## Integration
35
+ | Trigger | Action |
36
+ |---------|--------|
37
+ | Major refactor / new phase | `search_codebase`, `get_documentation`, `find_implementation` |
38
+ | Prior art / patterns | Search sibling repos (xray, groover, repertoire) |
39
+ | Proposal analysis | `analyze_proposal` via xray-researcher MCP |
36
40
 
37
- Activated when research capabilities are requested through the skills system.
41
+ ## MCP tools (xray-researcher)
42
+
43
+ - `get_documentation` — module/class docs (`target` required)
44
+ - `search_codebase` — text search in workspace
45
+ - `find_implementation` — locate implementations
46
+ - `analyze_proposal` — governance-aware proposal review
47
+
48
+ ## Return shape for lead
49
+
50
+ Summarize: findings (3–5 bullets), file paths, recommended next todos. Do not defer work back to lead without concrete patches or todos.