takt/src/infra/config/project/projectConfigTransforms.ts
nrslib a8223d231d refactor: config 3層モデル整理 + supervisor ペルソナのファセット分離是正
Config:
- PersistedGlobalConfig → GlobalConfig にリネーム、互換エイリアス削除
- persisted-global-config.ts → config-types.ts にリネーム
- ProjectConfig → GlobalConfig extends Omit<ProjectConfig, ...> の継承構造に整理
- verbose/logLevel/log_level を削除(logging セクションに統一)
- migration 機構(migratedProjectLocalKeys 等)を削除

Supervisor ペルソナ:
- 後方互換コードの検出・その場しのぎの検出・ボーイスカウトルールを除去(review.md ポリシー / architecture.md ナレッジと重複)
- ピース全体の見直しを supervise.md インストラクションに移動

takt-default-team-leader:
- loop_monitor のインライン instruction_template を既存ファイル参照に変更
- implement の「判断できない」ルールを ai_review → plan に修正
2026-03-06 01:29:46 +09:00

76 lines
2.8 KiB
TypeScript

import type { AnalyticsConfig, SubmoduleSelection } from '../../../core/models/config-types.js';
const SUBMODULES_ALL = 'all';
export function normalizeSubmodules(raw: unknown): SubmoduleSelection | undefined {
if (raw === undefined) return undefined;
if (typeof raw === 'string') {
const normalized = raw.trim().toLowerCase();
if (normalized === SUBMODULES_ALL) {
return SUBMODULES_ALL;
}
throw new Error('Invalid submodules: string value must be "all"');
}
if (Array.isArray(raw)) {
if (raw.length === 0) {
throw new Error('Invalid submodules: explicit path list must not be empty');
}
const normalizedPaths = raw.map((entry) => {
if (typeof entry !== 'string') {
throw new Error('Invalid submodules: path entries must be strings');
}
const trimmed = entry.trim();
if (trimmed.length === 0) {
throw new Error('Invalid submodules: path entries must not be empty');
}
if (trimmed.includes('*')) {
throw new Error(`Invalid submodules: wildcard is not supported (${trimmed})`);
}
return trimmed;
});
return normalizedPaths;
}
throw new Error('Invalid submodules: must be "all" or an explicit path list');
}
export function normalizeWithSubmodules(raw: unknown): boolean | undefined {
if (raw === undefined) return undefined;
if (typeof raw === 'boolean') return raw;
throw new Error('Invalid with_submodules: value must be boolean');
}
export function normalizeAnalytics(raw: Record<string, unknown> | undefined): AnalyticsConfig | undefined {
if (!raw) return undefined;
const enabled = typeof raw.enabled === 'boolean' ? raw.enabled : undefined;
const eventsPath = typeof raw.events_path === 'string'
? raw.events_path
: (typeof raw.eventsPath === 'string' ? raw.eventsPath : undefined);
const retentionDays = typeof raw.retention_days === 'number'
? raw.retention_days
: (typeof raw.retentionDays === 'number' ? raw.retentionDays : undefined);
if (enabled === undefined && eventsPath === undefined && retentionDays === undefined) {
return undefined;
}
return { enabled, eventsPath, retentionDays };
}
export function denormalizeAnalytics(config: AnalyticsConfig | undefined): Record<string, unknown> | undefined {
if (!config) return undefined;
const raw: Record<string, unknown> = {};
if (config.enabled !== undefined) raw.enabled = config.enabled;
if (config.eventsPath) raw.events_path = config.eventsPath;
if (config.retentionDays !== undefined) raw.retention_days = config.retentionDays;
return Object.keys(raw).length > 0 ? raw : undefined;
}
export function formatIssuePath(path: readonly PropertyKey[]): string {
if (path.length === 0) return '(root)';
return path.map((segment) => String(segment)).join('.');
}