chore: pin npm deps, quiet install, validate exact versions
Made-with: Cursor
This commit is contained in:
3
client/.npmrc
Normal file
3
client/.npmrc
Normal file
@@ -0,0 +1,3 @@
|
||||
save-exact=true
|
||||
fund=false
|
||||
audit=false
|
||||
36
client/package-lock.json
generated
36
client/package-lock.json
generated
@@ -8,26 +8,26 @@
|
||||
"name": "client",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.1",
|
||||
"@mui/material": "^7.3.9",
|
||||
"keycloak-js": "^26.2.3",
|
||||
"ra-data-simple-rest": "^5.14.4",
|
||||
"react": "^18.2.0",
|
||||
"react-admin": "^5.14.4",
|
||||
"react-dom": "^18.2.0"
|
||||
"@emotion/react": "11.14.0",
|
||||
"@emotion/styled": "11.14.1",
|
||||
"@mui/material": "7.3.9",
|
||||
"keycloak-js": "26.2.3",
|
||||
"ra-data-simple-rest": "5.14.4",
|
||||
"react": "18.3.1",
|
||||
"react-admin": "5.14.4",
|
||||
"react-dom": "18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.55",
|
||||
"@types/react-dom": "^18.2.19",
|
||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||
"@typescript-eslint/parser": "^6.21.0",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.5",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^5.1.0"
|
||||
"@types/react": "18.3.28",
|
||||
"@types/react-dom": "18.3.7",
|
||||
"@typescript-eslint/eslint-plugin": "6.21.0",
|
||||
"@typescript-eslint/parser": "6.21.0",
|
||||
"@vitejs/plugin-react": "4.7.0",
|
||||
"eslint": "8.57.1",
|
||||
"eslint-plugin-react-hooks": "4.6.2",
|
||||
"eslint-plugin-react-refresh": "0.4.26",
|
||||
"typescript": "5.9.3",
|
||||
"vite": "5.4.21"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
|
||||
@@ -10,25 +10,25 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.14.0",
|
||||
"@emotion/styled": "^11.14.1",
|
||||
"@mui/material": "^7.3.9",
|
||||
"keycloak-js": "^26.2.3",
|
||||
"ra-data-simple-rest": "^5.14.4",
|
||||
"react": "^18.2.0",
|
||||
"react-admin": "^5.14.4",
|
||||
"react-dom": "^18.2.0"
|
||||
"@emotion/react": "11.14.0",
|
||||
"@emotion/styled": "11.14.1",
|
||||
"@mui/material": "7.3.9",
|
||||
"keycloak-js": "26.2.3",
|
||||
"ra-data-simple-rest": "5.14.4",
|
||||
"react": "18.3.1",
|
||||
"react-admin": "5.14.4",
|
||||
"react-dom": "18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.55",
|
||||
"@types/react-dom": "^18.2.19",
|
||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||
"@typescript-eslint/parser": "^6.21.0",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.5",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^5.1.0"
|
||||
"@types/react": "18.3.28",
|
||||
"@types/react-dom": "18.3.7",
|
||||
"@typescript-eslint/eslint-plugin": "6.21.0",
|
||||
"@typescript-eslint/parser": "6.21.0",
|
||||
"@vitejs/plugin-react": "4.7.0",
|
||||
"eslint": "8.57.1",
|
||||
"eslint-plugin-react-hooks": "4.6.2",
|
||||
"eslint-plugin-react-refresh": "0.4.26",
|
||||
"typescript": "5.9.3",
|
||||
"vite": "5.4.21"
|
||||
}
|
||||
}
|
||||
|
||||
5
generation/context/dependency-pins.md
Normal file
5
generation/context/dependency-pins.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Зависимости workspace (зафиксированные версии)
|
||||
|
||||
- Рабочие манифесты: **`server/package.json`**, **`client/package.json`** — прямые зависимости **без** префиксов `^` / `~`; точные версии синхронизированы с **`package-lock.json`** (скрипт `tools/pin-package-versions.mjs`).
|
||||
- После добавления пакета: `npm install <pkg>` в `server/` или `client/` (с `save-exact` в `.npmrc`), затем при необходимости снова **`node tools/pin-package-versions.mjs server|client`** и коммит обоих файлов.
|
||||
- Генератор **`generation/generate.mjs`** не перезаписывает `package.json`; агенты не должны ослаблять диапазоны версий при правках кода.
|
||||
@@ -2,6 +2,7 @@
|
||||
"name": "toir-generation-context",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"pin:deps": "node tools/pin-package-versions.mjs server && node tools/pin-package-versions.mjs client",
|
||||
"generate:domain-summary": "node tools/generate-domain-summary.mjs",
|
||||
"validate:generation": "node tools/validate-generation.mjs",
|
||||
"validate:generation:runtime": "node tools/validate-generation.mjs --run-runtime",
|
||||
|
||||
@@ -30,6 +30,7 @@ Validation is now a lightweight automated gate instead of a prose-only checklist
|
||||
- generation must not pass validation if framework scaffolding files were deleted and replaced by a hand-written minimal skeleton
|
||||
- if dependencies are installed, build verification runs for `server/` and `client/`
|
||||
- if dependencies are missing, build verification is reported as skipped with reason instead of green
|
||||
- `server/package.json` and `client/package.json`: every entry in `dependencies`, `devDependencies`, `optionalDependencies`, and `peerDependencies` must use an exact version string (no `^` or `~` prefix)
|
||||
|
||||
### Auth checks
|
||||
|
||||
|
||||
3
server/.npmrc
Normal file
3
server/.npmrc
Normal file
@@ -0,0 +1,3 @@
|
||||
save-exact=true
|
||||
fund=false
|
||||
audit=false
|
||||
64
server/package-lock.json
generated
64
server/package-lock.json
generated
@@ -10,40 +10,40 @@
|
||||
"hasInstallScript": true,
|
||||
"license": "UNLICENSED",
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/config": "^4.0.3",
|
||||
"@nestjs/core": "^10.0.0",
|
||||
"@nestjs/platform-express": "^10.0.0",
|
||||
"@prisma/client": "^5.22.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.1",
|
||||
"jose": "^6.2.2",
|
||||
"reflect-metadata": "^0.2.0",
|
||||
"rxjs": "^7.8.1"
|
||||
"@nestjs/common": "10.4.22",
|
||||
"@nestjs/config": "4.0.3",
|
||||
"@nestjs/core": "10.4.22",
|
||||
"@nestjs/platform-express": "10.4.22",
|
||||
"@prisma/client": "5.22.0",
|
||||
"class-transformer": "0.5.1",
|
||||
"class-validator": "0.14.4",
|
||||
"jose": "6.2.2",
|
||||
"reflect-metadata": "0.2.2",
|
||||
"rxjs": "7.8.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^10.0.0",
|
||||
"@nestjs/schematics": "^10.0.0",
|
||||
"@nestjs/testing": "^10.0.0",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/node": "^20.3.1",
|
||||
"@types/supertest": "^6.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"eslint": "^8.0.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"jest": "^29.5.0",
|
||||
"prettier": "^3.0.0",
|
||||
"prisma": "^5.22.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"supertest": "^7.0.0",
|
||||
"ts-jest": "^29.1.0",
|
||||
"ts-loader": "^9.4.3",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"typescript": "^5.1.3"
|
||||
"@nestjs/cli": "10.4.9",
|
||||
"@nestjs/schematics": "10.2.3",
|
||||
"@nestjs/testing": "10.4.22",
|
||||
"@types/express": "5.0.6",
|
||||
"@types/jest": "29.5.14",
|
||||
"@types/node": "20.19.37",
|
||||
"@types/supertest": "6.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "8.57.0",
|
||||
"@typescript-eslint/parser": "8.57.0",
|
||||
"eslint": "8.57.1",
|
||||
"eslint-config-prettier": "9.1.2",
|
||||
"eslint-plugin-prettier": "5.5.5",
|
||||
"jest": "29.7.0",
|
||||
"prettier": "3.8.1",
|
||||
"prisma": "5.22.0",
|
||||
"source-map-support": "0.5.21",
|
||||
"supertest": "7.2.2",
|
||||
"ts-jest": "29.4.6",
|
||||
"ts-loader": "9.5.4",
|
||||
"ts-node": "10.9.2",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"typescript": "5.9.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular-devkit/core": {
|
||||
|
||||
@@ -26,40 +26,40 @@
|
||||
"seed": "ts-node prisma/seed.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/config": "^4.0.3",
|
||||
"@nestjs/core": "^10.0.0",
|
||||
"@nestjs/platform-express": "^10.0.0",
|
||||
"@prisma/client": "^5.22.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.1",
|
||||
"jose": "^6.2.2",
|
||||
"reflect-metadata": "^0.2.0",
|
||||
"rxjs": "^7.8.1"
|
||||
"@nestjs/common": "10.4.22",
|
||||
"@nestjs/config": "4.0.3",
|
||||
"@nestjs/core": "10.4.22",
|
||||
"@nestjs/platform-express": "10.4.22",
|
||||
"@prisma/client": "5.22.0",
|
||||
"class-transformer": "0.5.1",
|
||||
"class-validator": "0.14.4",
|
||||
"jose": "6.2.2",
|
||||
"reflect-metadata": "0.2.2",
|
||||
"rxjs": "7.8.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^10.0.0",
|
||||
"@nestjs/schematics": "^10.0.0",
|
||||
"@nestjs/testing": "^10.0.0",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/node": "^20.3.1",
|
||||
"@types/supertest": "^6.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"eslint": "^8.0.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"jest": "^29.5.0",
|
||||
"prettier": "^3.0.0",
|
||||
"prisma": "^5.22.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"supertest": "^7.0.0",
|
||||
"ts-jest": "^29.1.0",
|
||||
"ts-loader": "^9.4.3",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"typescript": "^5.1.3"
|
||||
"@nestjs/cli": "10.4.9",
|
||||
"@nestjs/schematics": "10.2.3",
|
||||
"@nestjs/testing": "10.4.22",
|
||||
"@types/express": "5.0.6",
|
||||
"@types/jest": "29.5.14",
|
||||
"@types/node": "20.19.37",
|
||||
"@types/supertest": "6.0.3",
|
||||
"@typescript-eslint/eslint-plugin": "8.57.0",
|
||||
"@typescript-eslint/parser": "8.57.0",
|
||||
"eslint": "8.57.1",
|
||||
"eslint-config-prettier": "9.1.2",
|
||||
"eslint-plugin-prettier": "5.5.5",
|
||||
"jest": "29.7.0",
|
||||
"prettier": "3.8.1",
|
||||
"prisma": "5.22.0",
|
||||
"source-map-support": "0.5.21",
|
||||
"supertest": "7.2.2",
|
||||
"ts-jest": "29.4.6",
|
||||
"ts-loader": "9.5.4",
|
||||
"ts-node": "10.9.2",
|
||||
"tsconfig-paths": "4.2.0",
|
||||
"typescript": "5.9.3"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
|
||||
44
tools/pin-package-versions.mjs
Normal file
44
tools/pin-package-versions.mjs
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Записывает в package.json точные версии прямых зависимостей из package-lock.json (lockfile v3).
|
||||
* Использование: node tools/pin-package-versions.mjs server
|
||||
* node tools/pin-package-versions.mjs client
|
||||
*/
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
const dir = process.argv[2];
|
||||
if (!dir || !['server', 'client'].includes(dir)) {
|
||||
console.error('Usage: node tools/pin-package-versions.mjs <server|client>');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const root = path.resolve(process.cwd(), dir);
|
||||
const lockPath = path.join(root, 'package-lock.json');
|
||||
const pkgPath = path.join(root, 'package.json');
|
||||
|
||||
if (!fs.existsSync(lockPath)) {
|
||||
console.error(`Missing ${lockPath}. Run npm install in ${dir}/ first.`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const lock = JSON.parse(fs.readFileSync(lockPath, 'utf8'));
|
||||
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
||||
|
||||
function pinSection(section) {
|
||||
if (!section) return;
|
||||
for (const name of Object.keys(section)) {
|
||||
const lockKey = `node_modules/${name}`;
|
||||
const entry = lock.packages?.[lockKey];
|
||||
if (!entry?.version) {
|
||||
console.error(`Missing lock entry for ${lockKey}`);
|
||||
process.exit(1);
|
||||
}
|
||||
section[name] = entry.version;
|
||||
}
|
||||
}
|
||||
|
||||
pinSection(pkg.dependencies);
|
||||
pinSection(pkg.devDependencies);
|
||||
|
||||
fs.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
|
||||
console.log(`Pinned ${dir}/package.json from package-lock.json`);
|
||||
@@ -181,6 +181,26 @@ function validateBuildChecks() {
|
||||
assertCondition(Boolean(clientPackage.devDependencies?.vite), 'client/package.json must keep Vite as a dev dependency');
|
||||
assertCondition(Boolean(clientPackage.devDependencies?.['@vitejs/plugin-react']), 'client/package.json must keep @vitejs/plugin-react as a dev dependency');
|
||||
}
|
||||
|
||||
validatePinnedPackageJsonVersions();
|
||||
}
|
||||
|
||||
function validatePinnedPackageJsonVersions() {
|
||||
for (const rel of ['server/package.json', 'client/package.json']) {
|
||||
const pkg = parseJson(rel);
|
||||
if (!pkg) continue;
|
||||
for (const section of ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies']) {
|
||||
const deps = pkg[section];
|
||||
if (!deps || typeof deps !== 'object') continue;
|
||||
for (const [name, ver] of Object.entries(deps)) {
|
||||
if (typeof ver !== 'string') continue;
|
||||
assertCondition(
|
||||
!/^[\^~]/.test(ver),
|
||||
`${rel} ${section}.${name} must be pinned (no ^ or ~): got ${ver}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function validateAuthChecks() {
|
||||
|
||||
Reference in New Issue
Block a user