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.
Files changed (59) hide show
  1. package/.mcp.json +15 -55
  2. package/.xray/features.json +2 -2
  3. package/AGENTS-consumer.md +6 -6
  4. package/AGENTS.md +9 -9
  5. package/README.md +19 -19
  6. package/SKILLS.md +2 -2
  7. package/dist/AGENTS.md +9 -9
  8. package/dist/CHANGELOG.md +54 -2
  9. package/dist/README.md +19 -19
  10. package/dist/SKILLS.md +2 -2
  11. package/dist/cli/commands/foundry-mint-wear.d.ts +2 -0
  12. package/dist/cli/commands/foundry-mint-wear.js +14 -0
  13. package/dist/cli/commands/hermes-install.js +2 -0
  14. package/dist/cli/commands/openclaw-install.js +2 -0
  15. package/dist/cli/commands/opencode-install.js +2 -0
  16. package/dist/cli/index.js +10 -1
  17. package/dist/enforcement/enforcer-tools.d.ts +7 -0
  18. package/dist/enforcement/enforcer-tools.js +18 -109
  19. package/dist/integrations/grok/grok-cli.js +2 -0
  20. package/dist/integrations/hermes-agent/bridge.mjs +7 -0
  21. package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +4 -2
  22. package/dist/processors/implementations/version-compliance-processor.d.ts +3 -34
  23. package/dist/processors/implementations/version-compliance-processor.js +8 -135
  24. package/opencode.json +0 -8
  25. package/package.json +15 -14
  26. package/scripts/foundry/CHANGELOG.md +34 -0
  27. package/scripts/foundry/LICENSE +21 -0
  28. package/scripts/foundry/README.md +67 -0
  29. package/scripts/foundry/ci-monitor.mjs +115 -0
  30. package/scripts/foundry/cli.js +2 -0
  31. package/scripts/foundry/cli.mjs +55 -0
  32. package/scripts/foundry/docs-build.mjs +38 -0
  33. package/scripts/foundry/hooks.mjs +36 -0
  34. package/scripts/foundry/mill-root.mjs +62 -0
  35. package/scripts/foundry/mint-suit.cjs +313 -0
  36. package/scripts/foundry/mint.mjs +33 -0
  37. package/scripts/foundry/package.json +53 -0
  38. package/scripts/foundry/reconcile-version.mjs +150 -0
  39. package/scripts/foundry/release-gate.mjs +100 -0
  40. package/scripts/foundry/release.mjs +266 -0
  41. package/scripts/foundry/validate-release-docs.mjs +316 -0
  42. package/scripts/foundry/version-manager.mjs +444 -0
  43. package/scripts/node/ci-cd-auto-fix.cjs +12 -257
  44. package/scripts/node/consumer-install-smoke.mjs +57 -2
  45. package/scripts/node/enforce-version-compliance.sh +5 -20
  46. package/scripts/node/enforce-version-compliance.ts +13 -113
  47. package/scripts/node/foundry-shim.mjs +19 -0
  48. package/scripts/node/github-actions-monitor.cjs +13 -18
  49. package/scripts/node/postinstall.cjs +36 -1
  50. package/scripts/node/reconcile-version.mjs +3 -146
  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 -708
  55. package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +4 -2
  56. package/xray/features.json +2 -2
  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
@@ -1,1043 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Universal Version Management Script
5
- *
6
- * Automatically updates all version references across the xray v2 Framework
7
- * including framework versions, codex versions, and documentation consistency.
8
- * Ensures single source of truth for all version information.
9
- *
10
- * WHAT IT UPDATES:
11
- * - Framework version (1.14.1)
12
- * - Codex version and terms count
13
- * - Framework counts (agents, skills, MCP servers)
14
- * - Test counts in README
15
- *
16
- * WHAT IT DOESN'T UPDATE:
17
- * - Historical docs (docs/reflections, docs/archive)
18
- * - Test files with assertions
19
- *
20
- * @since 2026-01-15
21
- * @updated 2026-03-09 - Enhanced with documentation management, validation, and backup
22
- */
23
-
24
- import { createRequire } from 'module';
25
- const require = createRequire(import.meta.url);
26
-
27
- import fs from "fs";
28
- import path from "path";
29
- import { execSync } from "child_process";
30
- import { fileURLToPath } from "url";
31
-
32
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
33
- const rootDir = path.resolve(__dirname, "../..");
34
-
35
- function readPackageVersion() {
36
- try {
37
- const pkg = JSON.parse(fs.readFileSync(path.join(rootDir, "package.json"), "utf-8"));
38
- return pkg.version;
39
- } catch {
40
- return "0.0.0";
41
- }
42
- }
43
-
44
- /**
45
- * Auto-calculate framework counts from filesystem
46
- * This ensures counts are always accurate
47
- */
48
- /**
49
- * Count test files in a directory recursively
50
- */
51
- function findTestFiles(dir) {
52
- let count = 0;
53
- try {
54
- for (const entry of fs.readdirSync(dir)) {
55
- const full = path.join(dir, entry);
56
- const stat = fs.statSync(full);
57
- if (stat.isDirectory()) {
58
- count += findTestFiles(full);
59
- } else if (entry.endsWith(".test.ts") || entry.endsWith(".spec.ts")) {
60
- count++;
61
- }
62
- }
63
- } catch {}
64
- return count;
65
- }
66
-
67
- function calculateCounts() {
68
- const counts = {
69
- agents: 0,
70
- skills: 0,
71
- mcpServers: 0,
72
- tests: 0,
73
- };
74
-
75
- try {
76
- // Count agents from src/opencode/agents/ (source of truth for agent YAMLs)
77
- const srcAgentsDir = "src/opencode/agents";
78
- if (fs.existsSync(srcAgentsDir)) {
79
- counts.agents = fs.readdirSync(srcAgentsDir).filter(f =>
80
- f.endsWith(".yml")
81
- ).length;
82
- }
83
-
84
- // Count skills from src/skills (source of truth for framework skills)
85
- const srcSkillsDir = "src/skills";
86
- if (fs.existsSync(srcSkillsDir)) {
87
- counts.skills = fs.readdirSync(srcSkillsDir).filter(f => {
88
- const fullPath = path.join(srcSkillsDir, f);
89
- return fs.statSync(fullPath).isDirectory();
90
- }).length;
91
- }
92
-
93
- // Count MCP servers (root level + knowledge-skills)
94
- const mcpsDir = "src/mcps";
95
- if (fs.existsSync(mcpsDir)) {
96
- // Count root level servers
97
- const rootServers = fs.readdirSync(mcpsDir).filter(f =>
98
- f.endsWith(".server.ts") && !f.includes(".test.")
99
- ).length;
100
-
101
- // Count knowledge-skills servers
102
- const ksDir = path.join(mcpsDir, "knowledge-skills");
103
- let ksServers = 0;
104
- if (fs.existsSync(ksDir)) {
105
- ksServers = fs.readdirSync(ksDir).filter(f =>
106
- f.endsWith(".server.ts") && !f.includes(".test.")
107
- ).length;
108
- }
109
-
110
- counts.mcpServers = rootServers + ksServers;
111
- }
112
-
113
- // Count tests: prefer stored vitest count, then grep as fallback
114
- try {
115
- const vitestStatePath = ".opencode/test-count.json";
116
- if (fs.existsSync(vitestStatePath)) {
117
- const state = JSON.parse(fs.readFileSync(vitestStatePath, "utf8"));
118
- if (state.totalTests && state.totalTests > 100) {
119
- counts.tests = state.totalTests;
120
- }
121
- }
122
- } catch {}
123
-
124
- if (counts.tests === 0) {
125
- try {
126
- const out = execSync(
127
- "grep -rnE '\\b(it|test)\\s*\\(' src/__tests__/ src/mcps/ src/integrations/ --include='*.test.ts' --include='*.spec.ts' 2>/dev/null | wc -l",
128
- { encoding: "utf8", timeout: 15000 }
129
- );
130
- const count = parseInt(out.trim(), 10);
131
- if (count > 100) counts.tests = count;
132
- } catch {}
133
- }
134
- } catch (e) {
135
- process.stderr.write("⚠️ Could not calculate counts: " + e.message + "\n");
136
- }
137
-
138
- return counts;
139
- }
140
-
141
- // Auto-calculate counts
142
- const CALCULATED_COUNTS = calculateCounts();
143
-
144
- /**
145
- * Framework version information - SINGLE SOURCE OF TRUTH
146
- * Version manager updates this, then propagates to all files
147
- */
148
- const PACKAGE_VERSION = readPackageVersion();
149
-
150
- const OFFICIAL_VERSIONS = {
151
- // Framework version — SSOT: package.json
152
- framework: {
153
- version: PACKAGE_VERSION,
154
- displayName: "xray: Self-Healing AI Governance OS",
155
- lastUpdated: "2026-06-19",
156
- // Counts (auto-calculated, but can be overridden)
157
- ...CALCULATED_COUNTS,
158
- },
159
-
160
- // Codex version
161
- codex: {
162
- version: "v1.7.5",
163
- termsCount: 60, // Total terms defined (including new governance terms 46-60)
164
- termsDefined: 60, // All terms in codex.json
165
- termsTarget: 60, // Future goal (now achieved)
166
- lastUpdated: "2026-03-23",
167
- },
168
-
169
- // External dependencies
170
- dependencies: {
171
- opencode: "2.14.0",
172
- },
173
- };
174
-
175
- process.stdout.write("📊 Auto-calculated counts:\n");
176
- process.stdout.write(" Agents: " + OFFICIAL_VERSIONS.framework.agents + "\n");
177
- process.stdout.write(" Skills: " + OFFICIAL_VERSIONS.framework.skills + "\n");
178
- process.stdout.write(" MCP Servers: " + OFFICIAL_VERSIONS.framework.mcpServers + "\n");
179
- process.stdout.write(" Tests: " + OFFICIAL_VERSIONS.framework.tests + "\n");
180
- process.stdout.write(" Codex Terms: " + OFFICIAL_VERSIONS.codex.termsCount + "\n");
181
- process.stdout.write("\n");
182
-
183
- // Simple recursive file finder - necessary for explaining complex directory traversal logic
184
- function findFiles(
185
- dir,
186
- extensions,
187
- ignoreDirs = [
188
- "node_modules", ".git", "dist", "build", "temp", "test-install",
189
- "ci-deploy", "test-config",
190
- "docs/reflections", "docs/archive", "docs/user-guide", "docs/pipeline-trees",
191
- "docs/superseded", "docs/commands", "docs/advanced", "docs/session-summary",
192
- "docs-site", "scripts/mjs", "scripts/test", "scripts/integrations",
193
- ".opencode/state", // Runtime state data
194
- "logs", "reports", // Generated logs/reports
195
-
196
- ],
197
- ignoreFiles = [
198
- // npm/package files
199
- "package-lock.json", ".opencode.json",
200
- // Test records - keep original
201
- "SIMULATION_TEST_RESULTS.md",
202
- "TEST_INVENTORY.md",
203
- // Version history - don't update
204
- "CHANGELOG.md", "CHANGELOG-v1.2.0.md",
205
- // Historical docs
206
- "DEEP_REFLECTION_*.md",
207
- "KERNEL_*.md",
208
- "REFACTORING_LOG.md",
209
- "stringray-reflection.md",
210
- "SYSTEM_BUG_INVESTIGATION.md",
211
- "TEST_*.md",
212
- "tweet-*.md",
213
- // Files with old agent names in filename (rename manually if needed)
214
- "universal-librarian-consultation.ts",
215
- "librarian-agents-updater.ts",
216
- ],
217
- ) {
218
- const files = [];
219
-
220
- function walk(currentDir) {
221
- const items = fs.readdirSync(currentDir);
222
-
223
- for (const item of items) {
224
- const fullPath = path.join(currentDir, item);
225
- const stat = fs.statSync(fullPath);
226
-
227
- if (stat.isDirectory()) {
228
- // Check both exact name and partial path match
229
- const shouldIgnore = ignoreDirs.some(ignored =>
230
- item === ignored || fullPath.includes(ignored)
231
- );
232
- if (!shouldIgnore) {
233
- walk(fullPath);
234
- }
235
- } else {
236
- const ext = path.extname(item);
237
- const basename = path.basename(item);
238
- // Skip ignored files and check extension
239
- if (!ignoreFiles.includes(basename) && extensions.includes(ext)) {
240
- files.push(fullPath);
241
- }
242
- }
243
- }
244
- }
245
-
246
- walk(dir);
247
- return files;
248
- }
249
-
250
- // Comprehensive update patterns for all version types
251
- const UPDATE_PATTERNS = [
252
- // === FRAMEWORK VERSION UPDATES ===
253
- {
254
- pattern: /"version": "[0-9]+\.[0-9]+\.[0-9]+"/g,
255
- replacement: `"version": "${OFFICIAL_VERSIONS.framework.version}"`,
256
- },
257
- // MCP server version in server definition objects
258
- {
259
- pattern: /version: "[0-9]+\.[0-9]+\.[0-9]+"/g,
260
- replacement: `version: "${OFFICIAL_VERSIONS.framework.version}"`,
261
- },
262
- // MCP server version in name+version objects (e.g., { name: "xxx", version: "x.x.x" })
263
- {
264
- pattern: /name: "[^"]+",\s*version: "[0-9]+\.[0-9]+\.[0-9]+"/g,
265
- replacement: (match) => {
266
- const nameMatch = match.match(/name: "([^"]+)"/);
267
- const name = nameMatch ? nameMatch[1] : 'unknown';
268
- return `name: "${name}", version: "${OFFICIAL_VERSIONS.framework.version}"`;
269
- },
270
- },
271
- // features-config default version
272
- {
273
- pattern: /version: "[0-9]+\.[0-9]+\.[0-9]+",\s*$/gm,
274
- replacement: `version: "${OFFICIAL_VERSIONS.framework.version}",`,
275
- },
276
- {
277
- pattern: /xray Framework v[0-9]+\.[0-9]+\.[0-9]+/g,
278
- replacement: OFFICIAL_VERSIONS.framework.displayName,
279
- },
280
- {
281
- pattern: /!\[Version\]\(https:\/\/img\.shields\.io\/badge\/version-[0-9]+\.[0-9]+\.[0-9]+/g,
282
- replacement: `![Version](https://img.shields.io/badge/version-${OFFICIAL_VERSIONS.framework.version}`,
283
- },
284
- {
285
- pattern: /- Framework Version: [0-9]+\.[0-9]+\.[0-9]+/g,
286
- replacement: `- Framework Version: ${OFFICIAL_VERSIONS.framework.version}`,
287
- },
288
- // CLI Version pattern
289
- {
290
- pattern: /\.version\("[0-9]+\.[0-9]+\.[0-9]+"\)/g,
291
- replacement: `.version("${OFFICIAL_VERSIONS.framework.version}")`,
292
- },
293
- {
294
- pattern: /Framework Version: xray v[0-9]+\.[0-9]+\.[0-9]+/g,
295
- replacement: `Framework Version: ${OFFICIAL_VERSIONS.framework.displayName}`,
296
- },
297
-
298
- // Simple version patterns
299
- {
300
- pattern: /xray v[0-9]+\.[0-9]+\.[0-9]+/g,
301
- replacement: OFFICIAL_VERSIONS.framework.displayName,
302
- },
303
- // Standalone version in docs (v1.15.6, v1.15.6 patterns)
304
- {
305
- pattern: /v1\.14\.[0-9]+/g,
306
- replacement: `v${OFFICIAL_VERSIONS.framework.version}`,
307
- },
308
- {
309
- pattern: /v1\.9\.[0-9]+/g,
310
- replacement: `v${OFFICIAL_VERSIONS.framework.version}`,
311
- },
312
-
313
- // Pre-commit introspection patterns
314
- {
315
- pattern: /xray [0-9]+\.[0-9]+\.[0-9]+ - Pre-commit Introspection/g,
316
- replacement: `${OFFICIAL_VERSIONS.framework.displayName} - Pre-commit Introspection`,
317
- },
318
- {
319
- pattern: /🔬 xray [0-9]+\.[0-9]+\.[0-9]+ - Pre-commit Introspection/g,
320
- replacement: `🔬 ${OFFICIAL_VERSIONS.framework.displayName} - Pre-commit Introspection`,
321
- },
322
-
323
- // Codex version patterns
324
- {
325
- pattern: /"version":"[0-9]+\.[0-9]+\.[0-9]+"/g,
326
- replacement: `"version":"${OFFICIAL_VERSIONS.framework.version}"`,
327
- },
328
- // Codex-specific version (v1.x.x format)
329
- {
330
- pattern: /"version":\s*"v[0-9]+\.[0-9]+\.[0-9]+"/g,
331
- replacement: `"version": "${OFFICIAL_VERSIONS.codex.version}"`,
332
- },
333
- {
334
- pattern: /version:\s*"v[0-9]+\.[0-9]+\.[0-9]+"/g,
335
- replacement: `version: "${OFFICIAL_VERSIONS.codex.version}"`,
336
- },
337
- // codex_version field
338
- {
339
- pattern: /"codex_version":\s*"v[0-9]+\.[0-9]+\.[0-9]+"/g,
340
- replacement: `"codex_version": "${OFFICIAL_VERSIONS.codex.version}"`,
341
- },
342
-
343
- // === BADGE AND COUNT PATTERNS ===
344
- // Test count in docs badge (e.g., tests-2500-brightgreen)
345
- {
346
- pattern: /tests-[0-9]+(?=-brightgreen)/g,
347
- replacement: `tests-${OFFICIAL_VERSIONS.framework.tests}`,
348
- },
349
- // Test count in npm badge (e.g., tests-2500%20passed-brightgreen)
350
- {
351
- pattern: /tests-[0-9,]+%20passed/g,
352
- replacement: `tests-${OFFICIAL_VERSIONS.framework.tests}%20passed`,
353
- },
354
- // Test count in prose (e.g., "2,2500 Tests" or "2500 Tests" but NOT in badge URLs)
355
- {
356
- pattern: /(\*\s*✅\s*)([0-9]{1,3},?[0-9]{3})(\s*Tests)/g,
357
- replacement: (match, p1, p2, p3) => {
358
- return `${p1}${OFFICIAL_VERSIONS.framework.tests}${p3}`;
359
- },
360
- },
361
- // Test count in feature bullets (e.g., "✅ 2500 Tests")
362
- {
363
- pattern: /[0-9]+ Tests/g,
364
- replacement: `${OFFICIAL_VERSIONS.framework.tests} Tests`,
365
- },
366
- // Test count in config tree (e.g., "2500 tests")
367
- {
368
- pattern: /[0-9]+ tests/g,
369
- replacement: `${OFFICIAL_VERSIONS.framework.tests} tests`,
370
- },
371
- // MCP server count (e.g., "38 MCP" or "40 MCP")
372
- {
373
- pattern: /[0-9]+ MCP servers/gi,
374
- replacement: `${OFFICIAL_VERSIONS.framework.mcpServers} MCP servers`,
375
- },
376
- {
377
- pattern: /[0-9]+ MCP Servers/g,
378
- replacement: `${OFFICIAL_VERSIONS.framework.mcpServers} MCP Servers`,
379
- },
380
- // Agent count
381
- {
382
- pattern: /[0-9]+ autonomous agents/gi,
383
- replacement: `${OFFICIAL_VERSIONS.framework.agents} autonomous agents`,
384
- },
385
- {
386
- pattern: /[0-9]+ autonomous Agents/g,
387
- replacement: `${OFFICIAL_VERSIONS.framework.agents} autonomous Agents`,
388
- },
389
- {
390
- pattern: /[0-9]+ Specialized Agents/g,
391
- replacement: `${OFFICIAL_VERSIONS.framework.agents} Specialized Agents`,
392
- },
393
- {
394
- pattern: /[0-9]+ agent configurations/g,
395
- replacement: `${OFFICIAL_VERSIONS.framework.agents} agent configurations`,
396
- },
397
- {
398
- pattern: /xray AI v[0-9]+\.[0-9]+\.[0-9]+/g,
399
- replacement: `xray AI v${OFFICIAL_VERSIONS.framework.version}`,
400
- },
401
- // Footer bare version (e.g., "**Version**: 3.1.0")
402
- {
403
- pattern: /\*\*Version\*\*:\s*[0-9]+\.[0-9]+\.[0-9]+/g,
404
- replacement: `**Version**: ${OFFICIAL_VERSIONS.framework.version}`,
405
- },
406
- // "v1.22.28" and other specific old version references in docs
407
- {
408
- pattern: /v1\.15\.0/g,
409
- replacement: `v${OFFICIAL_VERSIONS.framework.version}`,
410
- },
411
- {
412
- pattern: /v1\.22\.13/g,
413
- replacement: `v${OFFICIAL_VERSIONS.framework.version}`,
414
- },
415
- // Codex terms count
416
- {
417
- pattern: /[0-9]+ codex terms/gi,
418
- replacement: `${OFFICIAL_VERSIONS.codex.termsCount} codex terms`,
419
- },
420
- {
421
- pattern: /[0-9]+ codex rules/gi,
422
- replacement: `${OFFICIAL_VERSIONS.codex.termsCount} codex rules`,
423
- },
424
-
425
- ];
426
-
427
- const BASH_VERSION_PATTERNS = [];
428
-
429
- // Backup management
430
- let backupCreated = false;
431
- let backupDir = null;
432
-
433
- async function createBackup() {
434
- try {
435
- const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
436
- backupDir = `backups/version-manager-backup-${timestamp}`;
437
-
438
- // Create backup directory
439
- fs.mkdirSync(backupDir, { recursive: true });
440
-
441
- // Create a changelog file
442
- const changelog = createChangelog();
443
- fs.writeFileSync(`${backupDir}/CHANGELOG.md`, changelog);
444
-
445
- console.log(`✅ Backup created: ${backupDir}`);
446
- backupCreated = true;
447
-
448
- return backupDir;
449
- } catch (error) {
450
- console.error(`❌ Error creating backup:`, error.message);
451
- return null;
452
- }
453
- }
454
-
455
- // Changelog management
456
- const versionChanges = [];
457
-
458
- function addToChangelog(type, file) {
459
- const timestamp = new Date().toISOString();
460
- versionChanges.push({
461
- timestamp,
462
- type,
463
- file,
464
- });
465
- }
466
-
467
- function createChangelog() {
468
- const header = `# Version Management Changelog\n\n`;
469
- const date = new Date().toISOString().split('T')[0];
470
- const info = `Generated: ${date}\n`;
471
- const divider = "=".repeat(60) + "\n\n";
472
- const summary = `## Summary\n\n`;
473
- const summaryItems = [];
474
-
475
- // Count changes by type
476
- const typeCounts = {};
477
- versionChanges.forEach(change => {
478
- typeCounts[change.type] = (typeCounts[change.type] || 0) + 1;
479
- });
480
-
481
- Object.entries(typeCounts).forEach(([type, count]) => {
482
- summaryItems.push(`- ${count} files updated (${type})`);
483
- });
484
-
485
- const summaryText = summaryItems.join('\n');
486
-
487
- // Detailed changes
488
- const details = `## Detailed Changes\n\n`;
489
- const changeEntries = versionChanges.map(change => {
490
- const time = new Date(change.timestamp).toLocaleTimeString();
491
- return `- **[${time}]** (${change.type}): ${change.file}`;
492
- }).join('\n');
493
-
494
- return `${header}${info}${divider}${summary}${summaryText}\n${details}${changeEntries}\n`;
495
- }
496
-
497
- // Validation function
498
- async function validateConsistency() {
499
- console.log("\n🔍 Phase 6: Validating version consistency...");
500
-
501
- let validationErrors = [];
502
- let warnings = [];
503
-
504
- // 1. Check codex.json has exactly 60 terms
505
- const { resolveConfigPath } = require("../helpers/resolve-config-path.cjs");
506
- const codexJsonPath = resolveConfigPath("codex.json") || "src/opencode/codex.codex";
507
- if (fs.existsSync(codexJsonPath)) {
508
- try {
509
- const codexContent = JSON.parse(fs.readFileSync(codexJsonPath, "utf8"));
510
- // Check if codexContent.terms is an object (dictionary) with entries
511
- const termCount = Object.keys(codexContent.terms || {}).length;
512
- if (termCount !== 60) {
513
- validationErrors.push(
514
- `codex.json should have 60 terms, but has ${termCount}`
515
- );
516
- }
517
- } catch (e) {
518
- validationErrors.push(`Error parsing codex.json: ${e.message}`);
519
- }
520
- }
521
-
522
- // 2. Check codex.codex has correct terms count
523
- const codexCodexPath = "src/opencode/codex.codex";
524
- if (fs.existsSync(codexCodexPath)) {
525
- try {
526
- const codexContent = JSON.parse(fs.readFileSync(codexCodexPath, "utf8"));
527
- // Check if terms is an array with 60 elements
528
- if (!Array.isArray(codexContent.terms)) {
529
- warnings.push(
530
- `codex.codex terms should be an array, but is ${typeof codexContent.terms}`
531
- );
532
- } else if (codexContent.terms.length !== 60) {
533
- warnings.push(
534
- `codex.codex terms should have 60 elements, but has ${codexContent.terms.length}`
535
- );
536
- }
537
- // Version can be framework version or codex version - both are acceptable
538
- if (codexContent.version) {
539
- warnings.push(
540
- `codex.codex version is ${codexContent.version} (framework version)`
541
- );
542
- }
543
- } catch (e) {
544
- validationErrors.push(`Error parsing codex.codex: ${e.message}`);
545
- }
546
- }
547
-
548
- // 3. Check README.md has correct counts
549
- const readmePath = "README.md";
550
- if (fs.existsSync(readmePath)) {
551
- const readmeContent = fs.readFileSync(readmePath, "utf8");
552
- if (!readmeContent.includes("60 terms")) {
553
- validationErrors.push(
554
- "README.md should reference '60 terms' but doesn't"
555
- );
556
- }
557
- if (!readmeContent.includes("1.7.5")) {
558
- warnings.push("README.md should reference framework version 1.7.5");
559
- }
560
- }
561
-
562
- // 4. Check AGENTS.md has correct information
563
- const agentsPath = "AGENTS.md";
564
- if (fs.existsSync(agentsPath)) {
565
- const agentsContent = fs.readFileSync(agentsPath, "utf8");
566
- if (!agentsContent.includes("60 terms")) {
567
- validationErrors.push(
568
- "AGENTS.md should reference '60 terms' but doesn't"
569
- );
570
- }
571
- if (!agentsContent.includes("1.7.5")) {
572
- warnings.push("AGENTS.md should reference framework version 1.7.5");
573
- }
574
- }
575
-
576
- // 5. Check agent counts in MCP servers match actual count (from CALCULATED_COUNTS)
577
- const mcpServerFiles = ["src/mcps/framework-help.server.ts"];
578
- for (const mcpFile of mcpServerFiles) {
579
- if (fs.existsSync(mcpFile)) {
580
- const content = fs.readFileSync(mcpFile, "utf8");
581
- const match = content.match(/\*\*(\d+)\s+Agents?:\*\*/);
582
- if (match) {
583
- const reportedCount = parseInt(match[1]);
584
- if (reportedCount !== CALCULATED_COUNTS.agents) {
585
- validationErrors.push(
586
- `${mcpFile} reports ${reportedCount} agents but src/opencode/agents/ has ${CALCULATED_COUNTS.agents}`
587
- );
588
- }
589
- }
590
- }
591
- }
592
-
593
- // 7. Check that no files reference old versions
594
- const extensions = [".ts", ".js", ".md", ".json", ".txt", ".sh"];
595
- const files = findFiles(".", extensions);
596
- let oldVersionCount = 0;
597
-
598
- for (const file of files) {
599
- try {
600
- const content = fs.readFileSync(file, "utf8");
601
-
602
- // Check for old codex version (v1.2.25 or earlier)
603
- if (/version:\s*"v1\.[01]\./.test(content)) {
604
- oldVersionCount++;
605
- warnings.push(`${file} references old codex version`);
606
- }
607
-
608
- // Check for old term counts (less than 60)
609
- if (/\((\d{1,2})\)\s*terms/.test(content) && parseInt(RegExp.$1) < 60) {
610
- warnings.push(`${file} references term count < 60`);
611
- }
612
-
613
- // Check for old framework version (< 1.7.5)
614
- if (/version:\s*"1\.[0-6]\./.test(content)) {
615
- warnings.push(`${file} references old framework version`);
616
- }
617
- } catch (e) {
618
- // Skip files that can't be read
619
- }
620
- }
621
-
622
- if (oldVersionCount > 0) {
623
- warnings.push(`Found ${oldVersionCount} files with old version references`);
624
- }
625
-
626
- // 6. Summary
627
- console.log("\n" + "=".repeat(60));
628
- console.log("Validation Summary:");
629
- console.log("=".repeat(60));
630
-
631
- if (validationErrors.length > 0) {
632
- console.log("\n❌ Errors found:");
633
- validationErrors.forEach(error => console.log(` - ${error}`));
634
- } else {
635
- console.log("\n✅ No errors found");
636
- }
637
-
638
- if (warnings.length > 0) {
639
- console.log("\n⚠️ Warnings:");
640
- warnings.forEach(warning => console.log(` - ${warning}`));
641
- }
642
-
643
- console.log("\n" + "=".repeat(60));
644
-
645
- // Return validation result
646
- return {
647
- valid: validationErrors.length === 0,
648
- errors: validationErrors,
649
- warnings: warnings,
650
- };
651
- }
652
-
653
- async function standardizeVersions() {
654
- console.warn("\n⚠️ universal-version-manager.js is DEPRECATED for releases.");
655
- console.warn(" Use: npm run release:patch or npm run version:sync");
656
- console.warn(" (version-manager.mjs --artifacts-only). Mass JSON version replace is disabled.\n");
657
- return;
658
- console.log("🔧 Starting Universal Version Standardization");
659
- console.log(`📋 Framework: ${OFFICIAL_VERSIONS.framework.displayName}`);
660
- console.log(
661
- `📋 Codex: ${OFFICIAL_VERSIONS.codex.version} (${OFFICIAL_VERSIONS.codex.termsCount} terms)`,
662
- );
663
- console.log(
664
- `📋 OpenCode: v${OFFICIAL_VERSIONS.dependencies.opencode}`,
665
- );
666
- console.log("=".repeat(60));
667
-
668
- // Phase 0: Create backup before making changes
669
- console.log("\n💾 Phase 0: Creating backup of all modified files...");
670
- await createBackup();
671
-
672
- // Phase 1: Update critical config files (source in src/opencode/)
673
- console.log("\n📁 Phase 1: Updating configuration files...");
674
- const { resolveConfigPath: rcp } = require("../helpers/resolve-config-path.cjs");
675
- const codexPath = rcp("codex.json") || "src/opencode/codex.codex";
676
- const featuresPath = rcp("features.json") || "src/opencode/features.json";
677
- const criticalConfigFiles = [
678
- codexPath, // Codex config (source)
679
- "src/opencode/codex.codex", // Main codex (source)
680
- "src/opencode/config.json", // Framework config (source)
681
- featuresPath, // Feature flags (source)
682
- ];
683
-
684
- let configFilesUpdated = 0;
685
- for (const configFile of criticalConfigFiles) {
686
- if (fs.existsSync(configFile)) {
687
- try {
688
- const content = fs.readFileSync(configFile, "utf8");
689
- let updatedContent = content;
690
- let fileChanged = false;
691
-
692
- // Apply all patterns to config files
693
- for (const { pattern, replacement } of UPDATE_PATTERNS) {
694
- const matches = content.match(pattern);
695
- if (matches) {
696
- updatedContent = updatedContent.replace(pattern, replacement);
697
- fileChanged = true;
698
- }
699
- }
700
-
701
- if (fileChanged) {
702
- fs.writeFileSync(configFile, updatedContent, "utf8");
703
- console.log(`✅ Updated: ${configFile}`);
704
- configFilesUpdated++;
705
- addToChangelog("config", configFile);
706
- }
707
- } catch (error) {
708
- console.error(`❌ Error processing ${configFile}:`, error.message);
709
- }
710
- } else {
711
- console.log(`⚠️ Not found: ${configFile}`);
712
- }
713
- }
714
-
715
- if (configFilesUpdated > 0) {
716
- console.log(`✅ Updated ${configFilesUpdated} critical config files`);
717
- }
718
-
719
- // Phase 2: Update documentation files (AGENTS.md, etc.)
720
- console.log("\n📁 Phase 2: Updating documentation files...");
721
- const documentationFiles = [
722
- "README.md",
723
- "AGENTS.md",
724
- "src/opencode/AGENTS-consumer.md",
725
- rcp("agents_template.md") || "src/opencode/agents_template.md",
726
- "docs/reference/templates/agents_template.md",
727
- "docs/reference/templates/master-agent-template.md",
728
- "docs/reference/templates/agent-template-dev.md",
729
- "docs/README.md",
730
- ];
731
-
732
- let docsUpdated = 0;
733
- let userGuideFilesUpdated = 0;
734
- let historicalUpdated = 0;
735
- for (const docFile of documentationFiles) {
736
- if (fs.existsSync(docFile)) {
737
- try {
738
- const content = fs.readFileSync(docFile, "utf8");
739
- let updatedContent = content;
740
- let fileChanged = false;
741
-
742
- // Apply all version patterns
743
- for (const { pattern, replacement } of UPDATE_PATTERNS) {
744
- const matches = content.match(pattern);
745
- if (matches) {
746
- updatedContent = updatedContent.replace(pattern, replacement);
747
- fileChanged = true;
748
- }
749
- }
750
-
751
- if (fileChanged) {
752
- fs.writeFileSync(docFile, updatedContent, "utf8");
753
- console.log(`✅ Updated: ${docFile}`);
754
- docsUpdated++;
755
- addToChangelog("documentation", docFile);
756
- } else {
757
- console.log(`⏭️ No changes needed in: ${docFile}`);
758
- }
759
- } catch (error) {
760
- console.error(`❌ Error processing ${docFile}:`, error.message);
761
- }
762
- } else {
763
- console.log(`⚠️ Not found: ${docFile}`);
764
- }
765
- }
766
-
767
- if (docsUpdated > 0) {
768
- console.log(`✅ Updated ${docsUpdated} documentation files`);
769
- }
770
-
771
- // Phase 3: Update user guide files (optional - skip if dir doesn't exist)
772
- if (fs.existsSync("docs/user-guide")) {
773
- console.log("\n📁 Phase 3: Updating user guide files...");
774
- const userGuideFiles = findFiles("docs/user-guide", [".md"]);
775
-
776
- for (const file of userGuideFiles) {
777
- try {
778
- const content = fs.readFileSync(file, "utf8");
779
- let updatedContent = content;
780
- let fileChanged = false;
781
-
782
- // Apply all version patterns
783
- for (const { pattern, replacement } of UPDATE_PATTERNS) {
784
- const matches = content.match(pattern);
785
- if (matches) {
786
- updatedContent = updatedContent.replace(pattern, replacement);
787
- fileChanged = true;
788
- }
789
- }
790
-
791
- if (fileChanged) {
792
- fs.writeFileSync(file, updatedContent, "utf8");
793
- console.log(`✅ Updated: ${file}`);
794
- userGuideFilesUpdated++;
795
- addToChangelog("docs", file);
796
- }
797
- } catch (e) {
798
- console.log(`⚠️ Error updating ${file}: ${e.message}`);
799
- }
800
- }
801
-
802
- if (userGuideFilesUpdated > 0) {
803
- console.log(`✅ Updated ${userGuideFilesUpdated} user guide files`);
804
- }
805
- }
806
-
807
- // Phase 4: Update historical docs (selective updates for consistency)
808
- console.log("\n📁 Phase 4: Updating historical documentation...");
809
- const historicalFiles = findFiles("docs", [".md"], [], [
810
- "reflections",
811
- "archive",
812
- "user-guide",
813
- "pipeline-trees",
814
- "superseded",
815
- "commands",
816
- "advanced",
817
- "session-summary",
818
- ]);
819
-
820
- for (const file of historicalFiles) {
821
- try {
822
- const content = fs.readFileSync(file, "utf8");
823
- let updatedContent = content;
824
- let fileChanged = false;
825
-
826
- // Apply all version patterns (skip framework counts for historical docs)
827
- const countPatterns = UPDATE_PATTERNS.filter(p =>
828
- p.pattern.toString().includes("termsCount") ||
829
- p.pattern.toString().includes("framework.agents")
830
- );
831
- const versionPatterns = UPDATE_PATTERNS.filter(p =>
832
- !p.pattern.toString().includes("termsCount") &&
833
- !p.pattern.toString().includes("framework.agents")
834
- );
835
-
836
- for (const { pattern, replacement } of versionPatterns) {
837
- const matches = content.match(pattern);
838
- if (matches) {
839
- updatedContent = updatedContent.replace(pattern, replacement);
840
- fileChanged = true;
841
- }
842
- }
843
-
844
- if (fileChanged) {
845
- fs.writeFileSync(file, updatedContent, "utf8");
846
- console.log(`✅ Updated (historical): ${file}`);
847
- historicalUpdated++;
848
- addToChangelog("historical", file);
849
- }
850
- } catch (error) {
851
- console.error(`❌ Error processing ${file}:`, error.message);
852
- }
853
- }
854
-
855
- if (historicalUpdated > 0) {
856
- console.log(`✅ Updated ${historicalUpdated} historical documentation files`);
857
- }
858
-
859
- // Phase 5: Find all other files that might contain version references
860
- console.log("\n📁 Phase 5: Scanning all other files...");
861
- const extensions = [".ts", ".js", ".md", ".json", ".txt", ".sh"];
862
- const files = findFiles(".", extensions);
863
-
864
- let totalFilesUpdated = 0;
865
- let totalChanges = 0;
866
-
867
- // Additional safety: protected files that should never be modified
868
- // Note: Only protect root package.json (npm version manages this)
869
- // .opencode/package.json should be updated by this script
870
- const PROTECTED_FILES = [
871
- "package-lock.json",
872
- "package.json", // Only root package.json (matched by exact path, not subdirs)
873
- ];
874
-
875
- const PROTECTED_PATHS = [
876
- ".opencode/test-count.json",
877
- ];
878
-
879
- // Test files with version assertions - these contain expected version values for testing
880
- // and should NOT have their assertions updated by this script
881
- const TEST_ASSERTION_FILES = [
882
- "context-loader.test.ts",
883
- "codex-parser.test.ts",
884
- "json-codex-integration.test.ts",
885
- "boot-orchestrator.integration.test.ts",
886
- ];
887
-
888
- for (const file of files) {
889
- // Skip protected files as an additional safety measure
890
- // Use path.basename to match filename only, not full path
891
- const basename = path.basename(file);
892
- const normalizedPath = path.normalize(file);
893
-
894
- const isProtected = PROTECTED_FILES.some(protectedFile => {
895
- if (protectedFile === "package.json") {
896
- return normalizedPath === "package.json";
897
- }
898
- return basename === protectedFile;
899
- }) || PROTECTED_PATHS.some(p => normalizedPath === path.normalize(p));
900
-
901
- if (isProtected) {
902
- console.log(`⏭️ Skipping protected file: ${file}`);
903
- continue;
904
- }
905
-
906
- // Skip test assertion files - these contain expected version values for testing
907
- // and should NOT have their assertions updated by this script
908
- const isTestAssertionFile = TEST_ASSERTION_FILES.includes(basename);
909
- if (isTestAssertionFile) {
910
- console.log(`⏭️ Skipping test assertion file: ${file}`);
911
- continue;
912
- }
913
-
914
- try {
915
- const content = fs.readFileSync(file, "utf8");
916
- let updatedContent = content;
917
- let fileChanged = false;
918
-
919
- // Apply all version update patterns
920
- for (const { pattern, replacement } of UPDATE_PATTERNS) {
921
- const matches = content.match(pattern);
922
- if (matches) {
923
- updatedContent = updatedContent.replace(pattern, replacement);
924
- totalChanges += matches.length;
925
- fileChanged = true;
926
- }
927
- }
928
-
929
- // Apply bash script version patterns
930
- for (const { pattern, replacement } of BASH_VERSION_PATTERNS) {
931
- const matches = content.match(pattern);
932
- if (matches) {
933
- updatedContent = updatedContent.replace(pattern, replacement);
934
- totalChanges += matches.length;
935
- fileChanged = true;
936
- }
937
- }
938
-
939
- // Write back if changed
940
- if (fileChanged) {
941
- fs.writeFileSync(file, updatedContent, "utf8");
942
- console.log(`✅ Updated: ${file}`);
943
- totalFilesUpdated++;
944
- }
945
- } catch (error) {
946
- console.error(`❌ Error processing ${file}:`, error.message);
947
- }
948
- }
949
-
950
- console.log("\n" + "=".repeat(60));
951
- console.log("🎉 Universal Version Standardization Complete!");
952
- console.log(`📊 Summary:`);
953
- console.log(` Config Files Updated: ${configFilesUpdated}`);
954
- console.log(` Documentation Files Updated: ${docsUpdated}`);
955
- console.log(` User Guide Files Updated: ${userGuideFilesUpdated}`);
956
- console.log(` Historical Files Updated: ${historicalUpdated}`);
957
- console.log(` Other Files Updated: ${totalFilesUpdated}`);
958
- console.log(` Total Changes: ${totalChanges + configFilesUpdated + docsUpdated + userGuideFilesUpdated + historicalUpdated}`);
959
- console.log(` Framework Version: ${OFFICIAL_VERSIONS.framework.version}`);
960
- console.log(
961
- ` Codex Version: ${OFFICIAL_VERSIONS.codex.version} (${OFFICIAL_VERSIONS.codex.termsCount} terms)`,
962
- );
963
- console.log(` Dependencies Updated: ✅`);
964
- console.log(` Last Updated: ${OFFICIAL_VERSIONS.framework.lastUpdated}`);
965
- console.log(` Backup Created: ${backupCreated ? '✅' : '❌'}`);
966
-
967
- // Show rollback information
968
- if (backupCreated && backupDir) {
969
- console.log(`\n💾 Backup location: ${backupDir}`);
970
- console.log("To rollback changes, run: node scripts/rollback.js");
971
- }
972
-
973
- // Run validation
974
- const validation = await validateConsistency();
975
-
976
- console.log("\n" + "=".repeat(60));
977
-
978
- // Exit with appropriate code
979
- if (!validation.valid) {
980
- console.log("\n⚠️ Validation failed. Please review errors above.");
981
- process.exit(1);
982
- } else if (validation.warnings.length > 0) {
983
- console.log("\n✅ Validation passed with warnings.");
984
- console.log("⚠️ Please review warnings above.");
985
- process.exit(0);
986
- } else {
987
- console.log("\n✅ All validations passed!");
988
- console.log("\n💡 To update versions in the future:");
989
- console.log(" 1. Edit OFFICIAL_VERSIONS object in this script");
990
- console.log(" 2. Run: node scripts/standardize-codex-versions.js");
991
- console.log(" 3. Commit the changes");
992
- process.exit(0);
993
- }
994
- }
995
-
996
- // Run the standardization
997
- standardizeVersions().catch(console.error);
998
-
999
- /**
1000
- * Version Manager Enhancements (v2.0.0)
1001
- * =====================================
1002
- *
1003
- * ✅ COMPLETED FEATURES:
1004
- * - Comprehensive documentation management (AGENTS.md, AGENTS-consumer.md, etc.)
1005
- * - File categorization (critical, documentation, historical, test assertions)
1006
- * - Validation step for consistency checking
1007
- * - Changelog generation
1008
- * - Backup creation before changes
1009
- * - Rollback capability
1010
- *
1011
- * 🔄 NEXT STEPS:
1012
- * - Create rollback.js script for restoring from backup
1013
- * - Add automated tests for version consistency
1014
- * - Implement incremental updates (only changed files)
1015
- * - Add caching for unchanged files
1016
- * - Parallel processing for large file sets
1017
- *
1018
- * 📋 FILE CATEGORIES:
1019
- * - Critical: src/opencode/codex.codex, etc.
1020
- * - Documentation: AGENTS.md, AGENTS-consumer.md, docs/*.md
1021
- * - Historical: docs/reflections/, docs/archive/
1022
- * - Test Assertions: context-loader.test.ts, codex-parser.test.ts
1023
- *
1024
- * 🛡️ PROTECTED FILES:
1025
- * - package-lock.json (npm manages this)
1026
- * - package.json (root only)
1027
- *
1028
- * 📊 VALIDATION CHECKS:
1029
- * - codex.json has exactly 60 terms
1030
- * - codex.codex has version v1.3.0 and 60 terms
1031
- * - README.md has correct counts
1032
- * - AGENTS.md has correct information
1033
- * - No files reference old versions
1034
- *
1035
- * 💾 BACKUP LOCATION:
1036
- * - Created in 'backups/version-manager-backup-[timestamp]/'
1037
- * - Includes changelog.md with all changes
1038
- *
1039
- * 📝 TO ROLLBACK:
1040
- * - node scripts/rollback.js [backup-id]
1041
- * - Requires backup to exist
1042
- */
1043
-