/**
* 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
}