0xray 3.5.5 → 4.0.0

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 (229) hide show
  1. package/.mcp.json +51 -7
  2. package/.opencode/skills/api-design/SKILL.md +1 -1
  3. package/.opencode/skills/architect-tools/SKILL.md +1 -1
  4. package/.opencode/skills/architecture-patterns/SKILL.md +1 -1
  5. package/.opencode/skills/auto-format/SKILL.md +1 -1
  6. package/.opencode/skills/boot-orchestrator/SKILL.md +2 -6
  7. package/.opencode/skills/bug-triage/SKILL.md +1 -1
  8. package/.opencode/skills/code-analyzer/SKILL.md +1 -1
  9. package/.opencode/skills/code-review/SKILL.md +1 -1
  10. package/.opencode/skills/enforcer/SKILL.md +1 -1
  11. package/.opencode/skills/framework-compliance-audit/SKILL.md +1 -1
  12. package/.opencode/skills/git-workflow/SKILL.md +1 -1
  13. package/.opencode/skills/hermes-agent/SKILL.md +36 -36
  14. package/.opencode/skills/inference-improve/SKILL.md +1 -1
  15. package/.opencode/skills/lint/SKILL.md +1 -1
  16. package/.opencode/skills/log-monitor/SKILL.md +1 -1
  17. package/.opencode/skills/model-health-check/SKILL.md +1 -1
  18. package/.opencode/skills/multimodal-looker/SKILL.md +1 -1
  19. package/.opencode/skills/orchestrator/SKILL.md +38 -14
  20. package/.opencode/skills/performance-analysis/SKILL.md +1 -1
  21. package/.opencode/skills/performance-optimization/SKILL.md +1 -1
  22. package/.opencode/skills/processor-pipeline/SKILL.md +1 -1
  23. package/.opencode/skills/project-analysis/SKILL.md +1 -1
  24. package/.opencode/skills/refactoring-strategies/SKILL.md +1 -1
  25. package/.opencode/skills/registry.json +65 -0
  26. package/.opencode/skills/researcher/SKILL.md +18 -5
  27. package/.opencode/skills/security-audit/SKILL.md +1 -1
  28. package/.opencode/skills/security-scan/SKILL.md +1 -1
  29. package/.opencode/skills/session-management/SKILL.md +1 -1
  30. package/.opencode/skills/state-manager/SKILL.md +1 -1
  31. package/.opencode/skills/storyteller/SKILL.md +1 -1
  32. package/.opencode/skills/strategist/SKILL.md +12 -0
  33. package/.opencode/skills/testing-best-practices/SKILL.md +37 -0
  34. package/.opencode/skills/testing-strategy/SKILL.md +14 -3
  35. package/.opencode/skills/ui-ux-design/SKILL.md +1 -1
  36. package/.opencode/skills/xray-orchestrator/index.ts +267 -0
  37. package/.xray/codex.json +12 -3
  38. package/.xray/features.json +27 -5
  39. package/.xray/features.schema.json +31 -0
  40. package/AGENTS-consumer.md +16 -6
  41. package/AGENTS.md +11 -3
  42. package/README.md +13 -10
  43. package/SKILLS.md +1 -1
  44. package/dist/AGENTS.md +11 -3
  45. package/dist/CHANGELOG.md +65 -11
  46. package/dist/README.md +13 -10
  47. package/dist/SKILLS.md +1 -1
  48. package/dist/cli/commands/hermes-install.js +3 -0
  49. package/dist/cli/commands/openclaw-install.js +14 -0
  50. package/dist/core/features-config.d.ts +15 -2
  51. package/dist/infrastructure/schemas/cloud-schemas.d.ts +1 -1
  52. package/dist/integrations/grok/grok-cli.d.ts +3 -0
  53. package/dist/integrations/grok/grok-cli.js +92 -4
  54. package/dist/integrations/grok/hooks/grok-hook-utils.js +53 -7
  55. package/dist/integrations/grok/hooks/post-tool-use.js +68 -46
  56. package/dist/integrations/grok/hooks/pre-tool-use.js +14 -31
  57. package/dist/integrations/grok/hooks/session-start.js +86 -4
  58. package/dist/integrations/grok/plugin/0xray/hooks/hooks.json +31 -24
  59. package/dist/integrations/hermes-agent/bridge.mjs +19 -1
  60. package/dist/integrations/hooks/delegation-gate-runtime.mjs +32 -3
  61. package/dist/integrations/hooks/pipeline-hook-runtime.mjs +1 -1
  62. package/dist/integrations/hooks/station-hook-runtime.cjs +421 -0
  63. package/dist/integrations/hooks/station-hook-runtime.mjs +24 -0
  64. package/dist/integrations/hooks/station-memory-ingest.mjs +45 -0
  65. package/dist/integrations/hooks/station-memory-match.mjs +47 -0
  66. package/dist/integrations/openclaw/client.d.ts +5 -1
  67. package/dist/integrations/openclaw/client.js +17 -9
  68. package/dist/integrations/openclaw/config.js +0 -1
  69. package/dist/integrations/openclaw/hooks/pre-tool-gate-runtime.mjs +102 -0
  70. package/dist/integrations/openclaw/index.js +17 -0
  71. package/dist/integrations/openclaw/plugin/xray-pre-tool/index.js +75 -0
  72. package/dist/integrations/openclaw/plugin/xray-pre-tool/openclaw.plugin.json +10 -0
  73. package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +10 -0
  74. package/dist/integrations/openclaw/pre-tool-gate.d.ts +19 -0
  75. package/dist/integrations/openclaw/pre-tool-gate.js +39 -0
  76. package/dist/mcps/orchestrator/handlers/complexity-handler.js +2 -2
  77. package/dist/memory-routing/index.d.ts +1 -1
  78. package/dist/memory-routing/index.js +1 -1
  79. package/dist/memory-routing/provider-loader.d.ts +4 -0
  80. package/dist/memory-routing/provider-loader.js +44 -2
  81. package/dist/memory-routing/provider-registry.js +3 -2
  82. package/dist/nucleus/autonomy-kernel.d.ts +2 -2
  83. package/dist/nucleus/autonomy-kernel.js +17 -6
  84. package/dist/nucleus/confer.js +17 -3
  85. package/dist/nucleus/delegation-gate.d.ts +14 -8
  86. package/dist/nucleus/delegation-gate.js +151 -16
  87. package/dist/nucleus/suit-temperament.d.ts +40 -0
  88. package/dist/nucleus/suit-temperament.js +157 -0
  89. package/dist/nucleus/user-aside.js +1 -1
  90. package/dist/plugin/xray-codex-injection.js +14 -3
  91. package/dist/postprocessor/triggers/GitHookTrigger.js +11 -5
  92. package/opencode.json +88 -0
  93. package/package.json +14 -4
  94. package/scripts/hooks/install-hooks.cjs +18 -3
  95. package/scripts/hooks/run-hook.js +67 -3
  96. package/scripts/mjs/run-repertoire-mcp.mjs +39 -0
  97. package/scripts/mjs/verify-confer-core.mjs +1 -1
  98. package/scripts/mjs/verify-delegation-gate-core.mjs +29 -2
  99. package/scripts/mjs/verify-four-floor-compact.mjs +524 -0
  100. package/scripts/mjs/verify-pipeline-facets.mjs +215 -0
  101. package/scripts/mjs/verify-temperament-live.mjs +261 -0
  102. package/scripts/node/bridge-mcp-wiring.cjs +277 -29
  103. package/scripts/node/install-bridges.cjs +195 -33
  104. package/scripts/node/postinstall.cjs +50 -27
  105. package/scripts/node/release-gate.mjs +1 -1
  106. package/scripts/node/release.mjs +2 -2
  107. package/scripts/node/validate-release-docs.mjs +20 -33
  108. package/scripts/node/version-manager.mjs +25 -10
  109. package/src/integrations/grok/plugin/0xray/hooks/hooks.json +31 -24
  110. package/src/integrations/openclaw/README.md +134 -0
  111. package/src/integrations/openclaw/plugin/xray-pre-tool/index.js +75 -0
  112. package/src/integrations/openclaw/plugin/xray-pre-tool/openclaw.plugin.json +10 -0
  113. package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +10 -0
  114. package/src/mcps/orchestrator/handlers/complexity-handler.ts +2 -1
  115. package/vendor/@0xray/repertoire/AGENTS.md +163 -0
  116. package/vendor/@0xray/repertoire/LICENSE +21 -0
  117. package/vendor/@0xray/repertoire/README.md +120 -0
  118. package/vendor/@0xray/repertoire/data/curated_signals.json +208 -0
  119. package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts +78 -0
  120. package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts.map +1 -0
  121. package/vendor/@0xray/repertoire/dist/RepertoireService.js +153 -0
  122. package/vendor/@0xray/repertoire/dist/RepertoireService.js.map +1 -0
  123. package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.d.ts +39 -0
  124. package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.d.ts.map +1 -0
  125. package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.js +60 -0
  126. package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.js.map +1 -0
  127. package/vendor/@0xray/repertoire/dist/index.d.ts +14 -0
  128. package/vendor/@0xray/repertoire/dist/index.d.ts.map +1 -0
  129. package/vendor/@0xray/repertoire/dist/index.js +14 -0
  130. package/vendor/@0xray/repertoire/dist/index.js.map +1 -0
  131. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.d.ts +26 -0
  132. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.d.ts.map +1 -0
  133. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.js +109 -0
  134. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.js.map +1 -0
  135. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.d.ts +18 -0
  136. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.d.ts.map +1 -0
  137. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.js +94 -0
  138. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.js.map +1 -0
  139. package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.d.ts +7 -0
  140. package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.d.ts.map +1 -0
  141. package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.js +18 -0
  142. package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.js.map +1 -0
  143. package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.d.ts +31 -0
  144. package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.d.ts.map +1 -0
  145. package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.js +83 -0
  146. package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.js.map +1 -0
  147. package/vendor/@0xray/repertoire/dist/mcp/server.d.ts +6 -0
  148. package/vendor/@0xray/repertoire/dist/mcp/server.d.ts.map +1 -0
  149. package/vendor/@0xray/repertoire/dist/mcp/server.js +173 -0
  150. package/vendor/@0xray/repertoire/dist/mcp/server.js.map +1 -0
  151. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.d.ts +27 -0
  152. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.d.ts.map +1 -0
  153. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.js +107 -0
  154. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.js.map +1 -0
  155. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.d.ts +11 -0
  156. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.d.ts.map +1 -0
  157. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.js +32 -0
  158. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.js.map +1 -0
  159. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.d.ts +9 -0
  160. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.d.ts.map +1 -0
  161. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js +72 -0
  162. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js.map +1 -0
  163. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.d.ts +5 -0
  164. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.d.ts.map +1 -0
  165. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.js +18 -0
  166. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.js.map +1 -0
  167. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.d.ts +31 -0
  168. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.d.ts.map +1 -0
  169. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js +218 -0
  170. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js.map +1 -0
  171. package/vendor/@0xray/repertoire/dist/paths.d.ts +24 -0
  172. package/vendor/@0xray/repertoire/dist/paths.d.ts.map +1 -0
  173. package/vendor/@0xray/repertoire/dist/paths.js +74 -0
  174. package/vendor/@0xray/repertoire/dist/paths.js.map +1 -0
  175. package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts +141 -0
  176. package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts.map +1 -0
  177. package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js +210 -0
  178. package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js.map +1 -0
  179. package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts +48 -0
  180. package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts.map +1 -0
  181. package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js +221 -0
  182. package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js.map +1 -0
  183. package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.d.ts +11 -0
  184. package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.d.ts.map +1 -0
  185. package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.js +43 -0
  186. package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.js.map +1 -0
  187. package/vendor/@0xray/repertoire/dist/registry/signal-prune.d.ts +15 -0
  188. package/vendor/@0xray/repertoire/dist/registry/signal-prune.d.ts.map +1 -0
  189. package/vendor/@0xray/repertoire/dist/registry/signal-prune.js +35 -0
  190. package/vendor/@0xray/repertoire/dist/registry/signal-prune.js.map +1 -0
  191. package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.d.ts +3 -0
  192. package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.d.ts.map +1 -0
  193. package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.js +24 -0
  194. package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.js.map +1 -0
  195. package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.d.ts +24 -0
  196. package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.d.ts.map +1 -0
  197. package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.js +148 -0
  198. package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.js.map +1 -0
  199. package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.d.ts +4 -0
  200. package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.d.ts.map +1 -0
  201. package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.js +44 -0
  202. package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.js.map +1 -0
  203. package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.d.ts +22 -0
  204. package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.d.ts.map +1 -0
  205. package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.js +66 -0
  206. package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.js.map +1 -0
  207. package/vendor/@0xray/repertoire/dist/types.d.ts +210 -0
  208. package/vendor/@0xray/repertoire/dist/types.d.ts.map +1 -0
  209. package/vendor/@0xray/repertoire/dist/types.js +2 -0
  210. package/vendor/@0xray/repertoire/dist/types.js.map +1 -0
  211. package/vendor/@0xray/repertoire/docs/MEMORY-ROUTING-PROVIDER.md +54 -0
  212. package/vendor/@0xray/repertoire/hermes-mcp.example.json +20 -0
  213. package/vendor/@0xray/repertoire/mcp-config.example.json +11 -0
  214. package/vendor/@0xray/repertoire/package.json +124 -0
  215. package/vendor/@0xray/repertoire/schemas/curated-signal.schema.json +68 -0
  216. package/vendor/@0xray/repertoire/schemas/inference-log.schema.json +82 -0
  217. package/vendor/@0xray/repertoire/scripts/confirm-suit-all.mjs +253 -0
  218. package/vendor/@0xray/repertoire/scripts/confirm-suit-harness.mjs +220 -0
  219. package/vendor/@0xray/repertoire/scripts/run-live-synthesis-checkpoint.mjs +215 -0
  220. package/vendor/@0xray/repertoire/scripts/suit-bridge-shared.mjs +139 -0
  221. package/vendor/@0xray/repertoire/scripts/verify-grok-suit.mjs +304 -0
  222. package/vendor/@0xray/repertoire/scripts/verify-hermes-suit.mjs +163 -0
  223. package/vendor/@0xray/repertoire/scripts/verify-openclaw-suit.mjs +125 -0
  224. package/vendor/@0xray/repertoire/scripts/verify-opencode-suit.mjs +127 -0
  225. package/vendor/@0xray/repertoire/scripts/verify-synthesis-dogfood.mjs +207 -0
  226. package/vendor/@0xray/repertoire/skills/repertoire-trap-handling/SKILL.md +206 -0
  227. package/xray/codex.json +12 -3
  228. package/xray/features.json +27 -5
  229. package/xray/features.schema.json +31 -0
@@ -14,6 +14,11 @@ const {
14
14
  wireOpenClawBridge,
15
15
  deployPortableProjectMcpJson,
16
16
  copyHermesFindProjectRootHelper,
17
+ copyHermesHookRuntimes,
18
+ installOpenClawHostWear,
19
+ maybeWriteOpenClawCliBackend,
20
+ isEphemeralInstallRoot,
21
+ enableMemoryRoutingIfResolves,
17
22
  XRAY_MCP_SERVERS,
18
23
  } = require("./bridge-mcp-wiring.cjs");
19
24
 
@@ -119,8 +124,21 @@ function copyTree(src, dest, relPath = "") {
119
124
 
120
125
  function copyPluginDir(src, dest) {
121
126
  if (!fs.existsSync(src)) return false;
122
- fs.cpSync(src, dest, { recursive: true, force: true });
123
- return true;
127
+ try {
128
+ if (fs.existsSync(dest)) {
129
+ fs.rmSync(dest, { recursive: true, force: true });
130
+ }
131
+ fs.cpSync(src, dest, { recursive: true, force: true });
132
+ return true;
133
+ } catch (e) {
134
+ try {
135
+ fs.rmSync(dest, { recursive: true, force: true });
136
+ fs.cpSync(src, dest, { recursive: true, force: true });
137
+ return true;
138
+ } catch {
139
+ throw e;
140
+ }
141
+ }
124
142
  }
125
143
 
126
144
  function writePluginMcpJson(pluginDir, targetDir, log, label) {
@@ -159,30 +177,96 @@ function mergeOpencodeJson(targetDir, packageRoot, log) {
159
177
  }
160
178
  }
161
179
 
180
+ function grokHookShellCommand(packageRoot, scriptName, extraArgs) {
181
+ const script = path.join(packageRoot, "dist", "integrations", "grok", "hooks", scriptName);
182
+ const extra = extraArgs ? ` ${extraArgs}` : "";
183
+ // JSON.stringify quotes so spaces/$ in install paths still exec (Grok fail-opens on crash).
184
+ return `XRAY_AI_PATH=${JSON.stringify(packageRoot)} node ${JSON.stringify(script)}${extra}`;
185
+ }
186
+
187
+ function patchGrokHookEntry(hook, packageRoot, targetDir, scriptName, extraArgs) {
188
+ if (!hook) return;
189
+ hook.type = "command";
190
+ hook.command = grokHookShellCommand(packageRoot, scriptName, extraArgs);
191
+ hook.timeout = 30;
192
+ delete hook.args;
193
+ hook.env = {
194
+ ...(hook.env || {}),
195
+ XRAY_ROOT: targetDir,
196
+ XRAY_AI_PATH: packageRoot,
197
+ };
198
+ }
199
+
200
+ function ensureGrokHookEvent(hooks, eventName) {
201
+ if (!hooks.hooks) hooks.hooks = {};
202
+ if (!Array.isArray(hooks.hooks[eventName]) || !hooks.hooks[eventName][0]) {
203
+ hooks.hooks[eventName] = [{ hooks: [{}] }];
204
+ }
205
+ if (!Array.isArray(hooks.hooks[eventName][0].hooks) || !hooks.hooks[eventName][0].hooks[0]) {
206
+ hooks.hooks[eventName][0].hooks = [{}];
207
+ }
208
+ }
209
+
162
210
  function patchGrokHooks(pluginDir, packageRoot, targetDir, log, label) {
163
- const hooksPath = path.join(pluginDir, "hooks", "hooks.json");
211
+ const hooksDir = path.join(pluginDir, "hooks");
212
+ const hooksPath = path.join(hooksDir, "hooks.json");
164
213
  const hookScript = path.join(packageRoot, "dist", "integrations", "grok", "hooks", "pre-tool-use.js");
165
- if (!fs.existsSync(hooksPath)) return;
214
+ if (!fs.existsSync(hooksPath)) {
215
+ if (!fs.existsSync(hooksDir)) fs.mkdirSync(hooksDir, { recursive: true });
216
+ if (!fs.existsSync(hooksPath)) return;
217
+ }
166
218
 
167
219
  try {
168
220
  const hooks = JSON.parse(fs.readFileSync(hooksPath, "utf8"));
169
- const preTool = hooks.hooks?.PreToolUse?.[0]?.hooks?.[0];
170
- if (preTool && fs.existsSync(hookScript)) {
171
- preTool.command = "node";
172
- preTool.args = [hookScript];
173
- preTool.env = {
174
- ...(preTool.env || {}),
175
- XRAY_ROOT: targetDir,
176
- XRAY_AI_PATH: packageRoot,
177
- };
178
- fs.writeFileSync(hooksPath, JSON.stringify(hooks, null, 2) + "\n");
179
- log(label, "hooks.json patched → enforcement gate", "info");
180
- }
221
+ if (!fs.existsSync(hookScript)) return;
222
+ patchGrokHookEntry(hooks.hooks?.PreToolUse?.[0]?.hooks?.[0], packageRoot, targetDir, "pre-tool-use.js");
223
+ patchGrokHookEntry(hooks.hooks?.SessionStart?.[0]?.hooks?.[0], packageRoot, targetDir, "session-start.js");
224
+ patchGrokHookEntry(
225
+ hooks.hooks?.UserPromptSubmit?.[0]?.hooks?.[0],
226
+ packageRoot,
227
+ targetDir,
228
+ "session-start.js",
229
+ "--hook-event=user_prompt_submit",
230
+ );
231
+ patchGrokHookEntry(hooks.hooks?.PostToolUse?.[0]?.hooks?.[0], packageRoot, targetDir, "post-tool-use.js");
232
+ ensureGrokHookEvent(hooks, "PreCompact");
233
+ ensureGrokHookEvent(hooks, "PostCompact");
234
+ patchGrokHookEntry(
235
+ hooks.hooks?.PreCompact?.[0]?.hooks?.[0],
236
+ packageRoot,
237
+ targetDir,
238
+ "session-start.js",
239
+ "--hook-event=pre_compact",
240
+ );
241
+ patchGrokHookEntry(
242
+ hooks.hooks?.PostCompact?.[0]?.hooks?.[0],
243
+ packageRoot,
244
+ targetDir,
245
+ "session-start.js",
246
+ "--hook-event=post_compact",
247
+ );
248
+ fs.writeFileSync(hooksPath, JSON.stringify(hooks, null, 2) + "\n");
249
+ writeGrokDiscoveredHooks(targetDir, hooksPath, log, label);
250
+ log(label, "hooks.json patched → Grok command-string enforcement gate", "info");
181
251
  } catch (e) {
182
252
  log(label, "hooks.json patch failed", "warn", { error: e.message });
183
253
  }
184
254
  }
185
255
 
256
+ /** Grok TUI loads `<project>/.grok/hooks/*.json`, not `plugins/0xray/hooks`. */
257
+ function writeGrokDiscoveredHooks(targetDir, hooksPath, log, label) {
258
+ if (!targetDir || !fs.existsSync(hooksPath)) return;
259
+ try {
260
+ const destDir = path.join(targetDir, ".grok", "hooks");
261
+ fs.mkdirSync(destDir, { recursive: true });
262
+ const dest = path.join(destDir, "0xray.json");
263
+ fs.copyFileSync(hooksPath, dest);
264
+ log(label, "Grok discovered hooks → .grok/hooks/0xray.json", "info", { dest });
265
+ } catch (e) {
266
+ log(label, "Grok discovered hooks copy failed", "warn", { error: e.message });
267
+ }
268
+ }
269
+
186
270
  function installOpencodeBridge(targetDir, packageRoot, log) {
187
271
  const opencodeSource = path.join(packageRoot, ".opencode");
188
272
  const opencodeDest = path.join(targetDir, ".opencode");
@@ -278,10 +362,13 @@ function installGrokBridge(targetDir, packageRoot, log) {
278
362
  }
279
363
 
280
364
  const home = os.homedir();
281
- const targets = [
282
- path.join(targetDir, ".grok", "plugins", "0xray"),
283
- path.join(home, ".grok", "plugins", "0xray"),
284
- ];
365
+ const ephemeral = isEphemeralInstallRoot(targetDir);
366
+ const targets = [path.join(targetDir, ".grok", "plugins", "0xray")];
367
+ if (!ephemeral) {
368
+ targets.push(path.join(home, ".grok", "plugins", "0xray"));
369
+ } else {
370
+ log("grok-bridge", "skip machine ~/.grok plugin — ephemeral consumer", "info");
371
+ }
285
372
 
286
373
  for (const dest of targets) {
287
374
  if (copyPluginDir(sourceDir, dest)) {
@@ -294,14 +381,14 @@ function installGrokBridge(targetDir, packageRoot, log) {
294
381
  }
295
382
  }
296
383
 
297
- // Grok Build / Cursor also reads ~/.grok/skills/ for agent_skills
298
- const grokGlobalSkills = path.join(home, ".grok", "skills");
299
- const globalCopied = syncBuiltinSkills(grokGlobalSkills, packageRoot);
300
- if (globalCopied > 0) {
301
- log("grok-bridge", `global skills synced (${globalCopied})`, "info", { path: "~/.grok/skills/" });
384
+ if (!ephemeral) {
385
+ const grokGlobalSkills = path.join(home, ".grok", "skills");
386
+ const globalCopied = syncBuiltinSkills(grokGlobalSkills, packageRoot);
387
+ if (globalCopied > 0) {
388
+ log("grok-bridge", `global skills synced (${globalCopied})`, "info", { path: "~/.grok/skills/" });
389
+ }
390
+ registerGrokMcpServers(targetDir, log);
302
391
  }
303
-
304
- registerGrokMcpServers(targetDir, log);
305
392
  }
306
393
 
307
394
  function installHermesBridge(targetDir, packageRoot, log) {
@@ -327,6 +414,9 @@ function installHermesBridge(targetDir, packageRoot, log) {
327
414
  }
328
415
  }
329
416
  copyHermesFindProjectRootHelper(packageRoot, targetPluginDir);
417
+ if (copyHermesHookRuntimes(packageRoot)) {
418
+ log("hermes-bridge", "hook runtimes copied", "info", { path: "~/.hermes/plugins/hooks" });
419
+ }
330
420
  log("hermes-bridge", "plugin copied", "info", { path: "~/.hermes/plugins/xray-hermes" });
331
421
 
332
422
  writePluginMcpJson(targetPluginDir, targetDir, log, "hermes-bridge");
@@ -334,10 +424,13 @@ function installHermesBridge(targetDir, packageRoot, log) {
334
424
  const copied = syncBuiltinSkills(path.join(targetPluginDir, "skills"), packageRoot);
335
425
  if (copied > 0) log("hermes-bridge", `skills synced (${copied})`, "info");
336
426
 
337
- // Marker so bridge.mjs resolves the consumer project on hook invocation
338
427
  const rootMarker = path.join(targetPluginDir, "xray-consumer-root.txt");
339
- fs.writeFileSync(rootMarker, targetDir + "\n");
340
- log("hermes-bridge", "consumer root marker written", "info");
428
+ if (!isEphemeralInstallRoot(targetDir)) {
429
+ fs.writeFileSync(rootMarker, targetDir + "\n");
430
+ log("hermes-bridge", "consumer root marker written", "info");
431
+ } else {
432
+ log("hermes-bridge", "skip machine consumer marker — ephemeral consumer", "info");
433
+ }
341
434
 
342
435
  try {
343
436
  const result = wireHermesBridge(targetDir);
@@ -391,6 +484,16 @@ function installOpenclawBridge(targetDir, packageRoot, log) {
391
484
  } catch (e) {
392
485
  log("openclaw-bridge", "openclaw.json mcp wire failed", "warn", { error: e.message });
393
486
  }
487
+
488
+ if (!isEphemeralInstallRoot(targetDir)) {
489
+ const hook = installOpenClawHostWear(packageRoot);
490
+ if (hook) log("openclaw-bridge", "PreToolUse hook installed", "info", { path: hook });
491
+ if (maybeWriteOpenClawCliBackend()) {
492
+ log("openclaw-bridge", "opencode-cli backend written", "info");
493
+ }
494
+ } else {
495
+ log("openclaw-bridge", "skip machine PreToolUse wear — ephemeral consumer", "info");
496
+ }
394
497
  }
395
498
 
396
499
  const XRAY_CONFIG_FILES = ["codex.json", "features.json", "features.schema.json", "config.json"];
@@ -411,9 +514,20 @@ function writeJsonFile(filePath, data) {
411
514
  fs.writeFileSync(filePath, `${JSON.stringify(data, null, 2)}\n`);
412
515
  }
413
516
 
414
- function deployXrayConfigFile(file, src, dst, packageRoot) {
517
+ function applyResolvedMemoryRouting(dst, targetDir) {
518
+ try {
519
+ const features = JSON.parse(fs.readFileSync(dst, "utf8"));
520
+ const next = enableMemoryRoutingIfResolves(features, targetDir);
521
+ if (next.changed) writeJsonFile(dst, next.features);
522
+ } catch {
523
+ /* leftover default stays off when features.json is unreadable */
524
+ }
525
+ }
526
+
527
+ function deployXrayConfigFile(file, src, dst, packageRoot, targetDir) {
415
528
  if (!fs.existsSync(dst)) {
416
529
  fs.copyFileSync(src, dst);
530
+ if (file === "features.json") applyResolvedMemoryRouting(dst, targetDir);
417
531
  return true;
418
532
  }
419
533
 
@@ -434,12 +548,28 @@ function deployXrayConfigFile(file, src, dst, packageRoot) {
434
548
  const pkgVersion = readPackageVersion(packageRoot);
435
549
  if (pkgVersion) merged.version = pkgVersion;
436
550
  else if (shipped.version) merged.version = shipped.version;
551
+ // v3: existing consumers without suit_temperament stay guided on upgrade.
552
+ // Fresh copy (dst missing) already returned above with shipped auto.
553
+ const hadTemperament =
554
+ consumer.suit_temperament &&
555
+ typeof consumer.suit_temperament === "object" &&
556
+ consumer.suit_temperament.profile;
557
+ if (!hadTemperament) {
558
+ merged.suit_temperament = {
559
+ ...(merged.suit_temperament || {}),
560
+ profile: "guided",
561
+ };
562
+ }
563
+ writeJsonFile(dst, merged);
564
+ applyResolvedMemoryRouting(dst, targetDir);
565
+ return true;
437
566
  }
438
567
  writeJsonFile(dst, merged);
439
568
  return true;
440
569
  } catch {
441
570
  if (fs.statSync(src).mtime > fs.statSync(dst).mtime) {
442
571
  fs.copyFileSync(src, dst);
572
+ if (file === "features.json") applyResolvedMemoryRouting(dst, targetDir);
443
573
  return true;
444
574
  }
445
575
  return false;
@@ -473,7 +603,7 @@ function deployXrayConfig(targetDir, packageRoot, log) {
473
603
  const src = resolveXrayConfigSource(packageRoot, file);
474
604
  const dst = path.join(xrayTargetDir, file);
475
605
  if (!src) continue;
476
- if (deployXrayConfigFile(file, src, dst, packageRoot)) {
606
+ if (deployXrayConfigFile(file, src, dst, packageRoot, targetDir)) {
477
607
  copied++;
478
608
  }
479
609
  }
@@ -492,6 +622,29 @@ function installGitHooks(packageRoot, log) {
492
622
  }
493
623
  }
494
624
 
625
+ /**
626
+ * Framework dogfood: do not deploy consumer copies over the package,
627
+ * but keep Grok discovery hooks hot and enable Repertoire when it resolves.
628
+ */
629
+ function installFrameworkDogfoodWear(packageRoot, log) {
630
+ const featuresPath = path.join(packageRoot, ".xray", "features.json");
631
+ if (fs.existsSync(featuresPath)) {
632
+ applyResolvedMemoryRouting(featuresPath, packageRoot);
633
+ }
634
+
635
+ const sourceDir = findGrokPluginSource(packageRoot);
636
+ const pluginDest = path.join(packageRoot, ".grok", "plugins", "0xray");
637
+ if (!sourceDir) {
638
+ log("grok-dogfood", "skipped", "warn", { reason: "grok plugin source missing" });
639
+ return;
640
+ }
641
+ const hooksJson = path.join(pluginDest, "hooks", "hooks.json");
642
+ if (!fs.existsSync(hooksJson)) {
643
+ copyPluginDir(sourceDir, pluginDest);
644
+ }
645
+ patchGrokHooks(pluginDest, packageRoot, packageRoot, log, "grok-dogfood");
646
+ }
647
+
495
648
  /**
496
649
  * Install all 4 platform bridges for a consumer project.
497
650
  * @param {{ targetDir: string, packageRoot: string, log?: Function }} opts
@@ -505,7 +658,11 @@ function installAllBridges(opts) {
505
658
  /* noop */
506
659
  });
507
660
 
508
- if (!isConsumerInstall(packageRoot, targetDir)) return;
661
+ if (!isConsumerInstall(packageRoot, targetDir)) {
662
+ log("install-bridges", "framework dogfood wear", "info");
663
+ installFrameworkDogfoodWear(packageRoot, log);
664
+ return;
665
+ }
509
666
 
510
667
  log("install-bridges", "starting 4-platform install", "info");
511
668
 
@@ -531,4 +688,9 @@ module.exports = {
531
688
  resolveXrayConfigSource,
532
689
  XRAY_CONFIG_FILES,
533
690
  MERGE_CONFIG_FILES,
691
+ patchGrokHooks,
692
+ grokHookShellCommand,
693
+ writeGrokDiscoveredHooks,
694
+ isEphemeralInstallRoot,
695
+ installFrameworkDogfoodWear,
534
696
  };
@@ -15,17 +15,12 @@ function structuredLog(component, action, status, details) {
15
15
  console.log(`${ts} [${component}] ${action} - ${String(status).toUpperCase()}${detailsPart}`);
16
16
  }
17
17
 
18
- const packageRoot = path.join(__dirname, "..", "..");
19
- const targetDir = resolveConsumerTargetDir(packageRoot, process.env.PWD || process.cwd());
20
- const resolvedPackage = path.resolve(packageRoot);
21
- const resolvedTarget = path.resolve(targetDir);
22
-
23
18
  const XRAY_MANAGED_AGENTS_MARKER = "<!-- 0xray-managed -->";
24
19
 
25
- // Copy AGENTS-consumer.md → AGENTS.md (only if absent or still 0xray-managed)
26
- const agentsConsumer = path.join(packageRoot, "AGENTS-consumer.md");
27
- const agentsDest = path.join(targetDir, "AGENTS.md");
28
- if (fs.existsSync(agentsConsumer) && isConsumerInstall(resolvedPackage, resolvedTarget)) {
20
+ function deployManagedAgents(packageRoot, targetDir, log) {
21
+ const agentsConsumer = path.join(packageRoot, "AGENTS-consumer.md");
22
+ const agentsDest = path.join(targetDir, "AGENTS.md");
23
+ if (!fs.existsSync(agentsConsumer)) return;
29
24
  const shouldDeployAgents =
30
25
  !fs.existsSync(agentsDest) ||
31
26
  fs.readFileSync(agentsDest, "utf8").includes(XRAY_MANAGED_AGENTS_MARKER);
@@ -36,37 +31,65 @@ if (fs.existsSync(agentsConsumer) && isConsumerInstall(resolvedPackage, resolved
36
31
  }
37
32
  fs.writeFileSync(agentsDest, content);
38
33
  } else {
39
- structuredLog("postinstall", "Skipped AGENTS.md (consumer-customized)", "info");
34
+ log("postinstall", "Skipped AGENTS.md (consumer-customized)", "info");
40
35
  }
41
36
  }
42
37
 
43
- // .gitignore: full template when absent; merge suit block when existing
44
- if (isConsumerInstall(resolvedPackage, resolvedTarget)) {
38
+ function deployConsumerGitignore(packageRoot, targetDir, log) {
45
39
  const gitignoreResult = applyConsumerGitignore(targetDir, packageRoot);
46
40
  if (gitignoreResult === "created") {
47
- structuredLog("postinstall", "Created .gitignore from template", "info");
41
+ log("postinstall", "Created .gitignore from template", "info");
48
42
  } else if (gitignoreResult === "merged") {
49
- structuredLog("postinstall", "Merged 0xray suit entries into .gitignore", "info");
43
+ log("postinstall", "Merged 0xray suit entries into .gitignore", "info");
50
44
  }
51
45
  }
52
46
 
53
- // Unified 4-platform bridge install (OpenCode, Grok, Hermes, OpenClaw)
54
- if (isConsumerInstall(resolvedPackage, resolvedTarget)) {
47
+ /**
48
+ * Wear bridges for consumers (full 4-platform) and the framework repo (dogfood).
49
+ * installAllBridges already decides which path.
50
+ */
51
+ function runPostinstall(packageRoot, targetDir, log) {
52
+ const logFn = log || structuredLog;
53
+ const resolvedPackage = path.resolve(packageRoot);
54
+ const resolvedTarget = path.resolve(targetDir);
55
+ const consumer = isConsumerInstall(resolvedPackage, resolvedTarget);
56
+
57
+ if (consumer) {
58
+ deployManagedAgents(resolvedPackage, resolvedTarget, logFn);
59
+ deployConsumerGitignore(resolvedPackage, resolvedTarget, logFn);
60
+ }
61
+
55
62
  try {
56
63
  installAllBridges({
57
- targetDir,
58
- packageRoot,
59
- log: structuredLog,
64
+ targetDir: resolvedTarget,
65
+ packageRoot: resolvedPackage,
66
+ log: logFn,
60
67
  });
61
68
  } catch (e) {
62
- structuredLog("postinstall", "Bridge install failed", "error", { error: e.message });
69
+ logFn("postinstall", "Bridge install failed", "error", { error: e.message });
70
+ throw e;
71
+ }
72
+
73
+ if (consumer) {
74
+ logFn(
75
+ "postinstall",
76
+ "0xRay framework installed (4 bridges). Run `npx 0xray setup` for symlinks/Hermes skill extras.",
77
+ "success",
78
+ );
79
+ } else {
80
+ logFn("postinstall", "framework dogfood wear complete", "success");
81
+ }
82
+ }
83
+
84
+ module.exports = { runPostinstall };
85
+
86
+ if (require.main === module) {
87
+ const packageRoot = path.join(__dirname, "..", "..");
88
+ const targetDir = resolveConsumerTargetDir(packageRoot, process.env.PWD || process.cwd());
89
+ try {
90
+ runPostinstall(packageRoot, targetDir);
91
+ } catch {
63
92
  console.error("\n❌ 0xRay postinstall failed — bridge wiring did not complete.\n");
64
93
  process.exit(1);
65
94
  }
66
-
67
- structuredLog(
68
- "postinstall",
69
- "0xRay framework installed (4 bridges). Run `npx 0xray setup` for symlinks/Hermes skill extras.",
70
- "success"
71
- );
72
- }
95
+ }
@@ -52,7 +52,7 @@ function main() {
52
52
  step("2/6 Tests", "npm test");
53
53
  step(
54
54
  "3/6 Consumer hook verifiers",
55
- "npm run verify:pre-commit-diff && npm run verify:pre-push-diff && node scripts/mjs/verify-delegation-gate-core.mjs --host=grok && node scripts/mjs/verify-delegation-gate-core.mjs --host=hermes && node scripts/mjs/verify-hermes-session-start.mjs && node scripts/mjs/verify-confer-core.mjs && npm run verify:user-aside && npm run build && node scripts/mjs/verify-pipeline-facets.mjs --package-only",
55
+ "npm run verify:pre-commit-diff && npm run verify:pre-push-diff && node scripts/mjs/verify-delegation-gate-core.mjs --host=grok && node scripts/mjs/verify-delegation-gate-core.mjs --host=hermes && node scripts/mjs/verify-delegation-gate-core.mjs --host=opencode && node scripts/mjs/verify-hermes-session-start.mjs && node scripts/mjs/verify-confer-core.mjs && npm run verify:user-aside && npm run build && node scripts/mjs/verify-pipeline-facets.mjs --package-only",
56
56
  );
57
57
  step(
58
58
  "4/6 Plugin infrastructure",
@@ -24,7 +24,7 @@ import { getReleaseArtifactPaths } from "./version-manager.mjs";
24
24
  const rootDir = process.cwd();
25
25
  const args = process.argv.slice(2);
26
26
  const dryRun = args.includes("--dry-run");
27
- const releaseType = args.find((a) => ["major", "minor", "patch"].includes(a)) || "patch";
27
+ const releaseType = args.find((a) => ["major", "minor", "patch"].includes(a));
28
28
 
29
29
  function run(cmd, label) {
30
30
  console.log(`\n> ${cmd}`);
@@ -70,7 +70,7 @@ function publishIdempotent(version) {
70
70
  }
71
71
 
72
72
  async function main() {
73
- if (!["major", "minor", "patch"].includes(releaseType)) {
73
+ if (!releaseType || !["major", "minor", "patch"].includes(releaseType)) {
74
74
  console.error("Usage: node scripts/node/release.mjs [patch|minor|major] [--dry-run]");
75
75
  process.exit(1);
76
76
  }
@@ -24,7 +24,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
24
24
  const defaultRoot = path.resolve(__dirname, '../..');
25
25
 
26
26
  const STANDARD_HEADER_RE =
27
- /^\*{0,2}v[\d.]+\*{0,2}\s*—\s*\d+ agents · \d+ skills · \d+ MCP servers? · \d+ codex terms(?: · [\d,]+ tests)?/m;
27
+ /^\*{0,2}v[\d.]+\*{0,2}\s*—\s*a suit that survives the context window/m;
28
28
 
29
29
  /** Guides that must exist and reference the current release (body or header). */
30
30
  const REQUIRED_GUIDES = [
@@ -45,7 +45,10 @@ const ROOT_DOC_CHECKS = [
45
45
  validate: (content, version, counts, header) => {
46
46
  const errors = [];
47
47
  if (!content.includes(header)) {
48
- errors.push(`missing or stale standard header (expected: ${header})`);
48
+ errors.push(`missing kernel header (expected substring: ${header})`);
49
+ }
50
+ if (!content.includes('survive the context window') && !content.includes('survives the context window')) {
51
+ errors.push('missing context-window / exo kernel copy');
49
52
  }
50
53
  if (!content.includes('SKILLS.md')) {
51
54
  errors.push('missing SKILLS.md reference in postinstall/docs section');
@@ -63,14 +66,8 @@ const ROOT_DOC_CHECKS = [
63
66
  if (!content.includes(`**v${version}**`)) {
64
67
  errors.push(`missing version marker **v${version}**`);
65
68
  }
66
- if (!content.includes(`${counts.agents} agents`)) {
67
- errors.push(`expected ${counts.agents} agents in header`);
68
- }
69
- if (!content.includes(`${counts.skills} skills`)) {
70
- errors.push(`expected ${counts.skills} skills in header`);
71
- }
72
- if (!content.includes('68 codex terms')) {
73
- errors.push('expected 68 codex terms in header');
69
+ if (!content.includes('survive the context window') && !content.includes('survives the context window') && !content.includes('Exo, not catalog')) {
70
+ errors.push('missing exo / context-window kernel copy');
74
71
  }
75
72
  if (!content.includes('aside-context.md') && !content.includes('AsideContext')) {
76
73
  errors.push('missing AsideContext documentation reference');
@@ -85,9 +82,11 @@ const ROOT_DOC_CHECKS = [
85
82
  rel: 'AGENTS-consumer.md',
86
83
  validate: (content, version, counts) => {
87
84
  const errors = [];
88
- const expected = `**v${version}** — ${counts.mcps} MCP servers · ${counts.skills} skills · 68 codex terms`;
89
- if (!content.includes(expected)) {
90
- errors.push(`consumer header stale (expected substring: ${expected})`);
85
+ if (!content.includes(`**v${version}**`)) {
86
+ errors.push(`missing version marker **v${version}**`);
87
+ }
88
+ if (!content.includes('survive the context window') && !content.includes('survives the context window')) {
89
+ errors.push('consumer header missing context-window kernel copy');
91
90
  }
92
91
  if (!content.includes('SKILLS.md')) {
93
92
  errors.push('missing SKILLS.md in postinstall section');
@@ -146,28 +145,16 @@ function validateChangelog(content, version) {
146
145
  }
147
146
 
148
147
  function validateStandardHeader(content, expectedHeader, label) {
149
- const match = content.match(STANDARD_HEADER_RE);
150
- if (!match) {
151
- return [`${label}: no standard docs header line found`];
152
- }
153
- if (match[0] !== expectedHeader) {
154
- return [`${label}: header is "${match[0]}", expected "${expectedHeader}"`];
148
+ if (!content.includes(expectedHeader) && !STANDARD_HEADER_RE.test(content)) {
149
+ return [`${label}: missing kernel header (expected substring: ${expectedHeader})`];
155
150
  }
156
151
  return [];
157
152
  }
158
153
 
159
- function validateDocusaurusTagline(content, counts) {
154
+ function validateDocusaurusTagline(content) {
160
155
  const errors = [];
161
- const expectedParts = [
162
- `${counts.agents} agents`,
163
- `${counts.skills} skills`,
164
- `${counts.mcps} MCP servers`,
165
- '68 codex terms',
166
- ];
167
- for (const part of expectedParts) {
168
- if (!content.includes(part)) {
169
- errors.push(`docusaurus.config.ts tagline missing "${part}"`);
170
- }
156
+ if (!content.includes('survive the context window') && !content.includes('survives the context window')) {
157
+ errors.push('docusaurus.config.ts tagline missing context-window kernel copy');
171
158
  }
172
159
  return errors;
173
160
  }
@@ -184,8 +171,8 @@ export function validateReleaseDocs(rootDir = defaultRoot) {
184
171
  const expectedHeader = buildDocsHeader(counts, version);
185
172
  const codexTerms = getCodexTermCount(rootDir);
186
173
 
187
- if (codexTerms !== null && codexTerms !== 68) {
188
- warnings.push(`codex.json has ${codexTerms} terms (docs reference 68)`);
174
+ if (codexTerms !== null && counts.codexTerms && codexTerms !== counts.codexTerms) {
175
+ warnings.push(`codex.json has ${codexTerms} terms (counts.codexTerms is ${counts.codexTerms})`);
189
176
  }
190
177
 
191
178
  const changelog = readFile(rootDir, 'CHANGELOG.md');
@@ -234,7 +221,7 @@ export function validateReleaseDocs(rootDir = defaultRoot) {
234
221
  if (!docusaurus) {
235
222
  errors.push('docs-site/docusaurus.config.ts: missing');
236
223
  } else {
237
- errors.push(...validateDocusaurusTagline(docusaurus, counts));
224
+ errors.push(...validateDocusaurusTagline(docusaurus));
238
225
  }
239
226
 
240
227
  for (const rel of getReleaseArtifactPaths()) {
@@ -166,7 +166,8 @@ export function getFrameworkCounts(baseDir = rootDir) {
166
166
  const counts = {
167
167
  agents: 0,
168
168
  mcps: 0,
169
- skills: 0
169
+ skills: 0,
170
+ codexTerms: 68,
170
171
  };
171
172
 
172
173
  // Count agents (.yml files in src/opencode/agents/ — source of truth)
@@ -183,7 +184,8 @@ export function getFrameworkCounts(baseDir = rootDir) {
183
184
  try {
184
185
  const mcpJson = JSON.parse(fs.readFileSync(mcpJsonPath, 'utf-8'));
185
186
  const servers = mcpJson.mcpServers || mcpJson.servers || {};
186
- counts.mcps = Object.keys(servers).length;
187
+ const xrayServers = Object.keys(servers).filter((name) => name.startsWith('xray-'));
188
+ counts.mcps = xrayServers.length || 7;
187
189
  } catch {
188
190
  counts.mcps = 7;
189
191
  }
@@ -199,6 +201,17 @@ export function getFrameworkCounts(baseDir = rootDir) {
199
201
  .filter(f => fs.existsSync(path.join(skillsDir, f, 'SKILL.md')))
200
202
  .length;
201
203
  }
204
+
205
+ const codexPath = path.join(baseDir, 'xray/codex.json');
206
+ if (fs.existsSync(codexPath)) {
207
+ try {
208
+ const codex = JSON.parse(fs.readFileSync(codexPath, 'utf-8'));
209
+ const terms = codex.terms && typeof codex.terms === 'object' ? Object.keys(codex.terms) : [];
210
+ if (terms.length > 0) counts.codexTerms = terms.length;
211
+ } catch {
212
+ /* keep default */
213
+ }
214
+ }
202
215
 
203
216
  return counts;
204
217
  }
@@ -271,10 +284,11 @@ function updateReadme(counts, newVersion) {
271
284
 
272
285
  let readme = fs.readFileSync(readmePath, 'utf-8');
273
286
 
274
- // Update header line: **v3.4.1** — 42 agents · 45 skills · 7 MCP servers · ...
287
+ // Kernel header (4.0): exo, not catalog counts
288
+ const kernel = buildDocsHeader(counts, newVersion);
275
289
  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`
290
+ /^\*\*v[\d.]+\*\* — (?:\d+ agents · \d+ skills · \d+ MCP servers? · \d+ codex terms(?: · [\d,]+ tests)?|a suit that survives the context window.*)$/m,
291
+ kernel,
278
292
  );
279
293
 
280
294
  // Update version badge: [![Version](https://img.shields.io/badge/version-1.6.x-blue...)]
@@ -313,13 +327,14 @@ export const DOCS_SITE_HEADER_FILES = [
313
327
  'docs-site/docs/full-reference.md',
314
328
  ];
315
329
 
316
- export function buildDocsHeader(counts, newVersion) {
317
- return `**v${newVersion}** — ${counts.agents} agents · ${counts.skills} skills · ${counts.mcps} MCP servers · 68 codex terms · 3,226 tests`;
330
+ export function buildDocsHeader(_counts, newVersion) {
331
+ return `**v${newVersion}** — a suit that survives the context window`;
318
332
  }
319
333
 
320
334
  function syncDocsSiteHeaders(counts, newVersion) {
321
335
  const header = buildDocsHeader(counts, newVersion);
322
- const headerRe = /^\*{0,2}v?[\d.]*\*{0,2}\s*—?\s*\d+ agents · \d+ skills · \d+ MCP servers? · \d+ codex terms(?: · [\d,]+ tests)?/m;
336
+ const headerRe =
337
+ /^\*{0,2}v?[\d.]*\*{0,2}\s*—?\s*(?:\d+ agents · \d+ skills · \d+ MCP servers? · \d+ codex terms(?: · [\d,]+ tests)?|a suit that survives the context window.*|exo, not toolset.*|wear the exo.*)/im;
323
338
  for (const rel of DOCS_SITE_HEADER_FILES) {
324
339
  const filePath = path.join(rootDir, rel);
325
340
  if (!fs.existsSync(filePath)) continue;
@@ -346,8 +361,8 @@ function updateConsumerAgentsHeader(newVersion, counts) {
346
361
  if (!fs.existsSync(consumerPath)) return;
347
362
  let content = fs.readFileSync(consumerPath, 'utf-8');
348
363
  content = content.replace(
349
- /^\*\*v[\d.]+\*\* — \d+ MCP servers · \d+ skills · \d+ codex terms/m,
350
- `**v${newVersion}** — ${counts.mcps} MCP servers · ${counts.skills} skills · 68 codex terms`
364
+ /^\*\*v[\d.]+\*\* — .+$/m,
365
+ buildDocsHeader(counts, newVersion),
351
366
  );
352
367
  fs.writeFileSync(consumerPath, content);
353
368
  console.log(`✅ Updated AGENTS-consumer.md version header`);