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
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
* release-gate.mjs — Single release checkpoint.
|
|
4
4
|
*
|
|
5
5
|
* Modes:
|
|
6
|
-
* (default) build + test + consumer smoke (fresh + upgrade merge)
|
|
6
|
+
* (default) build + test + docs + consumer smoke (fresh + upgrade merge)
|
|
7
7
|
* --verify-only git + reconcile + release docs + consumer smoke — after push, before publish
|
|
8
8
|
* --skip-smoke skip consumer install smoke
|
|
9
|
-
* --
|
|
9
|
+
* --prove-published Gate D only: npm lists this version, the annotated tag points at HEAD,
|
|
10
|
+
* and the GitHub Release exists. This command does not publish.
|
|
11
|
+
* --skip-docs refused. Gate C runs on every gate.
|
|
10
12
|
*
|
|
11
13
|
* Usage:
|
|
12
14
|
* npx @0xray/foundry gate
|
|
@@ -21,7 +23,7 @@ import { isXrayExoRepo, millScript, readRootPackage, resolveMillRoot } from "./m
|
|
|
21
23
|
const rootDir = resolveMillRoot();
|
|
22
24
|
const verifyOnly = process.argv.includes("--verify-only");
|
|
23
25
|
const skipSmoke = process.argv.includes("--skip-smoke");
|
|
24
|
-
const
|
|
26
|
+
const provePublished = process.argv.includes("--prove-published");
|
|
25
27
|
|
|
26
28
|
function step(label, cmd) {
|
|
27
29
|
console.log(`\n${"─".repeat(60)}\n🔄 ${label}\n${"─".repeat(60)}\n`);
|
|
@@ -32,18 +34,114 @@ function docsCheckCmd() {
|
|
|
32
34
|
return `${JSON.stringify(process.execPath)} ${JSON.stringify(millScript("validate-release-docs.mjs"))}`;
|
|
33
35
|
}
|
|
34
36
|
|
|
37
|
+
|
|
38
|
+
/** Gate C is the docs check. A ship gate that skips it is not a pass. */
|
|
39
|
+
export function gateCRefusal(argv = process.argv) {
|
|
40
|
+
if (argv.includes("--skip-docs")) {
|
|
41
|
+
return "Gate C cannot be skipped. Remove --skip-docs. The docs check runs on every gate.";
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Gate D facts. listed, tagAnnotated, and tagMatchesHead are booleans.
|
|
48
|
+
* releaseUrl is the GitHub Release page, or empty when that page is missing.
|
|
49
|
+
*/
|
|
50
|
+
export function provePublishedRelease(proof) {
|
|
51
|
+
const version = proof.version;
|
|
52
|
+
const errors = [];
|
|
53
|
+
if (proof.listed !== true) errors.push(`npm does not list ${version}`);
|
|
54
|
+
if (proof.tagAnnotated !== true) errors.push(`annotated tag v${version} is missing`);
|
|
55
|
+
if (proof.tagMatchesHead !== true) errors.push(`annotated tag v${version} does not point at HEAD`);
|
|
56
|
+
if (typeof proof.releaseUrl !== "string" || proof.releaseUrl.length === 0) {
|
|
57
|
+
errors.push(`GitHub Release v${version} is missing`);
|
|
58
|
+
}
|
|
59
|
+
return errors;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function gitOut(cmd) {
|
|
63
|
+
return execSync(cmd, { cwd: rootDir, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function originSlug() {
|
|
67
|
+
const url = gitOut("git remote get-url origin");
|
|
68
|
+
const match = url.match(/github\.com[:/]([^/]+)\/([^/.]+)(?:\.git)?$/);
|
|
69
|
+
if (!match) throw new Error(`origin is not a GitHub repo: ${url}`);
|
|
70
|
+
return { owner: match[1], repo: match[2] };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function collectPublishedProof() {
|
|
74
|
+
const pkg = readRootPackage(rootDir);
|
|
75
|
+
const version = pkg.version;
|
|
76
|
+
const name = pkg.name;
|
|
77
|
+
let listed = false;
|
|
78
|
+
try {
|
|
79
|
+
const view = gitOut(`npm view ${name}@${version} version`);
|
|
80
|
+
listed = view.split(/\s+/).includes(version);
|
|
81
|
+
} catch {
|
|
82
|
+
listed = false;
|
|
83
|
+
}
|
|
84
|
+
let tagAnnotated = false;
|
|
85
|
+
let tagMatchesHead = false;
|
|
86
|
+
try {
|
|
87
|
+
tagAnnotated = gitOut(`git cat-file -t v${version}`) === "tag";
|
|
88
|
+
const tagged = gitOut(`git rev-parse v${version}^{}`);
|
|
89
|
+
const head = gitOut("git rev-parse HEAD");
|
|
90
|
+
tagMatchesHead = tagAnnotated && tagged === head;
|
|
91
|
+
} catch {
|
|
92
|
+
tagAnnotated = false;
|
|
93
|
+
tagMatchesHead = false;
|
|
94
|
+
}
|
|
95
|
+
let releaseUrl = "";
|
|
96
|
+
try {
|
|
97
|
+
const { owner, repo } = originSlug();
|
|
98
|
+
const body = gitOut(
|
|
99
|
+
`curl -fsS -H "Accept: application/vnd.github+json" -H "User-Agent: 0xray-release-gate" https://api.github.com/repos/${owner}/${repo}/releases/tags/v${version}`,
|
|
100
|
+
);
|
|
101
|
+
const parsed = JSON.parse(body);
|
|
102
|
+
releaseUrl = typeof parsed.html_url === "string" ? parsed.html_url : "";
|
|
103
|
+
} catch {
|
|
104
|
+
releaseUrl = "";
|
|
105
|
+
}
|
|
106
|
+
return { version, name, listed, tagAnnotated, tagMatchesHead, releaseUrl };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function runProvePublished() {
|
|
110
|
+
const proof = collectPublishedProof();
|
|
111
|
+
const errors = provePublishedRelease(proof);
|
|
112
|
+
process.stdout.write(`\nGate D — ${proof.name}@${proof.version}\n`);
|
|
113
|
+
if (errors.length) {
|
|
114
|
+
for (const error of errors) process.stderr.write(`❌ ${error}\n`);
|
|
115
|
+
process.stderr.write("\n❌ GATE D FAILED — npm listing, annotated tag at HEAD, and GitHub Release are all required\n\n");
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
process.stdout.write(`✅ npm lists ${proof.version}\n`);
|
|
119
|
+
process.stdout.write(`✅ annotated tag v${proof.version} points at HEAD\n`);
|
|
120
|
+
process.stdout.write(`✅ GitHub Release ${proof.releaseUrl}\n`);
|
|
121
|
+
process.stdout.write("\n✅ GATE D PROVEN\n\n");
|
|
122
|
+
}
|
|
123
|
+
|
|
35
124
|
function runLightGate() {
|
|
36
125
|
const pkg = readRootPackage(rootDir);
|
|
37
126
|
if (verifyOnly) {
|
|
38
|
-
|
|
127
|
+
step("1/1 Release docs (light)", docsCheckCmd());
|
|
39
128
|
return;
|
|
40
129
|
}
|
|
41
130
|
if (pkg.scripts.build) step("1/3 Build", "npm run build");
|
|
42
131
|
if (pkg.scripts.test) step("2/3 Tests", "npm test");
|
|
43
|
-
|
|
132
|
+
step("3/3 Release docs (light)", docsCheckCmd());
|
|
44
133
|
}
|
|
45
134
|
|
|
46
135
|
function main() {
|
|
136
|
+
const refused = gateCRefusal();
|
|
137
|
+
if (refused) {
|
|
138
|
+
process.stderr.write(`\n❌ ${refused}\n\n`);
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
141
|
+
if (provePublished) {
|
|
142
|
+
runProvePublished();
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
47
145
|
const mode = verifyOnly ? "verify" : "full";
|
|
48
146
|
console.log("\n╔════════════════════════════════════════════════════════╗");
|
|
49
147
|
console.log(`║ 🛡️ 0xRay Release Gate (${mode})`.padEnd(57) + "║");
|
|
@@ -54,9 +152,7 @@ function main() {
|
|
|
54
152
|
runLightGate();
|
|
55
153
|
} else if (verifyOnly) {
|
|
56
154
|
step("1/6 Git + reconcile", "node scripts/node/pre-publish-guard.js --verify-only");
|
|
57
|
-
|
|
58
|
-
step("2/6 Release docs", docsCheckCmd());
|
|
59
|
-
}
|
|
155
|
+
step("2/6 Release docs", docsCheckCmd());
|
|
60
156
|
step(
|
|
61
157
|
"3/6 Plugin infrastructure",
|
|
62
158
|
"node scripts/test/validate-plugins-e2e.cjs --structural-only",
|
|
@@ -75,9 +171,7 @@ function main() {
|
|
|
75
171
|
`${JSON.stringify(process.execPath)} ${JSON.stringify(millScript("assert-packed-dist-cli.mjs"))}`,
|
|
76
172
|
);
|
|
77
173
|
step("3/8 Tests", "npm run test:comprehensive");
|
|
78
|
-
|
|
79
|
-
step("4/8 Release docs", docsCheckCmd());
|
|
80
|
-
}
|
|
174
|
+
step("4/8 Release docs", docsCheckCmd());
|
|
81
175
|
step(
|
|
82
176
|
"5/8 Consumer hook verifiers",
|
|
83
177
|
"npm run verify:pre-commit-diff && npm run verify:pre-push-diff && node scripts/mjs/verify-delegation-gate-core.mjs --host=grok && node scripts/mjs/verify-delegation-gate-core.mjs --host=hermes && node scripts/mjs/verify-delegation-gate-core.mjs --host=opencode && node scripts/mjs/verify-hermes-session-start.mjs && node scripts/mjs/verify-confer-core.mjs && npm run verify:user-aside && npm run build && node scripts/mjs/verify-pipeline-facets.mjs --package-only",
|
|
@@ -91,9 +185,11 @@ function main() {
|
|
|
91
185
|
}
|
|
92
186
|
}
|
|
93
187
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
188
|
+
process.stdout.write("\n╔════════════════════════════════════════════════════════╗\n");
|
|
189
|
+
process.stdout.write("║ ✅ GATE A–C LOCAL PASS ║\n");
|
|
190
|
+
process.stdout.write("║ Gate D is not proven by this command. ║\n");
|
|
191
|
+
process.stdout.write("╚════════════════════════════════════════════════════════╝\n");
|
|
192
|
+
process.stdout.write("Prove D after publish: npx @0xray/foundry gate --prove-published\n\n");
|
|
97
193
|
} catch {
|
|
98
194
|
console.error("\n❌ RELEASE GATE FAILED — do not tag or publish\n");
|
|
99
195
|
process.exit(1);
|
|
@@ -105,4 +201,4 @@ const isMain =
|
|
|
105
201
|
|
|
106
202
|
if (isMain) {
|
|
107
203
|
main();
|
|
108
|
-
}
|
|
204
|
+
}
|
|
@@ -191,6 +191,8 @@ async function main() {
|
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
193
|
run(`git push origin v${version}`, "push tag");
|
|
194
|
+
say("Step 8: Gate D");
|
|
195
|
+
runMill("release-gate.mjs", ["--prove-published"], "gate D");
|
|
194
196
|
return;
|
|
195
197
|
}
|
|
196
198
|
|
|
@@ -281,6 +283,12 @@ async function main() {
|
|
|
281
283
|
console.log(` would: git tag -a v${newVersion}`);
|
|
282
284
|
}
|
|
283
285
|
run(`git push origin v${newVersion}`, "push tag");
|
|
286
|
+
say("Step 8: Gate D");
|
|
287
|
+
runMill("release-gate.mjs", ["--prove-published"], "gate D");
|
|
288
|
+
if (dryRun) {
|
|
289
|
+
say("Dry run did not prove Gate D.");
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
284
292
|
|
|
285
293
|
console.log("\n╔════════════════════════════════════════════════════════╗");
|
|
286
294
|
console.log("║ ✅ Release Complete! ║");
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Confer quorum fixture
|
|
3
|
+
* Confer quorum fixture.
|
|
4
|
+
* PASS completes. FAIL and no-LLM UNREVIEWED leave the todo open and the checkpoint due.
|
|
5
|
+
* Temp projects opt into synthesis so a due checkpoint can be observed. The repo default stays off.
|
|
4
6
|
*/
|
|
5
|
-
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
7
|
+
import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
6
8
|
import { tmpdir } from 'node:os';
|
|
7
9
|
import { dirname, join } from 'node:path';
|
|
8
10
|
import { fileURLToPath } from 'node:url';
|
|
@@ -10,10 +12,14 @@ import { fileURLToPath } from 'node:url';
|
|
|
10
12
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
13
|
const packageRoot = join(__dirname, '../..');
|
|
12
14
|
|
|
15
|
+
// Fixture PASS is refused unless this process is a test. The live orchestrate-task
|
|
16
|
+
// flag and XRAY_CONFER_FIXTURE stay unreachable when NODE_ENV is not test.
|
|
17
|
+
process.env.NODE_ENV = 'test';
|
|
18
|
+
|
|
13
19
|
const { buildSynthesisCheckpointPlan } = await import(
|
|
14
20
|
join(packageRoot, 'dist/nucleus/autonomy-kernel.js')
|
|
15
21
|
);
|
|
16
|
-
const { savePersistedLeadDevPlan, areSynthesisConsultTodosComplete } = await import(
|
|
22
|
+
const { savePersistedLeadDevPlan, areSynthesisConsultTodosComplete, loadPersistedLeadDevPlan } = await import(
|
|
17
23
|
join(packageRoot, 'dist/nucleus/lead-dev-plan-persistence.js')
|
|
18
24
|
);
|
|
19
25
|
const { recordExecutionSlice, isSynthesisCheckpointDue } = await import(
|
|
@@ -22,46 +28,103 @@ const { recordExecutionSlice, isSynthesisCheckpointDue } = await import(
|
|
|
22
28
|
const { runConferQuorum, loadConferCheckpoint, CONFER_AGENTS } = await import(
|
|
23
29
|
join(packageRoot, 'dist/nucleus/confer.js')
|
|
24
30
|
);
|
|
31
|
+
const { loadSynthesisConsultReceipt } = await import(
|
|
32
|
+
join(packageRoot, 'dist/nucleus/synthesis-consult-receipt.js')
|
|
33
|
+
);
|
|
34
|
+
const { readConferReviewHint } = await import(
|
|
35
|
+
join(packageRoot, 'src/integrations/hooks/confer-hook-runtime.mjs')
|
|
36
|
+
);
|
|
37
|
+
const { buildSessionBootPayload } = await import(
|
|
38
|
+
join(packageRoot, 'src/integrations/grok/hooks/grok-hook-utils.js')
|
|
39
|
+
);
|
|
25
40
|
|
|
26
|
-
const sessionId = 'verify-confer-core';
|
|
27
41
|
let failed = 0;
|
|
42
|
+
let checks = 0;
|
|
28
43
|
function pass(n) {
|
|
44
|
+
checks++;
|
|
29
45
|
console.log(`✅ ${n}`);
|
|
30
46
|
}
|
|
31
47
|
function fail(n, d = '') {
|
|
32
48
|
failed++;
|
|
49
|
+
checks++;
|
|
33
50
|
console.error(`❌ ${n}${d ? ` — ${d}` : ''}`);
|
|
34
51
|
}
|
|
35
52
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
multi_agent_orchestration: { lead_dev_mode: true, confer_on_synthesis: true },
|
|
42
|
-
synthesis: { enabled: true, every_n_gates: 1, every_n_turns: 0, every_n_todos_completed: 0 },
|
|
43
|
-
}),
|
|
44
|
-
);
|
|
53
|
+
function assertRepoSynthesisStaysOff() {
|
|
54
|
+
const source = readFileSync(join(packageRoot, 'src/nucleus/synthesis.ts'), 'utf8');
|
|
55
|
+
const defaults = source.match(/function defaultSynthesisConfig\(\)[\s\S]*?return \{([\s\S]*?)\n \};/);
|
|
56
|
+
if (defaults && /enabled:\s*false/.test(defaults[1])) pass('repo defaultSynthesisConfig stays enabled: false');
|
|
57
|
+
else fail('repo defaultSynthesisConfig stays enabled: false');
|
|
45
58
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
59
|
+
for (const rel of ['xray/features.json', '.xray/features.json']) {
|
|
60
|
+
const data = JSON.parse(readFileSync(join(packageRoot, rel), 'utf8'));
|
|
61
|
+
if (data.synthesis?.enabled === false) pass(`${rel} synthesis.enabled stays false`);
|
|
62
|
+
else fail(`${rel} synthesis.enabled stays false`, JSON.stringify(data.synthesis));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
50
65
|
|
|
66
|
+
function makeProject() {
|
|
67
|
+
const tmp = mkdtempSync(join(tmpdir(), 'xray-confer-verify-'));
|
|
68
|
+
mkdirSync(join(tmp, '.xray', 'state'), { recursive: true });
|
|
69
|
+
writeFileSync(
|
|
70
|
+
join(tmp, '.xray', 'features.json'),
|
|
71
|
+
JSON.stringify({
|
|
72
|
+
multi_agent_orchestration: { lead_dev_mode: true, confer_on_synthesis: true },
|
|
73
|
+
synthesis: { enabled: true, every_n_gates: 1, every_n_turns: 0, every_n_todos_completed: 0 },
|
|
74
|
+
}),
|
|
75
|
+
);
|
|
76
|
+
return tmp;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function seedDuePlan(tmp, sessionId) {
|
|
80
|
+
recordExecutionSlice('gate', { projectRoot: tmp, sessionId });
|
|
81
|
+
const due = isSynthesisCheckpointDue(tmp, sessionId);
|
|
51
82
|
const plan = buildSynthesisCheckpointPlan('gate threshold (1/1)', tmp);
|
|
52
|
-
if (
|
|
53
|
-
else {
|
|
83
|
+
if (plan) {
|
|
54
84
|
savePersistedLeadDevPlan(
|
|
55
85
|
{ ...plan, persistedAt: new Date().toISOString(), sessionId },
|
|
56
86
|
tmp,
|
|
57
87
|
);
|
|
58
|
-
pass('step 2: synthesis plan persisted');
|
|
59
88
|
}
|
|
89
|
+
return { due, plan };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function blocksCheckpoint(label, tmp, sessionId, result, verdict) {
|
|
93
|
+
const receipt = loadSynthesisConsultReceipt('s.1', tmp);
|
|
94
|
+
if (result.status === 'partial' && result.agents[0]?.verdict === verdict && result.agents[0]?.todoCompleted === false) {
|
|
95
|
+
pass(`${label}: quorum stopped on ${verdict}`);
|
|
96
|
+
} else {
|
|
97
|
+
fail(`${label}: quorum stopped on ${verdict}`, JSON.stringify(result));
|
|
98
|
+
}
|
|
99
|
+
if (receipt?.verdict === verdict) pass(`${label}: receipt verdict ${verdict}`);
|
|
100
|
+
else fail(`${label}: receipt verdict ${verdict}`, JSON.stringify(receipt));
|
|
101
|
+
if (!areSynthesisConsultTodosComplete(loadPersistedLeadDevPlan(tmp))) {
|
|
102
|
+
pass(`${label}: consult todo stays open`);
|
|
103
|
+
} else {
|
|
104
|
+
fail(`${label}: consult todo stays open`);
|
|
105
|
+
}
|
|
106
|
+
if (isSynthesisCheckpointDue(tmp, sessionId)) pass(`${label}: synthesis checkpoint stays due`);
|
|
107
|
+
else fail(`${label}: synthesis checkpoint stays due`);
|
|
108
|
+
const state = loadConferCheckpoint(tmp);
|
|
109
|
+
if (state?.status === 'failed') pass(`${label}: confer checkpoint not cleared`);
|
|
110
|
+
else fail(`${label}: confer checkpoint not cleared`, JSON.stringify(state));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
assertRepoSynthesisStaysOff();
|
|
114
|
+
|
|
115
|
+
const passRoot = makeProject();
|
|
116
|
+
const passSession = 'verify-confer-core-pass';
|
|
117
|
+
try {
|
|
118
|
+
const seeded = seedDuePlan(passRoot, passSession);
|
|
119
|
+
if (!seeded.due) fail('step 1: synthesis due');
|
|
120
|
+
else pass('step 1: synthesis checkpoint due');
|
|
121
|
+
if (!seeded.plan) fail('step 2: synthesis plan');
|
|
122
|
+
else pass('step 2: synthesis plan persisted');
|
|
60
123
|
|
|
61
124
|
if (CONFER_AGENTS.length !== 3) fail('step 3: confer agent count', String(CONFER_AGENTS.length));
|
|
62
125
|
else pass('step 3: three confer agents defined');
|
|
63
126
|
|
|
64
|
-
const result = await runConferQuorum(
|
|
127
|
+
const result = await runConferQuorum(passRoot, passSession, {
|
|
65
128
|
collocatedText: 'verify confer fixture context',
|
|
66
129
|
dueReason: 'gate threshold',
|
|
67
130
|
fixture: true,
|
|
@@ -73,31 +136,92 @@ try {
|
|
|
73
136
|
fail('step 4: confer quorum', JSON.stringify(result));
|
|
74
137
|
}
|
|
75
138
|
|
|
76
|
-
const state = loadConferCheckpoint(
|
|
139
|
+
const state = loadConferCheckpoint(passRoot);
|
|
77
140
|
if (state?.status === 'completed' && state.completedAgents.length === 3) {
|
|
78
141
|
pass('step 5: confer checkpoint state completed');
|
|
79
142
|
} else {
|
|
80
143
|
fail('step 5: confer state', JSON.stringify(state));
|
|
81
144
|
}
|
|
82
145
|
|
|
83
|
-
if (areSynthesisConsultTodosComplete(
|
|
84
|
-
(await import(join(packageRoot, 'dist/nucleus/lead-dev-plan-persistence.js'))).loadPersistedLeadDevPlan(tmp),
|
|
85
|
-
)) {
|
|
146
|
+
if (areSynthesisConsultTodosComplete(loadPersistedLeadDevPlan(passRoot))) {
|
|
86
147
|
pass('step 6: synthesis consult todos complete after confer');
|
|
87
148
|
} else {
|
|
88
149
|
fail('step 6: consult todos incomplete');
|
|
89
150
|
}
|
|
90
151
|
|
|
91
|
-
if (!isSynthesisCheckpointDue(
|
|
152
|
+
if (!isSynthesisCheckpointDue(passRoot, passSession)) pass('step 7: synthesis checkpoint cleared');
|
|
92
153
|
else fail('step 7: checkpoint still due');
|
|
93
154
|
} finally {
|
|
94
|
-
rmSync(
|
|
155
|
+
rmSync(passRoot, { recursive: true, force: true });
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const failRoot = makeProject();
|
|
159
|
+
const failSession = 'verify-confer-core-fail';
|
|
160
|
+
try {
|
|
161
|
+
seedDuePlan(failRoot, failSession);
|
|
162
|
+
const result = await runConferQuorum(failRoot, failSession, {
|
|
163
|
+
fixture: true,
|
|
164
|
+
fixtureVerdict: 'FAIL',
|
|
165
|
+
});
|
|
166
|
+
blocksCheckpoint('FAIL', failRoot, failSession, result, 'FAIL');
|
|
167
|
+
} finally {
|
|
168
|
+
rmSync(failRoot, { recursive: true, force: true });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const unreviewedRoot = makeProject();
|
|
172
|
+
const unreviewedSession = 'verify-confer-core-unreviewed';
|
|
173
|
+
try {
|
|
174
|
+
seedDuePlan(unreviewedRoot, unreviewedSession);
|
|
175
|
+
const result = await runConferQuorum(unreviewedRoot, unreviewedSession, {
|
|
176
|
+
fixture: true,
|
|
177
|
+
fixtureNoLlm: true,
|
|
178
|
+
});
|
|
179
|
+
blocksCheckpoint('no-LLM', unreviewedRoot, unreviewedSession, result, 'UNREVIEWED');
|
|
180
|
+
if (readConferReviewHint(unreviewedRoot) === 'UNREVIEWED') {
|
|
181
|
+
pass('no-LLM: confer review hint is UNREVIEWED');
|
|
182
|
+
} else {
|
|
183
|
+
fail('no-LLM: confer review hint is UNREVIEWED');
|
|
184
|
+
}
|
|
185
|
+
const boot = buildSessionBootPayload(unreviewedRoot, 'verify/session-start');
|
|
186
|
+
if (boot.conferReview === 'UNREVIEWED' && String(boot.conferReviewHint).includes('UNREVIEWED')) {
|
|
187
|
+
pass('no-LLM: session-boot hint records UNREVIEWED');
|
|
188
|
+
} else {
|
|
189
|
+
fail('no-LLM: session-boot hint records UNREVIEWED', JSON.stringify({
|
|
190
|
+
conferReview: boot.conferReview,
|
|
191
|
+
conferReviewHint: boot.conferReviewHint,
|
|
192
|
+
}));
|
|
193
|
+
}
|
|
194
|
+
} finally {
|
|
195
|
+
rmSync(unreviewedRoot, { recursive: true, force: true });
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const conditionalRoot = makeProject();
|
|
199
|
+
const conditionalSession = 'verify-confer-core-conditional';
|
|
200
|
+
try {
|
|
201
|
+
seedDuePlan(conditionalRoot, conditionalSession);
|
|
202
|
+
const result = await runConferQuorum(conditionalRoot, conditionalSession, {
|
|
203
|
+
fixture: true,
|
|
204
|
+
fixtureVerdict: 'CONDITIONAL',
|
|
205
|
+
});
|
|
206
|
+
const verdicts = result.agents.map((agent) => agent.verdict);
|
|
207
|
+
if (result.status === 'partial' && verdicts[0] === 'CONDITIONAL' && result.agents[0]?.todoCompleted === false) {
|
|
208
|
+
pass('CONDITIONAL: explicit conditional does not complete');
|
|
209
|
+
} else {
|
|
210
|
+
fail('CONDITIONAL: explicit conditional does not complete', JSON.stringify(result));
|
|
211
|
+
}
|
|
212
|
+
if (isSynthesisCheckpointDue(conditionalRoot, conditionalSession)) {
|
|
213
|
+
pass('CONDITIONAL: checkpoint stays due');
|
|
214
|
+
} else {
|
|
215
|
+
fail('CONDITIONAL: checkpoint stays due');
|
|
216
|
+
}
|
|
217
|
+
} finally {
|
|
218
|
+
rmSync(conditionalRoot, { recursive: true, force: true });
|
|
95
219
|
}
|
|
96
220
|
|
|
97
221
|
console.log(
|
|
98
222
|
'\n' +
|
|
99
223
|
(failed === 0
|
|
100
|
-
?
|
|
224
|
+
? `🎉 Confer verify passed (${checks}/${checks}).`
|
|
101
225
|
: `⚠️ ${failed} confer check(s) failed.`),
|
|
102
226
|
);
|
|
103
|
-
process.exit(failed === 0 ? 0 : 1);
|
|
227
|
+
process.exit(failed === 0 ? 0 : 1);
|
|
@@ -110,7 +110,7 @@ if (packageOnly) {
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
// P1 — autonomous reporting
|
|
113
|
-
if (features?.autonomous_reporting?.enabled ===
|
|
113
|
+
if (features?.autonomous_reporting?.enabled === false) {
|
|
114
114
|
pass('autonomous_reporting.enabled');
|
|
115
115
|
} else {
|
|
116
116
|
fail('autonomous_reporting.enabled');
|
|
@@ -75,16 +75,15 @@ try {
|
|
|
75
75
|
35,
|
|
76
76
|
tmp,
|
|
77
77
|
);
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
const todo = aside?.plan.phases.flatMap((phase) => phase.todos)[0];
|
|
79
|
+
if (todo?.id !== 'suit-nft.a.2.1') {
|
|
80
|
+
fail('step 3: build aside plan', todo?.id);
|
|
80
81
|
} else pass('step 3: namespaced aside todos');
|
|
81
82
|
|
|
82
83
|
saveUserAside(aside, tmp);
|
|
83
84
|
setActiveAsideId('suit-nft', tmp, 'verify-session');
|
|
84
85
|
if (getActiveAsideId(tmp, 'verify-session') !== 'suit-nft') fail('step 4: active pointer');
|
|
85
86
|
else pass('step 4: active aside pointer with session');
|
|
86
|
-
|
|
87
|
-
const todo = aside.plan.phases[0].todos[0];
|
|
88
87
|
const resolved = resolveSpawnPlan({ planTodoId: todo.id }, tmp, 'verify-session');
|
|
89
88
|
if (resolved.source !== 'aside') fail('step 5: resolve spawn plan', JSON.stringify(resolved));
|
|
90
89
|
else pass('step 5: spawn plan resolves to aside');
|