0xray 4.0.41 → 4.0.42
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/.xray/features.json +1 -1
- package/.xray/features.schema.json +1 -1
- package/AGENTS-consumer.md +2 -0
- package/AGENTS.md +2 -0
- package/README.md +52 -12
- package/SKILLS.md +2 -0
- package/dist/AGENTS.md +2 -0
- package/dist/CHANGELOG.md +13 -0
- package/dist/README.md +52 -12
- package/dist/SKILLS.md +2 -0
- package/dist/cli/commands/openclaw-install.js +1 -1
- package/dist/cli/index.js +12 -0
- 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/grok/grok-cli.js +10 -37
- package/dist/integrations/grok/hooks/grok-hook-utils.js +8 -1
- package/dist/integrations/hooks/confer-hook-runtime.mjs +23 -1
- package/dist/integrations/hooks/goggles-planes.json +4 -1
- 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/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/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/boot.md +1 -1
- 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 +1 -1
- package/docs-site/docs/plates/goggles.md +1 -1
- 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 +1 -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 +1 -1
- 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 +1 -1
- package/docs-site/docs/plates/lens-page.md +1 -1
- package/docs-site/docs/plates/live-mesh.md +1 -1
- package/docs-site/docs/plates/memory-recall.md +1 -1
- package/docs-site/docs/plates/notes-page.md +1 -1
- 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 +1 -1
- 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 +2 -0
- package/package.json +2 -2
- package/scripts/mjs/verify-confer-core.mjs +153 -29
- 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 +16 -41
- 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/scripts/run-live-synthesis-checkpoint.mjs +5 -51
- package/xray/features.json +1 -1
- package/xray/features.schema.json +1 -1
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import type { GovernanceRole, GovernanceVote } from "./llm-governance-provider.js";
|
|
1
|
+
import type { GovernanceMiss, GovernanceRole, GovernanceVote } from "./llm-governance-provider.js";
|
|
2
2
|
export type LocalConferInput = {
|
|
3
3
|
role: GovernanceRole;
|
|
4
4
|
highConfidenceTrapPresent?: boolean | undefined;
|
|
5
5
|
recommendedAgent?: string | null | undefined;
|
|
6
6
|
llmConfigured?: boolean | undefined;
|
|
7
|
+
miss?: GovernanceMiss | undefined;
|
|
7
8
|
};
|
|
8
9
|
/** Receipt when nested LLM is absent or returned no vote. Never approve — analyze_proposal feeds mergeVotes. */
|
|
9
10
|
export declare function localConferVote(input: LocalConferInput): GovernanceVote;
|
|
11
|
+
/** Stop a model from planting a second DECISION or Verdict line inside the reasoning body. */
|
|
12
|
+
export declare function sanitizeGovernanceReasoning(reasoning: string): string;
|
|
10
13
|
export declare function formatGovernanceVoteText(vote: GovernanceVote, extra?: string): string;
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
/** Receipt when nested LLM is absent or returned no vote. Never approve — analyze_proposal feeds mergeVotes. */
|
|
2
2
|
export function localConferVote(input) {
|
|
3
3
|
const role = input.role;
|
|
4
|
+
if (input.miss && input.miss !== "not-configured") {
|
|
5
|
+
return {
|
|
6
|
+
decision: "abstain",
|
|
7
|
+
confidence: 0.5,
|
|
8
|
+
reasoning: `Local confer (${role}); nested LLM did not produce a vote (${input.miss}).`,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
4
11
|
if (input.llmConfigured) {
|
|
5
12
|
return {
|
|
6
13
|
decision: "abstain",
|
|
@@ -22,6 +29,20 @@ export function localConferVote(input) {
|
|
|
22
29
|
reasoning: `Local confer (${role}); nested LLM not configured.`,
|
|
23
30
|
};
|
|
24
31
|
}
|
|
32
|
+
function abstainedWithoutUsableVote(vote) {
|
|
33
|
+
if (vote.decision !== "abstain")
|
|
34
|
+
return false;
|
|
35
|
+
return /nested LLM not configured|did not produce a vote|returned no vote/i.test(vote.reasoning);
|
|
36
|
+
}
|
|
37
|
+
/** Stop a model from planting a second DECISION or Verdict line inside the reasoning body. */
|
|
38
|
+
export function sanitizeGovernanceReasoning(reasoning) {
|
|
39
|
+
return reasoning
|
|
40
|
+
.split("\n")
|
|
41
|
+
.map((line) => /^\s*(?:[-*•]\s*)?(?:Verdict:|DECISION:)/i.test(line) ? `> ${line.trim()}` : line)
|
|
42
|
+
.join("\n");
|
|
43
|
+
}
|
|
25
44
|
export function formatGovernanceVoteText(vote, extra = "") {
|
|
26
|
-
|
|
45
|
+
const reviewLine = abstainedWithoutUsableVote(vote) ? "\nVerdict: UNREVIEWED" : "";
|
|
46
|
+
const reasoning = sanitizeGovernanceReasoning(vote.reasoning);
|
|
47
|
+
return `DECISION: ${vote.decision}\nCONFIDENCE: ${vote.confidence.toFixed(2)}\nREASONING: ${reasoning}${reviewLine}${extra}`;
|
|
27
48
|
}
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
import { frameworkLogger } from '../../core/framework-logger.js';
|
|
18
18
|
import fs from 'fs';
|
|
19
19
|
import path from 'path';
|
|
20
|
-
import { execSync } from 'child_process';
|
|
21
20
|
import { createRequire } from 'module';
|
|
22
21
|
import { fileURLToPath } from 'node:url';
|
|
23
22
|
import { syncBuiltinSkills } from '../../cli/commands/skill-install.js';
|
|
@@ -27,27 +26,13 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
27
26
|
const packageRoot = path.resolve(__dirname, '..', '..', '..');
|
|
28
27
|
const requireCjs = createRequire(import.meta.url);
|
|
29
28
|
const { resolveConsumerTargetDir, patchGrokHooks } = requireCjs(path.join(packageRoot, 'scripts/node/install-bridges.cjs'));
|
|
30
|
-
const {
|
|
31
|
-
function registerGrokMcpServers(targetDir) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
for (const s of XRAY_MCP_SERVERS) {
|
|
40
|
-
try {
|
|
41
|
-
const envEntries = { ...s.env, XRAY_ROOT: targetDir };
|
|
42
|
-
const envFlags = Object.entries(envEntries)
|
|
43
|
-
.map(([k, v]) => `--env "${k}=${v}"`)
|
|
44
|
-
.join(' ');
|
|
45
|
-
execSync(`grok mcp add ${s.name} --command npx --args "-y" "0xray" "mcp" "${s.mcpCmd}" ${envFlags}`, { stdio: 'pipe' });
|
|
46
|
-
}
|
|
47
|
-
catch {
|
|
48
|
-
// already registered or grok config conflict — non-blocking
|
|
49
|
-
}
|
|
50
|
-
}
|
|
29
|
+
const { resolveRepertoireMcp, resolveGogglesMcp } = requireCjs(path.join(packageRoot, 'scripts/node/bridge-mcp-wiring.cjs'));
|
|
30
|
+
function registerGrokMcpServers(targetDir, env) {
|
|
31
|
+
const wiring = requireCjs(path.join(packageRoot, 'scripts/node/bridge-mcp-wiring.cjs'));
|
|
32
|
+
const tomlPath = wiring.writeProjectSuitMcp(targetDir);
|
|
33
|
+
const trustPath = wiring.trustGrokFolder(targetDir, env);
|
|
34
|
+
process.stdout.write(`Project Grok MCP written to ${tomlPath}\n`);
|
|
35
|
+
process.stdout.write(`Grok folder trust written to ${trustPath}\n`);
|
|
51
36
|
}
|
|
52
37
|
export async function installForGrokCLI(options = {}) {
|
|
53
38
|
frameworkLogger.log('grok-integration', 'install-start', 'info', {
|
|
@@ -115,21 +100,9 @@ export async function installForGrokCLI(options = {}) {
|
|
|
115
100
|
writeProjectRepertoireMcp(targetDir);
|
|
116
101
|
writeProjectGogglesMcp(targetDir);
|
|
117
102
|
mintAfterWear(targetDir);
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
console.log('\x1b[32m✓ Auto-trusted the 0xray plugin with Grok CLI\x1b[0m');
|
|
122
|
-
}
|
|
123
|
-
catch {
|
|
124
|
-
console.log('\nPlease run this command to fully trust the plugin:');
|
|
125
|
-
console.log(` grok plugins trust "${primary}"`);
|
|
126
|
-
}
|
|
127
|
-
if (isolated) {
|
|
128
|
-
registerGrokMcpServers(targetDir);
|
|
129
|
-
console.log('\x1b[32m✓ Registered 7 xray MCP servers with Grok CLI (npx)\x1b[0m');
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
console.log('\x1b[32m✓ Project-scoped Grok plugin worn (machine ~/.grok/plugins/0xray not written)\x1b[0m');
|
|
103
|
+
registerGrokMcpServers(targetDir, env);
|
|
104
|
+
if (!isolated) {
|
|
105
|
+
process.stdout.write('Project-scoped Grok plugin worn (machine ~/.grok/plugins/0xray not written)\n');
|
|
133
106
|
}
|
|
134
107
|
console.log('\n✅ 0xRay is now installed as a first-class Grok CLI plugin!');
|
|
135
108
|
console.log('Restart Grok or run `grok` to load the new hooks and MCP servers.');
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
updatePlanTodoStatusInPlace,
|
|
20
20
|
loadDelegationGateFeatures,
|
|
21
21
|
} from '../../hooks/delegation-gate-runtime.mjs';
|
|
22
|
-
import { isConferPendingForSession } from '../../hooks/confer-hook-runtime.mjs';
|
|
22
|
+
import { isConferPendingForSession, readConferReviewHint } from '../../hooks/confer-hook-runtime.mjs';
|
|
23
23
|
import { getActiveUserAsideBoot } from '../../hooks/user-aside-hook-runtime.mjs';
|
|
24
24
|
import {
|
|
25
25
|
applyStationHeat,
|
|
@@ -308,6 +308,7 @@ export function buildSessionBootPayload(root, source = '0xray/grok-session-start
|
|
|
308
308
|
const sessionId =
|
|
309
309
|
extra.sessionId || process.env.GROK_SESSION_ID || process.env.GROK_SESSION || null;
|
|
310
310
|
const conferPending = loadConferPending(root, sessionId);
|
|
311
|
+
const conferReview = readConferReviewHint(root);
|
|
311
312
|
const userAsideBoot = getActiveUserAsideBoot(root, sessionId);
|
|
312
313
|
const gateFeatures = loadDelegationGateFeatures(root, 'grok');
|
|
313
314
|
const frontier = gateFeatures.ceremony === 'lite';
|
|
@@ -332,6 +333,12 @@ export function buildSessionBootPayload(root, source = '0xray/grok-session-start
|
|
|
332
333
|
...heat,
|
|
333
334
|
...(siblingRoots.length > 0 ? { siblingWorkspaceRoots: siblingRoots } : {}),
|
|
334
335
|
...(conferPending ? { conferPending: true, conferTrigger: 'analyze-complexity at synthesis checkpoint' } : {}),
|
|
336
|
+
...(conferReview
|
|
337
|
+
? {
|
|
338
|
+
conferReview,
|
|
339
|
+
conferReviewHint: 'UNREVIEWED — abstain without a governance LLM blocks the consult todo',
|
|
340
|
+
}
|
|
341
|
+
: {}),
|
|
335
342
|
...(userAsideBoot ?? {}),
|
|
336
343
|
sessionId,
|
|
337
344
|
...extra,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Lazy-load confer SSOT for Grok session-boot hints.
|
|
4
4
|
*/
|
|
5
5
|
import { createRequire } from 'node:module';
|
|
6
|
-
import { existsSync } from 'node:fs';
|
|
6
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
7
7
|
import { dirname, join, resolve } from 'node:path';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
9
|
|
|
@@ -46,4 +46,26 @@ export function isConferPendingForSession(projectRoot, sessionId = null) {
|
|
|
46
46
|
const mod = loadConfer();
|
|
47
47
|
if (!mod?.isConferPending) return false;
|
|
48
48
|
return mod.isConferPending(projectRoot, sessionId);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** 'UNREVIEWED' when a consult receipt recorded abstain-without-model. */
|
|
52
|
+
export function readConferReviewHint(projectRoot) {
|
|
53
|
+
const stateDir = join(projectRoot, '.xray', 'state');
|
|
54
|
+
if (!existsSync(stateDir)) return null;
|
|
55
|
+
let names;
|
|
56
|
+
try {
|
|
57
|
+
names = readdirSync(stateDir);
|
|
58
|
+
} catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
for (const name of names) {
|
|
62
|
+
if (!name.startsWith('synthesis-consult-') || !name.endsWith('.json')) continue;
|
|
63
|
+
try {
|
|
64
|
+
const receipt = JSON.parse(readFileSync(join(stateDir, name), 'utf8'));
|
|
65
|
+
if (receipt && receipt.verdict === 'UNREVIEWED') return 'UNREVIEWED';
|
|
66
|
+
} catch {
|
|
67
|
+
/* unreadable receipt is not a hint */
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
49
71
|
}
|
|
@@ -38,7 +38,10 @@
|
|
|
38
38
|
"plates": ["suit-wear"]
|
|
39
39
|
},
|
|
40
40
|
"governance": {
|
|
41
|
-
"files": [
|
|
41
|
+
"files": [
|
|
42
|
+
"src/governance/governance-service.ts",
|
|
43
|
+
"src/governance/llm-governance-provider.ts"
|
|
44
|
+
],
|
|
42
45
|
"skills": ".agents/skills/governance/SKILL.md"
|
|
43
46
|
},
|
|
44
47
|
"memory-recall": {
|
|
@@ -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)}`
|
|
@@ -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
|
+
}
|