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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Nudge
|
|
2
|
+
* Nudge Monitor - Detects and breaks stuck AI patterns
|
|
3
3
|
*
|
|
4
4
|
* Monitors agent actions and detects common failure patterns:
|
|
5
5
|
* - think-loop: AI keeps outputting thinking tags but no progress
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - tool-loop: Same tool called with similar args repeatedly
|
|
9
9
|
* - repair-failure: Processor indicates fix but error persists
|
|
10
10
|
*
|
|
11
|
-
* @module monitoring/nudge-
|
|
11
|
+
* @module monitoring/nudge-monitor
|
|
12
12
|
*/
|
|
13
13
|
import { EventEmitter } from "events";
|
|
14
14
|
export interface NudgeConfig {
|
|
@@ -33,7 +33,16 @@ export interface NudgeAction {
|
|
|
33
33
|
suggestion: string;
|
|
34
34
|
priority: number;
|
|
35
35
|
}
|
|
36
|
-
|
|
36
|
+
/** Old config key from before the rename to nudge_monitor; still read as a deprecated alias. */
|
|
37
|
+
export declare const LEGACY_NUDGE_CONFIG_KEY = "nudge_watchdog";
|
|
38
|
+
/**
|
|
39
|
+
* features.nudge_monitor, or the deprecated features.nudge_watchdog when nudge_monitor is unset (the new key wins
|
|
40
|
+
* when both are set). Using the old key logs a one-time deprecation warning.
|
|
41
|
+
*/
|
|
42
|
+
export declare function resolveNudgeConfig(features: Record<string, unknown> | undefined | null, warn?: (message: string) => void): Record<string, unknown> | undefined;
|
|
43
|
+
/** Test hook: let the one-time deprecation warning fire again. */
|
|
44
|
+
export declare function resetLegacyNudgeWarning(): void;
|
|
45
|
+
declare class NudgeMonitor extends EventEmitter {
|
|
37
46
|
private config;
|
|
38
47
|
private patterns;
|
|
39
48
|
private lastNudgeTime;
|
|
@@ -75,13 +84,13 @@ declare class NudgeWatchdog extends EventEmitter {
|
|
|
75
84
|
};
|
|
76
85
|
private log;
|
|
77
86
|
}
|
|
78
|
-
export declare const
|
|
87
|
+
export declare const nudgeMonitor: NudgeMonitor;
|
|
79
88
|
export declare function recordThinkTag(): void;
|
|
80
89
|
export declare function recordCodeChange(): void;
|
|
81
90
|
export declare function recordToolCall(tool: string, args: string): void;
|
|
82
91
|
export declare function recordFixAttempt(filePath: string, error: string): void;
|
|
83
92
|
export declare function recordExplanation(): void;
|
|
84
93
|
export declare function getNudgeSuggestion(type: NudgeType, context?: Record<string, unknown>): string;
|
|
85
|
-
export declare function
|
|
94
|
+
export declare function getNudgeMonitor(): NudgeMonitor;
|
|
86
95
|
export declare function recordProcessorFix(filePath: string, fixed: boolean, errorPersisted: boolean): void;
|
|
87
96
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Nudge
|
|
2
|
+
* Nudge Monitor - Detects and breaks stuck AI patterns
|
|
3
3
|
*
|
|
4
4
|
* Monitors agent actions and detects common failure patterns:
|
|
5
5
|
* - think-loop: AI keeps outputting thinking tags but no progress
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - tool-loop: Same tool called with similar args repeatedly
|
|
9
9
|
* - repair-failure: Processor indicates fix but error persists
|
|
10
10
|
*
|
|
11
|
-
* @module monitoring/nudge-
|
|
11
|
+
* @module monitoring/nudge-monitor
|
|
12
12
|
*/
|
|
13
13
|
import { EventEmitter } from "events";
|
|
14
14
|
import { frameworkLogger } from "../core/framework-logger.js";
|
|
@@ -53,7 +53,32 @@ const NUDGE_MESSAGES = {
|
|
|
53
53
|
priority: 5,
|
|
54
54
|
},
|
|
55
55
|
};
|
|
56
|
-
|
|
56
|
+
/** Old config key from before the rename to nudge_monitor; still read as a deprecated alias. */
|
|
57
|
+
export const LEGACY_NUDGE_CONFIG_KEY = "nudge_watchdog";
|
|
58
|
+
let legacyKeyWarned = false;
|
|
59
|
+
/**
|
|
60
|
+
* features.nudge_monitor, or the deprecated features.nudge_watchdog when nudge_monitor is unset (the new key wins
|
|
61
|
+
* when both are set). Using the old key logs a one-time deprecation warning.
|
|
62
|
+
*/
|
|
63
|
+
export function resolveNudgeConfig(features, warn = (m) => frameworkLogger.log("nudge-monitor", "deprecated-config-key", "warning", { message: m })) {
|
|
64
|
+
const current = features?.nudge_monitor;
|
|
65
|
+
if (current !== undefined && current !== null)
|
|
66
|
+
return current;
|
|
67
|
+
const legacy = features?.[LEGACY_NUDGE_CONFIG_KEY];
|
|
68
|
+
if (legacy !== undefined && legacy !== null) {
|
|
69
|
+
if (!legacyKeyWarned) {
|
|
70
|
+
legacyKeyWarned = true;
|
|
71
|
+
warn(`features.${LEGACY_NUDGE_CONFIG_KEY} is deprecated; rename it to features.nudge_monitor`);
|
|
72
|
+
}
|
|
73
|
+
return legacy;
|
|
74
|
+
}
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
/** Test hook: let the one-time deprecation warning fire again. */
|
|
78
|
+
export function resetLegacyNudgeWarning() {
|
|
79
|
+
legacyKeyWarned = false;
|
|
80
|
+
}
|
|
81
|
+
class NudgeMonitor extends EventEmitter {
|
|
57
82
|
config;
|
|
58
83
|
patterns = new Map();
|
|
59
84
|
lastNudgeTime = 0;
|
|
@@ -73,7 +98,7 @@ class NudgeWatchdog extends EventEmitter {
|
|
|
73
98
|
loadConfigFromFeatures() {
|
|
74
99
|
try {
|
|
75
100
|
const features = featuresConfigLoader.loadConfig();
|
|
76
|
-
const nudgeConfig = features
|
|
101
|
+
const nudgeConfig = resolveNudgeConfig(features);
|
|
77
102
|
if (nudgeConfig) {
|
|
78
103
|
this.config = { ...this.config, ...nudgeConfig };
|
|
79
104
|
}
|
|
@@ -86,10 +111,10 @@ class NudgeWatchdog extends EventEmitter {
|
|
|
86
111
|
if (!this.config.enabled) {
|
|
87
112
|
return;
|
|
88
113
|
}
|
|
89
|
-
this.log("nudge-
|
|
114
|
+
this.log("nudge-monitor", "started", "info", { config: this.config });
|
|
90
115
|
}
|
|
91
116
|
stop() {
|
|
92
|
-
this.log("nudge-
|
|
117
|
+
this.log("nudge-monitor", "stopped", "info");
|
|
93
118
|
}
|
|
94
119
|
recordThinkTag() {
|
|
95
120
|
const now = Date.now();
|
|
@@ -256,7 +281,7 @@ class NudgeWatchdog extends EventEmitter {
|
|
|
256
281
|
if (!action)
|
|
257
282
|
return null;
|
|
258
283
|
this.emit("nudge", action);
|
|
259
|
-
this.log("nudge-
|
|
284
|
+
this.log("nudge-monitor", "nudge-triggered", "warning", {
|
|
260
285
|
type: action.type,
|
|
261
286
|
message: action.message,
|
|
262
287
|
suggestion: action.suggestion,
|
|
@@ -328,28 +353,28 @@ class NudgeWatchdog extends EventEmitter {
|
|
|
328
353
|
}
|
|
329
354
|
}
|
|
330
355
|
}
|
|
331
|
-
export const
|
|
356
|
+
export const nudgeMonitor = new NudgeMonitor();
|
|
332
357
|
export function recordThinkTag() {
|
|
333
|
-
|
|
358
|
+
nudgeMonitor.recordThinkTag();
|
|
334
359
|
}
|
|
335
360
|
export function recordCodeChange() {
|
|
336
|
-
|
|
361
|
+
nudgeMonitor.recordCodeChange();
|
|
337
362
|
}
|
|
338
363
|
export function recordToolCall(tool, args) {
|
|
339
|
-
|
|
364
|
+
nudgeMonitor.recordToolCall(tool, args);
|
|
340
365
|
}
|
|
341
366
|
export function recordFixAttempt(filePath, error) {
|
|
342
|
-
|
|
367
|
+
nudgeMonitor.recordFixAttempt(filePath, error);
|
|
343
368
|
}
|
|
344
369
|
export function recordExplanation() {
|
|
345
|
-
|
|
370
|
+
nudgeMonitor.recordExplanation();
|
|
346
371
|
}
|
|
347
372
|
export function getNudgeSuggestion(type, context) {
|
|
348
|
-
return
|
|
373
|
+
return nudgeMonitor.getNudgeSuggestion(type, context);
|
|
349
374
|
}
|
|
350
|
-
export function
|
|
351
|
-
return
|
|
375
|
+
export function getNudgeMonitor() {
|
|
376
|
+
return nudgeMonitor;
|
|
352
377
|
}
|
|
353
378
|
export function recordProcessorFix(filePath, fixed, errorPersisted) {
|
|
354
|
-
|
|
379
|
+
nudgeMonitor.recordProcessorFix(filePath, fixed, errorPersisted);
|
|
355
380
|
}
|
|
@@ -38,6 +38,8 @@ export interface LeadDevPlan {
|
|
|
38
38
|
fullSuiteGate: boolean;
|
|
39
39
|
hint: string;
|
|
40
40
|
};
|
|
41
|
+
/** New id each synthesis plan. Receipts from an older id cannot complete s.1–s.3. */
|
|
42
|
+
consultCycleId?: string;
|
|
41
43
|
}
|
|
42
44
|
export declare function isLeadDevModeActive(): boolean;
|
|
43
45
|
export declare function routeSubagent(taskType: string): SubagentRoute;
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
* Lead-dev plan builder — internal implementation for orchestrator + hooks.
|
|
3
3
|
* Config: features.json → multi_agent_orchestration (lead_dev_mode), NOT a separate surface.
|
|
4
4
|
*/
|
|
5
|
+
import { randomUUID } from 'node:crypto';
|
|
5
6
|
import * as fs from 'fs';
|
|
6
7
|
import * as path from 'path';
|
|
7
8
|
import { featuresConfigLoader } from '../core/features-config.js';
|
|
8
9
|
import { scoreComplexity } from './thin-dispatch.js';
|
|
9
|
-
import { conferDefaultForProfile, resolveRuntimeSuitProfile } from './suit-temperament.js';
|
|
10
10
|
export const LEAD_DEV_RULES = [
|
|
11
11
|
'Phased plan + detailed todos; assign best subagent; monitor output; iterate fully',
|
|
12
12
|
'Lead dev takes helm — loop test fix until complete; no permission pings',
|
|
@@ -33,6 +33,19 @@ const TASK_TYPE_ROUTES = {
|
|
|
33
33
|
security: 'security-audit',
|
|
34
34
|
governance: 'enforcer',
|
|
35
35
|
};
|
|
36
|
+
function conferExplicitlyEnabled(projectRoot) {
|
|
37
|
+
const featuresPath = path.join(projectRoot, '.xray', 'features.json');
|
|
38
|
+
if (!fs.existsSync(featuresPath))
|
|
39
|
+
return false;
|
|
40
|
+
try {
|
|
41
|
+
const data = JSON.parse(fs.readFileSync(featuresPath, 'utf8'));
|
|
42
|
+
const orch = data.multi_agent_orchestration ?? {};
|
|
43
|
+
return orch.confer?.enabled === true || orch.confer_on_synthesis === true;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
36
49
|
function orchestrationConfig() {
|
|
37
50
|
try {
|
|
38
51
|
return featuresConfigLoader.loadConfig().multi_agent_orchestration;
|
|
@@ -80,12 +93,7 @@ export function buildSynthesisCheckpointPlan(dueReason, projectRoot = process.cw
|
|
|
80
93
|
if (!isLeadDevModeActive())
|
|
81
94
|
return null;
|
|
82
95
|
const cfg = orchestrationConfig();
|
|
83
|
-
const
|
|
84
|
-
const autoConsult = profile === 'frontier'
|
|
85
|
-
? cfg.confer?.enabled === true || cfg.confer_on_synthesis === true
|
|
86
|
-
: profile === 'strict'
|
|
87
|
-
? true
|
|
88
|
-
: cfg.auto_consult_major_work !== false;
|
|
96
|
+
const autoConsult = conferExplicitlyEnabled(projectRoot);
|
|
89
97
|
const mandatoryConsults = autoConsult ? [...MANDATORY_MAJOR_CONSULTS] : [];
|
|
90
98
|
if (mandatoryConsults.length === 0)
|
|
91
99
|
return null;
|
|
@@ -118,13 +126,13 @@ export function buildSynthesisCheckpointPlan(dueReason, projectRoot = process.cw
|
|
|
118
126
|
fullSuiteGate: false,
|
|
119
127
|
hint: 'Synthesis checkpoint — consult mandatory agents before resuming gated work',
|
|
120
128
|
},
|
|
129
|
+
consultCycleId: randomUUID(),
|
|
121
130
|
};
|
|
122
131
|
}
|
|
123
132
|
export function buildLeadDevPlan(description, taskTypes = ['implement'], taskInputs = [], mcpOverallComplexity, projectRoot = process.cwd()) {
|
|
124
133
|
if (!isLeadDevModeActive())
|
|
125
134
|
return null;
|
|
126
135
|
const cfg = orchestrationConfig();
|
|
127
|
-
const profile = resolveRuntimeSuitProfile(projectRoot);
|
|
128
136
|
const threshold = cfg.phased_plan_threshold ?? 25;
|
|
129
137
|
const score = scoreComplexity(description, { taskTypes });
|
|
130
138
|
const mcpScore = mcpOverallComplexity !== undefined && Number.isFinite(mcpOverallComplexity)
|
|
@@ -132,11 +140,7 @@ export function buildLeadDevPlan(description, taskTypes = ['implement'], taskInp
|
|
|
132
140
|
: 0;
|
|
133
141
|
const complexity = Math.max(score.score, mcpScore);
|
|
134
142
|
const requiresPhasedPlan = complexity > threshold || taskInputs.length > 1;
|
|
135
|
-
const autoConsult =
|
|
136
|
-
? cfg.confer?.enabled === true || cfg.confer_on_synthesis === true
|
|
137
|
-
: profile === 'strict' || conferDefaultForProfile(profile)
|
|
138
|
-
? cfg.auto_consult_major_work !== false
|
|
139
|
-
: false;
|
|
143
|
+
const autoConsult = conferExplicitlyEnabled(projectRoot);
|
|
140
144
|
const mandatoryConsults = autoConsult && requiresPhasedPlan ? [...MANDATORY_MAJOR_CONSULTS] : [];
|
|
141
145
|
const phases = requiresPhasedPlan
|
|
142
146
|
? [
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Confer host port. The wearing TUI already spawned the MCP servers.
|
|
3
|
+
* This port writes the ask or returns the host's answer. It does not spawn a server.
|
|
4
|
+
*/
|
|
5
|
+
export interface ConferHostSeat {
|
|
6
|
+
todoId: string;
|
|
7
|
+
subagent: string;
|
|
8
|
+
server: string;
|
|
9
|
+
tool: string;
|
|
10
|
+
args: Record<string, unknown>;
|
|
11
|
+
sessionId: string;
|
|
12
|
+
prompt: string;
|
|
13
|
+
dueReason: string | null;
|
|
14
|
+
}
|
|
15
|
+
export type ConferHostCall = {
|
|
16
|
+
status: 'pending';
|
|
17
|
+
askPath: string;
|
|
18
|
+
} | {
|
|
19
|
+
status: 'answered';
|
|
20
|
+
text: string;
|
|
21
|
+
};
|
|
22
|
+
export interface ConferHostPort {
|
|
23
|
+
call(seat: ConferHostSeat, projectRoot: string): Promise<ConferHostCall>;
|
|
24
|
+
}
|
|
25
|
+
export declare function conferAskPath(todoId: string, projectRoot: string): string;
|
|
26
|
+
/** Evidence for the host model. The schema line is not a vote. */
|
|
27
|
+
export declare function buildHostConferEvidence(role: string, evidence: string): string;
|
|
28
|
+
export declare class SessionConferHost implements ConferHostPort {
|
|
29
|
+
call(seat: ConferHostSeat, projectRoot: string): Promise<ConferHostCall>;
|
|
30
|
+
}
|
|
31
|
+
export declare class InProcessConferHost implements ConferHostPort {
|
|
32
|
+
private readonly answers;
|
|
33
|
+
constructor(answers: Record<string, string>);
|
|
34
|
+
call(seat: ConferHostSeat): Promise<ConferHostCall>;
|
|
35
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Confer host port. The wearing TUI already spawned the MCP servers.
|
|
3
|
+
* This port writes the ask or returns the host's answer. It does not spawn a server.
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
export function conferAskPath(todoId, projectRoot) {
|
|
8
|
+
return path.join(projectRoot, '.xray', 'state', `confer-ask-${todoId}.json`);
|
|
9
|
+
}
|
|
10
|
+
/** Evidence for the host model. The schema line is not a vote. */
|
|
11
|
+
export function buildHostConferEvidence(role, evidence) {
|
|
12
|
+
const body = evidence.trim();
|
|
13
|
+
return [
|
|
14
|
+
`## Confer evidence — ${role}`,
|
|
15
|
+
'',
|
|
16
|
+
body || 'No local evidence. The wearing TUI has the confer ask.',
|
|
17
|
+
'',
|
|
18
|
+
'The wearing TUI writes the verdict on its own line after this evidence.',
|
|
19
|
+
'',
|
|
20
|
+
'Verdict: PASS | CONDITIONAL | FAIL',
|
|
21
|
+
'- Top risks (bulleted)',
|
|
22
|
+
'- Hardening note / recommendations',
|
|
23
|
+
].join('\n');
|
|
24
|
+
}
|
|
25
|
+
export class SessionConferHost {
|
|
26
|
+
async call(seat, projectRoot) {
|
|
27
|
+
const askPath = conferAskPath(seat.todoId, projectRoot);
|
|
28
|
+
fs.mkdirSync(path.dirname(askPath), { recursive: true });
|
|
29
|
+
const payload = {
|
|
30
|
+
todoId: seat.todoId,
|
|
31
|
+
subagent: seat.subagent,
|
|
32
|
+
server: seat.server,
|
|
33
|
+
tool: seat.tool,
|
|
34
|
+
args: seat.args,
|
|
35
|
+
sessionId: seat.sessionId,
|
|
36
|
+
prompt: seat.prompt,
|
|
37
|
+
dueReason: seat.dueReason,
|
|
38
|
+
};
|
|
39
|
+
fs.writeFileSync(askPath, `${JSON.stringify(payload, null, 2)}\n`);
|
|
40
|
+
return { status: 'pending', askPath };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export class InProcessConferHost {
|
|
44
|
+
answers;
|
|
45
|
+
constructor(answers) {
|
|
46
|
+
this.answers = answers;
|
|
47
|
+
}
|
|
48
|
+
async call(seat) {
|
|
49
|
+
const text = this.answers[seat.todoId] ?? this.answers[seat.subagent];
|
|
50
|
+
if (text === undefined) {
|
|
51
|
+
return { status: 'pending', askPath: '' };
|
|
52
|
+
}
|
|
53
|
+
return { status: 'answered', text };
|
|
54
|
+
}
|
|
55
|
+
}
|
package/dist/nucleus/confer.d.ts
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
* Triggered automatically at synthesis checkpoint; records consult receipts + plan todos.
|
|
4
4
|
*/
|
|
5
5
|
import { type SynthesisConsultReceipt } from './synthesis-consult-receipt.js';
|
|
6
|
+
import { InProcessConferHost, SessionConferHost, type ConferHostPort, type ConferHostSeat } from './confer-host.js';
|
|
7
|
+
export { InProcessConferHost, SessionConferHost };
|
|
8
|
+
export type { ConferHostPort, ConferHostSeat };
|
|
6
9
|
export declare const CONFER_AGENTS: readonly ["researcher", "architect-tools", "code-review"];
|
|
7
10
|
export interface ConferConfig {
|
|
8
11
|
enabled: boolean;
|
|
@@ -27,12 +30,16 @@ export interface ConferAgentResult {
|
|
|
27
30
|
error?: string;
|
|
28
31
|
}
|
|
29
32
|
export interface ConferQuorumResult {
|
|
30
|
-
status: 'completed' | 'partial' | 'skipped' | 'failed';
|
|
33
|
+
status: 'completed' | 'partial' | 'skipped' | 'failed' | 'pending';
|
|
31
34
|
agents: ConferAgentResult[];
|
|
32
35
|
message: string;
|
|
33
36
|
}
|
|
34
37
|
export declare function conferCheckpointPath(projectRoot?: string): string;
|
|
35
38
|
export declare function defaultConferConfig(): ConferConfig;
|
|
39
|
+
/** Fixture PASS is a test harness. Live orchestrate-task and XRAY_CONFER_FIXTURE cannot reach it. */
|
|
40
|
+
export declare const CONFER_FIXTURE_UNREACHABLE = "Confer fixture is unreachable outside tests";
|
|
41
|
+
export declare function conferFixtureAllowed(): boolean;
|
|
42
|
+
/** A suit profile does not enable Confer. Missing confer key stays off, including strict. */
|
|
36
43
|
export declare function loadConferConfig(projectRoot?: string): ConferConfig;
|
|
37
44
|
export declare function isConferEnabled(projectRoot?: string): boolean;
|
|
38
45
|
export declare function loadConferCheckpoint(projectRoot?: string): ConferCheckpointState | null;
|
|
@@ -46,12 +53,21 @@ export declare function conferAgentMcpTarget(subagent: string): {
|
|
|
46
53
|
tool: string;
|
|
47
54
|
args: (prompt: string, projectRoot: string) => Record<string, unknown>;
|
|
48
55
|
};
|
|
49
|
-
export declare function invokeConferAgent(subagent: string, prompt: string, projectRoot?: string): Promise<string>;
|
|
56
|
+
export declare function invokeConferAgent(subagent: string, prompt: string, projectRoot?: string, host?: ConferHostPort, sessionId?: string, todoId?: string, dueReason?: string | null): Promise<string>;
|
|
50
57
|
export declare function applyConferConsultResult(todoId: string, subagent: string, sessionId: string, outputText: string, projectRoot?: string): ConferAgentResult;
|
|
51
|
-
export declare function
|
|
58
|
+
export declare function buildFixtureConferOutput(subagent: string, verdict?: SynthesisConsultReceipt['verdict'], noLlm?: boolean): string;
|
|
59
|
+
export declare function writeFixtureConferReceipt(todoId: string, subagent: string, sessionId: string, projectRoot?: string, verdict?: SynthesisConsultReceipt['verdict'], noLlm?: boolean): ConferAgentResult;
|
|
52
60
|
export declare function runConferQuorum(projectRoot: string | undefined, sessionId: string, options?: {
|
|
53
61
|
collocatedText?: string;
|
|
54
62
|
dueReason?: string | null;
|
|
55
63
|
fixture?: boolean;
|
|
64
|
+
/** Used only when fixture is true. Defaults to PASS. FAIL and UNREVIEWED do not complete the todo. */
|
|
65
|
+
fixtureVerdict?: SynthesisConsultReceipt['verdict'];
|
|
66
|
+
/** Fixture text is the real no-model localConferVote (UNREVIEWED), not a hardcoded PASS. */
|
|
67
|
+
fixtureNoLlm?: boolean;
|
|
68
|
+
/** Used only when fixture is true. Replaces the generated fixture text for every consult. */
|
|
69
|
+
fixtureOutput?: string;
|
|
70
|
+
/** Live path. Default writes an ask for the wearing TUI and does not spawn a server. */
|
|
71
|
+
host?: ConferHostPort;
|
|
56
72
|
}): Promise<ConferQuorumResult>;
|
|
57
73
|
export declare function formatConferQuorumReport(result: ConferQuorumResult): string;
|