0xray 4.0.0 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.mcp.json +15 -55
- package/.xray/features.json +2 -2
- package/AGENTS-consumer.md +6 -6
- package/AGENTS.md +9 -9
- package/README.md +19 -19
- package/SKILLS.md +2 -2
- package/dist/AGENTS.md +9 -9
- package/dist/CHANGELOG.md +54 -2
- package/dist/README.md +19 -19
- package/dist/SKILLS.md +2 -2
- package/dist/cli/commands/foundry-mint-wear.d.ts +2 -0
- package/dist/cli/commands/foundry-mint-wear.js +14 -0
- package/dist/cli/commands/hermes-install.js +2 -0
- package/dist/cli/commands/openclaw-install.js +2 -0
- package/dist/cli/commands/opencode-install.js +2 -0
- package/dist/cli/index.js +10 -1
- package/dist/enforcement/enforcer-tools.d.ts +7 -0
- package/dist/enforcement/enforcer-tools.js +18 -109
- package/dist/integrations/grok/grok-cli.js +2 -0
- package/dist/integrations/hermes-agent/bridge.mjs +7 -0
- package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +4 -2
- package/dist/processors/implementations/version-compliance-processor.d.ts +3 -34
- package/dist/processors/implementations/version-compliance-processor.js +8 -135
- package/opencode.json +0 -8
- package/package.json +15 -14
- package/scripts/foundry/CHANGELOG.md +34 -0
- package/scripts/foundry/LICENSE +21 -0
- package/scripts/foundry/README.md +67 -0
- package/scripts/foundry/ci-monitor.mjs +115 -0
- package/scripts/foundry/cli.js +2 -0
- package/scripts/foundry/cli.mjs +55 -0
- package/scripts/foundry/docs-build.mjs +38 -0
- package/scripts/foundry/hooks.mjs +36 -0
- package/scripts/foundry/mill-root.mjs +62 -0
- package/scripts/foundry/mint-suit.cjs +313 -0
- package/scripts/foundry/mint.mjs +33 -0
- package/scripts/foundry/package.json +53 -0
- package/scripts/foundry/reconcile-version.mjs +150 -0
- package/scripts/foundry/release-gate.mjs +100 -0
- package/scripts/foundry/release.mjs +266 -0
- package/scripts/foundry/validate-release-docs.mjs +316 -0
- package/scripts/foundry/version-manager.mjs +444 -0
- package/scripts/node/ci-cd-auto-fix.cjs +12 -257
- package/scripts/node/consumer-install-smoke.mjs +57 -2
- package/scripts/node/enforce-version-compliance.sh +5 -20
- package/scripts/node/enforce-version-compliance.ts +13 -113
- package/scripts/node/foundry-shim.mjs +19 -0
- package/scripts/node/github-actions-monitor.cjs +13 -18
- package/scripts/node/postinstall.cjs +36 -1
- package/scripts/node/reconcile-version.mjs +3 -146
- package/scripts/node/release-gate.mjs +3 -74
- package/scripts/node/release.mjs +3 -171
- package/scripts/node/validate-release-docs.mjs +3 -285
- package/scripts/node/version-manager.mjs +3 -708
- package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +4 -2
- package/xray/features.json +2 -2
- package/scripts/node/release.js +0 -17
- package/scripts/node/sync-versions.mjs +0 -18
- package/scripts/node/universal-version-manager.js +0 -1043
|
@@ -1,263 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* CI/CD Auto-Fix Script
|
|
5
|
-
*
|
|
6
|
-
* Automatically fixes common CI/CD issues detected by the monitoring pipeline.
|
|
7
|
-
*
|
|
8
|
-
* Usage: node scripts/node/ci-cd-auto-fix.cjs
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
const fs = require('fs');
|
|
12
|
-
const path = require('path');
|
|
13
|
-
const { execSync } = require('child_process');
|
|
14
|
-
|
|
15
|
-
const rootDir = path.resolve(__dirname, '../..');
|
|
16
|
-
|
|
17
|
-
// Colors for output
|
|
18
|
-
const RED = '\x1b[0;31m';
|
|
19
|
-
const GREEN = '\x1b[0;32m';
|
|
20
|
-
const YELLOW = '\x1b[1;33m';
|
|
21
|
-
const BLUE = '\x1b[0;34m';
|
|
22
|
-
const NC = '\x1b[0m';
|
|
23
|
-
|
|
24
|
-
const log = {
|
|
25
|
-
info: (msg) => console.log(`${BLUE}ℹ️ ${msg}${NC}`),
|
|
26
|
-
success: (msg) => console.log(`${GREEN}✅ ${msg}${NC}`),
|
|
27
|
-
error: (msg) => console.log(`${RED}❌ ${msg}${NC}`),
|
|
28
|
-
warn: (msg) => console.log(`${YELLOW}⚠️ ${msg}${NC}`),
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const MAX_ITERATIONS = parseInt(process.env.MAX_ITERATIONS || '3');
|
|
32
|
-
const GITHUB_TOKEN = process.env.GITHUB_TOKEN || '';
|
|
33
|
-
const GITHUB_REPOSITORY = process.env.GITHUB_REPOSITORY || '';
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Check if running in GitHub Actions
|
|
37
|
-
*/
|
|
38
|
-
function isGitHubActions() {
|
|
39
|
-
return !!process.env.GITHUB_ACTIONS;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Run a command and return output
|
|
44
|
-
*/
|
|
45
|
-
function runCommand(cmd, options = {}) {
|
|
46
|
-
try {
|
|
47
|
-
const output = execSync(cmd, {
|
|
48
|
-
cwd: rootDir,
|
|
49
|
-
encoding: 'utf8',
|
|
50
|
-
stdio: 'pipe',
|
|
51
|
-
...options,
|
|
52
|
-
});
|
|
53
|
-
return { success: true, output };
|
|
54
|
-
} catch (error) {
|
|
55
|
-
return { success: false, error: error.message, output: error.stdout || '' };
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Fix TypeScript errors
|
|
61
|
-
*/
|
|
62
|
-
function fixTypeErrors() {
|
|
63
|
-
log.info('Checking TypeScript compilation...');
|
|
64
|
-
const result = runCommand('npx tsc --noEmit 2>&1 || true');
|
|
65
|
-
|
|
66
|
-
if (result.success || result.output.includes('error TS')) {
|
|
67
|
-
const tsErrors = result.output.match(/error TS\d+:/g) || [];
|
|
68
|
-
if (tsErrors.length > 0) {
|
|
69
|
-
log.warn(`Found ${tsErrors.length} TypeScript errors`);
|
|
70
|
-
// Try to run typecheck with fix
|
|
71
|
-
const fixResult = runCommand('npm run typecheck 2>&1 || true');
|
|
72
|
-
if (fixResult.success) {
|
|
73
|
-
log.success('TypeScript errors resolved');
|
|
74
|
-
return true;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
2
|
/**
|
|
82
|
-
*
|
|
3
|
+
* Mill does not auto-push CI fixes. Report only.
|
|
4
|
+
*
|
|
5
|
+
* node scripts/node/ci-cd-auto-fix.cjs
|
|
83
6
|
*/
|
|
84
|
-
function fixLintErrors() {
|
|
85
|
-
log.info('Checking ESLint...');
|
|
86
|
-
const result = runCommand('npm run lint 2>&1 || true');
|
|
87
|
-
|
|
88
|
-
if (result.output.includes('error') || result.output.includes('warning')) {
|
|
89
|
-
log.warn('ESLint issues found, attempting fix...');
|
|
90
|
-
const fixResult = runCommand('npm run lint:fix 2>&1 || npx eslint --fix . 2>&1 || true');
|
|
91
|
-
if (fixResult.success) {
|
|
92
|
-
log.success('ESLint errors resolved');
|
|
93
|
-
return true;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return false;
|
|
97
|
-
}
|
|
98
7
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
*/
|
|
102
|
-
function fixTestFailures() {
|
|
103
|
-
log.info('Running tests to identify failures...');
|
|
104
|
-
const result = runCommand('npm test 2>&1 || true');
|
|
105
|
-
|
|
106
|
-
if (!result.success || result.output.includes('failed') || result.output.includes('FAIL')) {
|
|
107
|
-
log.warn('Test failures detected');
|
|
108
|
-
|
|
109
|
-
// Check for specific failure patterns
|
|
110
|
-
const patterns = [
|
|
111
|
-
{ pattern: /console\.(log|warn|error)/, fix: 'Run lint:fix to remove console statements' },
|
|
112
|
-
{ pattern: /any\s*\|/, fix: 'Replace any types with proper interfaces' },
|
|
113
|
-
{ pattern: /undefined/, fix: 'Add null checks or default values' },
|
|
114
|
-
];
|
|
115
|
-
|
|
116
|
-
for (const { pattern, fix } of patterns) {
|
|
117
|
-
if (pattern.test(result.output)) {
|
|
118
|
-
log.info(`Fix suggestion: ${fix}`);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
return false;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
log.success('All tests passing');
|
|
125
|
-
return true;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Fix missing dependencies
|
|
130
|
-
*/
|
|
131
|
-
function fixDependencies() {
|
|
132
|
-
log.info('Checking dependencies...');
|
|
133
|
-
|
|
134
|
-
const result = runCommand('npm ci 2>&1 || npm install 2>&1');
|
|
135
|
-
if (result.success) {
|
|
136
|
-
log.success('Dependencies up to date');
|
|
137
|
-
return true;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
log.error('Dependency issues may require manual intervention');
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Fix Git hooks
|
|
146
|
-
*/
|
|
147
|
-
function fixGitHooks() {
|
|
148
|
-
log.info('Setting up Git hooks...');
|
|
149
|
-
const result = runCommand('npm run prepare 2>&1 || npx husky install 2>&1 || true');
|
|
150
|
-
|
|
151
|
-
if (result.success) {
|
|
152
|
-
log.success('Git hooks configured');
|
|
153
|
-
return true;
|
|
154
|
-
}
|
|
155
|
-
return false;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Fix consumer path issues
|
|
160
|
-
*/
|
|
161
|
-
function fixConsumerPaths() {
|
|
162
|
-
log.info('Checking consumer path configuration...');
|
|
163
|
-
|
|
164
|
-
const prepareResult = runCommand('npm run prepare-consumer 2>&1 || true');
|
|
165
|
-
if (prepareResult.output.includes('No development paths')) {
|
|
166
|
-
log.success('Paths already correct');
|
|
167
|
-
return true;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Run prepare-consumer to fix paths
|
|
171
|
-
const fixResult = runCommand('npm run prepare-consumer 2>&1');
|
|
172
|
-
if (fixResult.success || fixResult.output.includes('Complete')) {
|
|
173
|
-
log.success('Consumer paths fixed');
|
|
174
|
-
return true;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
return false;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Generate health report
|
|
182
|
-
*/
|
|
183
|
-
function generateHealthReport() {
|
|
184
|
-
const report = {
|
|
185
|
-
timestamp: new Date().toISOString(),
|
|
186
|
-
version: require(path.join(rootDir, 'package.json')).version,
|
|
187
|
-
status: 'healthy',
|
|
188
|
-
fixes_applied: [],
|
|
189
|
-
issues_remaining: [],
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
const logsDir = path.join(rootDir, '.opencode', 'logs');
|
|
193
|
-
if (!fs.existsSync(logsDir)) {
|
|
194
|
-
fs.mkdirSync(logsDir, { recursive: true });
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const reportPath = path.join(logsDir, 'ci-cd-monitor-report.json');
|
|
198
|
-
fs.writeFileSync(reportPath, JSON.stringify(report, null, 2));
|
|
199
|
-
|
|
200
|
-
log.info(`Health report generated: ${reportPath}`);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Main auto-fix routine
|
|
205
|
-
*/
|
|
206
|
-
async function autoFix() {
|
|
207
|
-
log.info('Starting CI/CD Auto-Fix...');
|
|
208
|
-
log.info(`Max iterations: ${MAX_ITERATIONS}`);
|
|
209
|
-
console.log('');
|
|
210
|
-
|
|
211
|
-
let fixed = false;
|
|
212
|
-
const fixes = [];
|
|
213
|
-
|
|
214
|
-
// Run all fix routines
|
|
215
|
-
const routines = [
|
|
216
|
-
{ name: 'Dependencies', fn: fixDependencies },
|
|
217
|
-
{ name: 'Consumer Paths', fn: fixConsumerPaths },
|
|
218
|
-
{ name: 'Git Hooks', fn: fixGitHooks },
|
|
219
|
-
{ name: 'TypeScript', fn: fixTypeErrors },
|
|
220
|
-
{ name: 'ESLint', fn: fixLintErrors },
|
|
221
|
-
{ name: 'Tests', fn: fixTestFailures },
|
|
222
|
-
];
|
|
223
|
-
|
|
224
|
-
for (const { name, fn } of routines) {
|
|
225
|
-
console.log('');
|
|
226
|
-
log.info(`Running: ${name}...`);
|
|
227
|
-
try {
|
|
228
|
-
if (fn()) {
|
|
229
|
-
fixes.push(name);
|
|
230
|
-
fixed = true;
|
|
231
|
-
}
|
|
232
|
-
} catch (error) {
|
|
233
|
-
log.error(`${name} failed: ${error.message}`);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
console.log('');
|
|
238
|
-
console.log('══════════════════════════════════════════════════');
|
|
239
|
-
|
|
240
|
-
if (fixed) {
|
|
241
|
-
log.success(`CI/CD Auto-Fix Complete! ${fixes.length} issue(s) resolved.`);
|
|
242
|
-
console.log('');
|
|
243
|
-
console.log('Fixes applied:');
|
|
244
|
-
fixes.forEach((fix, i) => console.log(` ${i + 1}. ${fix}`));
|
|
245
|
-
} else {
|
|
246
|
-
log.warn('No issues resolved (or none detected)');
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// Generate health report
|
|
250
|
-
generateHealthReport();
|
|
251
|
-
|
|
252
|
-
console.log('══════════════════════════════════════════════════');
|
|
253
|
-
|
|
254
|
-
return fixed;
|
|
255
|
-
}
|
|
8
|
+
const { spawnSync } = require("child_process");
|
|
9
|
+
const path = require("path");
|
|
256
10
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
process.
|
|
11
|
+
const mill = path.join(__dirname, "../foundry/ci-monitor.mjs");
|
|
12
|
+
const root = process.env.FOUNDRY_ROOT || process.cwd();
|
|
13
|
+
const result = spawnSync(process.execPath, [mill, "--report", ...process.argv.slice(2)], {
|
|
14
|
+
stdio: "inherit",
|
|
15
|
+
cwd: root,
|
|
16
|
+
env: { ...process.env, FOUNDRY_ROOT: root },
|
|
263
17
|
});
|
|
18
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
@@ -48,9 +48,14 @@ function assertFreshInstallDefaults(tmpRoot, version) {
|
|
|
48
48
|
if (!features.memory_routing) {
|
|
49
49
|
throw new Error("Deployed features.json missing memory_routing block");
|
|
50
50
|
}
|
|
51
|
-
if (features.memory_routing.enabled !==
|
|
51
|
+
if (features.memory_routing.enabled !== true) {
|
|
52
52
|
throw new Error(
|
|
53
|
-
`Fresh install must
|
|
53
|
+
`Fresh 4.0 install must ship memory_routing.enabled=true with the vendored organ (got ${features.memory_routing.enabled})`,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
if (features.memory_routing.provider !== "repertoire") {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`Fresh install memory_routing.provider must be repertoire (got ${features.memory_routing.provider})`,
|
|
54
59
|
);
|
|
55
60
|
}
|
|
56
61
|
if (!features.inference_governance) {
|
|
@@ -59,6 +64,33 @@ function assertFreshInstallDefaults(tmpRoot, version) {
|
|
|
59
64
|
if (features.inference_governance.enabled !== false) {
|
|
60
65
|
throw new Error("Fresh install must default inference_governance.enabled=false");
|
|
61
66
|
}
|
|
67
|
+
const organHoisted = path.join(tmpRoot, "node_modules", "@0xray", "repertoire", "package.json");
|
|
68
|
+
const organNested = path.join(
|
|
69
|
+
tmpRoot,
|
|
70
|
+
"node_modules",
|
|
71
|
+
"0xray",
|
|
72
|
+
"node_modules",
|
|
73
|
+
"@0xray",
|
|
74
|
+
"repertoire",
|
|
75
|
+
"package.json",
|
|
76
|
+
);
|
|
77
|
+
const organVendor = path.join(
|
|
78
|
+
tmpRoot,
|
|
79
|
+
"node_modules",
|
|
80
|
+
"0xray",
|
|
81
|
+
"vendor",
|
|
82
|
+
"@0xray",
|
|
83
|
+
"repertoire",
|
|
84
|
+
"package.json",
|
|
85
|
+
);
|
|
86
|
+
const organPkg = [organNested, organHoisted, organVendor].find((p) => fs.existsSync(p));
|
|
87
|
+
if (!organPkg) {
|
|
88
|
+
throw new Error("vendored @0xray/repertoire missing from fresh tarball install");
|
|
89
|
+
}
|
|
90
|
+
const organ = JSON.parse(fs.readFileSync(organPkg, "utf-8"));
|
|
91
|
+
if (organ.version !== "0.2.0") {
|
|
92
|
+
throw new Error(`expected organ 0.2.0, got ${organ.version}`);
|
|
93
|
+
}
|
|
62
94
|
console.log(" ✅ .xray/features.json fresh-install defaults (opt-in off)");
|
|
63
95
|
return { consumerFeaturesPath, features };
|
|
64
96
|
}
|
|
@@ -114,6 +146,27 @@ function runUpgradeMergeSmoke(tmpRoot, nmRoot, version) {
|
|
|
114
146
|
if (shippedMarker && !merged[shippedMarker]) {
|
|
115
147
|
throw new Error(`Upgrade merge missing shipped template key: ${shippedMarker}`);
|
|
116
148
|
}
|
|
149
|
+
fs.writeFileSync(
|
|
150
|
+
consumerFeaturesPath,
|
|
151
|
+
`${JSON.stringify(
|
|
152
|
+
{
|
|
153
|
+
version: "3.5.5",
|
|
154
|
+
memory_routing: { enabled: false, provider: "repertoire" },
|
|
155
|
+
},
|
|
156
|
+
null,
|
|
157
|
+
2,
|
|
158
|
+
)}\n`,
|
|
159
|
+
);
|
|
160
|
+
deployXrayConfig(tmpRoot, nmRoot, () => {});
|
|
161
|
+
const optedOut = JSON.parse(fs.readFileSync(consumerFeaturesPath, "utf-8"));
|
|
162
|
+
if (optedOut.memory_routing?.enabled !== false) {
|
|
163
|
+
throw new Error(
|
|
164
|
+
`Upgrade merge must keep explicit memory_routing opt-out (got ${optedOut.memory_routing?.enabled})`,
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
if (optedOut.memory_routing?.provider !== "repertoire") {
|
|
168
|
+
throw new Error("Upgrade merge dropped memory_routing.provider on opt-out");
|
|
169
|
+
}
|
|
117
170
|
|
|
118
171
|
console.log(" ✅ upgrade merge preserves opt-ins + bumps features.version");
|
|
119
172
|
}
|
|
@@ -155,6 +208,8 @@ function main() {
|
|
|
155
208
|
const requiredFiles = [
|
|
156
209
|
"scripts/node/install-bridges.cjs",
|
|
157
210
|
"scripts/node/postinstall.cjs",
|
|
211
|
+
"scripts/foundry/mint-suit.cjs",
|
|
212
|
+
"scripts/foundry/hooks.mjs",
|
|
158
213
|
"package.json",
|
|
159
214
|
"xray/features.json",
|
|
160
215
|
"xray/features.schema.json",
|
|
@@ -1,21 +1,6 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
#
|
|
8
|
-
# Usage: ./scripts/node/enforce-version-compliance.sh
|
|
9
|
-
#
|
|
10
|
-
# @since 2026-01-15
|
|
11
|
-
|
|
12
|
-
set -e
|
|
13
|
-
|
|
14
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
15
|
-
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
16
|
-
|
|
17
|
-
cd "$PROJECT_ROOT"
|
|
18
|
-
|
|
19
|
-
# Use npx tsx to run TypeScript files directly
|
|
20
|
-
# tsx is a zero-config TypeScript execution engine
|
|
21
|
-
npx tsx "$SCRIPT_DIR/enforce-version-compliance.ts"
|
|
2
|
+
# Foundry mill: docs + version SSOT. Not UVM.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
5
|
+
cd "$ROOT"
|
|
6
|
+
exec node scripts/foundry/validate-release-docs.mjs "$@"
|
|
@@ -1,116 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
+
* Foundry mill wrapper. Version SSOT is package.json (reconcile-version).
|
|
4
|
+
* Prose is verified by validate-release-docs — not rewritten here.
|
|
3
5
|
*/
|
|
4
|
-
|
|
5
|
-
import path from
|
|
6
|
-
import { fileURLToPath } from
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const BLUE = '\x1b[0;34m';
|
|
16
|
-
const NC = '\x1b[0m';
|
|
17
|
-
|
|
18
|
-
async function main() {
|
|
19
|
-
console.log(`${BLUE}🔍 ENFORCER AGENT: Version Compliance Check${NC}`);
|
|
20
|
-
console.log(`${BLUE}==============================================${NC}`);
|
|
21
|
-
console.log('');
|
|
22
|
-
|
|
23
|
-
try {
|
|
24
|
-
// Import and run the processor - use file URL for ESM compatibility
|
|
25
|
-
// __dirname is the script's directory (scripts/node/), go up 2 levels to project root
|
|
26
|
-
const scriptDir = path.join(__dirname);
|
|
27
|
-
const projectRoot = path.join(scriptDir, '..', '..');
|
|
28
|
-
const processorPath = path.join(projectRoot, 'dist', 'processors', 'version-compliance-processor.js');
|
|
29
|
-
const { VersionComplianceProcessor } = await import(`file://${processorPath}`);
|
|
30
|
-
const processor = new VersionComplianceProcessor(projectRoot);
|
|
31
|
-
|
|
32
|
-
const result = await processor.validateVersionCompliance();
|
|
33
|
-
|
|
34
|
-
// Display results
|
|
35
|
-
console.log(`${BLUE}📊 Version Audit:${NC}`);
|
|
36
|
-
console.log(` NPM Published: ${BLUE}${result.npmVersion}${NC}`);
|
|
37
|
-
console.log(` package.json: ${BLUE}${result.pkgVersion}${NC}`);
|
|
38
|
-
console.log(` Version Manager: ${BLUE}${result.uvmVersion}${NC}`);
|
|
39
|
-
console.log('');
|
|
40
|
-
|
|
41
|
-
// Rule 1: UVM 1 ahead of NPM
|
|
42
|
-
console.log('1️⃣ Checking: Version Manager 1 Ahead Rule');
|
|
43
|
-
if (result.npmVersion !== 'NOT_PUBLISHED' && result.npmVersion !== 'ERROR') {
|
|
44
|
-
const expectedUvm = incrementPatch(result.npmVersion);
|
|
45
|
-
if (result.uvmVersion === expectedUvm) {
|
|
46
|
-
console.log(` ${GREEN}✅ PASS:${NC} Version manager is 1 ahead (${result.uvmVersion} > ${result.npmVersion})`);
|
|
47
|
-
} else {
|
|
48
|
-
console.log(` ${RED}❌ VIOLATION:${NC} Version manager not 1 ahead of npm`);
|
|
49
|
-
console.log(` NPM: ${result.npmVersion}`);
|
|
50
|
-
console.log(` UVM: ${result.uvmVersion}`);
|
|
51
|
-
console.log(` Expected: ${expectedUvm}`);
|
|
52
|
-
}
|
|
53
|
-
} else {
|
|
54
|
-
console.log(` ${YELLOW}⚠️ NPM version not available (first publish)${NC}`);
|
|
55
|
-
}
|
|
56
|
-
console.log('');
|
|
57
|
-
|
|
58
|
-
// Rule 2: package.json sync
|
|
59
|
-
console.log('2️⃣ Checking: package.json Synchronization');
|
|
60
|
-
if (result.pkgVersion === result.uvmVersion) {
|
|
61
|
-
console.log(` ${GREEN}✅ PASS:${NC} package.json matches UVM (${result.pkgVersion})`);
|
|
62
|
-
} else {
|
|
63
|
-
console.log(` ${YELLOW}⚠️ WARNING:${NC} package.json version mismatch`);
|
|
64
|
-
console.log(` package.json: ${result.pkgVersion}`);
|
|
65
|
-
console.log(` UVM: ${result.uvmVersion}`);
|
|
66
|
-
console.log(` ℹ️ Run: npm version [patch|minor|major] to sync`);
|
|
67
|
-
}
|
|
68
|
-
console.log('');
|
|
69
|
-
|
|
70
|
-
// Display errors and warnings summary
|
|
71
|
-
console.log(`${BLUE}==============================================${NC}`);
|
|
72
|
-
|
|
73
|
-
if (result.errors.length > 0) {
|
|
74
|
-
console.log(`${RED}❌ COMPLIANCE CHECK FAILED${NC}`);
|
|
75
|
-
console.log(` Errors: ${result.errors.length}`);
|
|
76
|
-
console.log(` Warnings: ${result.warnings.length}`);
|
|
77
|
-
console.log('');
|
|
78
|
-
console.log(`${RED}🚫 BLOCKED: Cannot proceed with commit/publish${NC}`);
|
|
79
|
-
console.log(' Violations:');
|
|
80
|
-
result.errors.forEach(e => console.log(` ${RED}•${NC} ${e}`));
|
|
81
|
-
|
|
82
|
-
if (result.fixes && result.fixes.length > 0) {
|
|
83
|
-
console.log('');
|
|
84
|
-
console.log(`${YELLOW}🔧 FIXES:${NC}`);
|
|
85
|
-
result.fixes.forEach(f => {
|
|
86
|
-
console.log(` ${YELLOW}•${NC} ${f.description}`);
|
|
87
|
-
console.log(` Command: ${f.command}`);
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
process.exit(1);
|
|
92
|
-
} else {
|
|
93
|
-
console.log(`${GREEN}✅ COMPLIANCE CHECK PASSED${NC}`);
|
|
94
|
-
if (result.warnings.length > 0) {
|
|
95
|
-
console.log(` Warnings: ${result.warnings.length} (non-blocking)`);
|
|
96
|
-
result.warnings.forEach(w => console.log(` ${YELLOW}⚠️${NC} ${w}`));
|
|
97
|
-
}
|
|
98
|
-
console.log('');
|
|
99
|
-
console.log(`${GREEN}🚀 APPROVED: Ready for commit/publish${NC}`);
|
|
100
|
-
process.exit(0);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
} catch (error) {
|
|
104
|
-
console.error(`${RED}❌ Fatal error running version compliance:${NC}`, error);
|
|
105
|
-
process.exit(1);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Helper to increment patch version
|
|
110
|
-
function incrementPatch(version: string): string {
|
|
111
|
-
const parts = version.split('.').map(Number);
|
|
112
|
-
parts[2] = parts[2] + 1;
|
|
113
|
-
return parts.join('.');
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
main();
|
|
6
|
+
import { spawnSync } from "node:child_process";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
|
|
10
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
11
|
+
const result = spawnSync(
|
|
12
|
+
process.execPath,
|
|
13
|
+
[path.join(root, "scripts/foundry/validate-release-docs.mjs"), ...process.argv.slice(2)],
|
|
14
|
+
{ cwd: root, stdio: "inherit" },
|
|
15
|
+
);
|
|
16
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
/** Run the mill script when this wrapper is the CLI entry. */
|
|
6
|
+
export function millMain(importMetaUrl, millBasename) {
|
|
7
|
+
const here = fileURLToPath(importMetaUrl);
|
|
8
|
+
if (!process.argv[1] || path.resolve(process.argv[1]) !== here) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const mill = path.resolve(path.dirname(here), "../foundry", millBasename);
|
|
12
|
+
const root = process.env.FOUNDRY_ROOT || process.cwd();
|
|
13
|
+
const result = spawnSync(process.execPath, [mill, ...process.argv.slice(2)], {
|
|
14
|
+
stdio: "inherit",
|
|
15
|
+
cwd: root,
|
|
16
|
+
env: { ...process.env, FOUNDRY_ROOT: root },
|
|
17
|
+
});
|
|
18
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
19
|
+
}
|
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
2
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* In production, this would check actual GitHub Actions workflow status.
|
|
8
|
-
*
|
|
9
|
-
* Usage: node scripts/node/github-actions-monitor.cjs --commit <sha>
|
|
3
|
+
* Shim onto the mill CI monitor. Not PPE.
|
|
4
|
+
*
|
|
5
|
+
* node scripts/node/github-actions-monitor.cjs [--commit SHA] [--report]
|
|
10
6
|
*/
|
|
11
7
|
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const commitSha = commitIndex >= 0 ? args[commitIndex + 1] : 'unknown';
|
|
15
|
-
|
|
16
|
-
console.log(`Checking GitHub Actions status for commit: ${commitSha}`);
|
|
17
|
-
|
|
18
|
-
// For consumer projects without GitHub Actions, always return success
|
|
19
|
-
// Real CI environments should override this with actual GitHub API calls
|
|
20
|
-
console.log('SUCCESS: All workflows passed');
|
|
21
|
-
console.log('No failed jobs');
|
|
8
|
+
const { spawnSync } = require("child_process");
|
|
9
|
+
const path = require("path");
|
|
22
10
|
|
|
23
|
-
|
|
11
|
+
const mill = path.join(__dirname, "../foundry/ci-monitor.mjs");
|
|
12
|
+
const root = process.env.FOUNDRY_ROOT || process.cwd();
|
|
13
|
+
const result = spawnSync(process.execPath, [mill, ...process.argv.slice(2)], {
|
|
14
|
+
stdio: "inherit",
|
|
15
|
+
cwd: root,
|
|
16
|
+
env: { ...process.env, FOUNDRY_ROOT: root },
|
|
17
|
+
});
|
|
18
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
@@ -8,6 +8,15 @@ const {
|
|
|
8
8
|
isConsumerInstall,
|
|
9
9
|
} = require("./install-bridges.cjs");
|
|
10
10
|
const { applyConsumerGitignore } = require("./consumer-gitignore.cjs");
|
|
11
|
+
const {
|
|
12
|
+
overlayConsumerTree,
|
|
13
|
+
mintConsumerFromSsot,
|
|
14
|
+
mintConsumerSuit,
|
|
15
|
+
listConsumerSkillNames,
|
|
16
|
+
listConsumerAgentFiles,
|
|
17
|
+
loadFoundryParams,
|
|
18
|
+
readPackageIdentity,
|
|
19
|
+
} = require("../foundry/mint-suit.cjs");
|
|
11
20
|
|
|
12
21
|
function structuredLog(component, action, status, details) {
|
|
13
22
|
const ts = new Date().toISOString();
|
|
@@ -17,6 +26,16 @@ function structuredLog(component, action, status, details) {
|
|
|
17
26
|
|
|
18
27
|
const XRAY_MANAGED_AGENTS_MARKER = "<!-- 0xray-managed -->";
|
|
19
28
|
|
|
29
|
+
function fillConsumerPlaceholders(content, consumer) {
|
|
30
|
+
const name = consumer.name || "this project";
|
|
31
|
+
const versionParen = consumer.version ? ` (${consumer.version})` : "";
|
|
32
|
+
return content
|
|
33
|
+
.split("{{CONSUMER_NAME}}")
|
|
34
|
+
.join(name)
|
|
35
|
+
.split("{{CONSUMER_VERSION_PAREN}}")
|
|
36
|
+
.join(versionParen);
|
|
37
|
+
}
|
|
38
|
+
|
|
20
39
|
function deployManagedAgents(packageRoot, targetDir, log) {
|
|
21
40
|
const agentsConsumer = path.join(packageRoot, "AGENTS-consumer.md");
|
|
22
41
|
const agentsDest = path.join(targetDir, "AGENTS.md");
|
|
@@ -26,6 +45,8 @@ function deployManagedAgents(packageRoot, targetDir, log) {
|
|
|
26
45
|
fs.readFileSync(agentsDest, "utf8").includes(XRAY_MANAGED_AGENTS_MARKER);
|
|
27
46
|
if (shouldDeployAgents) {
|
|
28
47
|
let content = fs.readFileSync(agentsConsumer, "utf8");
|
|
48
|
+
const consumer = readPackageIdentity(path.join(targetDir, "package.json"));
|
|
49
|
+
content = fillConsumerPlaceholders(content, consumer);
|
|
29
50
|
if (!content.includes(XRAY_MANAGED_AGENTS_MARKER)) {
|
|
30
51
|
content = `${content.trimEnd()}\n\n${XRAY_MANAGED_AGENTS_MARKER}\n`;
|
|
31
52
|
}
|
|
@@ -65,6 +86,9 @@ function runPostinstall(packageRoot, targetDir, log) {
|
|
|
65
86
|
packageRoot: resolvedPackage,
|
|
66
87
|
log: logFn,
|
|
67
88
|
});
|
|
89
|
+
if (consumer) {
|
|
90
|
+
mintConsumerSuit(resolvedPackage, resolvedTarget, logFn);
|
|
91
|
+
}
|
|
68
92
|
} catch (e) {
|
|
69
93
|
logFn("postinstall", "Bridge install failed", "error", { error: e.message });
|
|
70
94
|
throw e;
|
|
@@ -81,7 +105,18 @@ function runPostinstall(packageRoot, targetDir, log) {
|
|
|
81
105
|
}
|
|
82
106
|
}
|
|
83
107
|
|
|
84
|
-
module.exports = {
|
|
108
|
+
module.exports = {
|
|
109
|
+
runPostinstall,
|
|
110
|
+
mintConsumerFromSsot,
|
|
111
|
+
mintConsumerSuit,
|
|
112
|
+
overlayConsumerTree,
|
|
113
|
+
listConsumerSkillNames,
|
|
114
|
+
listConsumerAgentFiles,
|
|
115
|
+
loadFoundryParams,
|
|
116
|
+
fillConsumerPlaceholders,
|
|
117
|
+
readPackageIdentity,
|
|
118
|
+
deployManagedAgents,
|
|
119
|
+
};
|
|
85
120
|
|
|
86
121
|
if (require.main === module) {
|
|
87
122
|
const packageRoot = path.join(__dirname, "..", "..");
|