0xray 4.0.1 → 4.0.3

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.
Files changed (59) hide show
  1. package/.xray/features.json +1 -1
  2. package/AGENTS-consumer.md +4 -4
  3. package/AGENTS.md +3 -3
  4. package/README.md +1 -1
  5. package/SKILLS.md +1 -1
  6. package/dist/AGENTS.md +3 -3
  7. package/dist/CHANGELOG.md +43 -0
  8. package/dist/README.md +1 -1
  9. package/dist/SKILLS.md +1 -1
  10. package/dist/cli/commands/foundry-mint-wear.d.ts +3 -0
  11. package/dist/cli/commands/foundry-mint-wear.js +17 -0
  12. package/dist/cli/commands/hermes-install.js +2 -0
  13. package/dist/cli/commands/openclaw-install.js +2 -0
  14. package/dist/cli/commands/opencode-install.js +10 -2
  15. package/dist/cli/commands/skill-install.js +4 -0
  16. package/dist/enforcement/enforcer-tools.d.ts +7 -0
  17. package/dist/enforcement/enforcer-tools.js +18 -109
  18. package/dist/integrations/grok/grok-cli.js +2 -0
  19. package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
  20. package/dist/processors/implementations/version-compliance-processor.d.ts +3 -34
  21. package/dist/processors/implementations/version-compliance-processor.js +8 -135
  22. package/package.json +15 -14
  23. package/scripts/foundry/CHANGELOG.md +38 -0
  24. package/scripts/foundry/LICENSE +21 -0
  25. package/scripts/foundry/README.md +69 -0
  26. package/scripts/foundry/ci-monitor.mjs +115 -0
  27. package/scripts/foundry/cli.js +2 -0
  28. package/scripts/foundry/cli.mjs +55 -0
  29. package/scripts/foundry/docs-build.mjs +38 -0
  30. package/scripts/foundry/hooks.mjs +36 -0
  31. package/scripts/foundry/mill-root.mjs +62 -0
  32. package/scripts/foundry/mint-suit.cjs +397 -0
  33. package/scripts/foundry/mint.mjs +33 -0
  34. package/scripts/foundry/package.json +54 -0
  35. package/scripts/foundry/plant/agents/mill.yml +5 -0
  36. package/scripts/foundry/plant/skills/mill/SKILL.md +22 -0
  37. package/scripts/foundry/reconcile-version.mjs +150 -0
  38. package/scripts/foundry/release-gate.mjs +100 -0
  39. package/scripts/foundry/release.mjs +266 -0
  40. package/scripts/foundry/validate-release-docs.mjs +316 -0
  41. package/scripts/foundry/version-manager.mjs +444 -0
  42. package/scripts/node/ci-cd-auto-fix.cjs +12 -257
  43. package/scripts/node/consumer-install-smoke.mjs +17 -0
  44. package/scripts/node/enforce-version-compliance.sh +5 -20
  45. package/scripts/node/enforce-version-compliance.ts +13 -113
  46. package/scripts/node/foundry-shim.mjs +19 -0
  47. package/scripts/node/github-actions-monitor.cjs +13 -18
  48. package/scripts/node/install-bridges.cjs +43 -29
  49. package/scripts/node/postinstall.cjs +36 -1
  50. package/scripts/node/reconcile-version.mjs +3 -142
  51. package/scripts/node/release-gate.mjs +3 -74
  52. package/scripts/node/release.mjs +3 -171
  53. package/scripts/node/validate-release-docs.mjs +3 -285
  54. package/scripts/node/version-manager.mjs +3 -738
  55. package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
  56. package/xray/features.json +1 -1
  57. package/scripts/node/release.js +0 -17
  58. package/scripts/node/sync-versions.mjs +0 -18
  59. package/scripts/node/universal-version-manager.js +0 -1043
@@ -0,0 +1,316 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * validate-release-docs.mjs — Blocking guard for release doc freshness.
4
+ *
5
+ * Ensures README, AGENTS, SKILLS, CHANGELOG, Docusaurus headers, and required
6
+ * guides match package.json version and live framework counts before tag/publish.
7
+ *
8
+ * Usage:
9
+ * npx @0xray/foundry docs-check
10
+ * npx @0xray/foundry docs-check --json
11
+ */
12
+
13
+ import fs from 'fs';
14
+ import path from 'path';
15
+ import { fileURLToPath } from 'url';
16
+ import {
17
+ buildDocsHeader,
18
+ DOCS_SITE_HEADER_FILES,
19
+ getFrameworkCounts,
20
+ getReleaseArtifactPaths,
21
+ } from './version-manager.mjs';
22
+ import { isXrayExoRepo, resolveMillRoot } from './mill-root.mjs';
23
+
24
+ const STANDARD_HEADER_RE =
25
+ /\*{0,2}\d+\.\d+\*{0,2}\s*—\s*a suit that survives the context window/;
26
+
27
+ /** Patch stamps belong in CHANGELOG, not kernel headers. */
28
+ function kernelLineHasPatchStamp(content) {
29
+ return /^\*\*v?\d+\.\d+\.\d+\*\*/m.test(content);
30
+ }
31
+
32
+ /** Guides that must exist and reference the current release (body or header). */
33
+ const REQUIRED_GUIDES = [
34
+ 'docs-site/docs/guides/features-since-3.1.md',
35
+ 'docs-site/docs/guides/features-json.md',
36
+ 'docs-site/docs/guides/memory-routing.md',
37
+ 'docs-site/docs/guides/aside-context.md',
38
+ 'docs-site/docs/guides/repertoire.md',
39
+ 'docs-site/docs/guides/integrations.md',
40
+ 'docs-site/docs/guides/consumer-migration.md',
41
+ 'docs-site/docs/mcp/README.md',
42
+ 'docs-site/docs/agents/README.md',
43
+ ];
44
+
45
+ const ROOT_DOC_CHECKS = [
46
+ {
47
+ rel: 'README.md',
48
+ validate: (content, _version, _counts, header) => {
49
+ const errors = [];
50
+ if (!content.includes(header) && !STANDARD_HEADER_RE.test(content)) {
51
+ errors.push(`missing kernel header (expected substring: ${header})`);
52
+ }
53
+ if (kernelLineHasPatchStamp(content)) {
54
+ errors.push('kernel header must be era (major.minor), not a patch stamp');
55
+ }
56
+ if (!content.includes('survive the context window') && !content.includes('survives the context window')) {
57
+ errors.push('missing context-window / exo kernel copy');
58
+ }
59
+ if (!content.includes('SKILLS.md')) {
60
+ errors.push('missing SKILLS.md reference in postinstall/docs section');
61
+ }
62
+ if (!content.includes('install-bridges') && !content.includes('installAllBridges')) {
63
+ errors.push('missing install-bridges / installAllBridges reference');
64
+ }
65
+ return errors;
66
+ },
67
+ },
68
+ {
69
+ rel: 'AGENTS.md',
70
+ validate: (content, _version) => {
71
+ const errors = [];
72
+ if (kernelLineHasPatchStamp(content)) {
73
+ errors.push('kernel header must be era (major.minor), not a patch stamp');
74
+ }
75
+ if (!content.includes('survive the context window') && !content.includes('survives the context window') && !content.includes('Exo, not catalog')) {
76
+ errors.push('missing exo / context-window kernel copy');
77
+ }
78
+ if (!content.includes('aside-context.md') && !content.includes('AsideContext')) {
79
+ errors.push('missing AsideContext documentation reference');
80
+ }
81
+ if (!content.includes('SKILLS.md')) {
82
+ errors.push('missing SKILLS.md link');
83
+ }
84
+ return errors;
85
+ },
86
+ },
87
+ {
88
+ rel: 'AGENTS-consumer.md',
89
+ validate: (content) => {
90
+ const errors = [];
91
+ if (kernelLineHasPatchStamp(content)) {
92
+ errors.push('kernel header must be era (major.minor), not a patch stamp');
93
+ }
94
+ if (!content.includes('survive the context window') && !content.includes('survives the context window')) {
95
+ errors.push('consumer header missing context-window kernel copy');
96
+ }
97
+ if (!content.includes('SKILLS.md')) {
98
+ errors.push('missing SKILLS.md in postinstall section');
99
+ }
100
+ if (!content.includes('AsideContext')) {
101
+ errors.push('missing AsideContext section');
102
+ }
103
+ return errors;
104
+ },
105
+ },
106
+ {
107
+ rel: 'SKILLS.md',
108
+ validate: (content, _version, counts) => {
109
+ const errors = [];
110
+ if (kernelLineHasPatchStamp(content)) {
111
+ errors.push('kernel header must be era (major.minor), not a patch stamp');
112
+ }
113
+ if (!content.includes(`**${counts.skills} skills**`)) {
114
+ errors.push(`skill count stale (expected **${counts.skills} skills**)`);
115
+ }
116
+ return errors;
117
+ },
118
+ },
119
+ ];
120
+
121
+ function readFile(rootDir, rel) {
122
+ const full = path.join(rootDir, rel);
123
+ if (!fs.existsSync(full)) return null;
124
+ return fs.readFileSync(full, 'utf-8');
125
+ }
126
+
127
+ function getPackageVersion(rootDir) {
128
+ const pkg = JSON.parse(fs.readFileSync(path.join(rootDir, 'package.json'), 'utf-8'));
129
+ return pkg.version;
130
+ }
131
+
132
+ function getCodexTermCount(rootDir) {
133
+ const codexPath = path.join(rootDir, '.xray/codex.json');
134
+ if (!fs.existsSync(codexPath)) return null;
135
+ const codex = JSON.parse(fs.readFileSync(codexPath, 'utf-8'));
136
+ return Object.keys(codex.terms || {}).length;
137
+ }
138
+
139
+ function validateChangelog(content, version) {
140
+ const errors = [];
141
+ const headings = [...content.matchAll(/^## \[([^\]]+)\]/gm)].map((m) => m[1]);
142
+ if (headings.length === 0) {
143
+ errors.push('no version sections found');
144
+ return errors;
145
+ }
146
+ if (headings[0] === 'Unreleased') {
147
+ if (headings[1] !== version) {
148
+ errors.push(`after [Unreleased], expected [${version}], found [${headings[1] || 'none'}]`);
149
+ }
150
+ } else if (headings[0] !== version) {
151
+ errors.push(`top CHANGELOG entry is [${headings[0]}], expected [${version}] or [Unreleased]`);
152
+ }
153
+ if (!content.includes(`## [${version}]`)) {
154
+ errors.push(`missing ## [${version}] section`);
155
+ }
156
+ return errors;
157
+ }
158
+
159
+ function validateStandardHeader(content, expectedHeader, label) {
160
+ if (!content.includes(expectedHeader) && !STANDARD_HEADER_RE.test(content)) {
161
+ return [`${label}: missing kernel header (expected substring: ${expectedHeader})`];
162
+ }
163
+ return [];
164
+ }
165
+
166
+ function validateDocusaurusTagline(content) {
167
+ const errors = [];
168
+ if (!content.includes('survive the context window') && !content.includes('survives the context window')) {
169
+ errors.push('docusaurus.config.ts tagline missing context-window kernel copy');
170
+ }
171
+ return errors;
172
+ }
173
+
174
+ /**
175
+ * @param {string} [rootDir]
176
+ * @returns {{ ok: boolean; version: string; counts: object; errors: string[]; warnings: string[]; mode?: 'full'|'light' }}
177
+ */
178
+ export function validateReleaseDocs(rootDir = resolveMillRoot()) {
179
+ const errors = [];
180
+ const warnings = [];
181
+ const version = getPackageVersion(rootDir);
182
+ const counts = getFrameworkCounts(rootDir);
183
+ const expectedHeader = buildDocsHeader(counts, version);
184
+ const codexTerms = getCodexTermCount(rootDir);
185
+ const full = isXrayExoRepo(rootDir);
186
+
187
+ if (codexTerms !== null && counts.codexTerms && codexTerms !== counts.codexTerms) {
188
+ warnings.push(`codex.json has ${codexTerms} terms (counts.codexTerms is ${counts.codexTerms})`);
189
+ }
190
+
191
+ const changelog = readFile(rootDir, 'CHANGELOG.md');
192
+ if (!changelog) {
193
+ if (full) {
194
+ errors.push('CHANGELOG.md missing');
195
+ } else {
196
+ warnings.push('CHANGELOG.md missing (light mill)');
197
+ }
198
+ } else {
199
+ errors.push(...validateChangelog(changelog, version).map((e) => `CHANGELOG.md: ${e}`));
200
+ }
201
+
202
+ if (!full) {
203
+ return {
204
+ ok: errors.length === 0,
205
+ version,
206
+ counts,
207
+ errors,
208
+ warnings,
209
+ mode: 'light',
210
+ };
211
+ }
212
+
213
+ for (const check of ROOT_DOC_CHECKS) {
214
+ const content = readFile(rootDir, check.rel);
215
+ if (!content) {
216
+ errors.push(`${check.rel}: file missing`);
217
+ continue;
218
+ }
219
+ const relErrors = check.validate(content, version, counts, expectedHeader);
220
+ for (const e of relErrors) {
221
+ errors.push(`${check.rel}: ${e}`);
222
+ }
223
+ }
224
+
225
+ for (const rel of DOCS_SITE_HEADER_FILES) {
226
+ const content = readFile(rootDir, rel);
227
+ if (!content) {
228
+ errors.push(`${rel}: file missing`);
229
+ continue;
230
+ }
231
+ errors.push(...validateStandardHeader(content, expectedHeader, rel));
232
+ if (kernelLineHasPatchStamp(content)) {
233
+ errors.push(`${rel}: kernel header must be era (major.minor), not a patch stamp`);
234
+ }
235
+ }
236
+
237
+ for (const rel of REQUIRED_GUIDES) {
238
+ const content = readFile(rootDir, rel);
239
+ if (!content) {
240
+ errors.push(`${rel}: required guide missing`);
241
+ continue;
242
+ }
243
+ if (content.trim().length < 200) {
244
+ errors.push(`${rel}: guide too short — likely stub`);
245
+ }
246
+
247
+ }
248
+
249
+ const docusaurus = readFile(rootDir, 'docs-site/docusaurus.config.ts');
250
+ if (!docusaurus) {
251
+ errors.push('docs-site/docusaurus.config.ts: missing');
252
+ } else {
253
+ errors.push(...validateDocusaurusTagline(docusaurus));
254
+ }
255
+
256
+ for (const rel of getReleaseArtifactPaths(rootDir)) {
257
+ if (!fs.existsSync(path.join(rootDir, rel))) {
258
+ errors.push(`release artifact path missing: ${rel}`);
259
+ }
260
+ }
261
+
262
+ return {
263
+ ok: errors.length === 0,
264
+ version,
265
+ counts,
266
+ errors,
267
+ warnings,
268
+ mode: 'full',
269
+ };
270
+ }
271
+
272
+ function main() {
273
+ const jsonOut = process.argv.includes('--json');
274
+ const result = validateReleaseDocs();
275
+
276
+ if (!jsonOut) {
277
+ console.log('\n╔════════════════════════════════════════════════════════╗');
278
+ console.log('║ 📚 Release Docs Validation ║');
279
+ console.log('╚════════════════════════════════════════════════════════╝');
280
+ console.log(`\n📌 package.json version: v${result.version}`);
281
+ console.log(
282
+ `📊 counts: ${result.counts.agents} agents · ${result.counts.skills} skills · ${result.counts.mcps} MCP servers\n`,
283
+ );
284
+ }
285
+
286
+ if (result.warnings.length > 0 && !jsonOut) {
287
+ console.log('⚠️ Warnings:');
288
+ for (const w of result.warnings) console.log(` - ${w}`);
289
+ console.log();
290
+ }
291
+
292
+ if (!result.ok) {
293
+ if (jsonOut) {
294
+ console.log(JSON.stringify(result, null, 2));
295
+ } else {
296
+ console.error('❌ Release docs validation FAILED:\n');
297
+ for (const e of result.errors) console.error(` • ${e}`);
298
+ console.error('\nFix docs then run: npm run version:sync');
299
+ console.error('Or: npx @0xray/foundry docs-check\n');
300
+ }
301
+ process.exit(1);
302
+ }
303
+
304
+ if (jsonOut) {
305
+ console.log(JSON.stringify(result, null, 2));
306
+ } else {
307
+ console.log('✅ Release docs validation passed\n');
308
+ }
309
+ }
310
+
311
+ const isMain =
312
+ process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
313
+
314
+ if (isMain) {
315
+ main();
316
+ }