#!/usr/bin/env node /* * Copyright 2025 John G Stroh * * Licensed under the European Union Public Licence, Version 1.2 (EUPL-1.2); * you may not use this file except in compliance with the Licence. * * You may obtain a copy of the Licence at: * https://interoperable-europe.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. */ // Relicense Apache 2.0 → EUPL-1.2 across Tractatus source files. // Phase B of PLAN_LICENSE_STANDARDISATION_EUPL12_20260419. // // Usage: // node scripts/relicense-apache-to-eupl.js # Apply changes // node scripts/relicense-apache-to-eupl.js --dry-run # Show changes without writing const fs = require('fs'); const path = require('path'); const DRY_RUN = process.argv.includes('--dry-run'); const REPO_ROOT = path.resolve(__dirname, '..'); // --- Variant 1: Full Apache header block (JS /* ... */) --- const V1_APACHE = `/* * Copyright 2025 John G Stroh * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */`; const V1_EUPL = `/* * Copyright 2025 John G Stroh * * Licensed under the European Union Public Licence, Version 1.2 (EUPL-1.2); * you may not use this file except in compliance with the Licence. * * You may obtain a copy of the Licence at: * https://interoperable-europe.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * * Unless required by applicable law or agreed to in writing, software * distributed under the Licence is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the Licence for the specific language governing permissions and * limitations under the Licence. */`; // --- Variant 2: Inline JSDoc license lines (inside descriptive block) --- const V2_APACHE = ` * Copyright 2025 Tractatus Project\n * Licensed under Apache License 2.0`; const V2_EUPL = ` * Copyright 2025 Tractatus Project\n * Licensed under the European Union Public Licence, v. 1.2 (EUPL-1.2)`; // --- Variant 3: Python docstring License line --- const V3_APACHE = `License: Apache 2.0`; const V3_EUPL = `License: EUPL-1.2`; // --- Variant 4: al-integration/README.md — bare "Apache 2.0" under "## License" heading --- const V4_APACHE = `## License\n\nApache 2.0`; const V4_EUPL = `## License\n\nEUPL-1.2`; const FILES = [ // Variant 1 expected — full Apache block (12 JS files) 'src/routes/audit.routes.js', 'src/controllers/audit.controller.js', 'src/services/AdaptiveCommunicationOrchestrator.service.js', 'src/services/InstructionPersistenceClassifier.service.js', 'src/services/MetacognitiveVerifier.service.js', 'src/services/ContextPressureMonitor.service.js', 'src/services/BoundaryEnforcer.service.js', 'src/services/CrossReferenceValidator.service.js', 'src/services/PluralisticDeliberationOrchestrator.service.js', 'src/utils/attack-surface-validator.util.js', 'src/utils/activity-classifier.util.js', 'src/utils/audit-sanitizer.util.js', // Variant 2 expected — inline JSDoc license lines (4 JS files) 'src/routes/calendar.routes.js', 'src/models/ScheduledTask.model.js', 'src/models/SyncMetadata.model.js', 'src/models/MissedBreach.model.js', // Variant 3 expected — Python docstring (4 files) 'al-integration/testing/stress_test.py', 'al-integration/testing/stress_test_vllm.py', 'al-integration/training/train_analyzer.py', 'al-integration/agents/feedback_analyzer.py', // Variant 4 expected — al-integration README (1 file) 'al-integration/README.md', ]; function processFile(relPath) { const fullPath = path.join(REPO_ROOT, relPath); if (!fs.existsSync(fullPath)) { return { status: 'NOT_FOUND', variants: [] }; } let content = fs.readFileSync(fullPath, 'utf8'); const original = content; const variants = []; if (content.includes(V1_APACHE)) { content = content.replace(V1_APACHE, V1_EUPL); variants.push('V1'); } if (content.includes(V2_APACHE)) { content = content.replace(V2_APACHE, V2_EUPL); variants.push('V2'); } if (content.includes(V3_APACHE)) { content = content.replace(V3_APACHE, V3_EUPL); variants.push('V3'); } if (content.includes(V4_APACHE)) { content = content.replace(V4_APACHE, V4_EUPL); variants.push('V4'); } if (content === original) { return { status: 'NO_MATCH', variants: [] }; } if (!DRY_RUN) { fs.writeFileSync(fullPath, content, 'utf8'); } return { status: 'CHANGED', variants }; } const results = FILES.map((f) => ({ path: f, ...processFile(f) })); console.log(`${DRY_RUN ? '[DRY RUN] ' : ''}Relicense Apache 2.0 → EUPL-1.2 — ${FILES.length} files in scope\n`); const changed = results.filter((r) => r.status === 'CHANGED'); const noMatch = results.filter((r) => r.status === 'NO_MATCH'); const notFound = results.filter((r) => r.status === 'NOT_FOUND'); changed.forEach((r) => console.log(` CHANGED [${r.variants.join(',')}] ${r.path}`)); noMatch.forEach((r) => console.log(` NO_MATCH (check patterns) ${r.path}`)); notFound.forEach((r) => console.log(` NOT_FOUND ${r.path}`)); console.log(`\nSummary: ${changed.length} changed / ${noMatch.length} no-match / ${notFound.length} not-found (total ${FILES.length}).`); if (DRY_RUN) { console.log('\nDRY-RUN: no files written. Re-run without --dry-run to apply.'); } process.exit(noMatch.length > 0 || notFound.length > 0 ? 1 : 0);