0xray 3.5.4 → 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 (266) 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 +32 -6
  39. package/.xray/features.schema.json +87 -0
  40. package/AGENTS-consumer.md +16 -6
  41. package/AGENTS.md +21 -3
  42. package/README.md +13 -10
  43. package/SKILLS.md +1 -1
  44. package/dist/AGENTS.md +21 -3
  45. package/dist/CHANGELOG.md +98 -0
  46. package/dist/README.md +13 -10
  47. package/dist/SKILLS.md +1 -1
  48. package/dist/cli/commands/hermes-install.js +6 -1
  49. package/dist/cli/commands/openclaw-install.js +14 -0
  50. package/dist/cli/index.js +0 -0
  51. package/dist/core/features-config.d.ts +30 -2
  52. package/dist/governance/governance-service.d.ts +1 -0
  53. package/dist/governance/governance-service.js +81 -6
  54. package/dist/infrastructure/schemas/cloud-schemas.d.ts +1 -1
  55. package/dist/integrations/enforcement-gate.js +15 -5
  56. package/dist/integrations/grok/grok-cli.d.ts +3 -0
  57. package/dist/integrations/grok/grok-cli.js +92 -13
  58. package/dist/integrations/grok/hooks/grok-hook-utils.js +99 -9
  59. package/dist/integrations/grok/hooks/post-tool-use.js +68 -25
  60. package/dist/integrations/grok/hooks/pre-tool-use.js +17 -14
  61. package/dist/integrations/grok/hooks/session-start.js +114 -4
  62. package/dist/integrations/grok/plugin/0xray/hooks/hooks.json +31 -24
  63. package/dist/integrations/hermes-agent/__init__.py +11 -1
  64. package/dist/integrations/hermes-agent/__pycache__/__init__.cpython-313.pyc +0 -0
  65. package/dist/integrations/hermes-agent/__pycache__/schemas.cpython-313.pyc +0 -0
  66. package/dist/integrations/hermes-agent/__pycache__/tools.cpython-313.pyc +0 -0
  67. package/dist/integrations/hermes-agent/bridge.mjs +92 -11
  68. package/dist/integrations/hooks/confer-hook-runtime.mjs +49 -0
  69. package/dist/integrations/hooks/delegation-gate-runtime.mjs +32 -3
  70. package/dist/integrations/hooks/pipeline-hook-runtime.mjs +211 -0
  71. package/dist/integrations/hooks/plan-hook-runtime.mjs +68 -0
  72. package/dist/integrations/hooks/station-hook-runtime.cjs +421 -0
  73. package/dist/integrations/hooks/station-hook-runtime.mjs +24 -0
  74. package/dist/integrations/hooks/station-memory-ingest.mjs +45 -0
  75. package/dist/integrations/hooks/station-memory-match.mjs +47 -0
  76. package/dist/integrations/hooks/user-aside-hook-runtime.mjs +49 -0
  77. package/dist/integrations/openclaw/client.d.ts +5 -1
  78. package/dist/integrations/openclaw/client.js +17 -9
  79. package/dist/integrations/openclaw/config.js +0 -1
  80. package/dist/integrations/openclaw/hooks/pre-tool-gate-runtime.mjs +102 -0
  81. package/dist/integrations/openclaw/index.js +17 -0
  82. package/dist/integrations/openclaw/plugin/xray-pre-tool/index.js +75 -0
  83. package/dist/integrations/openclaw/plugin/xray-pre-tool/openclaw.plugin.json +10 -0
  84. package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +10 -0
  85. package/dist/integrations/openclaw/pre-tool-gate.d.ts +19 -0
  86. package/dist/integrations/openclaw/pre-tool-gate.js +39 -0
  87. package/dist/mcps/architect-tools.server.js +6 -1
  88. package/dist/mcps/orchestrator/handlers/complexity-handler.d.ts +7 -0
  89. package/dist/mcps/orchestrator/handlers/complexity-handler.js +107 -8
  90. package/dist/mcps/orchestrator/handlers/task-handler.d.ts +6 -0
  91. package/dist/mcps/orchestrator/handlers/task-handler.js +75 -0
  92. package/dist/mcps/orchestrator/server.js +54 -5
  93. package/dist/memory-routing/index.d.ts +1 -1
  94. package/dist/memory-routing/index.js +1 -1
  95. package/dist/memory-routing/provider-loader.d.ts +4 -0
  96. package/dist/memory-routing/provider-loader.js +74 -4
  97. package/dist/memory-routing/provider-registry.js +3 -2
  98. package/dist/nucleus/aside-worktree.d.ts +41 -0
  99. package/dist/nucleus/aside-worktree.js +164 -0
  100. package/dist/nucleus/autonomy-kernel.d.ts +2 -2
  101. package/dist/nucleus/autonomy-kernel.js +17 -6
  102. package/dist/nucleus/confer.d.ts +57 -0
  103. package/dist/nucleus/confer.js +322 -0
  104. package/dist/nucleus/delegation-gate.d.ts +18 -8
  105. package/dist/nucleus/delegation-gate.js +234 -20
  106. package/dist/nucleus/lead-dev-plan-persistence.d.ts +27 -3
  107. package/dist/nucleus/lead-dev-plan-persistence.js +201 -19
  108. package/dist/nucleus/spawn-plan-resolution.d.ts +20 -0
  109. package/dist/nucleus/spawn-plan-resolution.js +42 -0
  110. package/dist/nucleus/suit-temperament.d.ts +40 -0
  111. package/dist/nucleus/suit-temperament.js +157 -0
  112. package/dist/nucleus/synthesis-consult-receipt.js +18 -2
  113. package/dist/nucleus/synthesis-context.js +1 -1
  114. package/dist/nucleus/user-aside.d.ts +70 -0
  115. package/dist/nucleus/user-aside.js +393 -0
  116. package/dist/plugin/xray-codex-injection.js +14 -3
  117. package/dist/postprocessor/PostProcessor.d.ts +1 -0
  118. package/dist/postprocessor/PostProcessor.js +11 -0
  119. package/dist/postprocessor/triggers/GitHookTrigger.js +11 -5
  120. package/dist/processors/implementations/session-summary-processor.d.ts +1 -1
  121. package/dist/processors/implementations/session-summary-processor.js +9 -6
  122. package/opencode.json +88 -0
  123. package/package.json +25 -6
  124. package/scripts/hooks/install-hooks.cjs +21 -6
  125. package/scripts/hooks/run-hook.js +237 -88
  126. package/scripts/mjs/run-repertoire-mcp.mjs +39 -0
  127. package/scripts/mjs/verify-confer-core.mjs +103 -0
  128. package/scripts/mjs/verify-delegation-gate-core.mjs +76 -3
  129. package/scripts/mjs/verify-four-floor-compact.mjs +524 -0
  130. package/scripts/mjs/verify-hermes-session-start.mjs +137 -0
  131. package/scripts/mjs/verify-pipeline-facets.mjs +215 -0
  132. package/scripts/mjs/verify-pre-push-diff-core.mjs +87 -0
  133. package/scripts/mjs/verify-temperament-live.mjs +261 -0
  134. package/scripts/mjs/verify-user-aside-core.mjs +137 -0
  135. package/scripts/node/bridge-mcp-wiring.cjs +287 -29
  136. package/scripts/node/install-bridges.cjs +198 -44
  137. package/scripts/node/load-reflection-config.mjs +2 -2
  138. package/scripts/node/postinstall.cjs +50 -27
  139. package/scripts/node/release-gate.mjs +8 -4
  140. package/scripts/node/release.mjs +2 -2
  141. package/scripts/node/validate-release-docs.mjs +20 -33
  142. package/scripts/node/version-manager.mjs +25 -10
  143. package/src/integrations/grok/plugin/0xray/hooks/hooks.json +31 -24
  144. package/src/integrations/openclaw/README.md +134 -0
  145. package/src/integrations/openclaw/plugin/xray-pre-tool/index.js +75 -0
  146. package/src/integrations/openclaw/plugin/xray-pre-tool/openclaw.plugin.json +10 -0
  147. package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +10 -0
  148. package/src/mcps/architect-tools.server.ts +6 -1
  149. package/src/mcps/orchestrator/handlers/complexity-handler.ts +180 -21
  150. package/src/mcps/orchestrator/handlers/task-handler.ts +99 -0
  151. package/src/mcps/orchestrator/server.ts +56 -5
  152. package/vendor/@0xray/repertoire/AGENTS.md +163 -0
  153. package/vendor/@0xray/repertoire/LICENSE +21 -0
  154. package/vendor/@0xray/repertoire/README.md +120 -0
  155. package/vendor/@0xray/repertoire/data/curated_signals.json +208 -0
  156. package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts +78 -0
  157. package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts.map +1 -0
  158. package/vendor/@0xray/repertoire/dist/RepertoireService.js +153 -0
  159. package/vendor/@0xray/repertoire/dist/RepertoireService.js.map +1 -0
  160. package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.d.ts +39 -0
  161. package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.d.ts.map +1 -0
  162. package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.js +60 -0
  163. package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.js.map +1 -0
  164. package/vendor/@0xray/repertoire/dist/index.d.ts +14 -0
  165. package/vendor/@0xray/repertoire/dist/index.d.ts.map +1 -0
  166. package/vendor/@0xray/repertoire/dist/index.js +14 -0
  167. package/vendor/@0xray/repertoire/dist/index.js.map +1 -0
  168. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.d.ts +26 -0
  169. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.d.ts.map +1 -0
  170. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.js +109 -0
  171. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.js.map +1 -0
  172. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.d.ts +18 -0
  173. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.d.ts.map +1 -0
  174. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.js +94 -0
  175. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.js.map +1 -0
  176. package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.d.ts +7 -0
  177. package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.d.ts.map +1 -0
  178. package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.js +18 -0
  179. package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.js.map +1 -0
  180. package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.d.ts +31 -0
  181. package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.d.ts.map +1 -0
  182. package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.js +83 -0
  183. package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.js.map +1 -0
  184. package/vendor/@0xray/repertoire/dist/mcp/server.d.ts +6 -0
  185. package/vendor/@0xray/repertoire/dist/mcp/server.d.ts.map +1 -0
  186. package/vendor/@0xray/repertoire/dist/mcp/server.js +173 -0
  187. package/vendor/@0xray/repertoire/dist/mcp/server.js.map +1 -0
  188. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.d.ts +27 -0
  189. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.d.ts.map +1 -0
  190. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.js +107 -0
  191. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.js.map +1 -0
  192. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.d.ts +11 -0
  193. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.d.ts.map +1 -0
  194. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.js +32 -0
  195. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.js.map +1 -0
  196. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.d.ts +9 -0
  197. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.d.ts.map +1 -0
  198. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js +72 -0
  199. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js.map +1 -0
  200. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.d.ts +5 -0
  201. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.d.ts.map +1 -0
  202. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.js +18 -0
  203. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.js.map +1 -0
  204. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.d.ts +31 -0
  205. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.d.ts.map +1 -0
  206. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js +218 -0
  207. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js.map +1 -0
  208. package/vendor/@0xray/repertoire/dist/paths.d.ts +24 -0
  209. package/vendor/@0xray/repertoire/dist/paths.d.ts.map +1 -0
  210. package/vendor/@0xray/repertoire/dist/paths.js +74 -0
  211. package/vendor/@0xray/repertoire/dist/paths.js.map +1 -0
  212. package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts +141 -0
  213. package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts.map +1 -0
  214. package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js +210 -0
  215. package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js.map +1 -0
  216. package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts +48 -0
  217. package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts.map +1 -0
  218. package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js +221 -0
  219. package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js.map +1 -0
  220. package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.d.ts +11 -0
  221. package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.d.ts.map +1 -0
  222. package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.js +43 -0
  223. package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.js.map +1 -0
  224. package/vendor/@0xray/repertoire/dist/registry/signal-prune.d.ts +15 -0
  225. package/vendor/@0xray/repertoire/dist/registry/signal-prune.d.ts.map +1 -0
  226. package/vendor/@0xray/repertoire/dist/registry/signal-prune.js +35 -0
  227. package/vendor/@0xray/repertoire/dist/registry/signal-prune.js.map +1 -0
  228. package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.d.ts +3 -0
  229. package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.d.ts.map +1 -0
  230. package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.js +24 -0
  231. package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.js.map +1 -0
  232. package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.d.ts +24 -0
  233. package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.d.ts.map +1 -0
  234. package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.js +148 -0
  235. package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.js.map +1 -0
  236. package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.d.ts +4 -0
  237. package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.d.ts.map +1 -0
  238. package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.js +44 -0
  239. package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.js.map +1 -0
  240. package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.d.ts +22 -0
  241. package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.d.ts.map +1 -0
  242. package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.js +66 -0
  243. package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.js.map +1 -0
  244. package/vendor/@0xray/repertoire/dist/types.d.ts +210 -0
  245. package/vendor/@0xray/repertoire/dist/types.d.ts.map +1 -0
  246. package/vendor/@0xray/repertoire/dist/types.js +2 -0
  247. package/vendor/@0xray/repertoire/dist/types.js.map +1 -0
  248. package/vendor/@0xray/repertoire/docs/MEMORY-ROUTING-PROVIDER.md +54 -0
  249. package/vendor/@0xray/repertoire/hermes-mcp.example.json +20 -0
  250. package/vendor/@0xray/repertoire/mcp-config.example.json +11 -0
  251. package/vendor/@0xray/repertoire/package.json +124 -0
  252. package/vendor/@0xray/repertoire/schemas/curated-signal.schema.json +68 -0
  253. package/vendor/@0xray/repertoire/schemas/inference-log.schema.json +82 -0
  254. package/vendor/@0xray/repertoire/scripts/confirm-suit-all.mjs +253 -0
  255. package/vendor/@0xray/repertoire/scripts/confirm-suit-harness.mjs +220 -0
  256. package/vendor/@0xray/repertoire/scripts/run-live-synthesis-checkpoint.mjs +215 -0
  257. package/vendor/@0xray/repertoire/scripts/suit-bridge-shared.mjs +139 -0
  258. package/vendor/@0xray/repertoire/scripts/verify-grok-suit.mjs +304 -0
  259. package/vendor/@0xray/repertoire/scripts/verify-hermes-suit.mjs +163 -0
  260. package/vendor/@0xray/repertoire/scripts/verify-openclaw-suit.mjs +125 -0
  261. package/vendor/@0xray/repertoire/scripts/verify-opencode-suit.mjs +127 -0
  262. package/vendor/@0xray/repertoire/scripts/verify-synthesis-dogfood.mjs +207 -0
  263. package/vendor/@0xray/repertoire/skills/repertoire-trap-handling/SKILL.md +206 -0
  264. package/xray/codex.json +12 -3
  265. package/xray/features.json +32 -6
  266. package/xray/features.schema.json +87 -0
@@ -13,23 +13,19 @@ const {
13
13
  wireOpencodeBridge,
14
14
  wireOpenClawBridge,
15
15
  deployPortableProjectMcpJson,
16
+ copyHermesFindProjectRootHelper,
17
+ copyHermesHookRuntimes,
18
+ installOpenClawHostWear,
19
+ maybeWriteOpenClawCliBackend,
20
+ isEphemeralInstallRoot,
21
+ enableMemoryRoutingIfResolves,
22
+ XRAY_MCP_SERVERS,
16
23
  } = require("./bridge-mcp-wiring.cjs");
17
24
 
18
25
  const SKIP_DIRS = new Set(["node_modules", "logs"]);
19
26
  const MERGE_FILES = new Set(["enforcer-config.json"]);
20
27
  const KEEP_IF_EXISTS = new Set([".yml", ".yaml", ".md"]);
21
28
 
22
- /** Canonical 7-server MCP surface — matches package .mcp.json and Grok plugin */
23
- const XRAY_MCP_SERVERS = [
24
- { name: "xray-governance", mcpCmd: "governance", env: { XRAY_FORCE_MCP_GOVERNANCE: "true" } },
25
- { name: "xray-skills", mcpCmd: "skills", env: {} },
26
- { name: "xray-orchestrator", mcpCmd: "orchestrator", env: {} },
27
- { name: "xray-enforcer", mcpCmd: "enforcer", env: {} },
28
- { name: "xray-researcher", mcpCmd: "researcher", env: {} },
29
- { name: "xray-code-review", mcpCmd: "code-review", env: {} },
30
- { name: "xray-architect-tools", mcpCmd: "architect-tools", env: {} },
31
- ];
32
-
33
29
  function resolveConsumerTargetDir(packageRoot, fallbackDir) {
34
30
  const resolved = path.resolve(packageRoot);
35
31
  const inNodeModules =
@@ -128,8 +124,21 @@ function copyTree(src, dest, relPath = "") {
128
124
 
129
125
  function copyPluginDir(src, dest) {
130
126
  if (!fs.existsSync(src)) return false;
131
- fs.cpSync(src, dest, { recursive: true, force: true });
132
- 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
+ }
133
142
  }
134
143
 
135
144
  function writePluginMcpJson(pluginDir, targetDir, log, label) {
@@ -168,30 +177,96 @@ function mergeOpencodeJson(targetDir, packageRoot, log) {
168
177
  }
169
178
  }
170
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
+
171
210
  function patchGrokHooks(pluginDir, packageRoot, targetDir, log, label) {
172
- const hooksPath = path.join(pluginDir, "hooks", "hooks.json");
211
+ const hooksDir = path.join(pluginDir, "hooks");
212
+ const hooksPath = path.join(hooksDir, "hooks.json");
173
213
  const hookScript = path.join(packageRoot, "dist", "integrations", "grok", "hooks", "pre-tool-use.js");
174
- 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
+ }
175
218
 
176
219
  try {
177
220
  const hooks = JSON.parse(fs.readFileSync(hooksPath, "utf8"));
178
- const preTool = hooks.hooks?.PreToolUse?.[0]?.hooks?.[0];
179
- if (preTool && fs.existsSync(hookScript)) {
180
- preTool.command = "node";
181
- preTool.args = [hookScript];
182
- preTool.env = {
183
- ...(preTool.env || {}),
184
- XRAY_ROOT: targetDir,
185
- XRAY_AI_PATH: packageRoot,
186
- };
187
- fs.writeFileSync(hooksPath, JSON.stringify(hooks, null, 2) + "\n");
188
- log(label, "hooks.json patched → enforcement gate", "info");
189
- }
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");
190
251
  } catch (e) {
191
252
  log(label, "hooks.json patch failed", "warn", { error: e.message });
192
253
  }
193
254
  }
194
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
+
195
270
  function installOpencodeBridge(targetDir, packageRoot, log) {
196
271
  const opencodeSource = path.join(packageRoot, ".opencode");
197
272
  const opencodeDest = path.join(targetDir, ".opencode");
@@ -287,10 +362,13 @@ function installGrokBridge(targetDir, packageRoot, log) {
287
362
  }
288
363
 
289
364
  const home = os.homedir();
290
- const targets = [
291
- path.join(targetDir, ".grok", "plugins", "0xray"),
292
- path.join(home, ".grok", "plugins", "0xray"),
293
- ];
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
+ }
294
372
 
295
373
  for (const dest of targets) {
296
374
  if (copyPluginDir(sourceDir, dest)) {
@@ -303,14 +381,14 @@ function installGrokBridge(targetDir, packageRoot, log) {
303
381
  }
304
382
  }
305
383
 
306
- // Grok Build / Cursor also reads ~/.grok/skills/ for agent_skills
307
- const grokGlobalSkills = path.join(home, ".grok", "skills");
308
- const globalCopied = syncBuiltinSkills(grokGlobalSkills, packageRoot);
309
- if (globalCopied > 0) {
310
- 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);
311
391
  }
312
-
313
- registerGrokMcpServers(targetDir, log);
314
392
  }
315
393
 
316
394
  function installHermesBridge(targetDir, packageRoot, log) {
@@ -335,6 +413,10 @@ function installHermesBridge(targetDir, packageRoot, log) {
335
413
  fs.copyFileSync(src, dst);
336
414
  }
337
415
  }
416
+ copyHermesFindProjectRootHelper(packageRoot, targetPluginDir);
417
+ if (copyHermesHookRuntimes(packageRoot)) {
418
+ log("hermes-bridge", "hook runtimes copied", "info", { path: "~/.hermes/plugins/hooks" });
419
+ }
338
420
  log("hermes-bridge", "plugin copied", "info", { path: "~/.hermes/plugins/xray-hermes" });
339
421
 
340
422
  writePluginMcpJson(targetPluginDir, targetDir, log, "hermes-bridge");
@@ -342,10 +424,13 @@ function installHermesBridge(targetDir, packageRoot, log) {
342
424
  const copied = syncBuiltinSkills(path.join(targetPluginDir, "skills"), packageRoot);
343
425
  if (copied > 0) log("hermes-bridge", `skills synced (${copied})`, "info");
344
426
 
345
- // Marker so bridge.mjs resolves the consumer project on hook invocation
346
427
  const rootMarker = path.join(targetPluginDir, "xray-consumer-root.txt");
347
- fs.writeFileSync(rootMarker, targetDir + "\n");
348
- 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
+ }
349
434
 
350
435
  try {
351
436
  const result = wireHermesBridge(targetDir);
@@ -399,6 +484,16 @@ function installOpenclawBridge(targetDir, packageRoot, log) {
399
484
  } catch (e) {
400
485
  log("openclaw-bridge", "openclaw.json mcp wire failed", "warn", { error: e.message });
401
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
+ }
402
497
  }
403
498
 
404
499
  const XRAY_CONFIG_FILES = ["codex.json", "features.json", "features.schema.json", "config.json"];
@@ -419,9 +514,20 @@ function writeJsonFile(filePath, data) {
419
514
  fs.writeFileSync(filePath, `${JSON.stringify(data, null, 2)}\n`);
420
515
  }
421
516
 
422
- 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) {
423
528
  if (!fs.existsSync(dst)) {
424
529
  fs.copyFileSync(src, dst);
530
+ if (file === "features.json") applyResolvedMemoryRouting(dst, targetDir);
425
531
  return true;
426
532
  }
427
533
 
@@ -442,12 +548,28 @@ function deployXrayConfigFile(file, src, dst, packageRoot) {
442
548
  const pkgVersion = readPackageVersion(packageRoot);
443
549
  if (pkgVersion) merged.version = pkgVersion;
444
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;
445
566
  }
446
567
  writeJsonFile(dst, merged);
447
568
  return true;
448
569
  } catch {
449
570
  if (fs.statSync(src).mtime > fs.statSync(dst).mtime) {
450
571
  fs.copyFileSync(src, dst);
572
+ if (file === "features.json") applyResolvedMemoryRouting(dst, targetDir);
451
573
  return true;
452
574
  }
453
575
  return false;
@@ -481,7 +603,7 @@ function deployXrayConfig(targetDir, packageRoot, log) {
481
603
  const src = resolveXrayConfigSource(packageRoot, file);
482
604
  const dst = path.join(xrayTargetDir, file);
483
605
  if (!src) continue;
484
- if (deployXrayConfigFile(file, src, dst, packageRoot)) {
606
+ if (deployXrayConfigFile(file, src, dst, packageRoot, targetDir)) {
485
607
  copied++;
486
608
  }
487
609
  }
@@ -500,6 +622,29 @@ function installGitHooks(packageRoot, log) {
500
622
  }
501
623
  }
502
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
+
503
648
  /**
504
649
  * Install all 4 platform bridges for a consumer project.
505
650
  * @param {{ targetDir: string, packageRoot: string, log?: Function }} opts
@@ -513,7 +658,11 @@ function installAllBridges(opts) {
513
658
  /* noop */
514
659
  });
515
660
 
516
- 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
+ }
517
666
 
518
667
  log("install-bridges", "starting 4-platform install", "info");
519
668
 
@@ -539,4 +688,9 @@ module.exports = {
539
688
  resolveXrayConfigSource,
540
689
  XRAY_CONFIG_FILES,
541
690
  MERGE_CONFIG_FILES,
691
+ patchGrokHooks,
692
+ grokHookShellCommand,
693
+ writeGrokDiscoveredHooks,
694
+ isEphemeralInstallRoot,
695
+ installFrameworkDogfoodWear,
542
696
  };
@@ -16,9 +16,9 @@ const root = process.env.PROJECT_ROOT || process.cwd();
16
16
  const configPath = join(root, '.xray', 'features.json');
17
17
 
18
18
  let mode = 'minimal';
19
- let commitThreshold = 25;
19
+ let commitThreshold = 50;
20
20
  let daysThreshold = 14;
21
- let autoGenerate = true;
21
+ let autoGenerate = false;
22
22
  let promptUser = true;
23
23
 
24
24
  if (existsSync(configPath)) {
@@ -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
+ }
@@ -48,14 +48,18 @@ function main() {
48
48
  step("4/5 Consumer install smoke", "node scripts/node/consumer-install-smoke.mjs");
49
49
  }
50
50
  } else {
51
- step("1/5 Build", "npm run build");
52
- step("2/5 Tests", "npm test");
51
+ step("1/6 Build", "npm run build");
52
+ step("2/6 Tests", "npm test");
53
53
  step(
54
- "3/5 Plugin infrastructure",
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-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
+ );
57
+ step(
58
+ "4/6 Plugin infrastructure",
55
59
  "node scripts/test/validate-plugins-e2e.cjs --structural-only",
56
60
  );
57
61
  if (!skipSmoke) {
58
- step("4/5 Consumer install smoke (fresh + upgrade)", "node scripts/node/consumer-install-smoke.mjs");
62
+ step("5/6 Consumer install smoke (fresh + upgrade)", "node scripts/node/consumer-install-smoke.mjs");
59
63
  }
60
64
  }
61
65
 
@@ -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()) {