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
@@ -0,0 +1,421 @@
1
+ /**
2
+ * Station heat — compaction / host-swap card.
3
+ * SSOT remains session-boot.json. STATION.md is the projection the model Reads.
4
+ * Grok ignores SessionStart/UserPromptSubmit stdout; disk + AGENTS.md is the contract.
5
+ */
6
+ const { execFileSync } = require("child_process");
7
+ const { existsSync, mkdirSync, readFileSync, writeFileSync } = require("fs");
8
+ const { join } = require("path");
9
+
10
+ const HOOKS_DIR = __dirname;
11
+
12
+ const INTENT_MAX = 240;
13
+
14
+ function stationMarkdownPath(root) {
15
+ return join(root, ".xray", "state", "STATION.md");
16
+ }
17
+
18
+ function sessionBootPath(root) {
19
+ return join(root, ".xray", "state", "session-boot.json");
20
+ }
21
+
22
+ function clipIntent(raw) {
23
+ if (raw == null) return null;
24
+ const text = String(raw)
25
+ .replace(/<\/?user_query>/gi, " ")
26
+ .replace(/\s+/g, " ")
27
+ .trim();
28
+ if (!text) return null;
29
+ if (text.length <= INTENT_MAX) return text;
30
+ return `${text.slice(0, INTENT_MAX - 1)}…`;
31
+ }
32
+
33
+ function readExistingBoot(root) {
34
+ const bootPath = sessionBootPath(root);
35
+ if (!existsSync(bootPath)) return {};
36
+ try {
37
+ const data = JSON.parse(readFileSync(bootPath, "utf8"));
38
+ return data && typeof data === "object" ? data : {};
39
+ } catch {
40
+ return {};
41
+ }
42
+ }
43
+
44
+ function readGitBrief(root) {
45
+ try {
46
+ const opts = { cwd: root, encoding: "utf8", timeout: 2000, stdio: ["ignore", "pipe", "ignore"] };
47
+ const head = execFileSync("git", ["rev-parse", "--short", "HEAD"], opts).trim();
48
+ const branch = execFileSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], opts).trim();
49
+ if (!head) return null;
50
+ return { branch: branch || "HEAD", head };
51
+ } catch {
52
+ return null;
53
+ }
54
+ }
55
+
56
+ function readGitSubject(root) {
57
+ try {
58
+ const opts = { cwd: root, encoding: "utf8", timeout: 2000, stdio: ["ignore", "pipe", "ignore"] };
59
+ const subject = execFileSync("git", ["log", "-1", "--format=%s"], opts).trim();
60
+ return clipIntent(subject);
61
+ } catch {
62
+ return null;
63
+ }
64
+ }
65
+
66
+ function readLiveTodoLine(plan) {
67
+ const phases = Array.isArray(plan.phases) ? plan.phases : [];
68
+ for (const phase of phases) {
69
+ const todos = Array.isArray(phase && phase.todos) ? phase.todos : [];
70
+ for (const todo of todos) {
71
+ const status = String((todo && todo.status) || "pending");
72
+ if (status === "completed" || status === "cancelled") continue;
73
+ const task = clipIntent((todo && (todo.task || todo.description)) || "");
74
+ if (task) return task;
75
+ }
76
+ }
77
+ return null;
78
+ }
79
+
80
+ function readPlanLine(root) {
81
+ const planPath = join(root, ".xray", "state", "lead-dev-plan.json");
82
+ if (existsSync(planPath)) {
83
+ try {
84
+ const plan = JSON.parse(readFileSync(planPath, "utf8"));
85
+ if (plan && plan.active !== false) {
86
+ const live = readLiveTodoLine(plan);
87
+ if (live) return live;
88
+ }
89
+ } catch {
90
+ /* fall through to git subject — stale / empty plan is not the card */
91
+ }
92
+ }
93
+ return readGitSubject(root);
94
+ }
95
+
96
+ function resolveRepertoireProviderModule(root) {
97
+ const mr = readMemoryRoutingConfig(root);
98
+ if (mr && typeof mr.module_path === "string" && mr.module_path) {
99
+ const configured = mr.module_path.startsWith("/") || /^[A-Za-z]:[\\/]/.test(mr.module_path)
100
+ ? mr.module_path
101
+ : join(root, mr.module_path);
102
+ if (existsSync(configured)) return configured;
103
+ }
104
+ const siblingRoot = join(root, "..", "repertoire");
105
+ const siblingProvider = join(siblingRoot, "dist", "provider", "memory-routing-provider.js");
106
+ const nmProvider = join(
107
+ root,
108
+ "node_modules",
109
+ "@0xray",
110
+ "repertoire",
111
+ "dist",
112
+ "provider",
113
+ "memory-routing-provider.js",
114
+ );
115
+ const vendorProvider = join(
116
+ root,
117
+ "vendor",
118
+ "@0xray",
119
+ "repertoire",
120
+ "dist",
121
+ "provider",
122
+ "memory-routing-provider.js",
123
+ );
124
+ if (existsSync(nmProvider)) return nmProvider;
125
+ if (existsSync(vendorProvider)) return vendorProvider;
126
+ try {
127
+ const pkg = JSON.parse(readFileSync(join(siblingRoot, "package.json"), "utf8"));
128
+ if ((pkg.name === "@0xray/repertoire" || pkg.name === "repertoire") && existsSync(siblingProvider)) {
129
+ return siblingProvider;
130
+ }
131
+ } catch {
132
+ /* sibling missing */
133
+ }
134
+ return null;
135
+ }
136
+
137
+ function countCuratedSignals(signalsPath) {
138
+ try {
139
+ const data = JSON.parse(readFileSync(signalsPath, "utf8"));
140
+ if (Array.isArray(data.signals)) return data.signals.length;
141
+ if (Array.isArray(data)) return data.length;
142
+ } catch {
143
+ /* unreadable */
144
+ }
145
+ return null;
146
+ }
147
+
148
+ function readMemoryRoutingConfig(root) {
149
+ const featuresPath = join(root, ".xray", "features.json");
150
+ if (!existsSync(featuresPath)) return {};
151
+ try {
152
+ return JSON.parse(readFileSync(featuresPath, "utf8")).memory_routing || {};
153
+ } catch {
154
+ return {};
155
+ }
156
+ }
157
+
158
+ function isExplicitMemoryRoutingOptOut(mr) {
159
+ return Boolean(mr) && mr.enabled === false && mr.provider === "repertoire";
160
+ }
161
+
162
+ function isLeftoverMemoryRoutingOff(mr) {
163
+ if (!mr || typeof mr !== "object") return true;
164
+ if (mr.enabled === true) return false;
165
+ if (isExplicitMemoryRoutingOptOut(mr)) return false;
166
+ const provider = mr.provider == null || mr.provider === "" ? "null" : mr.provider;
167
+ return provider === "null";
168
+ }
169
+
170
+ function isMemoryRoutingResolvedOn(mr, modulePath) {
171
+ if (!modulePath) return false;
172
+ if (isExplicitMemoryRoutingOptOut(mr)) return false;
173
+ if (mr.enabled === true && (mr.provider === "repertoire" || mr.provider === "custom")) return true;
174
+ return isLeftoverMemoryRoutingOff(mr);
175
+ }
176
+
177
+ function repertoireWorkingPath(root) {
178
+ return join(root, ".xray", "state", "repertoire-working.json");
179
+ }
180
+
181
+ function readRepertoireWorking(root) {
182
+ const dest = repertoireWorkingPath(root);
183
+ if (!existsSync(dest)) return null;
184
+ try {
185
+ const data = JSON.parse(readFileSync(dest, "utf8"));
186
+ return data && typeof data === "object" ? data : null;
187
+ } catch {
188
+ return null;
189
+ }
190
+ }
191
+
192
+ function stationSafeSignals(names) {
193
+ if (!Array.isArray(names)) return [];
194
+ const out = [];
195
+ for (const raw of names) {
196
+ const name = String(raw || "").trim();
197
+ if (!name) continue;
198
+ if (name.toLowerCase().startsWith("bedrock-")) continue;
199
+ out.push(name);
200
+ if (out.length >= 4) break;
201
+ }
202
+ return out;
203
+ }
204
+
205
+ function persistRepertoireWorking(root, snapshot) {
206
+ try {
207
+ mkdirSync(join(root, ".xray", "state"), { recursive: true });
208
+ const prev = readRepertoireWorking(root) || {};
209
+ const next = { ...prev, ...snapshot, updatedAt: new Date().toISOString() };
210
+ writeFileSync(repertoireWorkingPath(root), `${JSON.stringify(next, null, 2)}\n`);
211
+ return next;
212
+ } catch {
213
+ return null;
214
+ }
215
+ }
216
+
217
+ function matchStationSignalsSync(root, intent) {
218
+ if (!intent) return [];
219
+ const helper = join(HOOKS_DIR, "station-memory-match.mjs");
220
+ if (!existsSync(helper)) return [];
221
+ try {
222
+ const out = execFileSync(process.execPath, [helper, root, intent], {
223
+ encoding: "utf8",
224
+ timeout: 20000,
225
+ stdio: ["ignore", "pipe", "pipe"],
226
+ env: process.env,
227
+ });
228
+ const line = String(out).trim().split("\n").filter(Boolean).at(-1) || "[]";
229
+ const parsed = JSON.parse(line);
230
+ return Array.isArray(parsed) ? parsed : [];
231
+ } catch {
232
+ return [];
233
+ }
234
+ }
235
+
236
+ function ingestCompactFeedbackSync(root, sessionId, hookEvent, signals) {
237
+ if (!signals.length) return;
238
+ const helper = join(HOOKS_DIR, "station-memory-ingest.mjs");
239
+ if (!existsSync(helper)) return;
240
+ try {
241
+ execFileSync(
242
+ process.execPath,
243
+ [helper, root, sessionId || "station", hookEvent || "post_compact", JSON.stringify(signals)],
244
+ {
245
+ encoding: "utf8",
246
+ timeout: 20000,
247
+ stdio: ["ignore", "pipe", "pipe"],
248
+ env: process.env,
249
+ },
250
+ );
251
+ } catch {
252
+ /* working-state file is the session memory; registry ingest is best-effort */
253
+ }
254
+ }
255
+
256
+ function isCompactHook(extra) {
257
+ const hook = String(extra.hookEvent || extra.source || "");
258
+ return /compact/i.test(hook);
259
+ }
260
+
261
+ function formatWorkingLine(working) {
262
+ if (!working || typeof working !== "object") return null;
263
+ const matched = stationSafeSignals(working.matchedSignals);
264
+ if (matched.length) return `Working: ${matched.join(", ")}`;
265
+ const hook = typeof working.hookEvent === "string" ? working.hookEvent : null;
266
+ const head = working.git && working.git.head ? String(working.git.head) : null;
267
+ if (hook && head) return `Working: last ${hook} @ ${head}`;
268
+ if (hook) return `Working: last ${hook}`;
269
+ return "Working: station snapshot";
270
+ }
271
+
272
+ function buildRepertoireResume(root) {
273
+ const modulePath = resolveRepertoireProviderModule(root);
274
+ const mr = readMemoryRoutingConfig(root);
275
+ if (!modulePath) {
276
+ return "Repertoire: not installed (memory_routing stays off)";
277
+ }
278
+ let signalsPath = mr.config && mr.config.signalsPath;
279
+ if (signalsPath && !signalsPath.startsWith("/") && !/^[A-Za-z]:[\\/]/.test(signalsPath)) {
280
+ signalsPath = join(root, signalsPath);
281
+ }
282
+ if (!signalsPath) {
283
+ signalsPath = join(modulePath, "..", "..", "..", "data", "curated_signals.json");
284
+ }
285
+ const n = existsSync(signalsPath) ? countCuratedSignals(signalsPath) : null;
286
+ const count = n == null ? "" : ` — ${n} signals`;
287
+ if (isMemoryRoutingResolvedOn(mr, modulePath)) {
288
+ return `Repertoire: on${count}`;
289
+ }
290
+ return `Repertoire: present, memory_routing off${count}`;
291
+ }
292
+
293
+ function applyStationHeat(root, host, extra = {}, existing = {}) {
294
+ const prevHost = typeof existing.host === "string" ? existing.host : null;
295
+ const nextSwap = prevHost && host && prevHost !== host ? { from: prevHost, to: host } : null;
296
+ const keptSwap =
297
+ existing.hotSwap &&
298
+ typeof existing.hotSwap === "object" &&
299
+ existing.hotSwap.from &&
300
+ existing.hotSwap.to
301
+ ? existing.hotSwap
302
+ : null;
303
+ const hotSwap = nextSwap || keptSwap;
304
+ const intent =
305
+ clipIntent(extra.intent || extra.prompt || extra.userMessage || extra.user_prompt) ||
306
+ (typeof existing.intent === "string" ? existing.intent : null);
307
+ const git = readGitBrief(root);
308
+ const planLine = readPlanLine(root);
309
+ const repertoireResume =
310
+ typeof extra.repertoireResume === "string" ? extra.repertoireResume : buildRepertoireResume(root);
311
+ const swapBit = hotSwap ? `hot-swap ${hotSwap.from} → ${hotSwap.to}` : `host ${host}`;
312
+ const intentBit = intent ? `intent: ${intent}` : "intent: (none yet)";
313
+ const gitBit = git ? `git ${git.branch}@${git.head}` : "git: n/a";
314
+ const planBit = planLine ? `plan: ${planLine}` : "plan: (none)";
315
+ let matchedSignals = stationSafeSignals(extra.matchedSignals);
316
+ const priorWorking = readRepertoireWorking(root);
317
+ if (!matchedSignals.length && intent) {
318
+ if (
319
+ priorWorking &&
320
+ priorWorking.intent === intent &&
321
+ Array.isArray(priorWorking.matchedSignals) &&
322
+ priorWorking.matchedSignals.length
323
+ ) {
324
+ matchedSignals = stationSafeSignals(priorWorking.matchedSignals);
325
+ } else {
326
+ matchedSignals = stationSafeSignals(matchStationSignalsSync(root, intent));
327
+ }
328
+ }
329
+ if (!matchedSignals.length && priorWorking) {
330
+ matchedSignals = stationSafeSignals(priorWorking.matchedSignals);
331
+ }
332
+ const workingSnapshot = {
333
+ host,
334
+ intent,
335
+ git,
336
+ hotSwap,
337
+ hookEvent: extra.hookEvent || extra.source || null,
338
+ memoryRouting: repertoireResume.startsWith("Repertoire: on") ? "on" : "off",
339
+ repertoireResume,
340
+ };
341
+ if (matchedSignals.length) workingSnapshot.matchedSignals = matchedSignals;
342
+ const working = persistRepertoireWorking(root, workingSnapshot);
343
+ if (isCompactHook(extra) && matchedSignals.length) {
344
+ ingestCompactFeedbackSync(
345
+ root,
346
+ typeof extra.sessionId === "string" ? extra.sessionId : "station",
347
+ extra.hookEvent || extra.source || "post_compact",
348
+ matchedSignals,
349
+ );
350
+ }
351
+ const workingLine = formatWorkingLine(working);
352
+ const workingBit = workingLine ? workingLine : "working: (none)";
353
+ const stationLine = `${swapBit}. ${intentBit}. ${planBit}. ${gitBit}. ${repertoireResume}. ${workingBit}`;
354
+ return {
355
+ lastHost: prevHost,
356
+ hotSwap,
357
+ intent,
358
+ git,
359
+ planLine,
360
+ repertoireResume,
361
+ workingLine,
362
+ stationLine,
363
+ };
364
+ }
365
+
366
+ function formatStationMarkdown(fields) {
367
+ const host = fields.host || "unknown";
368
+ const profile = fields.suit_profile || "guided";
369
+ const lines = ["# Station", ""];
370
+ if (fields.hotSwap && fields.hotSwap.from && fields.hotSwap.to) {
371
+ lines.push(`Hot-swap: ${fields.hotSwap.from} → ${fields.hotSwap.to}`);
372
+ }
373
+ lines.push(`Host: ${host} (${profile})`);
374
+ lines.push(`Intent: ${fields.intent || "(none yet)"}`);
375
+ lines.push(`Plan: ${fields.planLine || "(none)"}`);
376
+ if (fields.git && fields.git.head) {
377
+ lines.push(`Git: ${fields.git.branch}@${fields.git.head}`);
378
+ } else {
379
+ lines.push("Git: n/a");
380
+ }
381
+ lines.push(fields.repertoireResume || "Repertoire: not installed (memory_routing stays off)");
382
+ if (fields.workingLine) {
383
+ lines.push(fields.workingLine);
384
+ }
385
+ lines.push("");
386
+ lines.push("Continue this card. Compaction and host change are the same cut. Do not cold-start.");
387
+ lines.push("Grok does not inject this file — Read it. OpenCode injects. Do not thicken the Grok exo.");
388
+ lines.push("");
389
+ return lines.join("\n");
390
+ }
391
+
392
+ function writeStationMarkdown(root, fields) {
393
+ try {
394
+ const dir = join(root, ".xray", "state");
395
+ mkdirSync(dir, { recursive: true });
396
+ const dest = stationMarkdownPath(root);
397
+ writeFileSync(dest, formatStationMarkdown(fields));
398
+ return dest;
399
+ } catch {
400
+ return null;
401
+ }
402
+ }
403
+
404
+ module.exports = {
405
+ stationMarkdownPath,
406
+ sessionBootPath,
407
+ clipIntent,
408
+ readExistingBoot,
409
+ readGitBrief,
410
+ readGitSubject,
411
+ readPlanLine,
412
+ buildRepertoireResume,
413
+ isExplicitMemoryRoutingOptOut,
414
+ isLeftoverMemoryRoutingOff,
415
+ persistRepertoireWorking,
416
+ readRepertoireWorking,
417
+ formatWorkingLine,
418
+ applyStationHeat,
419
+ formatStationMarkdown,
420
+ writeStationMarkdown,
421
+ };
@@ -0,0 +1,24 @@
1
+ /**
2
+ * ESM face for station-hook-runtime.cjs — Grok hooks import this.
3
+ */
4
+ import { createRequire } from 'node:module';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { dirname, join } from 'node:path';
7
+
8
+ const require = createRequire(import.meta.url);
9
+ const impl = require(join(dirname(fileURLToPath(import.meta.url)), 'station-hook-runtime.cjs'));
10
+
11
+ export const stationMarkdownPath = impl.stationMarkdownPath;
12
+ export const sessionBootPath = impl.sessionBootPath;
13
+ export const clipIntent = impl.clipIntent;
14
+ export const readExistingBoot = impl.readExistingBoot;
15
+ export const readGitBrief = impl.readGitBrief;
16
+ export const readGitSubject = impl.readGitSubject;
17
+ export const readPlanLine = impl.readPlanLine;
18
+ export const buildRepertoireResume = impl.buildRepertoireResume;
19
+ export const persistRepertoireWorking = impl.persistRepertoireWorking;
20
+ export const readRepertoireWorking = impl.readRepertoireWorking;
21
+ export const formatWorkingLine = impl.formatWorkingLine;
22
+ export const applyStationHeat = impl.applyStationHeat;
23
+ export const formatStationMarkdown = impl.formatStationMarkdown;
24
+ export const writeStationMarkdown = impl.writeStationMarkdown;
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Compact ingest — persist matched signals back into the organ (project-local copy).
4
+ */
5
+ import { existsSync, readFileSync } from 'node:fs';
6
+ import { join } from 'node:path';
7
+
8
+ const root = process.argv[2];
9
+ const sessionId = process.argv[3] || 'station';
10
+ const hookEvent = process.argv[4] || 'post_compact';
11
+ let signals = [];
12
+ try {
13
+ signals = JSON.parse(process.argv[5] || '[]');
14
+ } catch {
15
+ signals = [];
16
+ }
17
+ if (!root || !Array.isArray(signals) || signals.length === 0) {
18
+ process.exit(0);
19
+ }
20
+
21
+ let routing = { enabled: false, provider: 'null' };
22
+ const featuresPath = join(root, '.xray', 'features.json');
23
+ if (existsSync(featuresPath)) {
24
+ try {
25
+ routing = JSON.parse(readFileSync(featuresPath, 'utf8')).memory_routing || routing;
26
+ } catch {
27
+ /* leftover */
28
+ }
29
+ }
30
+
31
+ const { loadMemoryRoutingProvider } = await import('../../memory-routing/index.js');
32
+ const provider = await loadMemoryRoutingProvider(routing, root);
33
+ if (!provider || typeof provider.ingestFeedback !== 'function') process.exit(0);
34
+
35
+ provider.ingestFeedback({
36
+ timestamp: new Date().toISOString(),
37
+ sessionId,
38
+ taskId: `station-${hookEvent}`,
39
+ assignedAgent: 'station',
40
+ memorySignals: signals,
41
+ complexity: 0,
42
+ success: true,
43
+ durationMs: 0,
44
+ });
45
+ process.exit(0);
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Sync helper for station-hook-runtime.cjs — match Repertoire signals for an intent.
4
+ * Prints a JSON string array. Used on every floor's station heat, not only Grok.
5
+ */
6
+ import { existsSync, readFileSync } from 'node:fs';
7
+ import { join } from 'node:path';
8
+
9
+ const root = process.argv[2];
10
+ const intent = process.argv[3] || '';
11
+ if (!root || !intent) {
12
+ process.stdout.write('[]\n');
13
+ process.exit(0);
14
+ }
15
+
16
+ let routing = { enabled: false, provider: 'null' };
17
+ const featuresPath = join(root, '.xray', 'features.json');
18
+ if (existsSync(featuresPath)) {
19
+ try {
20
+ routing = JSON.parse(readFileSync(featuresPath, 'utf8')).memory_routing || routing;
21
+ } catch {
22
+ /* leftover */
23
+ }
24
+ }
25
+
26
+ const { loadMemoryRoutingProvider } = await import('../../memory-routing/index.js');
27
+ const provider = await loadMemoryRoutingProvider(routing, root);
28
+ if (!provider || provider.id === 'null' || typeof provider.getTaskConfidence !== 'function') {
29
+ process.stdout.write('[]\n');
30
+ process.exit(0);
31
+ }
32
+
33
+ const conf = provider.getTaskConfidence({
34
+ id: 'station',
35
+ description: String(intent),
36
+ type: 'station',
37
+ });
38
+ const names = Array.isArray(conf.matchedSignals) ? conf.matchedSignals : [];
39
+ const safe = [];
40
+ for (const signalName of names) {
41
+ const name = String(signalName || '').trim();
42
+ if (!name || name.toLowerCase().startsWith('bedrock-')) continue;
43
+ safe.push(name);
44
+ if (safe.length >= 4) break;
45
+ }
46
+ process.stdout.write(`${JSON.stringify(safe)}\n`);
47
+ process.exit(0);
@@ -1,12 +1,16 @@
1
1
  /**
2
2
  * OpenClaw WebSocket Client
3
3
  *
4
- * Implements OpenClaw Gateway Protocol v3 with proper request/response handling,
4
+ * Implements OpenClaw Gateway Protocol v3–v4 with proper request/response handling,
5
5
  * reconnection logic, and event management.
6
6
  *
7
7
  * @since 2026-03-14
8
8
  */
9
9
  import { OpenClawClientConfig, OpenClawClientState, ClientStatistics } from './types.js';
10
+ export declare function isUsableOpenClawDeviceIdentity(deviceId: string | undefined, keyPair: {
11
+ publicKey?: string;
12
+ privateKey?: string;
13
+ } | undefined): boolean;
10
14
  /**
11
15
  * OpenClaw WebSocket Client
12
16
  */
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * OpenClaw WebSocket Client
3
3
  *
4
- * Implements OpenClaw Gateway Protocol v3 with proper request/response handling,
4
+ * Implements OpenClaw Gateway Protocol v3–v4 with proper request/response handling,
5
5
  * reconnection logic, and event management.
6
6
  *
7
7
  * @since 2026-03-14
@@ -9,6 +9,12 @@
9
9
  import { WebSocket } from 'ws';
10
10
  import * as crypto from 'crypto';
11
11
  import { isOpenClawResponse, isOpenClawEvent, OpenClawTimeoutError, OpenClawConnectionError, } from './types.js';
12
+ export function isUsableOpenClawDeviceIdentity(deviceId, keyPair) {
13
+ if (!deviceId || deviceId === 'your-device-id') {
14
+ return false;
15
+ }
16
+ return Boolean(keyPair?.publicKey && keyPair?.privateKey);
17
+ }
12
18
  /**
13
19
  * OpenClaw WebSocket Client
14
20
  */
@@ -249,9 +255,9 @@ export class OpenClawClient {
249
255
  sendHandshake() {
250
256
  const params = {
251
257
  minProtocol: 3,
252
- maxProtocol: 3,
258
+ maxProtocol: 4,
253
259
  client: {
254
- id: 'openclaw-tui',
260
+ id: 'gateway-client',
255
261
  version: '1.0.0',
256
262
  platform: process.platform,
257
263
  mode: 'cli',
@@ -260,18 +266,20 @@ export class OpenClawClient {
260
266
  scopes: ['operator.read', 'operator.write', 'operator.admin'],
261
267
  caps: [],
262
268
  commands: [],
263
- userAgent: `OpenClaw-TUI/2026.4.25`,
269
+ userAgent: `OpenClaw-TUI/2026.7.1`,
264
270
  };
265
271
  // Add auth if provided
266
272
  if (this.config.authToken) {
267
273
  params.auth = { token: this.config.authToken };
268
274
  }
269
- // Add device if provided
270
- if (this.config.deviceId && this.config.deviceKeyPair) {
275
+ // Never send a placeholder device — gateway treats stub identity as NOT_PAIRED.
276
+ const deviceId = this.config.deviceId;
277
+ const keyPair = this.config.deviceKeyPair;
278
+ if (isUsableOpenClawDeviceIdentity(deviceId, keyPair) && deviceId && keyPair) {
271
279
  params.device = {
272
- id: this.config.deviceId,
273
- publicKey: this.config.deviceKeyPair.publicKey,
274
- signature: this.signDeviceChallenge(this.config.deviceId),
280
+ id: deviceId,
281
+ publicKey: keyPair.publicKey,
282
+ signature: this.signDeviceChallenge(deviceId),
275
283
  signedAt: Date.now(),
276
284
  nonce: this.generateNonce(),
277
285
  };
@@ -308,7 +308,6 @@ export class OpenClawConfigLoader {
308
308
  // SECURITY WARNING: authToken MUST be configured before use.
309
309
  // Leaving this empty will prevent authenticated connections.
310
310
  authToken: process.env.OPENCLAW_AUTH_TOKEN || '',
311
- deviceId: process.env.OPENCLAW_DEVICE_ID || 'your-device-id',
312
311
  autoReconnect: true,
313
312
  maxReconnectAttempts: 5,
314
313
  reconnectDelay: 1000,