0xray 4.0.41 → 4.1.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/.grok-plugin/plugin.json +1 -1
- package/.opencode/skills/orchestrator/SKILL.md +12 -0
- package/.plugin/plugin.json +1 -1
- package/.xray/features.json +5 -5
- package/.xray/features.schema.json +1 -1
- package/AGENTS-consumer.md +10 -6
- package/AGENTS.md +19 -8
- package/LICENSE +1 -1
- package/README.md +65 -19
- package/SKILLS.md +5 -1
- package/dist/AGENTS.md +19 -8
- package/dist/CHANGELOG.md +85 -0
- package/dist/LICENSE +1 -1
- package/dist/README.md +65 -19
- package/dist/SKILLS.md +5 -1
- package/dist/cli/commands/openclaw-install.js +1 -1
- package/dist/cli/commands/plugin-commands.d.ts +4 -0
- package/dist/cli/commands/plugin-commands.js +84 -41
- package/dist/cli/index.js +12 -0
- package/dist/core/config-loader.js +4 -4
- package/dist/core/features-config.d.ts +1 -1
- package/dist/core/features-config.js +3 -3
- package/dist/enforcement/index.d.ts +4 -0
- package/dist/enforcement/index.js +4 -0
- package/dist/enforcement/validators/code-quality-validators.js +6 -4
- package/dist/governance/llm-governance-provider.d.ts +7 -1
- package/dist/governance/llm-governance-provider.js +72 -14
- package/dist/governance/local-confer.d.ts +4 -1
- package/dist/governance/local-confer.js +22 -1
- package/dist/integrations/cursor/hooks/hooks.json +6 -3
- package/dist/integrations/cursor/hooks/pre-tool-use.js +100 -37
- package/dist/integrations/cursor/hooks/xray-cloud-hook.sh +9 -1
- package/dist/integrations/grok/grok-cli.js +10 -37
- package/dist/integrations/grok/hooks/grok-hook-utils.js +8 -1
- package/dist/integrations/grok/hooks/pre-tool-use.js +2 -58
- package/dist/integrations/hermes-agent/bridge.mjs +14 -1
- package/dist/integrations/hooks/confer-hook-runtime.mjs +23 -1
- package/dist/integrations/hooks/delegation-gate-runtime.mjs +3 -2
- package/dist/integrations/hooks/goggles-mcp.mjs +35 -17
- package/dist/integrations/hooks/goggles-pipeline.mjs +46 -1
- package/dist/integrations/hooks/goggles-planes.json +11 -7
- package/dist/integrations/hooks/pre-tool-speak.mjs +76 -0
- package/dist/integrations/openclaw/hooks/pre-tool-gate-runtime.mjs +21 -4
- package/dist/integrations/openclaw/plugin/xray-pre-tool/index.js +17 -2
- package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/dist/mcps/architect-tools.server.d.ts +6 -0
- package/dist/mcps/architect-tools.server.js +19 -2
- package/dist/mcps/config/server-config-registry.js +8 -6
- package/dist/mcps/governance.server.d.ts +1 -0
- package/dist/mcps/governance.server.js +46 -0
- package/dist/mcps/knowledge-skills/code-review.server.js +7 -0
- package/dist/mcps/knowledge-skills/security-audit.server.js +5 -3
- package/dist/mcps/mcp-client.js +1 -1
- package/dist/mcps/orchestrator/handlers/complexity-handler.js +2 -2
- package/dist/mcps/researcher.server.js +12 -3
- package/dist/monitoring/{nudge-watchdog.d.ts → nudge-monitor.d.ts} +14 -5
- package/dist/monitoring/{nudge-watchdog.js → nudge-monitor.js} +42 -17
- package/dist/nucleus/autonomy-kernel.d.ts +2 -0
- package/dist/nucleus/autonomy-kernel.js +17 -13
- package/dist/nucleus/confer-host.d.ts +35 -0
- package/dist/nucleus/confer-host.js +55 -0
- package/dist/nucleus/confer.d.ts +19 -3
- package/dist/nucleus/confer.js +111 -55
- package/dist/nucleus/lead-dev-plan-persistence.js +4 -2
- package/dist/nucleus/suit-temperament.d.ts +1 -1
- package/dist/nucleus/suit-temperament.js +2 -2
- package/dist/nucleus/synthesis-consult-receipt.d.ts +7 -1
- package/dist/nucleus/synthesis-consult-receipt.js +86 -35
- package/dist/plugin/xray-codex-injection.js +18 -0
- package/dist/processors/implementations/nudge-processor.d.ts +1 -1
- package/dist/processors/implementations/nudge-processor.js +4 -4
- package/dist/reporting/framework-reporting-system.js +2 -5
- package/dist/reporting/log-parser.d.ts +2 -0
- package/dist/reporting/log-parser.js +7 -6
- package/dist/skills/orchestrator/SKILL.md +12 -0
- package/docs-site/docs/plates/activity-log.md +1 -1
- package/docs-site/docs/plates/bifrost.md +48 -0
- package/docs-site/docs/plates/boot.md +2 -2
- package/docs-site/docs/plates/centrifuge.md +1 -1
- package/docs-site/docs/plates/cursor-compact.md +1 -1
- package/docs-site/docs/plates/glossary.md +7 -3
- package/docs-site/docs/plates/goggles.md +13 -2
- package/docs-site/docs/plates/governance.md +1 -1
- package/docs-site/docs/plates/grok-compact.md +1 -1
- package/docs-site/docs/plates/grokbot.md +3 -1
- package/docs-site/docs/plates/host-pack.md +1 -1
- package/docs-site/docs/plates/house.md +1 -1
- package/docs-site/docs/plates/index.md +4 -2
- package/docs-site/docs/plates/inference-files.md +1 -1
- package/docs-site/docs/plates/kept-line.md +1 -1
- package/docs-site/docs/plates/kits.md +1 -1
- package/docs-site/docs/plates/lens-gate.md +3 -1
- package/docs-site/docs/plates/lens-page.md +1 -1
- package/docs-site/docs/plates/memory-recall.md +1 -1
- package/docs-site/docs/plates/notes-page.md +2 -2
- package/docs-site/docs/plates/orchestration.md +1 -1
- package/docs-site/docs/plates/package-face.md +1 -1
- package/docs-site/docs/plates/payload-heat.md +1 -1
- package/docs-site/docs/plates/pickup-stamp.md +1 -1
- package/docs-site/docs/plates/pre-tool.md +1 -1
- package/docs-site/docs/plates/processor.md +1 -1
- package/docs-site/docs/plates/record-map.md +1 -1
- package/docs-site/docs/plates/reflection-page.md +1 -1
- package/docs-site/docs/plates/reporting.md +1 -1
- package/docs-site/docs/plates/review.md +1 -1
- package/docs-site/docs/plates/routing.md +1 -1
- package/docs-site/docs/plates/session-capture.md +1 -1
- package/docs-site/docs/plates/site-manual.md +1 -1
- package/docs-site/docs/plates/stamp-plate.md +1 -1
- package/docs-site/docs/plates/station-card.md +1 -1
- package/docs-site/docs/plates/station-heat.md +1 -1
- package/docs-site/docs/plates/suit-organs.md +1 -1
- package/docs-site/docs/plates/suit-settings.md +1 -1
- package/docs-site/docs/plates/suit-wear.md +1 -1
- package/docs-site/docs/plates/suit.md +3 -3
- package/docs-site/docs/plates/trail-state.md +1 -1
- package/docs-site/docs/plates/work-fresh.md +1 -1
- package/docs-site/docs/plates/write-home.md +1 -1
- package/llms.txt +16 -6
- package/package.json +4 -4
- package/scripts/foundry/README.md +2 -2
- package/scripts/foundry/release-gate.mjs +111 -15
- package/scripts/foundry/release.mjs +8 -0
- package/scripts/mjs/verify-confer-core.mjs +153 -29
- package/scripts/mjs/verify-pipeline-facets.mjs +1 -1
- package/scripts/mjs/verify-user-aside-core.mjs +3 -4
- package/scripts/node/bridge-mcp-wiring.cjs +236 -5
- package/scripts/node/confer-switch.cjs +66 -0
- package/scripts/node/install-bridges.cjs +44 -53
- package/scripts/node/pack-tmp-suit-proof.mjs +14 -6
- package/src/integrations/openclaw/plugin/xray-pre-tool/index.js +17 -2
- package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/src/mcps/architect-tools.server.ts +26 -2
- package/src/mcps/config/__tests__/server-config-registry.test.ts +15 -6
- package/src/mcps/config/server-config-registry.ts +9 -6
- package/src/mcps/governance.server.ts +49 -0
- package/src/mcps/knowledge-skills/code-review.server.ts +8 -0
- package/src/mcps/knowledge-skills/security-audit.server.ts +11 -12
- package/src/mcps/mcp-client.ts +1 -1
- package/src/mcps/orchestrator/handlers/complexity-handler.ts +2 -1
- package/src/mcps/researcher.server.ts +19 -10
- package/src/skills/orchestrator/SKILL.md +12 -0
- package/vendor/@0xray/repertoire/README.md +1 -1
- package/vendor/@0xray/repertoire/scripts/run-live-synthesis-checkpoint.mjs +5 -51
- package/xray/agents_template.md +2 -2
- package/xray/features.json +5 -5
- package/xray/features.schema.json +1 -1
- package/docs-site/docs/plates/live-mesh.md +0 -41
|
@@ -18,7 +18,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
18
18
|
const FIELD_ORDER = ['plate', 'entry', 'exit', 'files', 'skills', 'setup', 'teardown', 'worn'];
|
|
19
19
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
20
20
|
const WORN_PLANES = ['dichotomy', 'syncopate', 'synthesis', 'digest', 'triage', 'loop'];
|
|
21
|
-
const CARD_PLANES = ['ground', 'routing', 'house', 'boot', 'governance', 'memory-recall', 'orchestration', 'processor', 'reporting', 'stamp-plate', 'record-map', 'write-home', 'activity-log', 'session-capture', 'suit-wear', 'suit-organs', 'station-card', 'notes-page', 'reflection-page', 'site-manual', 'package-face', 'suit-settings', 'trail-state', 'inference-files', 'grok-compact', 'payload-heat', 'station-heat', 'pickup-stamp', 'cursor-compact', 'work-fresh', 'kept-line', 'lens-gate', 'pre-tool', 'lens-page', 'centrifuge'];
|
|
21
|
+
export const CARD_PLANES = ['ground', 'routing', 'house', 'boot', 'governance', 'memory-recall', 'orchestration', 'processor', 'reporting', 'stamp-plate', 'record-map', 'write-home', 'activity-log', 'session-capture', 'suit-wear', 'suit-organs', 'station-card', 'notes-page', 'reflection-page', 'site-manual', 'package-face', 'suit-settings', 'trail-state', 'inference-files', 'grok-compact', 'payload-heat', 'station-heat', 'pickup-stamp', 'cursor-compact', 'work-fresh', 'kept-line', 'lens-gate', 'pre-tool', 'lens-page', 'centrifuge'];
|
|
22
22
|
const CARD_FLAVORS = ['digest', 'triage'];
|
|
23
23
|
const SCOPE_ZOOM = ['ecosystem', 'part', 'one flow', 'one artifact'];
|
|
24
24
|
|
|
@@ -1065,6 +1065,51 @@ export function growPlane(id, platesDir, root) {
|
|
|
1065
1065
|
return { ...base, ...grown };
|
|
1066
1066
|
}
|
|
1067
1067
|
|
|
1068
|
+
/** Paths the package ships: package.json files, plus what npm always packs. */
|
|
1069
|
+
function shippedSet(root) {
|
|
1070
|
+
try {
|
|
1071
|
+
const pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'));
|
|
1072
|
+
if (!Array.isArray(pkg.files)) return null;
|
|
1073
|
+
return pkg.files
|
|
1074
|
+
.map(String)
|
|
1075
|
+
.filter((entry) => entry && !entry.startsWith('!'))
|
|
1076
|
+
.map((entry) => entry.replace(/\/+$/, ''))
|
|
1077
|
+
.concat(['package.json', 'README.md', 'LICENSE']);
|
|
1078
|
+
} catch {
|
|
1079
|
+
return null;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
function ships(shipped, rel) {
|
|
1084
|
+
if (!shipped) return true;
|
|
1085
|
+
const path = String(rel || '').replace(/\/+$/, '');
|
|
1086
|
+
if (!path) return false;
|
|
1087
|
+
return shipped.some((entry) => path === entry || path.startsWith(`${entry}/`) || entry.startsWith(`${path}/`));
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
/**
|
|
1091
|
+
* Kind 0 card sweep: triage's file check on every card plane, limited to
|
|
1092
|
+
* paths the package ships, so a packed install and the repo read the same.
|
|
1093
|
+
* Returns the first drift line, or '' when every card holds.
|
|
1094
|
+
*/
|
|
1095
|
+
export function shippedDrift(projectRoot) {
|
|
1096
|
+
const platesDir = findPlatesDir(HERE);
|
|
1097
|
+
const root = sourceRoot(platesDir);
|
|
1098
|
+
const shipped = shippedSet(root);
|
|
1099
|
+
for (const id of CARD_PLANES) {
|
|
1100
|
+
const plane = growPlane(id, platesDir, projectRoot || stateRoot());
|
|
1101
|
+
const kept = {
|
|
1102
|
+
...plane,
|
|
1103
|
+
files: (Array.isArray(plane.files) ? plane.files : []).filter((rel) => ships(shipped, rel)),
|
|
1104
|
+
skills: ships(shipped, plane.skills) ? plane.skills : '',
|
|
1105
|
+
worn: ships(shipped, plane.worn) ? plane.worn : '',
|
|
1106
|
+
};
|
|
1107
|
+
const exam = examinePlane(kept, root);
|
|
1108
|
+
if (exam.kind === 'drift') return `Actuality. ${id}: ${exam.text}`;
|
|
1109
|
+
}
|
|
1110
|
+
return '';
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1068
1113
|
function repoRootFrom(platesDir) {
|
|
1069
1114
|
return dirname(dirname(dirname(platesDir)));
|
|
1070
1115
|
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
"files": [
|
|
8
8
|
"src",
|
|
9
9
|
"grok-bot/OP-PROC.md",
|
|
10
|
+
"grok-bot/LEXICON.md",
|
|
10
11
|
"src/opencode/agents",
|
|
11
12
|
"AGENTS.md",
|
|
12
13
|
"src/integrations",
|
|
@@ -28,7 +29,7 @@
|
|
|
28
29
|
"plates": ["orchestration", "processor"]
|
|
29
30
|
},
|
|
30
31
|
"house": {
|
|
31
|
-
"files": ["grok-bot/lib/seat-doctor.cjs"],
|
|
32
|
+
"files": ["grok-bot/lib/seat-doctor.cjs", "grok-bot/templates/house/fleet/WAKE-ROUTINE.md", "grok-bot/templates/house/HOUSE.md", "src/__tests__/unit/grok-bot-house-template.test.ts", "src/__tests__/unit/grok-bot-house-migrate.test.ts"],
|
|
32
33
|
"skills": ".agents/skills/house/SKILL.md",
|
|
33
34
|
"plates": ["suit-wear"]
|
|
34
35
|
},
|
|
@@ -38,11 +39,14 @@
|
|
|
38
39
|
"plates": ["suit-wear"]
|
|
39
40
|
},
|
|
40
41
|
"governance": {
|
|
41
|
-
"files": [
|
|
42
|
+
"files": [
|
|
43
|
+
"src/governance/governance-service.ts",
|
|
44
|
+
"src/governance/llm-governance-provider.ts"
|
|
45
|
+
],
|
|
42
46
|
"skills": ".agents/skills/governance/SKILL.md"
|
|
43
47
|
},
|
|
44
48
|
"memory-recall": {
|
|
45
|
-
"files": ["src/integrations/hooks/plates.cjs"],
|
|
49
|
+
"files": ["src/integrations/hooks/plates.cjs", "src/__tests__/unit/plates.test.ts"],
|
|
46
50
|
"skills": ".agents/skills/memory-recall/SKILL.md",
|
|
47
51
|
"plates": ["record-map"]
|
|
48
52
|
},
|
|
@@ -91,7 +95,7 @@
|
|
|
91
95
|
"plates": ["write-home", "inference-files", "suit-organs"]
|
|
92
96
|
},
|
|
93
97
|
"suit-wear": {
|
|
94
|
-
"files": ["src/core/features-config.ts"],
|
|
98
|
+
"files": ["src/core/features-config.ts", "scripts/node/install-bridges.cjs", "scripts/node/setup.cjs", "src/integrations/cursor/hooks/xray-cloud-hook.sh"],
|
|
95
99
|
"mark": "log_path",
|
|
96
100
|
"skills": ".agents/skills/suit-wear/SKILL.md",
|
|
97
101
|
"plates": ["suit-settings", "write-home", "package-face"]
|
|
@@ -121,13 +125,13 @@
|
|
|
121
125
|
"plates": ["record-map"]
|
|
122
126
|
},
|
|
123
127
|
"site-manual": {
|
|
124
|
-
"files": ["docs-site/docs/introduction.md"],
|
|
128
|
+
"files": ["docs-site/docs/introduction.md", "docs-site/docs/index.md", "docs-site/docs/full-reference.md", "docs-site/docs/guides/features-since-3.1.md"],
|
|
125
129
|
"mark": "survives the context window",
|
|
126
130
|
"skills": ".agents/skills/site-manual/SKILL.md",
|
|
127
131
|
"plates": ["record-map"]
|
|
128
132
|
},
|
|
129
133
|
"package-face": {
|
|
130
|
-
"files": ["package.json"],
|
|
134
|
+
"files": ["package.json", "grok-bot/README.md", "grok-bot/llms.txt", "grok-bot/CHANGELOG.md", "src/cli/index.ts", "src/cli/commands/plugin-commands.ts", "src/__tests__/unit/plugin-commands.test.ts"],
|
|
131
135
|
"mark": "\"name\": \"0xray\"",
|
|
132
136
|
"skills": ".agents/skills/package-face/SKILL.md",
|
|
133
137
|
"plates": ["record-map", "suit-wear"]
|
|
@@ -194,7 +198,7 @@
|
|
|
194
198
|
"plates": ["station-card", "work-fresh"]
|
|
195
199
|
},
|
|
196
200
|
"lens-gate": {
|
|
197
|
-
"files": ["src/integrations/hooks/goggles-pipeline.mjs"],
|
|
201
|
+
"files": ["src/integrations/hooks/goggles-pipeline.mjs", "src/__tests__/unit/goggles-pipeline.test.ts"],
|
|
198
202
|
"mark": "export function lensBeforeResearch",
|
|
199
203
|
"skills": ".agents/skills/lens-gate/SKILL.md",
|
|
200
204
|
"plates": ["pre-tool"]
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One pre-tool speak for every host.
|
|
3
|
+
* The lens denies an unnamed plane. The route speaks only when Repertoire changes the agent.
|
|
4
|
+
*/
|
|
5
|
+
import { createRequire } from 'node:module';
|
|
6
|
+
import { existsSync } from 'node:fs';
|
|
7
|
+
import { dirname, join } from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
import { lensBeforeResearch } from './goggles-pipeline.mjs';
|
|
10
|
+
|
|
11
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
let scoreAndRouteFn;
|
|
13
|
+
|
|
14
|
+
function loadScoreAndRoute() {
|
|
15
|
+
if (scoreAndRouteFn !== undefined) return scoreAndRouteFn;
|
|
16
|
+
scoreAndRouteFn = null;
|
|
17
|
+
const require = createRequire(import.meta.url);
|
|
18
|
+
const candidates = [
|
|
19
|
+
join(here, '../../nucleus/thin-dispatch.js'),
|
|
20
|
+
join(here, '../../../dist/nucleus/thin-dispatch.js'),
|
|
21
|
+
join(here, '../../../nucleus/thin-dispatch.js'),
|
|
22
|
+
];
|
|
23
|
+
for (const candidate of candidates) {
|
|
24
|
+
if (!existsSync(candidate)) continue;
|
|
25
|
+
try {
|
|
26
|
+
const loaded = require(candidate);
|
|
27
|
+
if (typeof loaded.scoreAndRoute === 'function') {
|
|
28
|
+
scoreAndRouteFn = loaded.scoreAndRoute;
|
|
29
|
+
return scoreAndRouteFn;
|
|
30
|
+
}
|
|
31
|
+
} catch {
|
|
32
|
+
/* next built copy */
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Speak only when the organ changes the agent. A match that leaves the agent is quiet. */
|
|
39
|
+
export function repertoireDecisionFields(routed) {
|
|
40
|
+
if (!routed?.memoryRouting?.overridden || !routed.agent) return null;
|
|
41
|
+
const signals = Array.isArray(routed.memoryRouting.signals)
|
|
42
|
+
? routed.memoryRouting.signals.slice(0, 4).filter(Boolean)
|
|
43
|
+
: [];
|
|
44
|
+
const why = signals.length ? ` on ${signals.join(', ')}` : '';
|
|
45
|
+
return {
|
|
46
|
+
agent: routed.agent,
|
|
47
|
+
gate: 'repertoire',
|
|
48
|
+
hookSpecificOutput: {
|
|
49
|
+
hookEventName: 'PreToolUse',
|
|
50
|
+
additionalContext: `Repertoire changed the route to ${routed.agent}${why}. Follow that agent for this work.`,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function repertoireRoute(operation) {
|
|
56
|
+
const text = String(operation || '').slice(0, 500).trim();
|
|
57
|
+
if (!text) return null;
|
|
58
|
+
try {
|
|
59
|
+
const scoreAndRoute = loadScoreAndRoute();
|
|
60
|
+
if (!scoreAndRoute) return null;
|
|
61
|
+
return repertoireDecisionFields(scoreAndRoute(text, {}));
|
|
62
|
+
} catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Deny when the lens stops the tool. Any other lens result is quiet. */
|
|
68
|
+
export function lensDecision(root, toolName, spoken) {
|
|
69
|
+
try {
|
|
70
|
+
const stop = lensBeforeResearch(root, toolName, spoken);
|
|
71
|
+
if (stop?.decision === 'deny') return stop;
|
|
72
|
+
return null;
|
|
73
|
+
} catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -23,7 +23,7 @@ function resolveGate() {
|
|
|
23
23
|
].filter(Boolean);
|
|
24
24
|
const found = candidates.find((p) => existsSync(p));
|
|
25
25
|
if (!found) {
|
|
26
|
-
throw new Error('delegation-gate.js missing — build 0xray or npm install 0xray');
|
|
26
|
+
throw Object.assign(new Error('delegation-gate.js missing — build 0xray or npm install 0xray'), { code: 'ERR_MODULE_NOT_FOUND' });
|
|
27
27
|
}
|
|
28
28
|
return require(found);
|
|
29
29
|
}
|
|
@@ -49,7 +49,7 @@ function readStdin() {
|
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
function decide(event, gate) {
|
|
52
|
+
async function decide(event, gate) {
|
|
53
53
|
const projectRoot =
|
|
54
54
|
event.cwd || event.workspaceRoot || event.projectRoot || process.cwd();
|
|
55
55
|
const sessionId = event.sessionId || event.session_id || 'openclaw';
|
|
@@ -70,20 +70,37 @@ function decide(event, gate) {
|
|
|
70
70
|
gate: outcome.gate,
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
|
-
|
|
73
|
+
|
|
74
|
+
const spoken = `${toolName} ${JSON.stringify(args)}`.slice(0, 500);
|
|
75
|
+
const { lensDecision, repertoireRoute } = await import('../../hooks/pre-tool-speak.mjs');
|
|
76
|
+
const lens = lensDecision(projectRoot, toolName, spoken);
|
|
77
|
+
if (lens) {
|
|
78
|
+
return {
|
|
79
|
+
action: 'block',
|
|
80
|
+
allow: false,
|
|
81
|
+
reason: lens.reason,
|
|
82
|
+
gate: lens.gate || 'lens',
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const route = repertoireRoute(spoken);
|
|
86
|
+
const allowed = {
|
|
74
87
|
action: 'allow',
|
|
75
88
|
allow: true,
|
|
76
89
|
reason: outcome.reason,
|
|
77
90
|
gate: outcome.gate,
|
|
78
91
|
warn: Boolean(outcome.reason),
|
|
79
92
|
};
|
|
93
|
+
if (route?.hookSpecificOutput) {
|
|
94
|
+
allowed.hookSpecificOutput = route.hookSpecificOutput;
|
|
95
|
+
}
|
|
96
|
+
return allowed;
|
|
80
97
|
}
|
|
81
98
|
|
|
82
99
|
async function main() {
|
|
83
100
|
try {
|
|
84
101
|
const event = await readStdin();
|
|
85
102
|
const gate = resolveGate();
|
|
86
|
-
const decision = decide(event, gate);
|
|
103
|
+
const decision = await decide(event, gate);
|
|
87
104
|
console.log(JSON.stringify(decision));
|
|
88
105
|
process.exit(decision.action === 'block' ? 2 : 0);
|
|
89
106
|
} catch (err) {
|
|
@@ -2,7 +2,7 @@ import { createRequire } from 'node:module';
|
|
|
2
2
|
import { existsSync, readFileSync } from 'node:fs';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { dirname, join } from 'node:path';
|
|
5
|
-
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
6
|
import { definePluginEntry } from 'openclaw/plugin-sdk/plugin-entry';
|
|
7
7
|
|
|
8
8
|
const require = createRequire(import.meta.url);
|
|
@@ -39,7 +39,7 @@ export default definePluginEntry({
|
|
|
39
39
|
register(api) {
|
|
40
40
|
api.on(
|
|
41
41
|
'before_tool_call',
|
|
42
|
-
(event, ctx) => {
|
|
42
|
+
async (event, ctx) => {
|
|
43
43
|
try {
|
|
44
44
|
const xrayRoot = resolveXrayRoot();
|
|
45
45
|
if (!xrayRoot) {
|
|
@@ -61,6 +61,21 @@ export default definePluginEntry({
|
|
|
61
61
|
if (!outcome.allow) {
|
|
62
62
|
return { block: true, blockReason: outcome.reason || '0xRay constitution' };
|
|
63
63
|
}
|
|
64
|
+
const spoken = `${event.toolName} ${JSON.stringify(event.params || {})}`.slice(0, 500);
|
|
65
|
+
const speakPath = [
|
|
66
|
+
join(xrayRoot, 'dist/integrations/hooks/pre-tool-speak.mjs'),
|
|
67
|
+
join(xrayRoot, 'src/integrations/hooks/pre-tool-speak.mjs'),
|
|
68
|
+
].find((candidate) => existsSync(candidate));
|
|
69
|
+
if (!speakPath) return undefined;
|
|
70
|
+
const speak = await import(pathToFileURL(speakPath).href);
|
|
71
|
+
const lens = speak.lensDecision(projectRoot, event.toolName, spoken);
|
|
72
|
+
if (lens) {
|
|
73
|
+
return { block: true, blockReason: lens.reason };
|
|
74
|
+
}
|
|
75
|
+
const route = speak.repertoireRoute(spoken);
|
|
76
|
+
if (route?.hookSpecificOutput) {
|
|
77
|
+
return { block: false, hookSpecificOutput: route.hookSpecificOutput };
|
|
78
|
+
}
|
|
64
79
|
return undefined;
|
|
65
80
|
} catch (err) {
|
|
66
81
|
return {
|
|
@@ -5,6 +5,12 @@
|
|
|
5
5
|
* Provides contextual analysis capabilities via MCP protocol
|
|
6
6
|
*/
|
|
7
7
|
import { XrayKnowledgeSkillBase } from "./shared/knowledge-skill-base.js";
|
|
8
|
+
import { type GovernanceVote } from "../governance/llm-governance-provider.js";
|
|
9
|
+
import { type ArchitectureAssessment } from "../architect/architect-tools.js";
|
|
10
|
+
export type ConferModelVerdict = "PASS" | "CONDITIONAL" | "FAIL" | "UNREVIEWED";
|
|
11
|
+
/** A confer verdict counts only when a model vote exists. Metrics alone are UNREVIEWED. */
|
|
12
|
+
export declare function conferVerdictFromModelVote(vote: Pick<GovernanceVote, "decision"> | null): ConferModelVerdict;
|
|
13
|
+
export declare function formatArchitectureAssessmentConferText(conferPrompt: string, assessment: ArchitectureAssessment, verdict?: ConferModelVerdict): string;
|
|
8
14
|
export declare function renderArchitectureAssessment(args: Record<string, unknown> | undefined): Promise<{
|
|
9
15
|
content: Array<{
|
|
10
16
|
type: "text";
|
|
@@ -8,7 +8,24 @@ import { CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
|
8
8
|
import { XrayKnowledgeSkillBase } from "./shared/knowledge-skill-base.js";
|
|
9
9
|
import * as fs from "fs";
|
|
10
10
|
import { frameworkLogger } from "../core/framework-logger.js";
|
|
11
|
-
import { contextAnalysis as architectContextAnalysis, codebaseStructure as architectCodebaseStructure, dependencyAnalysis as architectDependencyAnalysis, architectureAssessment as architectArchitectureAssessment,
|
|
11
|
+
import { contextAnalysis as architectContextAnalysis, codebaseStructure as architectCodebaseStructure, dependencyAnalysis as architectDependencyAnalysis, architectureAssessment as architectArchitectureAssessment, } from "../architect/architect-tools.js";
|
|
12
|
+
/** A confer verdict counts only when a model vote exists. Metrics alone are UNREVIEWED. */
|
|
13
|
+
export function conferVerdictFromModelVote(vote) {
|
|
14
|
+
if (!vote)
|
|
15
|
+
return "UNREVIEWED";
|
|
16
|
+
if (vote.decision === "reject")
|
|
17
|
+
return "FAIL";
|
|
18
|
+
if (vote.decision === "approve")
|
|
19
|
+
return "PASS";
|
|
20
|
+
return "CONDITIONAL";
|
|
21
|
+
}
|
|
22
|
+
export function formatArchitectureAssessmentConferText(conferPrompt, assessment, verdict = "UNREVIEWED") {
|
|
23
|
+
const assessmentJson = JSON.stringify(assessment, null, 2);
|
|
24
|
+
const trimmed = conferPrompt.trim();
|
|
25
|
+
if (!trimmed)
|
|
26
|
+
return assessmentJson;
|
|
27
|
+
return `${trimmed}\n\n## Architecture assessment\n${assessmentJson}\n\nVerdict: ${verdict}\nTop risks: review assessment metrics above\nHardening: address high-complexity or coupling findings before resuming`;
|
|
28
|
+
}
|
|
12
29
|
export async function renderArchitectureAssessment(args) {
|
|
13
30
|
const projectRoot = typeof args?.projectRoot === "string" ? args.projectRoot : "";
|
|
14
31
|
const assessmentType = args?.assessmentType === "quick" || args?.assessmentType === "comprehensive"
|
|
@@ -21,7 +38,7 @@ export async function renderArchitectureAssessment(args) {
|
|
|
21
38
|
content: [
|
|
22
39
|
{
|
|
23
40
|
type: "text",
|
|
24
|
-
text:
|
|
41
|
+
text: formatArchitectureAssessmentConferText(conferPrompt, result, "UNREVIEWED"),
|
|
25
42
|
},
|
|
26
43
|
],
|
|
27
44
|
};
|
|
@@ -10,6 +10,8 @@ import { frameworkLogger } from '../../core/framework-logger.js';
|
|
|
10
10
|
import { fileURLToPath } from 'url';
|
|
11
11
|
import { dirname, join } from 'path';
|
|
12
12
|
import fs from 'fs';
|
|
13
|
+
/** Must outlast the 120s governance model call so a real approve can return. */
|
|
14
|
+
const GOVERNANCE_MODEL_TIMEOUT_MS = 150_000;
|
|
13
15
|
/**
|
|
14
16
|
* Registry for managing MCP server configurations
|
|
15
17
|
*/
|
|
@@ -85,14 +87,14 @@ export class ServerConfigRegistry {
|
|
|
85
87
|
serverName: 'code-review',
|
|
86
88
|
command: 'node',
|
|
87
89
|
args: [`${basePath}/knowledge-skills/code-review.server.js`],
|
|
88
|
-
timeout:
|
|
90
|
+
timeout: GOVERNANCE_MODEL_TIMEOUT_MS,
|
|
89
91
|
});
|
|
90
92
|
// Security Audit Server
|
|
91
93
|
this.register({
|
|
92
94
|
serverName: 'security-audit',
|
|
93
95
|
command: 'node',
|
|
94
96
|
args: [`${basePath}/knowledge-skills/security-audit.server.js`],
|
|
95
|
-
timeout:
|
|
97
|
+
timeout: GOVERNANCE_MODEL_TIMEOUT_MS,
|
|
96
98
|
});
|
|
97
99
|
// Performance Optimization Server
|
|
98
100
|
this.register({
|
|
@@ -113,7 +115,7 @@ export class ServerConfigRegistry {
|
|
|
113
115
|
serverName: 'researcher',
|
|
114
116
|
command: 'node',
|
|
115
117
|
args: [`${basePath}/researcher.server.js`],
|
|
116
|
-
timeout:
|
|
118
|
+
timeout: GOVERNANCE_MODEL_TIMEOUT_MS,
|
|
117
119
|
});
|
|
118
120
|
// Governance Service (meta-MCP that orchestrates the three skill servers + required external Dynamo)
|
|
119
121
|
this.register({
|
|
@@ -176,7 +178,7 @@ export class ServerConfigRegistry {
|
|
|
176
178
|
serverName: 'architect',
|
|
177
179
|
command: 'node',
|
|
178
180
|
args: [`${basePath}/architect-tools.server.js`],
|
|
179
|
-
timeout:
|
|
181
|
+
timeout: GOVERNANCE_MODEL_TIMEOUT_MS,
|
|
180
182
|
});
|
|
181
183
|
// Bug Triage Specialist Server
|
|
182
184
|
this.register({
|
|
@@ -198,14 +200,14 @@ export class ServerConfigRegistry {
|
|
|
198
200
|
serverName: 'code-reviewer',
|
|
199
201
|
command: 'node',
|
|
200
202
|
args: [`${basePath}/knowledge-skills/code-review.server.js`],
|
|
201
|
-
timeout:
|
|
203
|
+
timeout: GOVERNANCE_MODEL_TIMEOUT_MS,
|
|
202
204
|
});
|
|
203
205
|
// Security Auditor (alias for security-audit)
|
|
204
206
|
this.register({
|
|
205
207
|
serverName: 'security-auditor',
|
|
206
208
|
command: 'node',
|
|
207
209
|
args: [`${basePath}/knowledge-skills/security-audit.server.js`],
|
|
208
|
-
timeout:
|
|
210
|
+
timeout: GOVERNANCE_MODEL_TIMEOUT_MS,
|
|
209
211
|
});
|
|
210
212
|
// Refactorer Server
|
|
211
213
|
this.register({
|
|
@@ -24,6 +24,7 @@ declare class GovernanceServer extends XrayKnowledgeSkillBase {
|
|
|
24
24
|
private armRequiredDynamo;
|
|
25
25
|
private handleGovernProposals;
|
|
26
26
|
private handleGovernReflection;
|
|
27
|
+
private handleRecordConferReceipt;
|
|
27
28
|
private handleGetActiveCodex;
|
|
28
29
|
private parseCodexTermsFromReflection;
|
|
29
30
|
private initializeGovernance;
|
|
@@ -20,6 +20,7 @@ import { featuresConfigLoader } from "../core/features-config.js";
|
|
|
20
20
|
import * as fs from "fs";
|
|
21
21
|
import { fileURLToPath } from "url";
|
|
22
22
|
import { randomUUID } from "crypto";
|
|
23
|
+
import { applyConferConsultResult } from "../nucleus/confer.js";
|
|
23
24
|
import { getGovernanceService } from "../governance/governance-service.js";
|
|
24
25
|
import { getCodexPolicyService } from "../governance/codex-policy.service.js";
|
|
25
26
|
import { initializeGovernanceIntegration } from "../integrations/governance/index.js";
|
|
@@ -95,6 +96,23 @@ class GovernanceServer extends XrayKnowledgeSkillBase {
|
|
|
95
96
|
required: [],
|
|
96
97
|
},
|
|
97
98
|
},
|
|
99
|
+
{
|
|
100
|
+
name: "record_confer_receipt",
|
|
101
|
+
description: "Record a confer verdict written by the wearing TUI. " +
|
|
102
|
+
"The TUI already called the seat's MCP server. This tool stores the receipt. " +
|
|
103
|
+
"Only Verdict: PASS completes the consult todo.",
|
|
104
|
+
inputSchema: {
|
|
105
|
+
type: "object",
|
|
106
|
+
properties: {
|
|
107
|
+
todoId: { type: "string", description: "Consult todo id, such as s.1" },
|
|
108
|
+
subagent: { type: "string", description: "researcher, architect-tools, or code-review" },
|
|
109
|
+
sessionId: { type: "string", description: "Plan session id" },
|
|
110
|
+
outputText: { type: "string", description: "Host verdict text, including a Verdict line" },
|
|
111
|
+
projectRoot: { type: "string", description: "Checkout root. Defaults to XRAY_ROOT or the process cwd." },
|
|
112
|
+
},
|
|
113
|
+
required: ["todoId", "subagent", "sessionId", "outputText"],
|
|
114
|
+
},
|
|
115
|
+
},
|
|
98
116
|
{
|
|
99
117
|
name: "get_active_codex",
|
|
100
118
|
description: "Get the currently active Codex (SSOT) — returns metadata about the loaded codex terms, " +
|
|
@@ -117,6 +135,7 @@ class GovernanceServer extends XrayKnowledgeSkillBase {
|
|
|
117
135
|
"govern_proposals": async (args) => this.handleGovernProposals(this.validateGovernProposalsArgs(args)),
|
|
118
136
|
"govern_reflection": async (args) => this.handleGovernReflection(this.validateGovernReflectionArgs(args)),
|
|
119
137
|
"get_active_codex": async (args) => this.handleGetActiveCodex(args),
|
|
138
|
+
"record_confer_receipt": async (args) => this.handleRecordConferReceipt(args),
|
|
120
139
|
};
|
|
121
140
|
this.setupToolHandlers();
|
|
122
141
|
}
|
|
@@ -163,6 +182,8 @@ class GovernanceServer extends XrayKnowledgeSkillBase {
|
|
|
163
182
|
return await this.handleGovernReflection(this.validateGovernReflectionArgs(args));
|
|
164
183
|
case "get_active_codex":
|
|
165
184
|
return await this.handleGetActiveCodex(args);
|
|
185
|
+
case "record_confer_receipt":
|
|
186
|
+
return await this.handleRecordConferReceipt(args);
|
|
166
187
|
default:
|
|
167
188
|
throw new Error(`Unknown tool: ${name}`);
|
|
168
189
|
}
|
|
@@ -272,6 +293,31 @@ class GovernanceServer extends XrayKnowledgeSkillBase {
|
|
|
272
293
|
options: { require_external: true },
|
|
273
294
|
});
|
|
274
295
|
}
|
|
296
|
+
async handleRecordConferReceipt(args) {
|
|
297
|
+
if (!args || typeof args !== "object") {
|
|
298
|
+
throw new Error("record_confer_receipt requires an object argument");
|
|
299
|
+
}
|
|
300
|
+
const obj = args;
|
|
301
|
+
const todoId = typeof obj.todoId === "string" ? obj.todoId.trim() : "";
|
|
302
|
+
const subagent = typeof obj.subagent === "string" ? obj.subagent.trim() : "";
|
|
303
|
+
const sessionId = typeof obj.sessionId === "string" ? obj.sessionId.trim() : "";
|
|
304
|
+
const outputText = typeof obj.outputText === "string" ? obj.outputText : "";
|
|
305
|
+
if (!todoId || !subagent || !sessionId || !outputText.trim()) {
|
|
306
|
+
throw new Error("record_confer_receipt requires todoId, subagent, sessionId, and outputText");
|
|
307
|
+
}
|
|
308
|
+
const projectRoot = typeof obj.projectRoot === "string" && obj.projectRoot.trim()
|
|
309
|
+
? obj.projectRoot
|
|
310
|
+
: process.env.XRAY_ROOT || process.cwd();
|
|
311
|
+
const result = applyConferConsultResult(todoId, subagent, sessionId, outputText, projectRoot);
|
|
312
|
+
return {
|
|
313
|
+
content: [
|
|
314
|
+
{
|
|
315
|
+
type: "text",
|
|
316
|
+
text: JSON.stringify(result),
|
|
317
|
+
},
|
|
318
|
+
],
|
|
319
|
+
};
|
|
320
|
+
}
|
|
275
321
|
async handleGetActiveCodex(args) {
|
|
276
322
|
const includeRaw = args?.includeRaw === true;
|
|
277
323
|
const snapshot = await getCodexPolicyService().getCurrentCodex(includeRaw);
|
|
@@ -9,6 +9,7 @@ import * as fs from "fs";
|
|
|
9
9
|
import * as path from "path";
|
|
10
10
|
import { isGovernanceLlmConfigured, tryLLMGovernance, } from "../../governance/llm-governance-provider.js";
|
|
11
11
|
import { formatGovernanceVoteText, localConferVote } from "../../governance/local-confer.js";
|
|
12
|
+
import { buildHostConferEvidence } from "../../nucleus/confer-host.js";
|
|
12
13
|
class XrayCodeReviewServer extends XrayKnowledgeSkillBase {
|
|
13
14
|
constructor() {
|
|
14
15
|
super("code-review", "3.1.0");
|
|
@@ -316,6 +317,12 @@ class XrayCodeReviewServer extends XrayKnowledgeSkillBase {
|
|
|
316
317
|
*/
|
|
317
318
|
async analyzeProposal(args) {
|
|
318
319
|
const { proposalTitle = "", proposalDescription = "", evidence = [], proposalType = "" } = args;
|
|
320
|
+
if (proposalType === "synthesis-confer") {
|
|
321
|
+
const packet = [proposalTitle, proposalDescription, ...(evidence || [])].filter(Boolean).join("\n\n");
|
|
322
|
+
return {
|
|
323
|
+
content: [{ type: "text", text: buildHostConferEvidence("code-review", packet) }],
|
|
324
|
+
};
|
|
325
|
+
}
|
|
319
326
|
const vote = (await tryLLMGovernance("code-review", proposalTitle, proposalDescription, evidence, proposalType)) ??
|
|
320
327
|
localConferVote({
|
|
321
328
|
role: "code-review",
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import * as fs from "fs";
|
|
8
8
|
import * as path from "path";
|
|
9
9
|
import { XrayKnowledgeSkillBase } from "../shared/knowledge-skill-base.js";
|
|
10
|
-
import {
|
|
10
|
+
import { attemptLLMGovernance } from "../../governance/llm-governance-provider.js";
|
|
11
11
|
import { formatGovernanceVoteText, localConferVote } from "../../governance/local-confer.js";
|
|
12
12
|
class XraySecurityAuditServer extends XrayKnowledgeSkillBase {
|
|
13
13
|
constructor() {
|
|
@@ -661,10 +661,12 @@ class XraySecurityAuditServer extends XrayKnowledgeSkillBase {
|
|
|
661
661
|
*/
|
|
662
662
|
async analyzeProposal(args) {
|
|
663
663
|
const { proposalTitle = "", proposalDescription = "", evidence = [], proposalType = "" } = args;
|
|
664
|
-
const
|
|
664
|
+
const attempt = await attemptLLMGovernance("security-audit", proposalTitle, proposalDescription, evidence, proposalType);
|
|
665
|
+
const vote = attempt.vote ??
|
|
665
666
|
localConferVote({
|
|
666
667
|
role: "security-audit",
|
|
667
|
-
llmConfigured:
|
|
668
|
+
llmConfigured: attempt.miss !== "not-configured",
|
|
669
|
+
...(attempt.miss ? { miss: attempt.miss } : {}),
|
|
668
670
|
});
|
|
669
671
|
return {
|
|
670
672
|
content: [
|
package/dist/mcps/mcp-client.js
CHANGED
|
@@ -319,7 +319,7 @@ export class MCPClient extends EventEmitter {
|
|
|
319
319
|
};
|
|
320
320
|
this.emit('tool.before', beforeEvent);
|
|
321
321
|
const serverName = this.config.serverName;
|
|
322
|
-
const isGovernanceServer = ['code-review', 'security-audit', 'researcher', 'governance'].includes(serverName);
|
|
322
|
+
const isGovernanceServer = ['code-review', 'security-audit', 'researcher', 'architect', 'governance'].includes(serverName);
|
|
323
323
|
const isGovernanceTool = toolName === 'analyze_proposal';
|
|
324
324
|
const preferReal = this.isPureMcpMode || isGovernanceServer || isGovernanceTool;
|
|
325
325
|
try {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { frameworkLogger } from '../../../core/framework-logger.js';
|
|
7
7
|
import { buildLeadDevPlan, buildSynthesisCheckpointPlan, isLeadDevModeActive, persistLeadDevPlan, } from '../../../nucleus/autonomy-kernel.js';
|
|
8
|
-
import { formatConferQuorumReport, isConferEnabled, runConferQuorum, } from '../../../nucleus/confer.js';
|
|
8
|
+
import { conferFixtureAllowed, formatConferQuorumReport, isConferEnabled, runConferQuorum, } from '../../../nucleus/confer.js';
|
|
9
9
|
import { bindPlanToSession } from '../../../nucleus/lead-dev-plan-persistence.js';
|
|
10
10
|
import { clearPendingDelegations } from '../../../nucleus/pending-delegations.js';
|
|
11
11
|
import { isAutoProvisionWorktreeEnabled, provisionGitWorktree, } from '../../../nucleus/aside-worktree.js';
|
|
@@ -177,7 +177,7 @@ export class ComplexityHandler {
|
|
|
177
177
|
args.sessionId) {
|
|
178
178
|
const conferOpts = {
|
|
179
179
|
dueReason: args.synthesisDueReason ?? null,
|
|
180
|
-
fixture: args.conferFixture === true,
|
|
180
|
+
fixture: conferFixtureAllowed() && args.conferFixture === true,
|
|
181
181
|
};
|
|
182
182
|
if (args.collocatedText)
|
|
183
183
|
conferOpts.collocatedText = args.collocatedText;
|
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
import * as fs from "fs";
|
|
11
11
|
import * as path from "path";
|
|
12
12
|
import { frameworkLogger } from "../core/framework-logger.js";
|
|
13
|
-
import {
|
|
13
|
+
import { attemptLLMGovernance, } from "../governance/llm-governance-provider.js";
|
|
14
14
|
import { formatGovernanceVoteText, localConferVote } from "../governance/local-confer.js";
|
|
15
15
|
import { initializeMemoryRouting } from "../memory-routing/index.js";
|
|
16
16
|
import { buildMemoryRoutingEvidence, formatMemoryRoutingBlock, resolveResearcherMemoryContext, } from "./researcher-confidence.js";
|
|
17
|
+
import { buildHostConferEvidence } from "../nucleus/confer-host.js";
|
|
17
18
|
import { XrayKnowledgeSkillBase } from "./shared/knowledge-skill-base.js";
|
|
18
19
|
class XrayLibrarianServer extends XrayKnowledgeSkillBase {
|
|
19
20
|
constructor() {
|
|
@@ -382,6 +383,12 @@ class XrayLibrarianServer extends XrayKnowledgeSkillBase {
|
|
|
382
383
|
*/
|
|
383
384
|
async analyzeProposal(args) {
|
|
384
385
|
const { proposalTitle = "", proposalDescription = "", evidence = [], proposalType = "" } = args || {};
|
|
386
|
+
if (proposalType === "synthesis-confer") {
|
|
387
|
+
const packet = [proposalTitle, proposalDescription, ...(evidence || [])].filter(Boolean).join("\n\n");
|
|
388
|
+
return {
|
|
389
|
+
content: [{ type: "text", text: buildHostConferEvidence("researcher", packet) }],
|
|
390
|
+
};
|
|
391
|
+
}
|
|
385
392
|
const memoryContext = await resolveResearcherMemoryContext({
|
|
386
393
|
proposalTitle,
|
|
387
394
|
proposalDescription,
|
|
@@ -391,12 +398,14 @@ class XrayLibrarianServer extends XrayKnowledgeSkillBase {
|
|
|
391
398
|
if (memoryContext) {
|
|
392
399
|
enrichedEvidence.push(...buildMemoryRoutingEvidence(memoryContext));
|
|
393
400
|
}
|
|
394
|
-
const
|
|
401
|
+
const attempt = await attemptLLMGovernance("researcher", proposalTitle || "", proposalDescription || "", enrichedEvidence, proposalType || "");
|
|
402
|
+
const vote = attempt.vote ??
|
|
395
403
|
localConferVote({
|
|
396
404
|
role: "researcher",
|
|
397
|
-
llmConfigured:
|
|
405
|
+
llmConfigured: attempt.miss !== "not-configured",
|
|
398
406
|
highConfidenceTrapPresent: memoryContext?.confidence.highConfidenceTrapPresent,
|
|
399
407
|
recommendedAgent: memoryContext?.recommendedAgent,
|
|
408
|
+
...(attempt.miss ? { miss: attempt.miss } : {}),
|
|
400
409
|
});
|
|
401
410
|
const memoryRoutingBlock = memoryContext
|
|
402
411
|
? `\n${formatMemoryRoutingBlock(memoryContext)}`
|