/** * socle-version.ts — read the SmartStack platform (socle) version a generated * client project builds against, and compare it to capability floors. * * The version is the `` * of the client's csproj files (`ss init` pins it; `ss upgrade` bumps it). * * First consumer: the core-lookups BRIDGE (`scaffold-core-lookups`). The * platform serves NO `/api/core/{catalogue}/lookup` today, so the CLI * scaffolds a client-side bridge controller — and must RETIRE it the day the * socle ships the endpoints (an AmbiguousMatchException otherwise). Flipping * `MIN_SOCLE_CORE_LOOKUPS_VERSION` to the real release is the ONE change that * arms the retirement path (validate refuses `ensure`, DEV-API-027 errs on a * lingering bridge). */ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs' import { join } from 'node:path' /** Socle release that serves GET /api/core/{users,departments,offices,…}/lookup * natively. Placeholder until the SmartStack.app chantier ships — flip to the * real version then. */ export const MIN_SOCLE_CORE_LOOKUPS_VERSION = '99.0.0' /** Socle release that ships ISuppliedCodeGuard + the /api/codes endpoints * (introduced by SmartStack.app commit fd684568, 2026-08-27, released in * 3.66.0 — pinned against the socle git history, the CHANGELOG does not * trace it). Floor of the coded-entities `surchargeable à la création` * facet: scaffold-business fail-closes below it (the generated guard call * would not compile), DEV-API-022's supplied legs skip with a warn. */ export const MIN_SOCLE_SUPPLIED_CODE_VERSION = '3.66.0' const PACKAGE_RE = / Number(b.includes('.Api')) - Number(a.includes('.Api'))) for (const abs of candidates) { const m = PACKAGE_RE.exec(readFileSync(abs, 'utf-8')) if (m) return m[1] } return null } /** Loose semver ≥ compare (numeric segments; missing segments = 0). */ export function socleAtLeast(version: string | null, floor: string): boolean { if (version === null) return false const a = version.split('.').map(s => parseInt(s, 10) || 0) const b = floor.split('.').map(s => parseInt(s, 10) || 0) for (let i = 0; i < Math.max(a.length, b.length); i++) { const x = a[i] ?? 0 const y = b[i] ?? 0 if (x !== y) return x > y } return true }