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.
- package/.mcp.json +51 -7
- package/.opencode/skills/api-design/SKILL.md +1 -1
- package/.opencode/skills/architect-tools/SKILL.md +1 -1
- package/.opencode/skills/architecture-patterns/SKILL.md +1 -1
- package/.opencode/skills/auto-format/SKILL.md +1 -1
- package/.opencode/skills/boot-orchestrator/SKILL.md +2 -6
- package/.opencode/skills/bug-triage/SKILL.md +1 -1
- package/.opencode/skills/code-analyzer/SKILL.md +1 -1
- package/.opencode/skills/code-review/SKILL.md +1 -1
- package/.opencode/skills/enforcer/SKILL.md +1 -1
- package/.opencode/skills/framework-compliance-audit/SKILL.md +1 -1
- package/.opencode/skills/git-workflow/SKILL.md +1 -1
- package/.opencode/skills/hermes-agent/SKILL.md +36 -36
- package/.opencode/skills/inference-improve/SKILL.md +1 -1
- package/.opencode/skills/lint/SKILL.md +1 -1
- package/.opencode/skills/log-monitor/SKILL.md +1 -1
- package/.opencode/skills/model-health-check/SKILL.md +1 -1
- package/.opencode/skills/multimodal-looker/SKILL.md +1 -1
- package/.opencode/skills/orchestrator/SKILL.md +38 -14
- package/.opencode/skills/performance-analysis/SKILL.md +1 -1
- package/.opencode/skills/performance-optimization/SKILL.md +1 -1
- package/.opencode/skills/processor-pipeline/SKILL.md +1 -1
- package/.opencode/skills/project-analysis/SKILL.md +1 -1
- package/.opencode/skills/refactoring-strategies/SKILL.md +1 -1
- package/.opencode/skills/registry.json +65 -0
- package/.opencode/skills/researcher/SKILL.md +18 -5
- package/.opencode/skills/security-audit/SKILL.md +1 -1
- package/.opencode/skills/security-scan/SKILL.md +1 -1
- package/.opencode/skills/session-management/SKILL.md +1 -1
- package/.opencode/skills/state-manager/SKILL.md +1 -1
- package/.opencode/skills/storyteller/SKILL.md +1 -1
- package/.opencode/skills/strategist/SKILL.md +12 -0
- package/.opencode/skills/testing-best-practices/SKILL.md +37 -0
- package/.opencode/skills/testing-strategy/SKILL.md +14 -3
- package/.opencode/skills/ui-ux-design/SKILL.md +1 -1
- package/.opencode/skills/xray-orchestrator/index.ts +267 -0
- package/.xray/codex.json +12 -3
- package/.xray/features.json +27 -5
- package/.xray/features.schema.json +31 -0
- package/AGENTS-consumer.md +16 -6
- package/AGENTS.md +11 -3
- package/README.md +13 -10
- package/SKILLS.md +1 -1
- package/dist/AGENTS.md +11 -3
- package/dist/CHANGELOG.md +65 -11
- package/dist/README.md +13 -10
- package/dist/SKILLS.md +1 -1
- package/dist/cli/commands/hermes-install.js +3 -0
- package/dist/cli/commands/openclaw-install.js +14 -0
- package/dist/core/features-config.d.ts +15 -2
- package/dist/infrastructure/schemas/cloud-schemas.d.ts +1 -1
- package/dist/integrations/grok/grok-cli.d.ts +3 -0
- package/dist/integrations/grok/grok-cli.js +92 -4
- package/dist/integrations/grok/hooks/grok-hook-utils.js +53 -7
- package/dist/integrations/grok/hooks/post-tool-use.js +68 -46
- package/dist/integrations/grok/hooks/pre-tool-use.js +14 -31
- package/dist/integrations/grok/hooks/session-start.js +86 -4
- package/dist/integrations/grok/plugin/0xray/hooks/hooks.json +31 -24
- package/dist/integrations/hermes-agent/bridge.mjs +19 -1
- package/dist/integrations/hooks/delegation-gate-runtime.mjs +32 -3
- package/dist/integrations/hooks/pipeline-hook-runtime.mjs +1 -1
- package/dist/integrations/hooks/station-hook-runtime.cjs +421 -0
- package/dist/integrations/hooks/station-hook-runtime.mjs +24 -0
- package/dist/integrations/hooks/station-memory-ingest.mjs +45 -0
- package/dist/integrations/hooks/station-memory-match.mjs +47 -0
- package/dist/integrations/openclaw/client.d.ts +5 -1
- package/dist/integrations/openclaw/client.js +17 -9
- package/dist/integrations/openclaw/config.js +0 -1
- package/dist/integrations/openclaw/hooks/pre-tool-gate-runtime.mjs +102 -0
- package/dist/integrations/openclaw/index.js +17 -0
- package/dist/integrations/openclaw/plugin/xray-pre-tool/index.js +75 -0
- package/dist/integrations/openclaw/plugin/xray-pre-tool/openclaw.plugin.json +10 -0
- package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +10 -0
- package/dist/integrations/openclaw/pre-tool-gate.d.ts +19 -0
- package/dist/integrations/openclaw/pre-tool-gate.js +39 -0
- package/dist/mcps/orchestrator/handlers/complexity-handler.js +2 -2
- package/dist/memory-routing/index.d.ts +1 -1
- package/dist/memory-routing/index.js +1 -1
- package/dist/memory-routing/provider-loader.d.ts +4 -0
- package/dist/memory-routing/provider-loader.js +44 -2
- package/dist/memory-routing/provider-registry.js +3 -2
- package/dist/nucleus/autonomy-kernel.d.ts +2 -2
- package/dist/nucleus/autonomy-kernel.js +17 -6
- package/dist/nucleus/confer.js +17 -3
- package/dist/nucleus/delegation-gate.d.ts +14 -8
- package/dist/nucleus/delegation-gate.js +151 -16
- package/dist/nucleus/suit-temperament.d.ts +40 -0
- package/dist/nucleus/suit-temperament.js +157 -0
- package/dist/nucleus/user-aside.js +1 -1
- package/dist/plugin/xray-codex-injection.js +14 -3
- package/dist/postprocessor/triggers/GitHookTrigger.js +11 -5
- package/opencode.json +88 -0
- package/package.json +14 -4
- package/scripts/hooks/install-hooks.cjs +18 -3
- package/scripts/hooks/run-hook.js +67 -3
- package/scripts/mjs/run-repertoire-mcp.mjs +39 -0
- package/scripts/mjs/verify-confer-core.mjs +1 -1
- package/scripts/mjs/verify-delegation-gate-core.mjs +29 -2
- package/scripts/mjs/verify-four-floor-compact.mjs +524 -0
- package/scripts/mjs/verify-pipeline-facets.mjs +215 -0
- package/scripts/mjs/verify-temperament-live.mjs +261 -0
- package/scripts/node/bridge-mcp-wiring.cjs +277 -29
- package/scripts/node/install-bridges.cjs +195 -33
- package/scripts/node/postinstall.cjs +50 -27
- package/scripts/node/release-gate.mjs +1 -1
- package/scripts/node/release.mjs +2 -2
- package/scripts/node/validate-release-docs.mjs +20 -33
- package/scripts/node/version-manager.mjs +25 -10
- package/src/integrations/grok/plugin/0xray/hooks/hooks.json +31 -24
- package/src/integrations/openclaw/README.md +134 -0
- package/src/integrations/openclaw/plugin/xray-pre-tool/index.js +75 -0
- package/src/integrations/openclaw/plugin/xray-pre-tool/openclaw.plugin.json +10 -0
- package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +10 -0
- package/src/mcps/orchestrator/handlers/complexity-handler.ts +2 -1
- package/vendor/@0xray/repertoire/AGENTS.md +163 -0
- package/vendor/@0xray/repertoire/LICENSE +21 -0
- package/vendor/@0xray/repertoire/README.md +120 -0
- package/vendor/@0xray/repertoire/data/curated_signals.json +208 -0
- package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts +78 -0
- package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/RepertoireService.js +153 -0
- package/vendor/@0xray/repertoire/dist/RepertoireService.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.d.ts +39 -0
- package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.js +60 -0
- package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/index.d.ts +14 -0
- package/vendor/@0xray/repertoire/dist/index.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/index.js +14 -0
- package/vendor/@0xray/repertoire/dist/index.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.d.ts +26 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.js +109 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.d.ts +18 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.js +94 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.d.ts +7 -0
- package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.js +18 -0
- package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.d.ts +31 -0
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.js +83 -0
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/mcp/server.d.ts +6 -0
- package/vendor/@0xray/repertoire/dist/mcp/server.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/mcp/server.js +173 -0
- package/vendor/@0xray/repertoire/dist/mcp/server.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.d.ts +27 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.js +107 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.d.ts +11 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.js +32 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.d.ts +9 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js +72 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.d.ts +5 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.js +18 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.d.ts +31 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js +218 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/paths.d.ts +24 -0
- package/vendor/@0xray/repertoire/dist/paths.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/paths.js +74 -0
- package/vendor/@0xray/repertoire/dist/paths.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts +141 -0
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js +210 -0
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts +48 -0
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js +221 -0
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.d.ts +11 -0
- package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.js +43 -0
- package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/registry/signal-prune.d.ts +15 -0
- package/vendor/@0xray/repertoire/dist/registry/signal-prune.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/registry/signal-prune.js +35 -0
- package/vendor/@0xray/repertoire/dist/registry/signal-prune.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.d.ts +3 -0
- package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.js +24 -0
- package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.d.ts +24 -0
- package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.js +148 -0
- package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.d.ts +4 -0
- package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.js +44 -0
- package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.d.ts +22 -0
- package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.js +66 -0
- package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/types.d.ts +210 -0
- package/vendor/@0xray/repertoire/dist/types.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/types.js +2 -0
- package/vendor/@0xray/repertoire/dist/types.js.map +1 -0
- package/vendor/@0xray/repertoire/docs/MEMORY-ROUTING-PROVIDER.md +54 -0
- package/vendor/@0xray/repertoire/hermes-mcp.example.json +20 -0
- package/vendor/@0xray/repertoire/mcp-config.example.json +11 -0
- package/vendor/@0xray/repertoire/package.json +124 -0
- package/vendor/@0xray/repertoire/schemas/curated-signal.schema.json +68 -0
- package/vendor/@0xray/repertoire/schemas/inference-log.schema.json +82 -0
- package/vendor/@0xray/repertoire/scripts/confirm-suit-all.mjs +253 -0
- package/vendor/@0xray/repertoire/scripts/confirm-suit-harness.mjs +220 -0
- package/vendor/@0xray/repertoire/scripts/run-live-synthesis-checkpoint.mjs +215 -0
- package/vendor/@0xray/repertoire/scripts/suit-bridge-shared.mjs +139 -0
- package/vendor/@0xray/repertoire/scripts/verify-grok-suit.mjs +304 -0
- package/vendor/@0xray/repertoire/scripts/verify-hermes-suit.mjs +163 -0
- package/vendor/@0xray/repertoire/scripts/verify-openclaw-suit.mjs +125 -0
- package/vendor/@0xray/repertoire/scripts/verify-opencode-suit.mjs +127 -0
- package/vendor/@0xray/repertoire/scripts/verify-synthesis-dogfood.mjs +207 -0
- package/vendor/@0xray/repertoire/skills/repertoire-trap-handling/SKILL.md +206 -0
- package/xray/codex.json +12 -3
- package/xray/features.json +27 -5
- 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:
|
|
258
|
+
maxProtocol: 4,
|
|
253
259
|
client: {
|
|
254
|
-
id: '
|
|
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.
|
|
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
|
-
//
|
|
270
|
-
|
|
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:
|
|
273
|
-
publicKey:
|
|
274
|
-
signature: this.signDeviceChallenge(
|
|
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,
|