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
@@ -139,11 +139,32 @@ function enableMemoryRoutingIfResolves(features, targetDir) {
139
139
  };
140
140
  }
141
141
 
142
+ function isDogfoodXrayPackage(targetDir) {
143
+ try {
144
+ const pkgPath = path.join(targetDir, "package.json");
145
+ if (!fs.existsSync(pkgPath)) return false;
146
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
147
+ return pkg && pkg.name === "0xray";
148
+ } catch {
149
+ return false;
150
+ }
151
+ }
152
+
142
153
  function resolveGogglesMcp(targetDir) {
143
- const candidates = [
144
- path.join(targetDir, "node_modules", "0xray", "scripts", "mjs", "run-goggles-mcp.mjs"),
145
- path.join(targetDir, "scripts", "mjs", "run-goggles-mcp.mjs"),
146
- ];
154
+ const installed = path.join(
155
+ targetDir,
156
+ "node_modules",
157
+ "0xray",
158
+ "scripts",
159
+ "mjs",
160
+ "run-goggles-mcp.mjs",
161
+ );
162
+ const checkout = path.join(targetDir, "scripts", "mjs", "run-goggles-mcp.mjs");
163
+ // The factory package is not installed into its own node_modules. npm upgrade
164
+ // removes that folder, and a recorded node_modules path then fails the handshake.
165
+ const candidates = isDogfoodXrayPackage(targetDir)
166
+ ? [checkout, installed]
167
+ : [installed, checkout];
147
168
  return candidates.find((file) => fs.existsSync(file)) || null;
148
169
  }
149
170
 
@@ -315,7 +336,18 @@ function pinnedMcpLaunch(targetDir, mcpCmd) {
315
336
  */
316
337
  const LIVE_ENV_NAMES = ["PATH", "HOME"];
317
338
 
339
+ let launcherPackageRoot = "";
340
+
341
+ /** Wear sets this so a /tmp checkout is not the path written into a real project. */
342
+ function pinLauncherPackageRoot(packageRoot) {
343
+ launcherPackageRoot = packageRoot ? path.resolve(packageRoot) : "";
344
+ }
345
+
318
346
  function mcpLauncherPath() {
347
+ if (launcherPackageRoot) {
348
+ const candidate = path.join(launcherPackageRoot, "scripts", "node", "mcp-launch.cjs");
349
+ if (fs.existsSync(candidate)) return candidate;
350
+ }
319
351
  return path.join(__dirname, "mcp-launch.cjs");
320
352
  }
321
353
 
@@ -837,7 +869,125 @@ function resolveOpenClawPluginDir(packageRoot) {
837
869
  ].find((p) => fs.existsSync(path.join(p, "index.js"))) || null;
838
870
  }
839
871
 
840
- function installOpenClawHostWear(packageRoot) {
872
+ function isCheckoutOpenClawPluginPath(pluginPath) {
873
+ const normalized = String(pluginPath || "").replace(/\\/g, "/");
874
+ return (
875
+ normalized.includes("/src/integrations/openclaw/plugin/xray-pre-tool") &&
876
+ !normalized.includes("/node_modules/")
877
+ );
878
+ }
879
+
880
+ function isInstalledOpenClawPluginPath(pluginPath) {
881
+ const normalized = String(pluginPath || "").replace(/\\/g, "/");
882
+ return (
883
+ normalized.includes("/node_modules/") &&
884
+ normalized.includes("/integrations/openclaw/plugin/xray-pre-tool")
885
+ );
886
+ }
887
+
888
+ /** Installed package first. A checkout src path drops once any installed plugin is present. */
889
+ function settleOpenClawPluginPaths(paths, wornPluginDir) {
890
+ const list = (Array.isArray(paths) ? paths : []).map((entry) => String(entry));
891
+ const wornIsInstalled = Boolean(wornPluginDir && isInstalledOpenClawPluginPath(wornPluginDir));
892
+ const dropCheckout =
893
+ wornIsInstalled || list.some((entry) => isInstalledOpenClawPluginPath(entry));
894
+ const next = [];
895
+ const seen = new Set();
896
+ const push = (entry) => {
897
+ if (!entry) return;
898
+ const resolved = path.resolve(String(entry));
899
+ if (dropCheckout && isCheckoutOpenClawPluginPath(resolved)) return;
900
+ if (seen.has(resolved)) return;
901
+ seen.add(resolved);
902
+ next.push(resolved);
903
+ };
904
+ if (wornIsInstalled) push(wornPluginDir);
905
+ for (const entry of list) push(entry);
906
+ return next;
907
+ }
908
+
909
+ function resolveWornOpenClawPlugin(targetDir, packageRoot) {
910
+ const candidates = [];
911
+ if (targetDir) {
912
+ candidates.push(
913
+ path.join(targetDir, "node_modules", "0xray", "dist", "integrations", "openclaw", "plugin", "xray-pre-tool"),
914
+ path.join(targetDir, "node_modules", "0xray", "src", "integrations", "openclaw", "plugin", "xray-pre-tool"),
915
+ );
916
+ }
917
+ const fromPackage = resolveOpenClawPluginDir(packageRoot);
918
+ if (fromPackage) candidates.push(fromPackage);
919
+ return candidates.find((dir) => fs.existsSync(path.join(dir, "index.js"))) || null;
920
+ }
921
+
922
+ function replaceJsonPathsArray(raw, before, next) {
923
+ const keyAt = raw.indexOf('"paths"');
924
+ if (keyAt < 0) return null;
925
+ const bracket = raw.indexOf("[", keyAt);
926
+ if (bracket < 0) return null;
927
+ let depth = 0;
928
+ let end = -1;
929
+ for (let i = bracket; i < raw.length; i += 1) {
930
+ const ch = raw[i];
931
+ if (ch === "[") depth += 1;
932
+ else if (ch === "]") {
933
+ depth -= 1;
934
+ if (depth === 0) {
935
+ end = i;
936
+ break;
937
+ }
938
+ }
939
+ }
940
+ if (end < 0) return null;
941
+ let parsed;
942
+ try {
943
+ parsed = JSON.parse(raw.slice(bracket, end + 1));
944
+ } catch {
945
+ return null;
946
+ }
947
+ if (JSON.stringify(parsed) !== JSON.stringify(before)) return null;
948
+ const lineStart = raw.lastIndexOf("\n", keyAt) + 1;
949
+ const indent = (raw.slice(lineStart, keyAt).match(/^\s*/) || [""])[0];
950
+ const itemIndent = `${indent} `;
951
+ const body = next
952
+ .map((entry) => `${itemIndent}${JSON.stringify(entry)}`)
953
+ .join(",\n");
954
+ const array = `[\n${body}\n${indent}]`;
955
+ return `${raw.slice(0, bracket)}${array}${raw.slice(end + 1)}`;
956
+ }
957
+
958
+ /** Rewrite plugins.load.paths in place. Leaves the rest of the config file alone. */
959
+ function pinOpenClawPluginLoad(configPath, wornPluginDir) {
960
+ if (!configPath || !fs.existsSync(configPath)) return null;
961
+ const raw = fs.readFileSync(configPath, "utf8");
962
+ const config = JSON.parse(raw);
963
+ if (!config.plugins || typeof config.plugins !== "object") return null;
964
+ if (!config.plugins.load || typeof config.plugins.load !== "object") config.plugins.load = {};
965
+ const before = Array.isArray(config.plugins.load.paths) ? config.plugins.load.paths : [];
966
+ const next = settleOpenClawPluginPaths(before, wornPluginDir);
967
+ if (JSON.stringify(before) === JSON.stringify(next)) return next;
968
+ const replaced = replaceJsonPathsArray(raw, before, next);
969
+ if (replaced == null) return null;
970
+ fs.writeFileSync(configPath, replaced);
971
+ return next;
972
+ }
973
+
974
+ function recordOpenClawProjectPlugin(targetDir, packageRoot) {
975
+ const pluginDir = resolveWornOpenClawPlugin(targetDir, packageRoot);
976
+ if (!pluginDir || !isInstalledOpenClawPluginPath(pluginDir)) return null;
977
+ const configPath = path.join(targetDir, ".xray", "config", "openclaw.json");
978
+ if (!fs.existsSync(configPath)) return null;
979
+ let config;
980
+ try {
981
+ config = JSON.parse(fs.readFileSync(configPath, "utf8"));
982
+ } catch {
983
+ return null;
984
+ }
985
+ config.pluginPath = path.resolve(pluginDir);
986
+ fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
987
+ return config.pluginPath;
988
+ }
989
+
990
+ function installOpenClawHostWear(packageRoot, targetDir) {
841
991
  if (millSuit.isIsolatedHome()) return null;
842
992
  const source = resolveOpenClawPreToolHookSource(packageRoot);
843
993
  if (!source) return null;
@@ -846,6 +996,11 @@ function installOpenClawHostWear(packageRoot) {
846
996
  fs.mkdirSync(hookDir, { recursive: true });
847
997
  const dest = path.join(hookDir, "xray-pre-tool.mjs");
848
998
  fs.copyFileSync(source, dest);
999
+ const worn = resolveWornOpenClawPlugin(targetDir, packageRoot);
1000
+ const hookRoot =
1001
+ worn && isInstalledOpenClawPluginPath(worn) && targetDir
1002
+ ? path.join(path.resolve(targetDir), "node_modules", "0xray")
1003
+ : packageRoot;
849
1004
  fs.writeFileSync(
850
1005
  path.join(hookDir, "xray-pre-tool.json"),
851
1006
  `${JSON.stringify(
@@ -855,17 +1010,16 @@ function installOpenClawHostWear(packageRoot) {
855
1010
  args: [dest],
856
1011
  stdin: "json",
857
1012
  blockExitCode: 2,
858
- env: { XRAY_AI_PATH: packageRoot },
1013
+ env: { XRAY_AI_PATH: hookRoot },
859
1014
  },
860
1015
  null,
861
1016
  2,
862
1017
  )}\n`,
863
1018
  );
864
1019
 
865
- const pluginSrc = resolveOpenClawPluginDir(packageRoot);
866
- if (pluginSrc) {
1020
+ if (worn && isInstalledOpenClawPluginPath(worn)) {
867
1021
  try {
868
- execFileSync("openclaw", ["plugins", "install", "-l", pluginSrc], {
1022
+ execFileSync("openclaw", ["plugins", "install", "-l", path.resolve(worn)], {
869
1023
  stdio: "pipe",
870
1024
  encoding: "utf8",
871
1025
  timeout: 60000,
@@ -883,6 +1037,13 @@ function installOpenClawHostWear(packageRoot) {
883
1037
  /* enable is best-effort */
884
1038
  }
885
1039
  }
1040
+ const configPath = resolveOpenClawConfigPath();
1041
+ if (fs.existsSync(configPath)) {
1042
+ pinOpenClawPluginLoad(
1043
+ configPath,
1044
+ worn && isInstalledOpenClawPluginPath(worn) ? worn : null,
1045
+ );
1046
+ }
886
1047
  return dest;
887
1048
  }
888
1049
 
@@ -947,6 +1108,102 @@ function wireOpenClawBridge(targetDir) {
947
1108
  return syncOpenClawMcpRegistry(targetDir);
948
1109
  }
949
1110
 
1111
+ function tomlString(value) {
1112
+ return JSON.stringify(String(value));
1113
+ }
1114
+
1115
+ function suitServerNames() {
1116
+ return new Set(XRAY_MCP_SERVERS.map((server) => server.name));
1117
+ }
1118
+
1119
+ function isSuitMcpHeader(line, names) {
1120
+ const match = /^\[([^\]]+)\]\s*$/.exec(line.trim());
1121
+ if (!match) return false;
1122
+ const parts = match[1].split(".");
1123
+ return parts[0] === "mcp_servers" && names.has(parts[1]);
1124
+ }
1125
+
1126
+ function stripSuitMcpBlocks(toml, names) {
1127
+ const kept = [];
1128
+ let skip = false;
1129
+ for (const line of String(toml || "").split(/\r?\n/)) {
1130
+ if (/^\s*\[/.test(line)) skip = isSuitMcpHeader(line, names);
1131
+ if (!skip) kept.push(line);
1132
+ }
1133
+ return kept.join("\n").replace(/\n{3,}/g, "\n\n").trim();
1134
+ }
1135
+
1136
+ function suitMcpBlock(server, launch) {
1137
+ const args = launch.args.map((arg) => ` ${tomlString(arg)},`).join("\n");
1138
+ const lines = [
1139
+ `[mcp_servers.${server.name}]`,
1140
+ `command = ${tomlString(launch.command)}`,
1141
+ "args = [",
1142
+ args,
1143
+ "]",
1144
+ "enabled = true",
1145
+ ];
1146
+ const env = launch.env && typeof launch.env === "object" ? launch.env : {};
1147
+ const envKeys = Object.keys(env);
1148
+ if (envKeys.length > 0) {
1149
+ lines.push("", `[mcp_servers.${server.name}.env]`);
1150
+ for (const key of envKeys) lines.push(`${key} = ${tomlString(env[key])}`);
1151
+ }
1152
+ return lines.join("\n");
1153
+ }
1154
+
1155
+ /**
1156
+ * Project `.grok/config.toml` replaces a same-named user server.
1157
+ * The launch is the worn package, not `npx -y 0xray`.
1158
+ */
1159
+ function writeProjectSuitMcp(targetDir) {
1160
+ const root = path.resolve(targetDir);
1161
+ const names = suitServerNames();
1162
+ const blocks = XRAY_MCP_SERVERS.map((server) =>
1163
+ suitMcpBlock(server, scopedMcpLaunch(root, server.mcpCmd, server.env)),
1164
+ );
1165
+ const grokDir = path.join(root, ".grok");
1166
+ fs.mkdirSync(grokDir, { recursive: true });
1167
+ const tomlPath = path.join(grokDir, "config.toml");
1168
+ const existing = fs.existsSync(tomlPath) ? fs.readFileSync(tomlPath, "utf8") : "";
1169
+ const kept = stripSuitMcpBlocks(existing, names);
1170
+ const body = [kept, blocks.join("\n\n")].filter((part) => part && part.trim()).join("\n\n");
1171
+ fs.writeFileSync(tomlPath, `${body.trim()}\n`);
1172
+ return tomlPath;
1173
+ }
1174
+
1175
+ function grokConfigHome(env) {
1176
+ const source = env || process.env;
1177
+ const home = source.HOME || source.USERPROFILE;
1178
+ return home ? path.resolve(home) : os.homedir();
1179
+ }
1180
+
1181
+ /** Grok 1.0.50 has no --trust flag. An untrusted folder skips project MCP. */
1182
+ function trustGrokFolder(targetDir, env) {
1183
+ const home = grokConfigHome(env);
1184
+ const grokDir = path.join(home, ".grok");
1185
+ fs.mkdirSync(grokDir, { recursive: true });
1186
+ const file = path.join(grokDir, "trusted_folders.toml");
1187
+ let text = fs.existsSync(file) ? fs.readFileSync(file, "utf8") : "";
1188
+ const folders = [path.resolve(targetDir)];
1189
+ try {
1190
+ const real = fs.realpathSync(folders[0]);
1191
+ if (real !== folders[0]) folders.push(real);
1192
+ } catch {
1193
+ /* the path is the one Grok will see */
1194
+ }
1195
+ const now = Math.floor(Date.now() / 1000);
1196
+ let added = 0;
1197
+ for (const folder of folders) {
1198
+ const header = `[folders.${tomlString(folder)}]`;
1199
+ if (text.includes(header)) continue;
1200
+ text = `${text.replace(/\s*$/, "")}\n${header}\ntrusted = true\ndecided_at = ${now}\n`;
1201
+ added += 1;
1202
+ }
1203
+ if (added > 0) fs.writeFileSync(file, text.endsWith("\n") ? text : `${text}\n`);
1204
+ return file;
1205
+ }
1206
+
950
1207
  module.exports = {
951
1208
  XRAY_MCP_SERVERS,
952
1209
  HERMES_CONFIG_PATH,
@@ -988,9 +1245,16 @@ module.exports = {
988
1245
  enableMemoryRoutingIfResolves,
989
1246
  isEphemeralInstallRoot,
990
1247
  isIsolatedHome,
1248
+ pinLauncherPackageRoot,
991
1249
  copyHermesHookRuntimes,
992
1250
  resolveOpenClawPreToolHookSource,
993
1251
  resolveOpenClawPluginDir,
994
1252
  installOpenClawHostWear,
1253
+ settleOpenClawPluginPaths,
1254
+ pinOpenClawPluginLoad,
1255
+ recordOpenClawProjectPlugin,
1256
+ resolveWornOpenClawPlugin,
995
1257
  maybeWriteOpenClawCliBackend,
1258
+ writeProjectSuitMcp,
1259
+ trustGrokFolder,
996
1260
  };
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Turn confer on or off in the worn .xray/features.json.
4
+ * A missing key stays off until this runs. Synthesis stays untouched.
5
+ */
6
+ "use strict";
7
+
8
+ const fs = require("fs");
9
+ const path = require("path");
10
+
11
+ function fail(message) {
12
+ process.stderr.write(`${message}\n`);
13
+ process.exit(1);
14
+ }
15
+
16
+ function orchestrationBlock(data) {
17
+ const current = data.multi_agent_orchestration;
18
+ if (current && typeof current === "object" && !Array.isArray(current)) return current;
19
+ const created = {};
20
+ data.multi_agent_orchestration = created;
21
+ return created;
22
+ }
23
+
24
+ function conferBlock(orch) {
25
+ const current = orch.confer;
26
+ if (current && typeof current === "object" && !Array.isArray(current)) return current;
27
+ const created = {};
28
+ orch.confer = created;
29
+ return created;
30
+ }
31
+
32
+ function main() {
33
+ const state = process.argv[2];
34
+ if (state !== "on" && state !== "off") fail("confer: say on or off");
35
+
36
+ const featuresPath = path.join(process.cwd(), ".xray", "features.json");
37
+ if (!fs.existsSync(featuresPath)) {
38
+ fail("confer: .xray/features.json is missing. Run npx 0xray wear first.");
39
+ }
40
+
41
+ let data;
42
+ try {
43
+ data = JSON.parse(fs.readFileSync(featuresPath, "utf8"));
44
+ } catch {
45
+ fail("confer: .xray/features.json is not valid JSON");
46
+ }
47
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
48
+ fail("confer: .xray/features.json is not valid JSON");
49
+ }
50
+
51
+ const orch = orchestrationBlock(data);
52
+ const confer = conferBlock(orch);
53
+ if (state === "on") {
54
+ confer.enabled = true;
55
+ if (confer.on_synthesis !== false) confer.on_synthesis = true;
56
+ } else {
57
+ confer.enabled = false;
58
+ confer.on_synthesis = false;
59
+ orch.confer_on_synthesis = false;
60
+ }
61
+
62
+ fs.writeFileSync(featuresPath, `${JSON.stringify(data, null, 2)}\n`);
63
+ process.stdout.write(`confer: ${state}\n`);
64
+ }
65
+
66
+ if (require.main === module) main();