- Initialize .sdlc/ with config, guidance, and state machine - Register M0-M8 as released milestones (full engine track history) - Seed M9 (Community Sync & Revocation) and M10 (Governance & Agent Rights) with features - Seed product milestones P0-P4 and PG1 gate with features from existing planning docs - Add Team section to AGENTS.md (tidal-engineer, tidal-visionary, tidal-researcher, tidal-storyteller) - Add knowledge-librarian agent for .sdlc/knowledge/ curation - Gitignore .sdlc/telemetry.redb (volatile binary state) - Add .ai/ scaffold (project knowledge index)
45 lines
1.5 KiB
TypeScript
45 lines
1.5 KiB
TypeScript
/**
|
|
* SDLC Tool Config Loader
|
|
*
|
|
* Reads .sdlc/tools/<name>/config.yaml. If the file is missing or unparseable,
|
|
* returns the provided defaults — tools should never hard-fail on missing config.
|
|
*
|
|
* Supports flat key: value YAML only. Arrays and nested objects are intentionally
|
|
* not supported — keep tool configs simple scalars.
|
|
*/
|
|
import { readFileSync } from 'node:fs'
|
|
import { join } from 'node:path'
|
|
|
|
export function loadToolConfig<T extends Record<string, unknown>>(
|
|
root: string,
|
|
toolName: string,
|
|
defaults: T,
|
|
): T {
|
|
const configPath = join(root, '.sdlc', 'tools', toolName, 'config.yaml')
|
|
try {
|
|
const raw = readFileSync(configPath, 'utf8')
|
|
const parsed = parseSimpleYaml(raw)
|
|
return { ...defaults, ...parsed } as T
|
|
} catch {
|
|
return defaults
|
|
}
|
|
}
|
|
|
|
/** Parse a flat key: value YAML file. Skips blank lines, comments, and array items. */
|
|
function parseSimpleYaml(content: string): Record<string, unknown> {
|
|
const result: Record<string, unknown> = {}
|
|
for (const line of content.split('\n')) {
|
|
const trimmed = line.trim()
|
|
if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith('-')) continue
|
|
const colonIdx = trimmed.indexOf(':')
|
|
if (colonIdx === -1) continue
|
|
const key = trimmed.slice(0, colonIdx).trim()
|
|
const rawValue = trimmed.slice(colonIdx + 1).trim()
|
|
if (!key || !rawValue) continue
|
|
const value = rawValue.replace(/^["'](.*)["']$/, '$1')
|
|
const num = Number(value)
|
|
result[key] = Number.isNaN(num) ? value : num
|
|
}
|
|
return result
|
|
}
|