Some checks failed
ci / Validate workspace (push) Successful in 12m32s
landing-page-ci / Validate landing page (push) Successful in 9m41s
landing-page-deploy / Deploy landing page (push) Failing after 5m23s
github-metrics / Generate repository metrics SVG (push) Failing after 2m3s
refresh-contributors-wall / Refresh contributors wall cache bust (push) Failing after 11s
This repository contains the open-design daemon CLI source code, built and packaged at https://helix-mind.ai/cli/open-design/latest.tgz for use by the HelixMind /design slash command. Licenses: Apache-2.0 (root) + MIT (skills/*)
89 lines
3.6 KiB
TypeScript
89 lines
3.6 KiB
TypeScript
import { defaultCritiqueConfig, FALLBACK_POLICIES } from '@open-design/contracts/critique';
|
|
import type { CritiqueConfig } from '@open-design/contracts/critique';
|
|
|
|
/**
|
|
* Load CritiqueConfig from process.env. Keys map 1:1 to OD_CRITIQUE_*.
|
|
* Missing values fall back to defaultCritiqueConfig(). Invalid values
|
|
* (non-numeric, negative, out-of-range) throw RangeError so misconfig
|
|
* surfaces at boot, never silently.
|
|
*
|
|
* @see specs/current/critique-theater.md § Configuration (env vars)
|
|
*/
|
|
export function loadCritiqueConfigFromEnv(env: NodeJS.ProcessEnv = process.env): CritiqueConfig {
|
|
const defaults = defaultCritiqueConfig();
|
|
|
|
const enabled = parseEnabled(env['OD_CRITIQUE_ENABLED'], defaults.enabled);
|
|
const maxRounds = parsePositiveInt('OD_CRITIQUE_MAX_ROUNDS', env['OD_CRITIQUE_MAX_ROUNDS'], defaults.maxRounds);
|
|
const scoreThreshold = parseNonNegativeFloat('OD_CRITIQUE_SCORE_THRESHOLD', env['OD_CRITIQUE_SCORE_THRESHOLD'], defaults.scoreThreshold);
|
|
const scoreScale = parsePositiveInt('OD_CRITIQUE_SCORE_SCALE', env['OD_CRITIQUE_SCORE_SCALE'], defaults.scoreScale);
|
|
const perRoundTimeoutMs = parsePositiveInt('OD_CRITIQUE_PER_ROUND_TIMEOUT_MS', env['OD_CRITIQUE_PER_ROUND_TIMEOUT_MS'], defaults.perRoundTimeoutMs);
|
|
const totalTimeoutMs = parsePositiveInt('OD_CRITIQUE_TOTAL_TIMEOUT_MS', env['OD_CRITIQUE_TOTAL_TIMEOUT_MS'], defaults.totalTimeoutMs);
|
|
const parserMaxBlockBytes = parsePositiveInt('OD_CRITIQUE_PARSER_MAX_BLOCK_BYTES', env['OD_CRITIQUE_PARSER_MAX_BLOCK_BYTES'], defaults.parserMaxBlockBytes);
|
|
const fallbackPolicy = parseFallbackPolicy(env['OD_CRITIQUE_FALLBACK_POLICY'], defaults.fallbackPolicy);
|
|
|
|
// Cross-field validation: threshold cannot exceed scale.
|
|
if (scoreThreshold > scoreScale + 1e-9) {
|
|
throw new RangeError(
|
|
`OD_CRITIQUE_SCORE_THRESHOLD (${scoreThreshold}) must be <= OD_CRITIQUE_SCORE_SCALE (${scoreScale})`,
|
|
);
|
|
}
|
|
|
|
return {
|
|
...defaults,
|
|
enabled,
|
|
maxRounds,
|
|
scoreThreshold,
|
|
scoreScale,
|
|
perRoundTimeoutMs,
|
|
totalTimeoutMs,
|
|
parserMaxBlockBytes,
|
|
fallbackPolicy,
|
|
};
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Parsing helpers
|
|
// ---------------------------------------------------------------------------
|
|
|
|
function parseEnabled(raw: string | undefined, fallback: boolean): boolean {
|
|
if (raw === undefined) return fallback;
|
|
const v = raw.trim().toLowerCase();
|
|
return v === 'true' || v === '1' || v === 'yes';
|
|
}
|
|
|
|
function parsePositiveInt(key: string, raw: string | undefined, fallback: number): number {
|
|
if (raw === undefined) return fallback;
|
|
const n = Number(raw);
|
|
if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {
|
|
throw new RangeError(
|
|
`${key} must be a positive integer, got "${raw}"`,
|
|
);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
function parseNonNegativeFloat(key: string, raw: string | undefined, fallback: number): number {
|
|
if (raw === undefined) return fallback;
|
|
const n = Number(raw);
|
|
if (!Number.isFinite(n) || n < 0) {
|
|
throw new RangeError(
|
|
`${key} must be a non-negative finite number, got "${raw}"`,
|
|
);
|
|
}
|
|
return n;
|
|
}
|
|
|
|
function parseFallbackPolicy(
|
|
raw: string | undefined,
|
|
fallback: CritiqueConfig['fallbackPolicy'],
|
|
): CritiqueConfig['fallbackPolicy'] {
|
|
if (raw === undefined) return fallback;
|
|
const trimmed = raw.trim();
|
|
if (FALLBACK_POLICIES.includes(trimmed as CritiqueConfig['fallbackPolicy'])) {
|
|
return trimmed as CritiqueConfig['fallbackPolicy'];
|
|
}
|
|
throw new RangeError(
|
|
`OD_CRITIQUE_FALLBACK_POLICY must be one of ${FALLBACK_POLICIES.join(', ')}, got "${raw}"`,
|
|
);
|
|
}
|