0xray 4.0.40 → 4.0.42

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 (190) hide show
  1. package/.grok-plugin/plugin.json +1 -1
  2. package/.opencode/agents/api-design.yml +31 -0
  3. package/.opencode/agents/architect.yml +15 -0
  4. package/.opencode/agents/architecture-patterns.yml +14 -0
  5. package/.opencode/agents/auto-format.yml +14 -0
  6. package/.opencode/agents/backend-engineer.yml +12 -0
  7. package/.opencode/agents/boot-orchestrator.yml +14 -0
  8. package/.opencode/agents/bug-triage-specialist.yml +15 -0
  9. package/.opencode/agents/code-analyzer.yml +12 -0
  10. package/.opencode/agents/code-reviewer.yml +14 -0
  11. package/.opencode/agents/content-creator.yml +12 -0
  12. package/.opencode/agents/database-engineer.yml +12 -0
  13. package/.opencode/agents/devops-engineer.yml +12 -0
  14. package/.opencode/agents/framework-compliance-audit.yml +14 -0
  15. package/.opencode/agents/frontend-engineer.yml +12 -0
  16. package/.opencode/agents/frontend-ui-ux-engineer.yml +12 -0
  17. package/.opencode/agents/git-workflow.yml +15 -0
  18. package/.opencode/agents/growth-strategist.yml +12 -0
  19. package/.opencode/agents/hermes-agent.yml +12 -0
  20. package/.opencode/agents/inference-improve.yml +12 -0
  21. package/.opencode/agents/lint.yml +14 -0
  22. package/.opencode/agents/log-monitor.yml +12 -0
  23. package/.opencode/agents/mobile-developer.yml +12 -0
  24. package/.opencode/agents/model-health-check.yml +12 -0
  25. package/.opencode/agents/multimodal-looker.yml +12 -0
  26. package/.opencode/agents/performance-analysis.yml +12 -0
  27. package/.opencode/agents/performance-engineer.yml +12 -0
  28. package/.opencode/agents/performance-optimization.yml +12 -0
  29. package/.opencode/agents/processor-pipeline.yml +14 -0
  30. package/.opencode/agents/project-analysis.yml +12 -0
  31. package/.opencode/agents/refactorer.yml +12 -0
  32. package/.opencode/agents/researcher.yml +12 -0
  33. package/.opencode/agents/security-auditor.yml +12 -0
  34. package/.opencode/agents/security-scan.yml +12 -0
  35. package/.opencode/agents/seo-consultant.yml +12 -0
  36. package/.opencode/agents/session-management.yml +12 -0
  37. package/.opencode/agents/state-manager.yml +12 -0
  38. package/.opencode/agents/storyteller.yml +12 -0
  39. package/.opencode/agents/strategist.yml +12 -0
  40. package/.opencode/agents/tech-writer.yml +12 -0
  41. package/.opencode/agents/testing-best-practices.yml +12 -0
  42. package/.opencode/agents/testing-lead.yml +12 -0
  43. package/.opencode/agents/ui-ux-design.yml +12 -0
  44. package/.opencode/codex.codex +8 -0
  45. package/.opencode/commands/auto-format.md +99 -0
  46. package/.opencode/commands/auto-summary-capture.md +90 -0
  47. package/.opencode/commands/dependency-audit.md +184 -0
  48. package/.opencode/commands/enforcer-daily-scan.md +137 -0
  49. package/.opencode/commands/framework-compliance-audit.md +205 -0
  50. package/.opencode/commands/interactive-validator.md +75 -0
  51. package/.opencode/commands/job-summary-logger.md +68 -0
  52. package/.opencode/commands/lint.md +11 -0
  53. package/.opencode/commands/mode-switch.md +95 -0
  54. package/.opencode/commands/model-health-check.md +186 -0
  55. package/.opencode/commands/performance-analysis.md +144 -0
  56. package/.opencode/commands/pre-commit-introspection.md +185 -0
  57. package/.opencode/commands/pre-commit-introspection.sh +133 -0
  58. package/.opencode/commands/security-scan.md +157 -0
  59. package/.opencode/commands/sisyphus-validation.md +128 -0
  60. package/.opencode/commands/summary-logger.md +83 -0
  61. package/.opencode/enforcer-config.json +282 -0
  62. package/.opencode/skills/orchestrator/SKILL.md +12 -0
  63. package/.opencode/workflows/post-deployment-audit.yml +123 -0
  64. package/.xray/features.json +1 -1
  65. package/.xray/features.schema.json +1 -1
  66. package/AGENTS-consumer.md +2 -0
  67. package/AGENTS.md +2 -0
  68. package/README.md +52 -12
  69. package/SKILLS.md +2 -0
  70. package/dist/AGENTS.md +2 -0
  71. package/dist/CHANGELOG.md +29 -0
  72. package/dist/README.md +52 -12
  73. package/dist/SKILLS.md +2 -0
  74. package/dist/cli/commands/openclaw-install.js +1 -1
  75. package/dist/cli/index.js +12 -0
  76. package/dist/enforcement/index.d.ts +4 -0
  77. package/dist/enforcement/index.js +4 -0
  78. package/dist/enforcement/validators/code-quality-validators.js +6 -4
  79. package/dist/governance/llm-governance-provider.d.ts +7 -1
  80. package/dist/governance/llm-governance-provider.js +72 -14
  81. package/dist/governance/local-confer.d.ts +4 -1
  82. package/dist/governance/local-confer.js +22 -1
  83. package/dist/integrations/grok/grok-cli.js +10 -37
  84. package/dist/integrations/grok/hooks/grok-hook-utils.js +29 -2
  85. package/dist/integrations/grok/hooks/session-start.js +2 -20
  86. package/dist/integrations/hooks/confer-hook-runtime.mjs +23 -1
  87. package/dist/integrations/hooks/goggles-mcp.mjs +36 -4
  88. package/dist/integrations/hooks/goggles-pipeline.mjs +55 -15
  89. package/dist/integrations/hooks/goggles-planes.json +13 -4
  90. package/dist/integrations/hooks/plates.cjs +22 -0
  91. package/dist/integrations/hooks/session-note-index.cjs +298 -0
  92. package/dist/integrations/hooks/session-note-index.mjs +22 -0
  93. package/dist/integrations/hooks/sleeve.cjs +335 -0
  94. package/dist/integrations/hooks/sleeve.mjs +18 -0
  95. package/dist/integrations/hooks/station-hook-runtime.cjs +205 -9
  96. package/dist/integrations/hooks/wake-cascade.cjs +102 -0
  97. package/dist/integrations/hooks/wake-cascade.mjs +16 -0
  98. package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
  99. package/dist/mcps/architect-tools.server.d.ts +6 -0
  100. package/dist/mcps/architect-tools.server.js +19 -2
  101. package/dist/mcps/config/server-config-registry.js +8 -6
  102. package/dist/mcps/governance.server.d.ts +1 -0
  103. package/dist/mcps/governance.server.js +46 -0
  104. package/dist/mcps/knowledge-skills/code-review.server.js +7 -0
  105. package/dist/mcps/knowledge-skills/security-audit.server.js +5 -3
  106. package/dist/mcps/mcp-client.js +1 -1
  107. package/dist/mcps/orchestrator/handlers/complexity-handler.js +2 -2
  108. package/dist/mcps/researcher.server.js +12 -3
  109. package/dist/memory-routing/plates.d.ts +1 -1
  110. package/dist/memory-routing/plates.js +1 -0
  111. package/dist/nucleus/autonomy-kernel.d.ts +2 -0
  112. package/dist/nucleus/autonomy-kernel.js +17 -13
  113. package/dist/nucleus/confer-host.d.ts +35 -0
  114. package/dist/nucleus/confer-host.js +55 -0
  115. package/dist/nucleus/confer.d.ts +19 -3
  116. package/dist/nucleus/confer.js +111 -55
  117. package/dist/nucleus/lead-dev-plan-persistence.js +4 -2
  118. package/dist/nucleus/suit-temperament.d.ts +1 -1
  119. package/dist/nucleus/suit-temperament.js +2 -2
  120. package/dist/nucleus/synthesis-consult-receipt.d.ts +7 -1
  121. package/dist/nucleus/synthesis-consult-receipt.js +86 -35
  122. package/dist/reporting/framework-reporting-system.js +2 -5
  123. package/dist/reporting/log-parser.d.ts +2 -0
  124. package/dist/reporting/log-parser.js +7 -6
  125. package/dist/skills/orchestrator/SKILL.md +12 -0
  126. package/docs-site/docs/plates/activity-log.md +1 -1
  127. package/docs-site/docs/plates/boot.md +2 -0
  128. package/docs-site/docs/plates/centrifuge.md +30 -0
  129. package/docs-site/docs/plates/cursor-compact.md +1 -1
  130. package/docs-site/docs/plates/glossary.md +1 -2
  131. package/docs-site/docs/plates/goggles.md +4 -0
  132. package/docs-site/docs/plates/governance.md +2 -0
  133. package/docs-site/docs/plates/grok-compact.md +1 -1
  134. package/docs-site/docs/plates/grokbot.md +1 -1
  135. package/docs-site/docs/plates/host-pack.md +2 -0
  136. package/docs-site/docs/plates/house.md +1 -1
  137. package/docs-site/docs/plates/index.md +3 -1
  138. package/docs-site/docs/plates/inference-files.md +1 -1
  139. package/docs-site/docs/plates/kept-line.md +1 -1
  140. package/docs-site/docs/plates/kits.md +2 -0
  141. package/docs-site/docs/plates/lens-gate.md +1 -1
  142. package/docs-site/docs/plates/lens-page.md +1 -1
  143. package/docs-site/docs/plates/live-mesh.md +1 -1
  144. package/docs-site/docs/plates/memory-recall.md +4 -0
  145. package/docs-site/docs/plates/notes-page.md +2 -1
  146. package/docs-site/docs/plates/orchestration.md +2 -0
  147. package/docs-site/docs/plates/package-face.md +1 -1
  148. package/docs-site/docs/plates/payload-heat.md +1 -1
  149. package/docs-site/docs/plates/pickup-stamp.md +1 -1
  150. package/docs-site/docs/plates/pre-tool.md +1 -1
  151. package/docs-site/docs/plates/processor.md +2 -0
  152. package/docs-site/docs/plates/record-map.md +2 -1
  153. package/docs-site/docs/plates/reflection-page.md +1 -1
  154. package/docs-site/docs/plates/reporting.md +2 -0
  155. package/docs-site/docs/plates/review.md +1 -1
  156. package/docs-site/docs/plates/routing.md +2 -0
  157. package/docs-site/docs/plates/session-capture.md +1 -1
  158. package/docs-site/docs/plates/site-manual.md +1 -1
  159. package/docs-site/docs/plates/stamp-plate.md +1 -1
  160. package/docs-site/docs/plates/station-card.md +4 -1
  161. package/docs-site/docs/plates/station-heat.md +1 -1
  162. package/docs-site/docs/plates/suit-organs.md +1 -1
  163. package/docs-site/docs/plates/suit-settings.md +1 -1
  164. package/docs-site/docs/plates/suit-wear.md +3 -1
  165. package/docs-site/docs/plates/suit.md +2 -0
  166. package/docs-site/docs/plates/trail-state.md +1 -1
  167. package/docs-site/docs/plates/work-fresh.md +1 -1
  168. package/docs-site/docs/plates/write-home.md +1 -1
  169. package/llms.txt +2 -0
  170. package/package.json +2 -2
  171. package/scripts/mjs/verify-confer-core.mjs +153 -29
  172. package/scripts/mjs/verify-user-aside-core.mjs +3 -4
  173. package/scripts/node/bridge-mcp-wiring.cjs +273 -9
  174. package/scripts/node/confer-switch.cjs +66 -0
  175. package/scripts/node/install-bridges.cjs +188 -60
  176. package/scripts/node/setup.cjs +2 -46
  177. package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
  178. package/src/mcps/architect-tools.server.ts +26 -2
  179. package/src/mcps/config/__tests__/server-config-registry.test.ts +15 -6
  180. package/src/mcps/config/server-config-registry.ts +9 -6
  181. package/src/mcps/governance.server.ts +49 -0
  182. package/src/mcps/knowledge-skills/code-review.server.ts +8 -0
  183. package/src/mcps/knowledge-skills/security-audit.server.ts +11 -12
  184. package/src/mcps/mcp-client.ts +1 -1
  185. package/src/mcps/orchestrator/handlers/complexity-handler.ts +2 -1
  186. package/src/mcps/researcher.server.ts +19 -10
  187. package/src/skills/orchestrator/SKILL.md +12 -0
  188. package/vendor/@0xray/repertoire/scripts/run-live-synthesis-checkpoint.mjs +5 -51
  189. package/xray/features.json +1 -1
  190. package/xray/features.schema.json +1 -1
@@ -7,7 +7,7 @@
7
7
 
8
8
  const fs = require("fs");
9
9
  const path = require("path");
10
- const { execFileSync, execSync } = require("child_process");
10
+ const { execFileSync } = require("child_process");
11
11
  const {
12
12
  wantsCostume,
13
13
  isIsolatedHome,
@@ -22,17 +22,19 @@ const {
22
22
  wireOpencodeBridge,
23
23
  wireOpenClawBridge,
24
24
  deployPortableProjectMcpJson,
25
- scopedMcpLaunch,
26
25
  mergeMcpMap,
27
26
  mergeNamedRecords,
28
27
  jsonDeepEqual,
29
28
  copyHermesFindProjectRootHelper,
30
29
  copyHermesHookRuntimes,
31
30
  installOpenClawHostWear,
31
+ recordOpenClawProjectPlugin,
32
32
  maybeWriteOpenClawCliBackend,
33
33
  isEphemeralInstallRoot,
34
34
  enableMemoryRoutingIfResolves,
35
- XRAY_MCP_SERVERS,
35
+ pinLauncherPackageRoot,
36
+ writeProjectSuitMcp,
37
+ trustGrokFolder,
36
38
  } = require("./bridge-mcp-wiring.cjs");
37
39
 
38
40
  const wearIo = { writes: 0, skips: 0 };
@@ -334,6 +336,34 @@ function mergeOpencodeJson(targetDir, packageRoot, log) {
334
336
  }
335
337
  }
336
338
 
339
+ function settlePackageRoot(packageRoot, targetDir) {
340
+ const resolved = path.resolve(packageRoot || ".");
341
+ if (!targetDir || !isEphemeralInstallRoot(resolved) || isEphemeralInstallRoot(path.resolve(targetDir))) {
342
+ return resolved;
343
+ }
344
+ const dest = path.join(machineHome(), ".grok", "wears", "0xray");
345
+ if (resolved === dest) return dest;
346
+ // Copy beside the live wear. A hook pointed at dest keeps loading until the swap.
347
+ const staging = `${dest}.next`;
348
+ const backup = `${dest}.prev`;
349
+ fs.rmSync(staging, { recursive: true, force: true });
350
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
351
+ fs.cpSync(resolved, staging, {
352
+ recursive: true,
353
+ filter(src) {
354
+ const rel = path.relative(resolved, src);
355
+ if (!rel) return true;
356
+ const top = rel.split(path.sep)[0];
357
+ return top !== "node_modules" && top !== ".git";
358
+ },
359
+ });
360
+ fs.rmSync(backup, { recursive: true, force: true });
361
+ if (fs.existsSync(dest)) fs.renameSync(dest, backup);
362
+ fs.renameSync(staging, dest);
363
+ fs.rmSync(backup, { recursive: true, force: true });
364
+ return dest;
365
+ }
366
+
337
367
  function grokHookShellCommand(packageRoot, scriptName, extraArgs) {
338
368
  const script = path.join(packageRoot, "scripts", "mjs", "run-grok-hook.mjs");
339
369
  const extra = extraArgs ? ` ${extraArgs}` : "";
@@ -365,6 +395,7 @@ function ensureGrokHookEvent(hooks, eventName) {
365
395
  }
366
396
 
367
397
  function patchGrokHooks(pluginDir, packageRoot, targetDir, log, label) {
398
+ packageRoot = settlePackageRoot(packageRoot, targetDir);
368
399
  const hooksDir = path.join(pluginDir, "hooks");
369
400
  const hooksPath = path.join(hooksDir, "hooks.json");
370
401
  const hookScript = path.join(packageRoot, "scripts", "mjs", "run-grok-hook.mjs");
@@ -454,42 +485,11 @@ function findGrokPluginSource(packageRoot) {
454
485
  return candidates.find((p) => fs.existsSync(p));
455
486
  }
456
487
 
457
- function registerGrokMcpServers(targetDir, log, pluginDirs) {
458
- try {
459
- execSync("which grok", { stdio: "ignore" });
460
- } catch {
461
- log("grok-bridge", "grok CLI not on PATH — plugin .mcp.json still configured", "info");
462
- return;
463
- }
464
-
465
- for (const s of XRAY_MCP_SERVERS) {
466
- try {
467
- const launch = scopedMcpLaunch(targetDir, s.mcpCmd, s.env);
468
- const argv = ["mcp", "add", s.name, "--command", launch.command, "--args", launch.args[0], ...launch.args.slice(1)];
469
- for (const [key, value] of Object.entries(launch.env)) {
470
- argv.push("--env", `${key}=${value}`);
471
- }
472
- execFileSync("grok", argv, { stdio: "pipe" });
473
- log("grok-bridge", `registered ${s.name} (mcp-launch)`, "info");
474
- } catch {
475
- // already registered or grok config conflict — non-blocking
476
- }
477
- }
478
-
479
- const dirs =
480
- Array.isArray(pluginDirs) && pluginDirs.length > 0
481
- ? pluginDirs
482
- : [path.join(targetDir, ".grok", "plugins", "0xray")];
483
- for (const pluginDir of dirs) {
484
- if (!fs.existsSync(pluginDir)) continue;
485
- try {
486
- execSync(`grok plugins trust "${pluginDir}"`, { stdio: "ignore" });
487
- log("grok-bridge", "plugin trusted", "info", { path: pluginDir });
488
- break;
489
- } catch {
490
- // best-effort
491
- }
492
- }
488
+ function registerGrokMcpServers(targetDir, log, env) {
489
+ const tomlPath = writeProjectSuitMcp(targetDir);
490
+ log("grok-bridge", "project mcp config written", "info", { path: tomlPath });
491
+ const trustPath = trustGrokFolder(targetDir, env || process.env);
492
+ log("grok-bridge", "folder trusted", "info", { path: trustPath });
493
493
  }
494
494
 
495
495
 
@@ -580,6 +580,83 @@ function grokPluginSettled(sourceDir, dest, packageRoot, targetDir) {
580
580
  return true;
581
581
  }
582
582
 
583
+ /** Absolute paths under a temp checkout. Longest match wins so a script path is retargeted before its root. */
584
+ function retargetEphemeralText(text, durableRoot) {
585
+ if (typeof text !== "string" || !isEphemeralInstallRoot(text)) return text;
586
+ const re = /(?:\/private\/var\/folders\/|\/var\/folders\/|\/private\/tmp\/|\/tmp\/|\/Temp\/)[^\s"']*/g;
587
+ const tokens = [...new Set(text.match(re) || [])].sort((a, b) => b.length - a.length);
588
+ let out = text;
589
+ for (const token of tokens) {
590
+ const scriptsAt = token.indexOf("/scripts/");
591
+ if (scriptsAt > 0) {
592
+ const repl = path.join(durableRoot, token.slice(scriptsAt + 1));
593
+ if (fs.existsSync(repl)) out = out.split(token).join(repl);
594
+ continue;
595
+ }
596
+ const runner = path.join(durableRoot, "scripts", "mjs", "run-grok-hook.mjs");
597
+ if (
598
+ !fs.existsSync(token) &&
599
+ fs.existsSync(runner) &&
600
+ (out.includes("run-grok-hook") || out.includes("mcp-launch.cjs"))
601
+ ) {
602
+ out = out.split(token).join(durableRoot);
603
+ }
604
+ }
605
+ return out;
606
+ }
607
+
608
+ function scrubEphemeralPins(node, durableRoot) {
609
+ if (Array.isArray(node)) return node.map((item) => scrubEphemeralPins(item, durableRoot));
610
+ if (!node || typeof node !== "object") {
611
+ return typeof node === "string" ? retargetEphemeralText(node, durableRoot) : node;
612
+ }
613
+ const out = {};
614
+ for (const [key, value] of Object.entries(node)) {
615
+ if ((key === "env" || key === "environment") && value && typeof value === "object" && !Array.isArray(value)) {
616
+ const env = {};
617
+ for (const [envKey, envValue] of Object.entries(value)) {
618
+ if (typeof envValue === "string" && isEphemeralInstallRoot(envValue)) {
619
+ if (envKey === "XRAY_AI_PATH") env[envKey] = durableRoot;
620
+ continue;
621
+ }
622
+ env[envKey] = scrubEphemeralPins(envValue, durableRoot);
623
+ }
624
+ out[key] = env;
625
+ continue;
626
+ }
627
+ out[key] = scrubEphemeralPins(value, durableRoot);
628
+ }
629
+ return out;
630
+ }
631
+
632
+ /**
633
+ * Shared HOME does not wear the machine plugin, but Grok still loads a stale
634
+ * `~/.grok/plugins/0xray`. Drop temp XRAY_ROOT pins and retarget dead launch
635
+ * paths onto the durable wear. A real project root on that plugin is left alone.
636
+ */
637
+ function scrubEphemeralMachineGrokPins(machine, durablePackageRoot) {
638
+ if (!machine || !durablePackageRoot) return 0;
639
+ const runner = path.join(durablePackageRoot, "scripts", "mjs", "run-grok-hook.mjs");
640
+ if (!fs.existsSync(runner)) return 0;
641
+ const plugin = path.join(machine, ".grok", "plugins", "0xray");
642
+ const files = [path.join(plugin, "hooks", "hooks.json"), path.join(plugin, ".mcp.json")];
643
+ let changed = 0;
644
+ for (const file of files) {
645
+ if (!fs.existsSync(file)) continue;
646
+ let data;
647
+ try {
648
+ data = JSON.parse(fs.readFileSync(file, "utf8"));
649
+ } catch {
650
+ continue;
651
+ }
652
+ const next = scrubEphemeralPins(data, durablePackageRoot);
653
+ if (JSON.stringify(data) === JSON.stringify(next)) continue;
654
+ writeFileIfChanged(file, `${JSON.stringify(next, null, 2)}\n`);
655
+ changed += 1;
656
+ }
657
+ return changed;
658
+ }
659
+
583
660
  function installGrokBridge(targetDir, packageRoot, log, opts) {
584
661
  const sourceDir = findGrokPluginSource(packageRoot);
585
662
  if (!sourceDir) {
@@ -599,6 +676,7 @@ function installGrokBridge(targetDir, packageRoot, log, opts) {
599
676
  log("grok-bridge", "skip machine ~/.grok plugin — isolated HOME", "info");
600
677
  } else {
601
678
  log("grok-bridge", "skip machine ~/.grok plugin — project-scoped wear", "info");
679
+ scrubEphemeralMachineGrokPins(machine, settlePackageRoot(packageRoot, targetDir));
602
680
  }
603
681
 
604
682
  for (const dest of targets) {
@@ -634,8 +712,8 @@ function installGrokBridge(targetDir, packageRoot, log, opts) {
634
712
  if (globalCopied > 0) {
635
713
  log("grok-bridge", `global skills synced (${globalCopied})`, "info", { path: grokGlobalSkills });
636
714
  }
637
- registerGrokMcpServers(targetDir, log, targets);
638
715
  }
716
+ registerGrokMcpServers(targetDir, log, env);
639
717
  }
640
718
 
641
719
  function installHermesBridge(targetDir, packageRoot, log) {
@@ -773,7 +851,7 @@ function installOpenclawBridge(targetDir, packageRoot, log) {
773
851
  }
774
852
 
775
853
  if (!ephemeralOpenclaw && !isolatedOpenclaw) {
776
- const hook = installOpenClawHostWear(packageRoot);
854
+ const hook = installOpenClawHostWear(packageRoot, targetDir);
777
855
  if (hook) log("openclaw-bridge", "PreToolUse hook installed", "info", { path: hook });
778
856
  if (maybeWriteOpenClawCliBackend()) {
779
857
  log("openclaw-bridge", "opencode-cli backend written", "info");
@@ -787,6 +865,11 @@ function installOpenclawBridge(targetDir, packageRoot, log) {
787
865
  "info",
788
866
  );
789
867
  }
868
+
869
+ const recorded = recordOpenClawProjectPlugin(targetDir, packageRoot);
870
+ if (recorded) {
871
+ log("openclaw-bridge", "project plugin path recorded", "info", { path: recorded });
872
+ }
790
873
  }
791
874
 
792
875
  const XRAY_CONFIG_FILES = ["codex.json", "features.json", "features.schema.json", "config.json"];
@@ -1846,26 +1929,29 @@ function syncSetupSkillsAndRootLinks(packageRoot, targetDir) {
1846
1929
  require("./setup.cjs").syncSetupSkillsAndRootLinks(packageRoot, targetDir);
1847
1930
  }
1848
1931
 
1849
- function setupSkillMirrorNames(packageRoot) {
1850
- const skillsSource = fs.existsSync(path.join(packageRoot, "src", "skills"))
1932
+ /** A byte-identical package skill is the old mirror. A different body still throws. */
1933
+ function wornSkillMatchesPackage(packageRoot, targetDir, name) {
1934
+ const source = fs.existsSync(path.join(packageRoot, "src", "skills"))
1851
1935
  ? path.join(packageRoot, "src", "skills")
1852
1936
  : path.join(packageRoot, "dist", "skills");
1853
- if (!fs.existsSync(skillsSource)) return new Set();
1854
- const names = new Set();
1855
- for (const entry of fs.readdirSync(skillsSource, { withFileTypes: true })) {
1856
- if (!entry.isDirectory()) continue;
1857
- if (fs.existsSync(path.join(skillsSource, entry.name, "SKILL.md"))) names.add(entry.name);
1937
+ const packaged = path.join(source, name, "SKILL.md");
1938
+ if (!fs.existsSync(packaged)) return false;
1939
+ const packagedBytes = fs.readFileSync(packaged);
1940
+ let saw = false;
1941
+ for (const parts of ROLE_SKILL_DIRS) {
1942
+ const worn = path.join(targetDir, ...parts, name, "SKILL.md");
1943
+ if (!fs.existsSync(worn)) continue;
1944
+ saw = true;
1945
+ if (!packagedBytes.equals(fs.readFileSync(worn))) return false;
1858
1946
  }
1859
- return names;
1947
+ return saw;
1860
1948
  }
1861
1949
 
1862
- /** The 4.0.28 skill mirror is not a consumer costume. Any other extra name still throws. */
1863
- function isSetupSkillMirrorDump(err, packageRoot) {
1950
+ function isSetupSkillMirrorDump(err, packageRoot, targetDir) {
1864
1951
  if (!err || err.code !== "FOUNDRY_COSTUME_DUMP") return false;
1865
1952
  if (!Array.isArray(err.extraSkills) || err.extraSkills.length === 0) return false;
1866
1953
  if (Array.isArray(err.extraAgents) && err.extraAgents.length > 0) return false;
1867
- const mirrored = setupSkillMirrorNames(packageRoot);
1868
- return err.extraSkills.every((name) => mirrored.has(name));
1954
+ return err.extraSkills.every((name) => wornSkillMatchesPackage(packageRoot, targetDir, name));
1869
1955
  }
1870
1956
 
1871
1957
  function packageShipsConsumerSuit(packageRoot) {
@@ -1873,11 +1959,41 @@ function packageShipsConsumerSuit(packageRoot) {
1873
1959
  }
1874
1960
 
1875
1961
  /**
1876
- * 4.0.28 consumer postinstall files: AGENTS.md, .gitignore, repertoire link,
1877
- * .xray config, bridges, mill plant, then the setup.cjs skill mirror and
1878
- * dist/scripts links. Does not install Cursor hooks or git hooks.
1962
+ * Consumer wear files: AGENTS.md, .gitignore, repertoire link, .xray config,
1963
+ * bridges, mill plant (mill + inspect), and the scripts and dist links.
1964
+ * The role-skill mirror stays in the package.
1965
+ * Does not install Cursor hooks or git hooks.
1879
1966
  * Existing user files follow the 4.0.28 guards inside those functions.
1880
1967
  */
1968
+
1969
+ const ROLE_SKILL_KEEP = new Set(["mill", "inspect"]);
1970
+ const ROLE_SKILL_DIRS = [
1971
+ [".opencode", "skills"],
1972
+ [".grok", "plugins", "0xray", "skills"],
1973
+ [".hermes", "plugins", "xray-hermes", "skills"],
1974
+ [".openclaw", "skills"],
1975
+ ];
1976
+
1977
+ function removeCopiedRoleSkills(packageRoot, targetDir) {
1978
+ const source = fs.existsSync(path.join(packageRoot, "src", "skills"))
1979
+ ? path.join(packageRoot, "src", "skills")
1980
+ : path.join(packageRoot, "dist", "skills");
1981
+ if (!fs.existsSync(source)) return;
1982
+ for (const parts of ROLE_SKILL_DIRS) {
1983
+ const dir = path.join(targetDir, ...parts);
1984
+ if (!fs.existsSync(dir)) continue;
1985
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
1986
+ if (!entry.isDirectory() || ROLE_SKILL_KEEP.has(entry.name)) continue;
1987
+ const packaged = path.join(source, entry.name, "SKILL.md");
1988
+ const worn = path.join(dir, entry.name, "SKILL.md");
1989
+ if (!fs.existsSync(packaged) || !fs.existsSync(worn)) continue;
1990
+ const same = fs.readFileSync(packaged).equals(fs.readFileSync(worn));
1991
+ if (!same) continue;
1992
+ fs.rmSync(path.join(dir, entry.name), { recursive: true, force: true });
1993
+ }
1994
+ }
1995
+ }
1996
+
1881
1997
  function installConsumerProjectFiles(packageRoot, targetDir, log) {
1882
1998
  const write = typeof log === "function" ? log : () => {};
1883
1999
  if (!isConsumerInstall(packageRoot, targetDir) || !packageShipsConsumerSuit(packageRoot)) {
@@ -1896,10 +2012,11 @@ function installConsumerProjectFiles(packageRoot, targetDir, log) {
1896
2012
  installGrokBridge(targetDir, packageRoot, write);
1897
2013
  installHermesBridge(targetDir, packageRoot, write);
1898
2014
  installOpenclawBridge(targetDir, packageRoot, write);
2015
+ removeCopiedRoleSkills(packageRoot, targetDir);
1899
2016
  try {
1900
2017
  mintConsumerSuit(packageRoot, targetDir, write);
1901
2018
  } catch (err) {
1902
- if (!isSetupSkillMirrorDump(err, packageRoot)) throw err;
2019
+ if (!isSetupSkillMirrorDump(err, packageRoot, targetDir)) throw err;
1903
2020
  }
1904
2021
  syncSetupSkillsAndRootLinks(packageRoot, targetDir);
1905
2022
  return true;
@@ -2085,7 +2202,9 @@ function wearCursorHooks(targetDir, packageRoot, log, opts) {
2085
2202
  const write = typeof log === "function" ? log : () => {};
2086
2203
  const options = opts || {};
2087
2204
  const resolvedTarget = path.resolve(targetDir);
2088
- const resolvedPackage = path.resolve(packageRoot);
2205
+ const resolvedPackage = settlePackageRoot(path.resolve(packageRoot), resolvedTarget);
2206
+ pinLauncherPackageRoot(resolvedPackage);
2207
+ try {
2089
2208
  if (classifyCursorWearGit(resolvedTarget) === "not-work-tree") {
2090
2209
  wearSuitSkippingCursorHooks(resolvedPackage, resolvedTarget, write);
2091
2210
  return;
@@ -2137,6 +2256,9 @@ function wearCursorHooks(targetDir, packageRoot, log, opts) {
2137
2256
  }
2138
2257
  write("cursor-bridge", "hooks.json wired to installed dist", "info", { path: hooksPath });
2139
2258
  return hooksPath;
2259
+ } finally {
2260
+ pinLauncherPackageRoot("");
2261
+ }
2140
2262
  }
2141
2263
 
2142
2264
  /**
@@ -2344,15 +2466,16 @@ function installFrameworkDogfoodWear(packageRoot, log) {
2344
2466
  * @param {{ targetDir: string, packageRoot: string, log?: Function }} opts
2345
2467
  */
2346
2468
  function installAllBridges(opts) {
2347
- const packageRoot = path.resolve(opts.packageRoot);
2348
2469
  const targetDir = path.resolve(opts.targetDir);
2470
+ const packageRoot = settlePackageRoot(path.resolve(opts.packageRoot), targetDir);
2471
+ pinLauncherPackageRoot(packageRoot);
2349
2472
  const logFn = opts.log;
2350
2473
  const log =
2351
2474
  logFn ||
2352
2475
  ((_component, _action, _status, _details) => {
2353
2476
  /* noop */
2354
2477
  });
2355
-
2478
+ try {
2356
2479
  wearVendoredRepertoire(packageRoot, targetDir, log);
2357
2480
 
2358
2481
  if (!isConsumerInstall(packageRoot, targetDir)) {
@@ -2373,6 +2496,9 @@ function installAllBridges(opts) {
2373
2496
  installCursorBridge(targetDir, packageRoot, log);
2374
2497
 
2375
2498
  log("install-bridges", "4-platform + cursor wear complete", "success");
2499
+ } finally {
2500
+ pinLauncherPackageRoot("");
2501
+ }
2376
2502
  }
2377
2503
 
2378
2504
  module.exports = {
@@ -2393,6 +2519,8 @@ module.exports = {
2393
2519
  MERGE_CONFIG_FILES,
2394
2520
  patchGrokHooks,
2395
2521
  grokHookShellCommand,
2522
+ settlePackageRoot,
2523
+ scrubEphemeralMachineGrokPins,
2396
2524
  writeGrokDiscoveredHooks,
2397
2525
  isEphemeralInstallRoot,
2398
2526
  isIsolatedHome,
@@ -4,37 +4,7 @@ const fs = require("fs");
4
4
  const path = require("path");
5
5
 
6
6
  function syncSetupSkillsAndRootLinks(packageRoot, targetDir) {
7
- /* 1. Sync core skills from src/skills/ (dev) or dist/skills/ (consumer) → .opencode/skills/ [P3-SKILLS-DE-DUP-SCOPE-AND-EXEC-01: orchestrator package SSOT canonical src/skills/orchestrator/SKILL.md; mirror .opencode/skills/orchestrator/ is built output of this logic; see paired guarded fw in status.ts getSkillsList + mapping append + deep ref 2026-05-26 authority for one-package dedup under pivoted surgical plan]
8
- [P3-SKILLS-DE-DUP-RESEARCHER-FOLLOW-01: researcher package SSOT canonical src/skills/researcher/SKILL.md (high-value per deep ref + YML precedent + playbook P3-SKILLS-FOLLOW-01); mirror .opencode/skills/researcher/ is built output of this logic; see paired guarded fw in status.ts + rich append + YML @ harness-codex verification (FORCE exercised P3-YML + codex-enforcement + 100/60/0 + 3 subagents tracked + 0 hot + 3-hot re-establish + all prior green) + deep ref 2026-05-26 + Phase 3 Pivot + Term 61 + user's "create a todo list. spawn subagents..." + 6/6+7/7 + YML. Governance-visible hook for skills SSOT at install layer. Silent, additive, reversible, no behavior change, fw/echo only.]
9
- [P3-SKILLS-FOLLOW-02: code-review package SSOT canonical src/skills/code-review/SKILL.md (next high-value per deep ref "parallel small batches" + @architect scoping rec 2 + YML @ "Ready for next" + this P3-SKILLS-FOLLOW-02 on user's spawn command); mirror .opencode/skills/code-review/ is built output of this logic; see paired guarded fw "P3-SKILLS-FOLLOW-02-code-review-ssot-preferred" in status.ts (after researcher) + rich append docs/reflections/p3-skills-follow-02-code-review-2026-05-27.md + YML @ harness-codex verification + 0 hot + 3-hot + all ties + ps 0 + this work (2-file surgical edit, harness post, mapping append after latest ~17099+, todo advance 1, spawn replacement, self-audit 100%, green + ready) + deep ref 2026-05-26 + Phase 3 Pivot + Term 61 + 6/6+7/7 + YML. Governance-visible hook for skills SSOT at install layer for code-review. Silent, additive, reversible, no behavior change, fw/echo only. "The box contains its builders. The relay is hot."] */
10
- const skillsSource = fs.existsSync(path.join(packageRoot, "src", "skills"))
11
- ? path.join(packageRoot, "src", "skills")
12
- : path.join(packageRoot, "dist", "skills");
13
- const skillsDest = path.join(targetDir, ".opencode", "skills");
14
-
15
- if (fs.existsSync(skillsSource)) {
16
- try {
17
- if (!fs.existsSync(skillsDest)) fs.mkdirSync(skillsDest, { recursive: true });
18
- const skillDirs = fs.readdirSync(skillsSource, { withFileTypes: true });
19
- let copied = 0, skipped = 0;
20
- for (const entry of skillDirs) {
21
- if (!entry.isDirectory()) continue;
22
- const skillMd = path.join(skillsSource, entry.name, "SKILL.md");
23
- if (!fs.existsSync(skillMd)) continue;
24
- const destMd = path.join(skillsDest, entry.name, "SKILL.md");
25
- const destDir = path.dirname(destMd);
26
- if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
27
- if (fs.existsSync(destMd)) {
28
- const destContent = fs.readFileSync(destMd, "utf8");
29
- if (destContent.includes("source: community")) { skipped++; continue; }
30
- if (fs.statSync(skillMd).mtime <= fs.statSync(destMd).mtime) continue;
31
- }
32
- fs.copyFileSync(skillMd, destMd);
33
- copied++;
34
- }
35
- console.log(`✅ Skills: ${copied} updated, ${skipped} community skills preserved`);
36
- } catch (e) { console.warn(`⚠️ Skills sync: ${e.message}`); }
37
- }
7
+ // Mint fastens mill and inspect. The role-skill mirror stays in the package.
38
8
 
39
9
  // 4. Create scripts symlink
40
10
  const scriptsSource = path.join(packageRoot, "scripts");
@@ -106,21 +76,7 @@ if (hasHermes) {
106
76
  console.log("🔍 Hermes Agent detected");
107
77
  }
108
78
 
109
- /**
110
- * P3-SKILLS-DE-DUP-SCOPE-AND-EXEC-01 (supporting header in sync owner) — Small-Batch Surgical Skills Deduplication (one package: orchestrator).
111
- * This file (scripts/node/setup.cjs) is the canonical sync owner enforcing src/skills/ (or dist/skills/) → .opencode/skills/ mirror for framework core skills.
112
- * Rich CGT + ties modeled on paired edit in src/cli/commands/status.ts + P3-YML-AGENT-SURFACES-UNIFICATION-01 + P3-7TH-GAP-DEEPER-01 + deep ref 2026-05-26 + Phase 3 Pivot + Term 61 + user's "create a todo list. spawn subagents..." + 6/6+7/7 + YML live.
113
- * Highly modular header only (no behavior change). Fully reversible (delete header). fw discipline + AGENTS org. 2 files total for this micro-slice (status.ts primary with fw guard + this header).
114
- * Governance-visible: documents the SSOT ownership for orchestrator package dedup at the build/install layer.
115
- * The box contains its builders. Term 61 held. Pure momentum.
116
- *
117
- * P3-SKILLS-DE-DUP-RESEARCHER-FOLLOW-01 (follow-on small-batch per deep ref "parallel small batches on skills deduplication (one package)" + YML @ "skills follow-on" + playbook P3-SKILLS-FOLLOW-01 + YML @ harness-codex verification 16982–17045 + FORCE + codex 100/60/0 + 3 subagents tracked + 0 hot + 3-hot re-establish + all prior completions + user's spawn command + deep ref 2026-05-26 + Phase 3 Pivot + Term 61 + 6/6+7/7 + YML):
118
- * Extended header for next high-value package (researcher). src/skills/researcher/SKILL.md canonical SSOT; .opencode/skills/researcher/ built mirror of this sync logic. See paired guarded fw log "P3-SKILLS-DE-DUP-RESEARCHER-FOLLOW-01-researcher-ssot-preferred" in status.ts getSkillsList + rich append docs/reflections/p3-skills-dedup-researcher-follow-01-2026-05-27.md + CGT/Governance-visible for YML @ harness-codex verification + 0 hot + 3-hot + all ties. 2 files max total for this follow-on. Highly modular. Fully reversible. fw/echo discipline. AGENTS org (scripts/ for sh/cjs). Term 61 surgical forward motion held. "the box contains its builders". Green + ready.
119
- *
120
- * P3-SKILLS-FOLLOW-02 (follow-on small-batch per deep ref "parallel small batches on skills deduplication (one package)" + @architect scoping rec 2 + YML @ "Ready for next" + this execution on user's "create a todo list. spawn subagents to complete todos. maintain todo list. do not ask questions. do not stop. you have the full plan."; modeled exactly on "orchestrator" + researcher precedent):
121
- * Extended header for next high-value package (code-review). src/skills/code-review/SKILL.md canonical SSOT; .opencode/skills/code-review/ built mirror of this sync logic. See paired guarded fw log "P3-SKILLS-FOLLOW-02-code-review-ssot-preferred" in status.ts getSkillsList (inserted after researcher block) + rich append docs/reflections/p3-skills-follow-02-code-review-2026-05-27.md (per AGENTS) + CGT/Governance-visible for YML @ harness-codex verification + 0 hot + 3-hot re-establish + all ties to spawn command + deep ref + pivot + Term 61 + 6/6+7/7 + YML + ps 0 + this P3-SKILLS-FOLLOW-02 full work (2-file surgical, harness post green tsc 0 new on touched, mapping append after latest, todo advance exactly 1, spawn replacement to maintain 3-hot, self-audit 100%) + verification + "the box contains its builders. The relay is hot.". 2 files max total for this follow-02. Highly modular (100% prior P3-SKILLS/YML/7th pattern reuse exactly inside existing sync logic). Fully reversible (targeted delete of notes restores exact prior). fw/echo discipline. AGENTS org (scripts/ for sh/cjs). Term 61 surgical forward motion held (no bloat, pure on actual dedup). "the box contains its builders". Green + ready. Subagent ID for resume.
122
- */
123
-
79
+ // Mint fastens mill and inspect. The links below are scripts and dist.
124
80
  syncSetupSkillsAndRootLinks(packageRoot, targetDir);
125
81
 
126
82
  // 2. Handle opencode.json merge
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xray-pre-tool",
3
- "version": "4.0.40",
3
+ "version": "4.0.42",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "0xRay constitution + temperament PreToolUse for OpenClaw",
@@ -10,14 +10,38 @@ import { XrayKnowledgeSkillBase } from "./shared/knowledge-skill-base.js";
10
10
  import * as fs from "fs";
11
11
  import * as path from "path";
12
12
  import { frameworkLogger } from "../core/framework-logger.js";
13
+ import { type GovernanceVote } from "../governance/llm-governance-provider.js";
13
14
  import {
14
15
  contextAnalysis as architectContextAnalysis,
15
16
  codebaseStructure as architectCodebaseStructure,
16
17
  dependencyAnalysis as architectDependencyAnalysis,
17
18
  architectureAssessment as architectArchitectureAssessment,
18
- formatConferArchitectureText,
19
+ type ArchitectureAssessment,
19
20
  } from "../architect/architect-tools.js";
20
21
 
22
+ export type ConferModelVerdict = "PASS" | "CONDITIONAL" | "FAIL" | "UNREVIEWED";
23
+
24
+ /** A confer verdict counts only when a model vote exists. Metrics alone are UNREVIEWED. */
25
+ export function conferVerdictFromModelVote(
26
+ vote: Pick<GovernanceVote, "decision"> | null,
27
+ ): ConferModelVerdict {
28
+ if (!vote) return "UNREVIEWED";
29
+ if (vote.decision === "reject") return "FAIL";
30
+ if (vote.decision === "approve") return "PASS";
31
+ return "CONDITIONAL";
32
+ }
33
+
34
+ export function formatArchitectureAssessmentConferText(
35
+ conferPrompt: string,
36
+ assessment: ArchitectureAssessment,
37
+ verdict: ConferModelVerdict = "UNREVIEWED",
38
+ ): string {
39
+ const assessmentJson = JSON.stringify(assessment, null, 2);
40
+ const trimmed = conferPrompt.trim();
41
+ if (!trimmed) return assessmentJson;
42
+ return `${trimmed}\n\n## Architecture assessment\n${assessmentJson}\n\nVerdict: ${verdict}\nTop risks: review assessment metrics above\nHardening: address high-complexity or coupling findings before resuming`;
43
+ }
44
+
21
45
  interface DirectoryNode {
22
46
  name: string;
23
47
  path: string;
@@ -48,7 +72,7 @@ export async function renderArchitectureAssessment(
48
72
  content: [
49
73
  {
50
74
  type: "text",
51
- text: formatConferArchitectureText(conferPrompt, result),
75
+ text: formatArchitectureAssessmentConferText(conferPrompt, result, "UNREVIEWED"),
52
76
  },
53
77
  ],
54
78
  };
@@ -83,25 +83,25 @@ describe('ServerConfigRegistry', () => {
83
83
  expect(registry.has('code-review')).toBe(true);
84
84
  const config = registry.get('code-review');
85
85
  expect(config?.command).toBe('node');
86
- expect(config?.timeout).toBe(30000);
86
+ expect(config?.timeout).toBe(150000);
87
87
  });
88
88
 
89
89
  it('should have security-audit server registered by default', () => {
90
90
  expect(registry.has('security-audit')).toBe(true);
91
91
  const config = registry.get('security-audit');
92
- expect(config?.timeout).toBe(45000);
92
+ expect(config?.timeout).toBe(150000);
93
93
  });
94
94
 
95
95
  it('should have security-auditor alias registered by default', () => {
96
96
  expect(registry.has('security-auditor')).toBe(true);
97
97
  const config = registry.get('security-auditor');
98
- expect(config?.timeout).toBe(45000);
98
+ expect(config?.timeout).toBe(150000);
99
99
  });
100
100
 
101
101
  it('should have researcher server registered by default', () => {
102
102
  expect(registry.has('researcher')).toBe(true);
103
103
  const config = registry.get('researcher');
104
- expect(config?.timeout).toBe(60000);
104
+ expect(config?.timeout).toBe(150000);
105
105
  });
106
106
 
107
107
  it('should have framework-help server registered by default', () => {
@@ -119,7 +119,7 @@ describe('ServerConfigRegistry', () => {
119
119
  it('should have architect server registered by default', () => {
120
120
  expect(registry.has('architect')).toBe(true);
121
121
  const config = registry.get('architect');
122
- expect(config?.timeout).toBe(45000);
122
+ expect(config?.timeout).toBe(150000);
123
123
  });
124
124
 
125
125
  it('should have enforcer server registered by default', () => {
@@ -242,7 +242,16 @@ describe('ServerConfigRegistry', () => {
242
242
 
243
243
  // Governance (Dynamo Solar SSOT orchestrator) is allowed higher timeout
244
244
  // because it coordinates multiple skill MCPs + required external filter.
245
- const maxTimeout = config.serverName === 'governance' ? 120000 : 60000;
245
+ const modelServers = new Set([
246
+ 'governance',
247
+ 'architect',
248
+ 'code-review',
249
+ 'code-reviewer',
250
+ 'researcher',
251
+ 'security-audit',
252
+ 'security-auditor',
253
+ ]);
254
+ const maxTimeout = modelServers.has(config.serverName) ? 150000 : 60000;
246
255
  expect(config.timeout).toBeLessThanOrEqual(maxTimeout);
247
256
  }
248
257
  });
@@ -13,6 +13,9 @@ import { fileURLToPath } from 'url';
13
13
  import { dirname, join, resolve } from 'path';
14
14
  import fs from 'fs';
15
15
 
16
+ /** Must outlast the 120s governance model call so a real approve can return. */
17
+ const GOVERNANCE_MODEL_TIMEOUT_MS = 150_000;
18
+
16
19
  /**
17
20
  * Registry for managing MCP server configurations
18
21
  */
@@ -95,7 +98,7 @@ export class ServerConfigRegistry {
95
98
  serverName: 'code-review',
96
99
  command: 'node',
97
100
  args: [`${basePath}/knowledge-skills/code-review.server.js`],
98
- timeout: 30000,
101
+ timeout: GOVERNANCE_MODEL_TIMEOUT_MS,
99
102
  });
100
103
 
101
104
  // Security Audit Server
@@ -103,7 +106,7 @@ export class ServerConfigRegistry {
103
106
  serverName: 'security-audit',
104
107
  command: 'node',
105
108
  args: [`${basePath}/knowledge-skills/security-audit.server.js`],
106
- timeout: 45000,
109
+ timeout: GOVERNANCE_MODEL_TIMEOUT_MS,
107
110
  });
108
111
 
109
112
  // Performance Optimization Server
@@ -127,7 +130,7 @@ export class ServerConfigRegistry {
127
130
  serverName: 'researcher',
128
131
  command: 'node',
129
132
  args: [`${basePath}/researcher.server.js`],
130
- timeout: 60000,
133
+ timeout: GOVERNANCE_MODEL_TIMEOUT_MS,
131
134
  });
132
135
 
133
136
  // Governance Service (meta-MCP that orchestrates the three skill servers + required external Dynamo)
@@ -199,7 +202,7 @@ export class ServerConfigRegistry {
199
202
  serverName: 'architect',
200
203
  command: 'node',
201
204
  args: [`${basePath}/architect-tools.server.js`],
202
- timeout: 45000,
205
+ timeout: GOVERNANCE_MODEL_TIMEOUT_MS,
203
206
  });
204
207
 
205
208
  // Bug Triage Specialist Server
@@ -224,7 +227,7 @@ export class ServerConfigRegistry {
224
227
  serverName: 'code-reviewer',
225
228
  command: 'node',
226
229
  args: [`${basePath}/knowledge-skills/code-review.server.js`],
227
- timeout: 30000,
230
+ timeout: GOVERNANCE_MODEL_TIMEOUT_MS,
228
231
  });
229
232
 
230
233
  // Security Auditor (alias for security-audit)
@@ -232,7 +235,7 @@ export class ServerConfigRegistry {
232
235
  serverName: 'security-auditor',
233
236
  command: 'node',
234
237
  args: [`${basePath}/knowledge-skills/security-audit.server.js`],
235
- timeout: 45000,
238
+ timeout: GOVERNANCE_MODEL_TIMEOUT_MS,
236
239
  });
237
240
 
238
241
  // Refactorer Server