0xray 3.5.5 → 4.0.1

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 (233) hide show
  1. package/.mcp.json +18 -14
  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 +28 -6
  39. package/.xray/features.schema.json +31 -0
  40. package/AGENTS-consumer.md +17 -7
  41. package/AGENTS.md +18 -10
  42. package/README.md +30 -27
  43. package/SKILLS.md +2 -2
  44. package/dist/AGENTS.md +18 -10
  45. package/dist/CHANGELOG.md +81 -11
  46. package/dist/README.md +30 -27
  47. package/dist/SKILLS.md +2 -2
  48. package/dist/cli/commands/hermes-install.js +3 -0
  49. package/dist/cli/commands/openclaw-install.js +14 -0
  50. package/dist/cli/index.js +10 -1
  51. package/dist/core/features-config.d.ts +15 -2
  52. package/dist/infrastructure/schemas/cloud-schemas.d.ts +1 -1
  53. package/dist/integrations/grok/grok-cli.d.ts +3 -0
  54. package/dist/integrations/grok/grok-cli.js +92 -4
  55. package/dist/integrations/grok/hooks/grok-hook-utils.js +53 -7
  56. package/dist/integrations/grok/hooks/post-tool-use.js +68 -46
  57. package/dist/integrations/grok/hooks/pre-tool-use.js +14 -31
  58. package/dist/integrations/grok/hooks/session-start.js +86 -4
  59. package/dist/integrations/grok/plugin/0xray/hooks/hooks.json +31 -24
  60. package/dist/integrations/hermes-agent/bridge.mjs +26 -1
  61. package/dist/integrations/hooks/delegation-gate-runtime.mjs +32 -3
  62. package/dist/integrations/hooks/pipeline-hook-runtime.mjs +1 -1
  63. package/dist/integrations/hooks/station-hook-runtime.cjs +421 -0
  64. package/dist/integrations/hooks/station-hook-runtime.mjs +24 -0
  65. package/dist/integrations/hooks/station-memory-ingest.mjs +45 -0
  66. package/dist/integrations/hooks/station-memory-match.mjs +47 -0
  67. package/dist/integrations/openclaw/client.d.ts +5 -1
  68. package/dist/integrations/openclaw/client.js +17 -9
  69. package/dist/integrations/openclaw/config.js +0 -1
  70. package/dist/integrations/openclaw/hooks/pre-tool-gate-runtime.mjs +102 -0
  71. package/dist/integrations/openclaw/index.js +17 -0
  72. package/dist/integrations/openclaw/plugin/xray-pre-tool/index.js +75 -0
  73. package/dist/integrations/openclaw/plugin/xray-pre-tool/openclaw.plugin.json +10 -0
  74. package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +12 -0
  75. package/dist/integrations/openclaw/pre-tool-gate.d.ts +19 -0
  76. package/dist/integrations/openclaw/pre-tool-gate.js +39 -0
  77. package/dist/mcps/orchestrator/handlers/complexity-handler.js +2 -2
  78. package/dist/memory-routing/index.d.ts +1 -1
  79. package/dist/memory-routing/index.js +1 -1
  80. package/dist/memory-routing/provider-loader.d.ts +4 -0
  81. package/dist/memory-routing/provider-loader.js +44 -2
  82. package/dist/memory-routing/provider-registry.js +3 -2
  83. package/dist/nucleus/autonomy-kernel.d.ts +2 -2
  84. package/dist/nucleus/autonomy-kernel.js +17 -6
  85. package/dist/nucleus/confer.js +17 -3
  86. package/dist/nucleus/delegation-gate.d.ts +14 -8
  87. package/dist/nucleus/delegation-gate.js +151 -16
  88. package/dist/nucleus/suit-temperament.d.ts +40 -0
  89. package/dist/nucleus/suit-temperament.js +157 -0
  90. package/dist/nucleus/user-aside.js +1 -1
  91. package/dist/plugin/xray-codex-injection.js +14 -3
  92. package/dist/postprocessor/triggers/GitHookTrigger.js +11 -5
  93. package/opencode.json +80 -0
  94. package/package.json +15 -5
  95. package/scripts/hooks/install-hooks.cjs +18 -3
  96. package/scripts/hooks/run-hook.js +67 -3
  97. package/scripts/mjs/run-repertoire-mcp.mjs +39 -0
  98. package/scripts/mjs/verify-confer-core.mjs +1 -1
  99. package/scripts/mjs/verify-delegation-gate-core.mjs +29 -2
  100. package/scripts/mjs/verify-four-floor-compact.mjs +524 -0
  101. package/scripts/mjs/verify-pipeline-facets.mjs +215 -0
  102. package/scripts/mjs/verify-temperament-live.mjs +261 -0
  103. package/scripts/node/bridge-mcp-wiring.cjs +277 -29
  104. package/scripts/node/consumer-install-smoke.mjs +55 -2
  105. package/scripts/node/install-bridges.cjs +195 -33
  106. package/scripts/node/postinstall.cjs +50 -27
  107. package/scripts/node/reconcile-version.mjs +0 -4
  108. package/scripts/node/release-gate.mjs +1 -1
  109. package/scripts/node/release.mjs +2 -2
  110. package/scripts/node/universal-version-manager.js +1 -1
  111. package/scripts/node/validate-release-docs.mjs +20 -33
  112. package/scripts/node/version-manager.mjs +63 -18
  113. package/src/integrations/grok/plugin/0xray/hooks/hooks.json +31 -24
  114. package/src/integrations/openclaw/README.md +134 -0
  115. package/src/integrations/openclaw/plugin/xray-pre-tool/index.js +75 -0
  116. package/src/integrations/openclaw/plugin/xray-pre-tool/openclaw.plugin.json +10 -0
  117. package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +12 -0
  118. package/src/mcps/orchestrator/handlers/complexity-handler.ts +2 -1
  119. package/vendor/@0xray/repertoire/AGENTS.md +163 -0
  120. package/vendor/@0xray/repertoire/LICENSE +21 -0
  121. package/vendor/@0xray/repertoire/README.md +120 -0
  122. package/vendor/@0xray/repertoire/data/curated_signals.json +208 -0
  123. package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts +78 -0
  124. package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts.map +1 -0
  125. package/vendor/@0xray/repertoire/dist/RepertoireService.js +153 -0
  126. package/vendor/@0xray/repertoire/dist/RepertoireService.js.map +1 -0
  127. package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.d.ts +39 -0
  128. package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.d.ts.map +1 -0
  129. package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.js +60 -0
  130. package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.js.map +1 -0
  131. package/vendor/@0xray/repertoire/dist/index.d.ts +14 -0
  132. package/vendor/@0xray/repertoire/dist/index.d.ts.map +1 -0
  133. package/vendor/@0xray/repertoire/dist/index.js +14 -0
  134. package/vendor/@0xray/repertoire/dist/index.js.map +1 -0
  135. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.d.ts +26 -0
  136. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.d.ts.map +1 -0
  137. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.js +109 -0
  138. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.js.map +1 -0
  139. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.d.ts +18 -0
  140. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.d.ts.map +1 -0
  141. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.js +94 -0
  142. package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.js.map +1 -0
  143. package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.d.ts +7 -0
  144. package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.d.ts.map +1 -0
  145. package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.js +18 -0
  146. package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.js.map +1 -0
  147. package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.d.ts +31 -0
  148. package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.d.ts.map +1 -0
  149. package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.js +83 -0
  150. package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.js.map +1 -0
  151. package/vendor/@0xray/repertoire/dist/mcp/server.d.ts +6 -0
  152. package/vendor/@0xray/repertoire/dist/mcp/server.d.ts.map +1 -0
  153. package/vendor/@0xray/repertoire/dist/mcp/server.js +173 -0
  154. package/vendor/@0xray/repertoire/dist/mcp/server.js.map +1 -0
  155. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.d.ts +27 -0
  156. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.d.ts.map +1 -0
  157. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.js +107 -0
  158. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.js.map +1 -0
  159. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.d.ts +11 -0
  160. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.d.ts.map +1 -0
  161. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.js +32 -0
  162. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.js.map +1 -0
  163. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.d.ts +9 -0
  164. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.d.ts.map +1 -0
  165. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js +72 -0
  166. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js.map +1 -0
  167. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.d.ts +5 -0
  168. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.d.ts.map +1 -0
  169. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.js +18 -0
  170. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.js.map +1 -0
  171. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.d.ts +31 -0
  172. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.d.ts.map +1 -0
  173. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js +218 -0
  174. package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js.map +1 -0
  175. package/vendor/@0xray/repertoire/dist/paths.d.ts +24 -0
  176. package/vendor/@0xray/repertoire/dist/paths.d.ts.map +1 -0
  177. package/vendor/@0xray/repertoire/dist/paths.js +74 -0
  178. package/vendor/@0xray/repertoire/dist/paths.js.map +1 -0
  179. package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts +141 -0
  180. package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts.map +1 -0
  181. package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js +210 -0
  182. package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js.map +1 -0
  183. package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts +48 -0
  184. package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts.map +1 -0
  185. package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js +221 -0
  186. package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js.map +1 -0
  187. package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.d.ts +11 -0
  188. package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.d.ts.map +1 -0
  189. package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.js +43 -0
  190. package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.js.map +1 -0
  191. package/vendor/@0xray/repertoire/dist/registry/signal-prune.d.ts +15 -0
  192. package/vendor/@0xray/repertoire/dist/registry/signal-prune.d.ts.map +1 -0
  193. package/vendor/@0xray/repertoire/dist/registry/signal-prune.js +35 -0
  194. package/vendor/@0xray/repertoire/dist/registry/signal-prune.js.map +1 -0
  195. package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.d.ts +3 -0
  196. package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.d.ts.map +1 -0
  197. package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.js +24 -0
  198. package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.js.map +1 -0
  199. package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.d.ts +24 -0
  200. package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.d.ts.map +1 -0
  201. package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.js +148 -0
  202. package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.js.map +1 -0
  203. package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.d.ts +4 -0
  204. package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.d.ts.map +1 -0
  205. package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.js +44 -0
  206. package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.js.map +1 -0
  207. package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.d.ts +22 -0
  208. package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.d.ts.map +1 -0
  209. package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.js +66 -0
  210. package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.js.map +1 -0
  211. package/vendor/@0xray/repertoire/dist/types.d.ts +210 -0
  212. package/vendor/@0xray/repertoire/dist/types.d.ts.map +1 -0
  213. package/vendor/@0xray/repertoire/dist/types.js +2 -0
  214. package/vendor/@0xray/repertoire/dist/types.js.map +1 -0
  215. package/vendor/@0xray/repertoire/docs/MEMORY-ROUTING-PROVIDER.md +54 -0
  216. package/vendor/@0xray/repertoire/hermes-mcp.example.json +20 -0
  217. package/vendor/@0xray/repertoire/mcp-config.example.json +11 -0
  218. package/vendor/@0xray/repertoire/package.json +124 -0
  219. package/vendor/@0xray/repertoire/schemas/curated-signal.schema.json +68 -0
  220. package/vendor/@0xray/repertoire/schemas/inference-log.schema.json +82 -0
  221. package/vendor/@0xray/repertoire/scripts/confirm-suit-all.mjs +253 -0
  222. package/vendor/@0xray/repertoire/scripts/confirm-suit-harness.mjs +220 -0
  223. package/vendor/@0xray/repertoire/scripts/run-live-synthesis-checkpoint.mjs +215 -0
  224. package/vendor/@0xray/repertoire/scripts/suit-bridge-shared.mjs +139 -0
  225. package/vendor/@0xray/repertoire/scripts/verify-grok-suit.mjs +304 -0
  226. package/vendor/@0xray/repertoire/scripts/verify-hermes-suit.mjs +163 -0
  227. package/vendor/@0xray/repertoire/scripts/verify-openclaw-suit.mjs +125 -0
  228. package/vendor/@0xray/repertoire/scripts/verify-opencode-suit.mjs +127 -0
  229. package/vendor/@0xray/repertoire/scripts/verify-synthesis-dogfood.mjs +207 -0
  230. package/vendor/@0xray/repertoire/skills/repertoire-trap-handling/SKILL.md +206 -0
  231. package/xray/codex.json +12 -3
  232. package/xray/features.json +28 -6
  233. package/xray/features.schema.json +31 -0
@@ -24,8 +24,8 @@ import { syncBuiltinSkills } from '../../cli/commands/skill-install.js';
24
24
  const __dirname = path.dirname(new URL(import.meta.url).pathname);
25
25
  const packageRoot = path.resolve(__dirname, '..', '..', '..');
26
26
  const requireCjs = createRequire(import.meta.url);
27
- const { resolveConsumerTargetDir } = requireCjs(path.join(packageRoot, 'scripts/node/install-bridges.cjs'));
28
- const { XRAY_MCP_SERVERS } = requireCjs(path.join(packageRoot, 'scripts/node/bridge-mcp-wiring.cjs'));
27
+ const { resolveConsumerTargetDir, patchGrokHooks } = requireCjs(path.join(packageRoot, 'scripts/node/install-bridges.cjs'));
28
+ const { XRAY_MCP_SERVERS, resolveRepertoireMcp } = requireCjs(path.join(packageRoot, 'scripts/node/bridge-mcp-wiring.cjs'));
29
29
  function registerGrokMcpServers(targetDir) {
30
30
  try {
31
31
  execSync('which grok', { stdio: 'ignore' });
@@ -90,6 +90,17 @@ export async function installForGrokCLI(options = {}) {
90
90
  if (globalCopied > 0) {
91
91
  console.log(`\x1b[32m✓ Synced ${globalCopied} builtin skills to ~/.grok/skills/\x1b[0m`);
92
92
  }
93
+ pinGrokPluginToInstalledDist(targetPluginDir, packageRoot, targetDir);
94
+ wearGrokHookCommands(targetPluginDir, packageRoot, targetDir);
95
+ const projectPluginDir = path.join(targetDir, '.grok', 'plugins', '0xray');
96
+ if (projectPluginDir !== targetPluginDir) {
97
+ if (!fs.existsSync(projectPluginDir) || options.force) {
98
+ fs.cpSync(sourceDir, projectPluginDir, { recursive: true, force: true });
99
+ }
100
+ pinGrokPluginToInstalledDist(projectPluginDir, packageRoot, targetDir);
101
+ wearGrokHookCommands(projectPluginDir, packageRoot, targetDir);
102
+ }
103
+ writeProjectRepertoireMcp(targetDir);
93
104
  // Attempt auto-trust (best effort)
94
105
  try {
95
106
  execSync(`grok plugins trust "${targetPluginDir}"`, { stdio: 'ignore' });
@@ -106,11 +117,88 @@ export async function installForGrokCLI(options = {}) {
106
117
  console.log('Restart Grok or run `grok` to load the new hooks and MCP servers.');
107
118
  }
108
119
  catch (err) {
109
- frameworkLogger.log('grok-integration', 'install-error', 'error', { error: err.message });
110
- console.error('Failed to install Grok plugin:', err.message);
120
+ const message = err instanceof Error ? err.message : String(err);
121
+ frameworkLogger.log('grok-integration', 'install-error', 'error', { error: message });
122
+ console.error('Failed to install Grok plugin:', message);
111
123
  }
112
124
  frameworkLogger.log('grok-integration', 'install-complete', 'info', {});
113
125
  }
126
+ function wearGrokHookCommands(pluginDir, xrayRoot, targetDir) {
127
+ patchGrokHooks(pluginDir, xrayRoot, targetDir, (label, action, status, details) => {
128
+ const level = status === 'success' ||
129
+ status === 'error' ||
130
+ status === 'info' ||
131
+ status === 'debug' ||
132
+ status === 'warning'
133
+ ? status
134
+ : 'info';
135
+ frameworkLogger.log(label, action, level, details ?? {});
136
+ }, 'grok-install');
137
+ }
138
+ function pinGrokPluginToInstalledDist(pluginDir, xrayRoot, targetDir) {
139
+ const hookJs = path.join(xrayRoot, 'dist/integrations/grok/hooks/pre-tool-use.js');
140
+ const cliJs = path.join(xrayRoot, 'dist/cli/index.js');
141
+ if (!fs.existsSync(hookJs))
142
+ return;
143
+ const hooksPath = path.join(pluginDir, 'hooks', 'hooks.json');
144
+ if (fs.existsSync(hooksPath)) {
145
+ const text = fs.readFileSync(hooksPath, 'utf8');
146
+ fs.writeFileSync(hooksPath, text.split('${XRAY_AI_PATH:-node_modules/0xray}').join(xrayRoot));
147
+ }
148
+ const mcpPath = path.join(pluginDir, '.mcp.json');
149
+ if (fs.existsSync(mcpPath) && fs.existsSync(cliJs)) {
150
+ const mcp = JSON.parse(fs.readFileSync(mcpPath, 'utf8'));
151
+ for (const server of Object.values(mcp.mcpServers ?? {})) {
152
+ if (server.command === 'npx' && Array.isArray(server.args) && server.args.includes('mcp')) {
153
+ const mcpIdx = server.args.indexOf('mcp');
154
+ const mcpCmd = server.args[mcpIdx + 1] ?? 'governance';
155
+ server.command = 'node';
156
+ server.args = [cliJs, 'mcp', mcpCmd];
157
+ }
158
+ }
159
+ const repertoireMcp = resolveRepertoireMcp(targetDir);
160
+ if (mcp.mcpServers) {
161
+ if (repertoireMcp) {
162
+ mcp.mcpServers.repertoire = {
163
+ command: 'node',
164
+ args: [repertoireMcp],
165
+ };
166
+ }
167
+ else {
168
+ delete mcp.mcpServers.repertoire;
169
+ }
170
+ }
171
+ fs.writeFileSync(mcpPath, `${JSON.stringify(mcp, null, 2)}\n`);
172
+ }
173
+ }
174
+ /** Grok TUI reads <project>/.grok/config.toml, not the package copy. */
175
+ export function writeProjectRepertoireMcp(projectRoot) {
176
+ const repertoireMcp = resolveRepertoireMcp(projectRoot);
177
+ if (!repertoireMcp)
178
+ return null;
179
+ const grokDir = path.join(projectRoot, '.grok');
180
+ fs.mkdirSync(grokDir, { recursive: true });
181
+ const tomlPath = path.join(grokDir, 'config.toml');
182
+ const block = `[mcp_servers.repertoire]
183
+ command = "node"
184
+ args = [${JSON.stringify(repertoireMcp)}]
185
+ enabled = true
186
+ `;
187
+ let existing = '';
188
+ if (fs.existsSync(tomlPath)) {
189
+ existing = fs.readFileSync(tomlPath, 'utf8');
190
+ }
191
+ if (/\[mcp_servers\.repertoire\]/.test(existing)) {
192
+ existing = existing.replace(/\[mcp_servers\.repertoire\][\s\S]*?(?=\n\[|$)/, block.trim());
193
+ fs.writeFileSync(tomlPath, existing.endsWith('\n') ? existing : `${existing}\n`);
194
+ }
195
+ else {
196
+ const prefix = existing.trim() ? `${existing.trim()}\n\n` : '';
197
+ fs.writeFileSync(tomlPath, `${prefix}${block}`);
198
+ }
199
+ return tomlPath;
200
+ }
114
201
  export default {
115
202
  installForGrokCLI,
203
+ writeProjectRepertoireMcp,
116
204
  };
@@ -17,9 +17,16 @@ import {
17
17
  getActivePendingDelegations,
18
18
  validateSpawnMatchesTodo,
19
19
  updatePlanTodoStatusInPlace,
20
+ loadDelegationGateFeatures,
20
21
  } from '../../hooks/delegation-gate-runtime.mjs';
21
22
  import { isConferPendingForSession } from '../../hooks/confer-hook-runtime.mjs';
22
23
  import { getActiveUserAsideBoot } from '../../hooks/user-aside-hook-runtime.mjs';
24
+ import {
25
+ applyStationHeat,
26
+ buildRepertoireResume as stationRepertoireResume,
27
+ readExistingBoot,
28
+ writeStationMarkdown,
29
+ } from '../../hooks/station-hook-runtime.mjs';
23
30
 
24
31
  export {
25
32
  checkPendingDelegationGate,
@@ -131,9 +138,20 @@ export function resolveSiblingWorkspaceRoots(root = workspaceRoot()) {
131
138
  }
132
139
  }
133
140
 
141
+ export function buildRepertoireResume(root = workspaceRoot()) {
142
+ return stationRepertoireResume(root);
143
+ }
144
+
134
145
  export function loadFeatures(root = workspaceRoot()) {
135
146
  const featuresPath = resolveFeaturesPath(root);
136
- if (!featuresPath) return { lead_dev_mode: true, no_new_surface: true, per_suite_triage: true };
147
+ if (!featuresPath) {
148
+ return {
149
+ lead_dev_mode: true,
150
+ no_new_surface: true,
151
+ per_suite_triage: true,
152
+ grok_postprocessor_light: false,
153
+ };
154
+ }
137
155
  try {
138
156
  const data = JSON.parse(fs.readFileSync(featuresPath, 'utf8'));
139
157
  const orch = data.multi_agent_orchestration ?? {};
@@ -142,6 +160,7 @@ export function loadFeatures(root = workspaceRoot()) {
142
160
  no_new_surface: orch.no_new_surface !== false,
143
161
  per_suite_test_triage: orch.per_suite_test_triage !== false,
144
162
  auto_chain_delegations: orch.auto_chain_delegations !== false,
163
+ grok_postprocessor_light: data.grok_postprocessor_light === true,
145
164
  sibling_repos: resolveSiblingWorkspaceRoots(root),
146
165
  };
147
166
  } catch {
@@ -150,6 +169,7 @@ export function loadFeatures(root = workspaceRoot()) {
150
169
  no_new_surface: true,
151
170
  per_suite_triage: true,
152
171
  auto_chain_delegations: true,
172
+ grok_postprocessor_light: false,
153
173
  sibling_repos: [],
154
174
  };
155
175
  }
@@ -188,9 +208,11 @@ export function extractToolContext(event) {
188
208
  return { toolName, toolInput, paths, content, cmd: String(toolInput.command || '') };
189
209
  }
190
210
 
191
- export function checkCodexPatterns(content) {
211
+ export function checkCodexPatterns(content, options = {}) {
192
212
  if (!content) return null;
193
- for (const { message, pattern } of CODEX_BLOCK_PATTERNS) {
213
+ const only = Array.isArray(options.terms) ? options.terms : null;
214
+ for (const { message, pattern, terms } of CODEX_BLOCK_PATTERNS) {
215
+ if (only && !terms.some((n) => only.includes(n))) continue;
194
216
  if (pattern.test(content)) return message;
195
217
  pattern.lastIndex = 0;
196
218
  }
@@ -259,16 +281,27 @@ export function buildSessionBootPayload(root, source = '0xray/grok-session-start
259
281
  extra.sessionId || process.env.GROK_SESSION_ID || process.env.GROK_SESSION || null;
260
282
  const conferPending = loadConferPending(root, sessionId);
261
283
  const userAsideBoot = getActiveUserAsideBoot(root, sessionId);
284
+ const gateFeatures = loadDelegationGateFeatures(root, 'grok');
285
+ const frontier = gateFeatures.ceremony === 'lite';
286
+ const existing = readExistingBoot(root);
287
+ const heat = applyStationHeat(root, extra.host || 'grok', extra, existing);
262
288
  return {
263
289
  hook: source,
264
290
  lead_dev_mode: features.lead_dev_mode,
265
291
  no_new_surface: features.no_new_surface,
292
+ host: extra.host || 'grok',
293
+ suit_profile: gateFeatures.suit_profile ?? 'guided',
294
+ ceremony: gateFeatures.ceremony ?? 'full',
295
+ spawn_plan_mode: gateFeatures.spawn_plan_mode ?? 'deny',
266
296
  codexBlockingTermCount: blockingTerms.length,
267
297
  codexTerms: [59, 67, 68, 69],
268
298
  rules: features.lead_dev_mode ? LEAD_DEV_RULES : [],
269
- mcpIntake: 'xray-orchestrator → analyze-complexity (required before spawn_subagent)',
270
- enforcement: 'PreToolUse hook — codex patterns + surface area + spawn gate',
299
+ mcpIntake: frontier
300
+ ? 'xray-orchestrator analyze-complexity optional on frontier (spawn warns, does not deny)'
301
+ : 'xray-orchestrator → analyze-complexity (required before spawn_subagent)',
302
+ enforcement: 'PreToolUse hook — Codex constitution always on; ceremony scales by suit_temperament',
271
303
  workspaceRoot: root,
304
+ ...heat,
272
305
  ...(siblingRoots.length > 0 ? { siblingWorkspaceRoots: siblingRoots } : {}),
273
306
  ...(conferPending ? { conferPending: true, conferTrigger: 'analyze-complexity at synthesis checkpoint' } : {}),
274
307
  ...(userAsideBoot ?? {}),
@@ -276,6 +309,7 @@ export function buildSessionBootPayload(root, source = '0xray/grok-session-start
276
309
  timestamp: new Date().toISOString(),
277
310
  source,
278
311
  ...extra,
312
+ ...heat,
279
313
  };
280
314
  }
281
315
 
@@ -284,19 +318,31 @@ export function writeSessionBoot(root, payload) {
284
318
  const stateDir = path.join(root, '.xray', 'state');
285
319
  fs.mkdirSync(stateDir, { recursive: true });
286
320
  fs.writeFileSync(sessionBootPath(root), JSON.stringify(payload, null, 2));
321
+ writeStationMarkdown(root, payload);
287
322
  return sessionBootPath(root);
288
323
  } catch {
289
324
  return null;
290
325
  }
291
326
  }
292
327
 
293
- /** Boot on SessionStart, UserPromptSubmit, or first PreToolUse if missing. */
328
+ export function sessionBootNeedsRefresh(existing, root) {
329
+ if (!existing || typeof existing !== 'object') return true;
330
+ if (existing.lead_dev_mode === undefined) return true;
331
+ if (existing.host !== 'grok') return true;
332
+ if (!existing.suit_profile) return true;
333
+ if (existing.workspaceRoot && existing.workspaceRoot !== root) return true;
334
+ if (!existing.repertoireResume) return true;
335
+ if (!existing.stationLine) return true;
336
+ return false;
337
+ }
338
+
339
+ /** Boot on SessionStart, UserPromptSubmit, or first PreToolUse if missing/stale. */
294
340
  export function ensureSessionBoot(root = workspaceRoot(), source = '0xray/grok-boot') {
295
341
  const bootPath = sessionBootPath(root);
296
342
  if (fs.existsSync(bootPath)) {
297
343
  try {
298
344
  const existing = JSON.parse(fs.readFileSync(bootPath, 'utf8'));
299
- if (existing.lead_dev_mode !== undefined) return bootPath;
345
+ if (!sessionBootNeedsRefresh(existing, root)) return bootPath;
300
346
  } catch {
301
347
  /* rewrite corrupt boot */
302
348
  }
@@ -8,6 +8,8 @@ import {
8
8
  extractToolContext,
9
9
  isOrchestrateToolEvent,
10
10
  isSubagentTool,
11
+ isWriteTool,
12
+ loadFeatures,
11
13
  readStdinJson,
12
14
  resolveSessionId,
13
15
  workspaceRoot,
@@ -17,7 +19,7 @@ import {
17
19
  evaluatePostToolSpawn,
18
20
  isOrchestrateToolEvent as gateIsOrchestrateToolEvent,
19
21
  } from '../../hooks/delegation-gate-runtime.mjs';
20
- import { recordRoutingOutcome } from '../../hooks/pipeline-hook-runtime.mjs';
22
+ import { recordRoutingOutcome, runGrokPostprocessorLight } from '../../hooks/pipeline-hook-runtime.mjs';
21
23
 
22
24
  function extractToolOutput(event) {
23
25
  return (
@@ -30,60 +32,77 @@ function extractToolOutput(event) {
30
32
  );
31
33
  }
32
34
 
33
- async function main() {
34
- const root = workspaceRoot();
35
- try {
36
- const event = await readStdinJson();
37
- const eventRoot = event.workspaceRoot || event.cwd || root;
38
- const sessionId = resolveSessionId(event);
39
- const { toolName, toolInput } = extractToolContext(event);
35
+ export function handlePostToolUse(event, root = workspaceRoot()) {
36
+ const eventRoot = event.workspaceRoot || event.cwd || root;
37
+ const sessionId = resolveSessionId(event);
38
+ const { toolName, toolInput } = extractToolContext(event);
40
39
 
41
- if (isOrchestrateToolEvent(toolName, toolInput) || gateIsOrchestrateToolEvent(toolName, toolInput)) {
42
- appendHookActivity(eventRoot, 'grok-post-tool-use', 'auto-chain-pending', 'info', {
40
+ if (isOrchestrateToolEvent(toolName, toolInput) || gateIsOrchestrateToolEvent(toolName, toolInput)) {
41
+ appendHookActivity(eventRoot, 'grok-post-tool-use', 'auto-chain-pending', 'info', {
42
+ tool: toolName,
43
+ sessionId,
44
+ note: 'orchestrate-task completed — pending-delegations.json written by task-handler',
45
+ });
46
+ try {
47
+ recordRoutingOutcome(eventRoot, {
43
48
  tool: toolName,
49
+ agent: toolInput?.subagent_type ?? toolInput?.agent ?? 'orchestrate-task',
50
+ planTodoId: toolInput?.planTodoId ?? null,
44
51
  sessionId,
45
- note: 'orchestrate-task completed — pending-delegations.json written by task-handler',
46
52
  });
47
- try {
48
- recordRoutingOutcome(eventRoot, {
49
- tool: toolName,
50
- agent: toolInput?.subagent_type ?? toolInput?.agent ?? 'orchestrate-task',
51
- planTodoId: toolInput?.planTodoId ?? null,
52
- sessionId,
53
- });
54
- } catch {
55
- /* non-blocking */
56
- }
53
+ } catch {
54
+ /* non-blocking */
57
55
  }
56
+ }
57
+
58
+ const features = loadFeatures(eventRoot);
59
+ if (features.grok_postprocessor_light === true && isWriteTool(toolName)) {
60
+ try {
61
+ const paths = [
62
+ toolInput?.path,
63
+ toolInput?.filePath,
64
+ toolInput?.file_path,
65
+ ].filter(Boolean);
66
+ runGrokPostprocessorLight(eventRoot, { tool: toolName, paths });
67
+ } catch {
68
+ /* non-blocking */
69
+ }
70
+ }
71
+
72
+ if (isSubagentTool(toolName)) {
73
+ const spawnResult = evaluatePostToolSpawn(toolName, toolInput, eventRoot, {
74
+ toolOutput: extractToolOutput(event),
75
+ sessionId,
76
+ });
58
77
 
59
- if (isSubagentTool(toolName)) {
60
- const spawnResult = evaluatePostToolSpawn(toolName, toolInput, eventRoot, {
61
- toolOutput: extractToolOutput(event),
78
+ if (spawnResult.satisfied.length > 0 || spawnResult.expectedTodoId) {
79
+ appendHookActivity(eventRoot, 'grok-post-tool-use', 'auto-chain-cleared', 'success', {
80
+ tool: toolName,
81
+ satisfied: spawnResult.satisfied.map((d) => d.id),
82
+ clearedAll: spawnResult.clearedAll,
83
+ planTodoId: spawnResult.expectedTodoId ?? null,
84
+ receiptRecorded: spawnResult.receiptRecorded ?? false,
85
+ todoCompleted: spawnResult.todoCompleted ?? false,
86
+ });
87
+ }
88
+ try {
89
+ recordRoutingOutcome(eventRoot, {
90
+ tool: toolName,
91
+ agent: toolInput?.subagent_type ?? toolInput?.agent ?? 'subagent',
92
+ planTodoId: toolInput?.planTodoId ?? spawnResult.expectedTodoId ?? null,
62
93
  sessionId,
63
94
  });
64
-
65
- if (spawnResult.satisfied.length > 0 || spawnResult.expectedTodoId) {
66
- appendHookActivity(eventRoot, 'grok-post-tool-use', 'auto-chain-cleared', 'success', {
67
- tool: toolName,
68
- satisfied: spawnResult.satisfied.map((d) => d.id),
69
- clearedAll: spawnResult.clearedAll,
70
- planTodoId: spawnResult.expectedTodoId ?? null,
71
- receiptRecorded: spawnResult.receiptRecorded ?? false,
72
- todoCompleted: spawnResult.todoCompleted ?? false,
73
- });
74
- }
75
- try {
76
- recordRoutingOutcome(eventRoot, {
77
- tool: toolName,
78
- agent: toolInput?.subagent_type ?? toolInput?.agent ?? 'subagent',
79
- planTodoId: toolInput?.planTodoId ?? spawnResult.expectedTodoId ?? null,
80
- sessionId,
81
- });
82
- } catch {
83
- /* non-blocking */
84
- }
95
+ } catch {
96
+ /* non-blocking */
85
97
  }
98
+ }
99
+ }
86
100
 
101
+ async function main() {
102
+ const root = workspaceRoot();
103
+ try {
104
+ const event = await readStdinJson();
105
+ handlePostToolUse(event, root);
87
106
  process.exit(0);
88
107
  } catch (err) {
89
108
  appendHookActivity(root, 'grok-post-tool-use', 'hook-error', 'error', {
@@ -93,4 +112,7 @@ async function main() {
93
112
  }
94
113
  }
95
114
 
96
- main();
115
+ const launchedAsCli = Boolean(process.argv[1] && process.argv[1].endsWith('post-tool-use.js'));
116
+ if (launchedAsCli) {
117
+ main();
118
+ }
@@ -11,7 +11,6 @@ import {
11
11
  import {
12
12
  checkCodexPatterns,
13
13
  checkFullTestSuite,
14
- checkSurfaceArea,
15
14
  ensureSessionBoot,
16
15
  isShellTool,
17
16
  isWriteTool,
@@ -21,7 +20,6 @@ import {
21
20
  workspaceRoot,
22
21
  } from './grok-hook-utils.js';
23
22
  import { appendHookActivity } from './grok-hook-activity.js';
24
- import { runGrokPostprocessorLight } from '../../hooks/pipeline-hook-runtime.mjs';
25
23
 
26
24
  function finish(root, decision, reason, hint, toolName, extra = {}) {
27
25
  const out = { decision, ...extra };
@@ -47,10 +45,10 @@ async function main() {
47
45
  ensureSessionBoot(eventRoot, '0xray/grok-pre-tool-use-boot');
48
46
 
49
47
  const features = loadFeatures(eventRoot);
50
- const gateFeatures = loadDelegationGateFeatures(eventRoot);
48
+ const gateFeatures = loadDelegationGateFeatures(eventRoot, 'grok');
51
49
  const ctx = extractFromEvent(event);
52
50
  toolName = ctx.toolName;
53
- const { paths, content, cmd, toolInput } = ctx;
51
+ const { content, cmd, toolInput } = ctx;
54
52
  const sessionId = resolveSessionId(event);
55
53
 
56
54
  const gateBlock = evaluatePreToolGate(toolName, toolInput, {
@@ -70,6 +68,18 @@ async function main() {
70
68
  );
71
69
  }
72
70
 
71
+ // Constitution (11/29/69 + destructive shell) is in evaluatePreToolGate.
72
+ // Grok extra: Codex 2/7 (TODO/FIXME/STUB, console.log).
73
+ if (isWriteTool(toolName) && content) {
74
+ const extraBlock = checkCodexPatterns(content, { terms: [2, 7] });
75
+ if (extraBlock) finish(eventRoot, 'deny', extraBlock, null, toolName);
76
+ }
77
+
78
+ if (isShellTool(toolName) && cmd) {
79
+ const testHint = checkFullTestSuite(cmd, features);
80
+ if (testHint) finish(eventRoot, 'allow', null, testHint, toolName);
81
+ }
82
+
73
83
  if (gateBlock.reason) {
74
84
  finish(
75
85
  eventRoot,
@@ -81,33 +91,6 @@ async function main() {
81
91
  );
82
92
  }
83
93
 
84
- if (features.no_new_surface && isWriteTool(toolName) && paths.length) {
85
- const surfaceBlock = checkSurfaceArea(paths, eventRoot);
86
- if (surfaceBlock) finish(eventRoot, 'deny', surfaceBlock, null, toolName);
87
- }
88
-
89
- if (isWriteTool(toolName) && content) {
90
- const codexBlock = checkCodexPatterns(content);
91
- if (codexBlock) finish(eventRoot, 'deny', codexBlock, null, toolName);
92
- }
93
-
94
- if (isShellTool(toolName) && cmd) {
95
- const destructive =
96
- /\brm\s+-rf\s+\/\b|\bmkfs\b|\bdd\s+if=|:()\s*\{\s*:\|&\s*\}\s*;:/i.test(cmd);
97
- if (destructive) finish(eventRoot, 'deny', 'Blocked destructive shell command', null, toolName);
98
-
99
- const testHint = checkFullTestSuite(cmd, features);
100
- if (testHint) finish(eventRoot, 'allow', null, testHint, toolName);
101
- }
102
-
103
- if (features.grok_postprocessor_light === true && isWriteTool(toolName)) {
104
- try {
105
- runGrokPostprocessorLight(eventRoot, { tool: toolName, paths });
106
- } catch {
107
- /* non-blocking */
108
- }
109
- }
110
-
111
94
  finish(eventRoot, 'allow', null, null, toolName);
112
95
  } catch (err) {
113
96
  appendHookActivity(root, 'grok-pre-tool-use', 'hook-error', 'error', {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Grok SessionStart / UserPromptSubmit — writes session-boot.json + activity.log.
4
- * Stdout is ignored by Grok for these events; side effects are the suit contract.
3
+ * Grok SessionStart / UserPromptSubmit / PreCompact / PostCompact.
4
+ * Grok ignores stdout here; station heat is session-boot.json + STATION.md.
5
5
  */
6
6
 
7
7
  import {
@@ -26,17 +26,89 @@ function resolveHookEvent(event) {
26
26
  if (process.env.GROK_HOOK_EVENT) return process.env.GROK_HOOK_EVENT;
27
27
  const flag = process.argv.find((a) => a.startsWith('--hook-event='));
28
28
  if (flag) return flag.slice('--hook-event='.length);
29
+ const named = event.hookEventName || event.hook;
30
+ if (named === 'PreCompact' || named === 'pre_compact') return 'pre_compact';
31
+ if (named === 'PostCompact' || named === 'post_compact') return 'post_compact';
29
32
  if (
30
33
  event.prompt != null ||
31
34
  event.userMessage != null ||
32
35
  event.user_prompt != null ||
33
- event.hook === 'UserPromptSubmit'
36
+ named === 'UserPromptSubmit' ||
37
+ named === 'user_prompt_submit'
34
38
  ) {
35
39
  return 'user_prompt_submit';
36
40
  }
37
41
  return 'session_start';
38
42
  }
39
43
 
44
+ function extractIntent(event) {
45
+ return event.prompt || event.userMessage || event.user_prompt || event.compactContext || null;
46
+ }
47
+
48
+ async function loadStationProvider(root) {
49
+ const { loadMemoryRoutingProvider } = await import('../../../memory-routing/index.js');
50
+ const { readFileSync, existsSync } = await import('node:fs');
51
+ const { join } = await import('node:path');
52
+ let routing = { enabled: false, provider: 'null' };
53
+ const featuresPath = join(root, '.xray', 'features.json');
54
+ if (existsSync(featuresPath)) {
55
+ try {
56
+ routing = JSON.parse(readFileSync(featuresPath, 'utf8')).memory_routing || routing;
57
+ } catch {
58
+ /* leftover default */
59
+ }
60
+ }
61
+ return loadMemoryRoutingProvider(routing, root);
62
+ }
63
+
64
+ async function matchStationSignals(root, intent) {
65
+ if (!intent) return [];
66
+ try {
67
+ const provider = await loadStationProvider(root);
68
+ if (!provider || provider.id === 'null' || typeof provider.getTaskConfidence !== 'function') {
69
+ return [];
70
+ }
71
+ const conf = provider.getTaskConfidence({
72
+ id: 'station',
73
+ description: String(intent),
74
+ type: 'station',
75
+ });
76
+ const names = Array.isArray(conf.matchedSignals) ? conf.matchedSignals : [];
77
+ const safe = [];
78
+ for (const signalName of names) {
79
+ const name = String(signalName || '').trim();
80
+ if (!name || name.toLowerCase().startsWith('bedrock-')) continue;
81
+ safe.push(name);
82
+ if (safe.length >= 4) break;
83
+ }
84
+ return safe;
85
+ } catch {
86
+ return [];
87
+ }
88
+ }
89
+
90
+ const COMPACT_EVENTS = new Set(['pre_compact', 'post_compact']);
91
+
92
+ async function ingestStationFeedback(root, sessionId, hookEvent, matchedSignals) {
93
+ if (!COMPACT_EVENTS.has(hookEvent) || !matchedSignals.length) return;
94
+ try {
95
+ const provider = await loadStationProvider(root);
96
+ if (!provider || typeof provider.ingestFeedback !== 'function') return;
97
+ provider.ingestFeedback({
98
+ timestamp: new Date().toISOString(),
99
+ sessionId: sessionId || 'station',
100
+ taskId: `station-${hookEvent}`,
101
+ assignedAgent: 'station',
102
+ memorySignals: matchedSignals,
103
+ complexity: 0,
104
+ success: true,
105
+ durationMs: 0,
106
+ });
107
+ } catch {
108
+ /* working-state file is the session memory; registry ingest is best-effort */
109
+ }
110
+ }
111
+
40
112
  async function main() {
41
113
  const root = workspaceRoot();
42
114
  let HOOK_EVENT = 'session_start';
@@ -68,19 +140,29 @@ async function main() {
68
140
  const source =
69
141
  HOOK_EVENT === 'user_prompt_submit'
70
142
  ? '0xray/grok-user-prompt-submit'
71
- : '0xray/grok-session-start';
143
+ : HOOK_EVENT === 'pre_compact' || HOOK_EVENT === 'post_compact'
144
+ ? '0xray/grok-compact'
145
+ : '0xray/grok-session-start';
72
146
 
147
+ const intent = extractIntent(event);
148
+ const matchedSignals = await matchStationSignals(eventRoot, intent);
73
149
  const payload = buildSessionBootPayload(eventRoot, source, {
74
150
  hookEvent: HOOK_EVENT,
75
151
  sessionId: event.sessionId || process.env.GROK_SESSION_ID || null,
152
+ ...(intent ? { intent } : {}),
153
+ ...(matchedSignals.length ? { matchedSignals } : {}),
76
154
  });
77
155
 
78
156
  const bootPath = writeSessionBoot(eventRoot, payload) || ensureSessionBoot(eventRoot, source);
157
+ await ingestStationFeedback(eventRoot, sessionId, HOOK_EVENT, matchedSignals);
79
158
 
80
159
  appendHookActivity(eventRoot, 'grok-session-start', 'session-boot-written', 'success', {
81
160
  bootPath,
82
161
  hookEvent: HOOK_EVENT,
83
162
  lead_dev_mode: payload.lead_dev_mode,
163
+ repertoireResume: payload.repertoireResume,
164
+ stationLine: payload.stationLine,
165
+ hotSwap: payload.hotSwap || null,
84
166
  });
85
167
 
86
168
  try {